diff --git a/hardhat.config.ts b/hardhat.config.ts index a3c27460..5b1668eb 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -1,5 +1,6 @@ import '@typechain/hardhat'; import '@nomiclabs/hardhat-truffle5'; +import '@nomicfoundation/hardhat-chai-matchers'; import 'hardhat-gas-reporter'; require('solidity-coverage'); // require because no TS typings available import dotenv from 'dotenv'; @@ -24,7 +25,7 @@ const config: HardhatUserConfig = { currency: 'USD', }, typechain: { - target: 'truffle-v5', + target: 'ethers-v5', }, }; diff --git a/package.json b/package.json index b0c48464..7bad0e31 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,6 @@ "dependencies": { "@metamask/eth-sig-util": "4.0.1", "@openzeppelin/contracts": "4.7.3", - "@openzeppelin/test-helpers": "0.5.16", "bn.js": "5.2.1", "chai": "4.3.6", "chai-as-promised": "7.1.1", @@ -37,16 +36,19 @@ "web3-utils": "1.8.0" }, "devDependencies": { + "@nomicfoundation/hardhat-chai-matchers": "1.0.3", + "@nomicfoundation/hardhat-network-helpers": "1.0.6", "@nomiclabs/hardhat-truffle5": "2.0.7", "@nomiclabs/hardhat-web3": "2.0.0", + "@nomiclabs/hardhat-ethers": "2.1.1", "@typechain/hardhat": "6.1.3", - "@typechain/truffle-v5": "7.0.0", + "@typechain/ethers-v5": "10.1.0", "@types/chai": "4.3.3", "@types/chai-as-promised": "7.1.5", "@types/eth-sig-util": "2.1.1", "@types/ethereumjs-util": "6.1.0", "@types/mocha": "9.1.1", - "@types/node": "18.7.18", + "@types/node": "18.7.21", "@typescript-eslint/eslint-plugin": "5.38.0", "@typescript-eslint/parser": "5.38.0", "acquit": "1.2.1", @@ -61,6 +63,7 @@ "eslint-plugin-promise": "6.0.1", "eslint-plugin-standard": "5.0.0", "ethereumjs-wallet": "1.0.2", + "ethers": "5.7.1", "hardhat": "2.11.2", "hardhat-gas-reporter": "1.0.9", "rimraf": "3.0.2", @@ -68,7 +71,7 @@ "solhint": "3.3.7", "solidity-coverage": "0.8.2", "ts-node": "10.9.1", - "typechain": "7.0.1", + "typechain": "8.1.0", "typescript": "4.8.3" }, "bin": { diff --git a/src/asserts.ts b/src/asserts.ts index 2b5a78a5..afd23c1b 100644 --- a/src/asserts.ts +++ b/src/asserts.ts @@ -1,32 +1,22 @@ -import { expect, toBN } from './prelude'; -import BN from 'bn.js'; +import { expect } from './prelude'; -export function toBNExtended (value: string | number | BN): BN { - if (typeof value === 'string' || typeof value === 'number') { - return toBN(value); - } - return value; -} - -export function assertRoughlyEqualValues (expected: string | number | BN, actual: string | number | BN, relativeDiff: number) { - let expectedBN = toBNExtended(expected); - let actualBN = toBNExtended(actual); - if (expectedBN.isNeg() !== actualBN.isNeg()) { - expect(actualBN).to.be.bignumber.equal(expectedBN, 'Values are of different sign'); - } +export function assertRoughlyEqualValues (expected: string | number | bigint, actual: string | number | bigint, relativeDiff: number) { + let expectedBN = BigInt(expected); + let actualBN = BigInt(actual); + expect(expectedBN * actualBN).to.be.gte(0, 'Values are of different sign'); - expectedBN = expectedBN.abs(); - actualBN = actualBN.abs(); + if (expectedBN < 0) expectedBN = -expectedBN; + if (actualBN < 0) actualBN = -actualBN; let multiplerNumerator = relativeDiff; - let multiplerDenominator = toBN('1'); + let multiplerDenominator = 1n; while (!Number.isInteger(multiplerNumerator)) { - multiplerDenominator = multiplerDenominator.mul(toBN('10')); + multiplerDenominator = multiplerDenominator * 10n; multiplerNumerator *= 10; } - const diff = expectedBN.sub(actualBN).abs(); - const treshold = expectedBN.mul(toBN(multiplerNumerator.toString())).div(multiplerDenominator); - if (!diff.lte(treshold)) { - expect(actualBN).to.be.bignumber.equal(expectedBN, `${actual} != ${expected} with ${relativeDiff} precision`); + const diff = expectedBN > actualBN ? expectedBN - actualBN : actualBN - expectedBN; + const treshold = expectedBN * BigInt(multiplerNumerator) / multiplerDenominator; + if (diff > treshold) { + expect(actualBN).to.be.equal(expectedBN, `${actual} != ${expected} with ${relativeDiff} precision`); } } diff --git a/src/permit.ts b/src/permit.ts index 19b76f52..b5b3eb3b 100644 --- a/src/permit.ts +++ b/src/permit.ts @@ -1,8 +1,9 @@ -import { MessageTypes, signTypedData, SignTypedDataVersion, TypedDataUtils, TypedMessage } from '@metamask/eth-sig-util'; +import { SignTypedDataVersion, TypedDataUtils } from '@metamask/eth-sig-util'; import { fromRpcSig } from 'ethereumjs-util'; import { Token } from './utils'; import { constants } from './prelude'; - +import { CallOverrides, BigNumber } from 'ethers'; +import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; export const TypedDataVersion = SignTypedDataVersion.V4; export const defaultDeadline = constants.MAX_UINT256; @@ -30,7 +31,7 @@ export const DaiLikePermit = [ { name: 'allowed', type: 'bool' }, ]; -export function trim0x (bigNumber: BN | string) { +export function trim0x (bigNumber: bigint | string) { const s = bigNumber.toString(); if (s.startsWith('0x')) { return s.substring(2); @@ -61,11 +62,10 @@ export function buildData ( spender: string, value: string, nonce: string, - deadline: string = defaultDeadline + deadline: string = defaultDeadline.toString() ) { return { - primaryType: 'Permit', - types: { EIP712Domain, Permit }, + types: { Permit }, domain: { name, version, chainId, verifyingContract }, message: { owner, spender, value, nonce, deadline }, } as const; @@ -80,45 +80,38 @@ export function buildDataLikeDai ( spender: string, nonce: string, allowed: boolean, - expiry: string = defaultDeadline + expiry: string = defaultDeadline.toString() ) { return { - primaryType: 'Permit', - types: { EIP712Domain, Permit: DaiLikePermit }, + types: { Permit: DaiLikePermit }, domain: { name, version, chainId, verifyingContract }, message: { holder, spender, nonce, expiry, allowed }, } as const; } export interface PermittableToken extends Token { - nonces(owner: string, txDetails?: Truffle.TransactionDetails): Promise; - name(txDetails?: Truffle.TransactionDetails): Promise; -} - -export function signWithPk (privateKey: Buffer | string, data: TypedMessage) { - const buffer = Buffer.isBuffer(privateKey) ? privateKey : Buffer.from(trim0x(privateKey), 'hex'); - return signTypedData({ privateKey: buffer, data, version: TypedDataVersion }); + nonces(owner: string, overrides?: CallOverrides): Promise; + name(overrides?: CallOverrides): Promise; } /* * @param permitContract The contract object with ERC20Permit type and token address for which the permit creating. */ export async function getPermit ( - owner: string, - ownerPrivateKey: string, + owner: SignerWithAddress, permitContract: PermittableToken, tokenVersion: string, chainId: number, spender: string, value: string, - deadline = defaultDeadline + deadline = defaultDeadline.toString() ) { - const nonce = await permitContract.nonces(owner); + const nonce = await permitContract.nonces(owner.address); const name = await permitContract.name(); - const data = buildData(name, tokenVersion, chainId, permitContract.address, owner, spender, value, nonce.toString(), deadline); - const signature = signWithPk(ownerPrivateKey, data); + const data = buildData(name, tokenVersion, chainId, permitContract.address, owner.address, spender, value, nonce.toString(), deadline); + const signature = await owner._signTypedData(data.domain, data.types, data.message); const { v, r, s } = fromRpcSig(signature); - const permitCall = permitContract.contract.methods.permit(owner, spender, value, deadline, v, r, s).encodeABI(); + const permitCall = permitContract.interface.encodeFunctionData('permit', [owner.address, spender, value, deadline, v, r, s]); return cutSelector(permitCall); } @@ -126,24 +119,23 @@ export async function getPermit ( * @param permitContract The contract object with ERC20PermitLikeDai type and token address for which the permit creating. */ export async function getPermitLikeDai ( - holder: string, - holderPrivateKey: string, + holder: SignerWithAddress, permitContract: PermittableToken, tokenVersion: string, chainId: number, spender: string, allowed: boolean, - expiry = defaultDeadline + expiry = defaultDeadline.toString() ) { - const nonce = await permitContract.nonces(holder); + const nonce = await permitContract.nonces(holder.address); const name = await permitContract.name(); - const data = buildDataLikeDai(name, tokenVersion, chainId, permitContract.address, holder, spender, nonce.toString(), allowed, expiry); - const signature = signWithPk(holderPrivateKey, data); + const data = buildDataLikeDai(name, tokenVersion, chainId, permitContract.address, holder.address, spender, nonce.toString(), allowed, expiry); + const signature = await holder._signTypedData(data.domain, data.types, data.message); const { v, r, s } = fromRpcSig(signature); - const permitCall = permitContract.contract.methods.permit(holder, spender, nonce, expiry, allowed, v, r, s).encodeABI(); + const permitCall = permitContract.interface.encodeFunctionData('permit(address,address,uint256,uint256,bool,uint8,bytes32,bytes32)', [holder.address, spender, nonce, expiry, allowed, v, r, s]); return cutSelector(permitCall); } -export function withTarget (target: BN | string, data: BN | string) { +export function withTarget (target: bigint | string, data: bigint | string) { return target.toString() + trim0x(data); } diff --git a/src/prelude.ts b/src/prelude.ts index 07f9f27a..68567449 100644 --- a/src/prelude.ts +++ b/src/prelude.ts @@ -1,43 +1,24 @@ -import chai, { Assertion, AssertionError, assert, expect, config, should } from 'chai'; -import 'chai-bn'; -import chaiAsPromised from 'chai-as-promised'; +import { Assertion, AssertionError, assert, expect, config, should } from 'chai'; import { toWei } from 'web3-utils'; -import BN from 'bn.js'; -chai.use(chaiAsPromised); -// eslint-disable-next-line @typescript-eslint/no-var-requires -const { time: timeImpl } = require('@openzeppelin/test-helpers'); - -export function toBN (num: string | number, base?: number | 'hex'): BN { - if (typeof(num) === 'string' && num.startsWith('0x')) { - return new BN(num.substring(2), 16); - } - return new BN(num, base); -} +import { time } from '@nomicfoundation/hardhat-network-helpers'; export const constants = { ZERO_ADDRESS: '0x0000000000000000000000000000000000000000', EEE_ADDRESS: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', ZERO_BYTES32: '0x0000000000000000000000000000000000000000000000000000000000000000', - MAX_UINT256: toBN('2').pow(toBN('256')).sub(toBN('1')).toString(), - MAX_INT256: toBN('2').pow(toBN('255')).sub(toBN('1')).toString(), - MIN_INT256: toBN('2').pow(toBN('255')).mul(toBN('-1')).toString(), + MAX_UINT256: (2n ** 256n) - 1n, + MAX_INT256: (2n ** 255n) - 1n, + MIN_INT256: -(2n ** 255n), + MAX_UINT128: (2n ** 128n) - 1n, } as const; // utils export { - BN, + time, }; -//test-helpers -export type Time = { - increaseTo: (target: string | number | BN) => Promise, - latest: () => Promise -} - -export const time: Time = timeImpl; - -export function ether (n: string): BN { - return toBN(toWei(n, 'ether')); +export function ether (n: string): bigint { + return BigInt(toWei(n, 'ether')); } // chai diff --git a/src/profileEVM.ts b/src/profileEVM.ts index 71f4672d..408aa41b 100644 --- a/src/profileEVM.ts +++ b/src/profileEVM.ts @@ -1,6 +1,5 @@ -import { promisify } from 'util'; import { PathLike, promises as fs } from 'fs'; -import { toBN } from './prelude'; +import { ethers } from 'hardhat'; export const gasspectOptionsDefault = { minOpGasCost: 300, // minimal gas cost of returned operations @@ -30,10 +29,10 @@ function _normalizeOp (ops: Op[], i: number) { ops[i].op = 'STATICCALL-' + ops[i].stack[ops[i].stack.length - 8].substr(62, 2); } else { ops[i].args = [ - '0x' + ops[i].stack[ops[i].stack.length - 2].substr(24), + '0x' + ops[i].stack[ops[i].stack.length - 2].substring(24), '0x' + (ops[i].memory || []).join('').substr( - 2 * toBN(ops[i].stack[ops[i].stack.length - 3]).toNumber(), - 2 * toBN(ops[i].stack[ops[i].stack.length - 4]).toNumber(), + 2 * Number(ops[i].stack[ops[i].stack.length - 3]), + 2 * Number(ops[i].stack[ops[i].stack.length - 4]), ), ]; if (ops[i].gasCost === 100) { @@ -43,10 +42,10 @@ function _normalizeOp (ops: Op[], i: number) { } if (['CALL', 'DELEGATECALL', 'CALLCODE'].indexOf(ops[i].op) !== -1) { ops[i].args = [ - '0x' + ops[i].stack[ops[i].stack.length - 2].substr(24), + '0x' + ops[i].stack[ops[i].stack.length - 2].substring(24), '0x' + (ops[i].memory || []).join('').substr( - 2 * toBN(ops[i].stack[ops[i].stack.length - 4]).toNumber(), - 2 * toBN(ops[i].stack[ops[i].stack.length - 5]).toNumber(), + 2 * Number(ops[i].stack[ops[i].stack.length - 4]), + 2 * Number(ops[i].stack[ops[i].stack.length - 5]), ), ]; ops[i].gasCost = ops[i].gasCost - ops[i + 1].gas; @@ -69,7 +68,7 @@ function _normalizeOp (ops: Op[], i: number) { if (ops[i].gasCost === 100) { ops[i].op += '_R'; } - if (ops[i].gasCost === 20000) { + if (ops[i].gasCost >= 20000) { ops[i].op += '_I'; } @@ -79,23 +78,14 @@ function _normalizeOp (ops: Op[], i: number) { } if (ops[i].op === 'EXTCODESIZE') { ops[i].args = [ - '0x' + ops[i].stack[ops[i].stack.length - 1].substr(24), + '0x' + ops[i].stack[ops[i].stack.length - 1].substring(24), ]; ops[i].res = ops[i + 1].stack[ops[i + 1].stack.length - 1]; } } export async function profileEVM (txHash: string, instruction: string[], optionalTraceFile?: PathLike | fs.FileHandle) { - if (!web3.currentProvider || typeof web3.currentProvider === 'string' || !web3.currentProvider.send) { - throw new Error('Unsupported provider'); - } - - const trace = await promisify(web3.currentProvider.send.bind(web3.currentProvider))({ - jsonrpc: '2.0', - method: 'debug_traceTransaction', - params: [txHash, {}], - id: new Date().getTime(), - }); + const trace = await ethers.provider.send('debug_traceTransaction', [ txHash ]); const str = JSON.stringify(trace); @@ -111,18 +101,9 @@ export async function profileEVM (txHash: string, instruction: string[], optiona export async function gasspectEVM (txHash: string, gasspectOptions: Record = {}, optionalTraceFile?: PathLike | fs.FileHandle) { const options = { ...gasspectOptionsDefault, ...gasspectOptions }; - if (!web3.currentProvider || typeof web3.currentProvider === 'string' || !web3.currentProvider.send) { - throw new Error('Unsupported provider'); - } - - const trace = await promisify(web3.currentProvider.send.bind(web3.currentProvider))({ - jsonrpc: '2.0', - method: 'debug_traceTransaction', - params: [txHash, {}], - id: new Date().getTime(), - }); + const trace = await ethers.provider.send('debug_traceTransaction', [ txHash ]); - const ops: Op[] = trace?.result.structLogs; + const ops: Op[] = trace.structLogs; const traceAddress = [0, -1]; for (const [i, op] of ops.entries()) { @@ -145,7 +126,7 @@ export async function gasspectEVM (txHash: string, gasspectOptions: Record setTimeout(resolve, delay)); await time.increaseTo(seconds); } -export interface Token extends Truffle.ContractInstance { +export interface Token extends BaseContract { balanceOf( account: string, - txDetails?: Truffle.TransactionDetails - ): Promise; + overrides?: CallOverrides + ): Promise; } -export async function trackReceivedTokenAndTx ( +export async function trackReceivedTokenAndTx ( token: Token | {address: typeof constants.ZERO_ADDRESS} | {address: typeof constants.EEE_ADDRESS}, wallet: string, - txPromise: (...args: T) => Promise>, + txPromise: (...args: T) => Promise, ...args: T ) { const [balanceFunc, isETH] = 'balanceOf' in token ? [() => token.balanceOf(wallet), false] - : [async () => toBN(await web3.eth.getBalance(wallet)), true]; + : [async () => (await ethers.provider.getBalance(wallet)), true]; const preBalance = await balanceFunc(); const txResult = await txPromise(...args); - const txFees = (wallet.toLowerCase() === txResult.receipt.from.toLowerCase() && isETH) - ? toBN(txResult.receipt.gasUsed).mul(toBN(txResult.receipt.effectiveGasPrice)) - : toBN('0'); + const txReceipt = await txResult.wait(); + const txFees = (wallet.toLowerCase() === txResult.from.toLowerCase() && isETH) + ? txReceipt.gasUsed.toBigInt() * txReceipt.effectiveGasPrice.toBigInt() + : 0n; const postBalance = await balanceFunc(); return [postBalance.sub(preBalance).add(txFees), txResult] as const; } @@ -45,21 +49,12 @@ export function fixSignature (signature: string) { return signature.slice(0, 130) + vHex; } -// signs message in node (ganache auto-applies "Ethereum Signed Message" prefix) -export async function signMessage (signer: string, messageHex = '0x') { - return fixSignature(await web3.eth.sign(messageHex, signer)); +export async function signMessage (signer: SignerWithAddress, messageHex: string | Bytes = '0x') { + return fixSignature(await signer.signMessage(messageHex)); } export async function countInstructions (txHash: string, instructions: string[]) { - if (!web3.currentProvider || typeof web3.currentProvider === 'string' || !web3.currentProvider.send) { - throw new Error('Unsupported provider'); - } - const trace = await promisify(web3.currentProvider.send.bind(web3.currentProvider))({ - jsonrpc: '2.0', - method: 'debug_traceTransaction', - params: [txHash, {}], - id: new Date().getTime(), - }); + const trace = await ethers.provider.send('debug_traceTransaction', [ txHash ]); const str = JSON.stringify(trace); diff --git a/test/Permitable.test.ts b/test/Permitable.test.ts index 025f6803..c4d7a10b 100644 --- a/test/Permitable.test.ts +++ b/test/Permitable.test.ts @@ -1,97 +1,98 @@ -import { expect, toBN } from '../src/prelude'; +import { expect } from '../src/prelude'; import { fromRpcSig } from 'ethereumjs-util'; -import { defaultDeadline, buildData, buildDataLikeDai, getPermit, getPermitLikeDai, signWithPk } from '../src/permit'; -import { web3 } from 'hardhat'; -import types from '../typechain-types'; - -const ERC20PermitMock = artifacts.require('ERC20PermitMock'); -const DaiLikePermitMock = artifacts.require('DaiLikePermitMock'); -const PermitableMock = artifacts.require('PermitableMock'); - -const value = toBN(42); -const nonce = '0'; - -contract('Permitable', function ([wallet1, wallet2]) { - const initContext = async () => { - const permittableMock = await PermitableMock.new(); - const chainId = await web3.eth.getChainId(); - const account = await web3.eth.accounts.create(); - const wallet = { - address: account.address, - privateKey: account.privateKey, - }; - const owner = wallet.address; - const holder = owner; - const erc20PermitMock: types.ERC20PermitMockInstance = undefined!; - const daiLikePermitMock: types.DaiLikePermitMockInstance = undefined!; - return { permittableMock, chainId, wallet, owner, holder, erc20PermitMock, daiLikePermitMock }; - }; - - let context: Awaited> = undefined!; - - before(async () => { - context = await initContext(); - }); +import { defaultDeadline, buildData, buildDataLikeDai, getPermit, getPermitLikeDai } from '../src/permit'; +import { ethers } from 'hardhat'; +import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; +import { loadFixture } from '@nomicfoundation/hardhat-network-helpers'; +import { cutSelector } from '../src/permit'; +import { constants } from '../src/prelude'; + +const value = 42n; + +describe('Permitable', async function () { + let signer1: SignerWithAddress; + let signer2: SignerWithAddress; - beforeEach(async function () { - context.erc20PermitMock = await ERC20PermitMock.new('USDC', 'USDC', wallet1, toBN(100)); - context.daiLikePermitMock = await DaiLikePermitMock.new('DAI', 'DAI', wallet1, toBN(100)); + before(async function () { + [signer1, signer2] = await ethers.getSigners(); }); + async function deployTokens () { + const PermitableMock = await ethers.getContractFactory('PermitableMock'); + const ERC20PermitMock = await ethers.getContractFactory('ERC20PermitMock'); + const DaiLikePermitMock = await ethers.getContractFactory('DaiLikePermitMock'); + + const chainId = (await ethers.provider.getNetwork()).chainId; + const permitableMock = await PermitableMock.deploy(); + const erc20PermitMock = await ERC20PermitMock.deploy('USDC', 'USDC', signer1.address, 100n); + const daiLikePermitMock = await DaiLikePermitMock.deploy('DAI', 'DAI', signer1.address, 100n); + return { permitableMock, erc20PermitMock, daiLikePermitMock, chainId }; + } + it('should be permitted for IERC20Permit', async function () { - const permit = await getPermit(context.owner, context.wallet.privateKey, context.erc20PermitMock, '1', context.chainId, wallet2, value.toString()); - await context.permittableMock.mockPermit(context.erc20PermitMock.address, permit); - expect(await context.erc20PermitMock.nonces(context.owner)).to.be.bignumber.equal('1'); - expect(await context.erc20PermitMock.allowance(context.owner, wallet2)).to.be.bignumber.equal(value); + const { permitableMock, erc20PermitMock, chainId } = await loadFixture(deployTokens); + + const permit = await getPermit(signer1, erc20PermitMock, '1', chainId, signer2.address, value.toString()); + await permitableMock.mockPermit(erc20PermitMock.address, permit); + expect(await erc20PermitMock.nonces(signer1.address)).to.be.equal('1'); + expect(await erc20PermitMock.allowance(signer1.address, signer2.address)).to.be.equal(value); }); it('should not be permitted for IERC20Permit', async function () { - const data = buildData(await context.erc20PermitMock.name(), '1', context.chainId, context.erc20PermitMock.address, context.owner, wallet2, value.toString(), nonce); - const signature = signWithPk(context.wallet.privateKey, data); - const { v, r, s } = fromRpcSig(signature); + const { permitableMock, erc20PermitMock, chainId } = await loadFixture(deployTokens); - const permit = web3.eth.abi.encodeParameter( - 'tuple(address,address,uint256,uint256,uint8,bytes32,bytes32)', - [context.owner, wallet1, value, defaultDeadline, v, r, s], - ); - await expect(context.permittableMock.mockPermit(context.erc20PermitMock.address, permit)) - .to.eventually.be.rejectedWith('ERC20Permit: invalid signature'); + const name = await erc20PermitMock.name(); + const nonce = await erc20PermitMock.nonces(signer1.address); + const data = buildData(name, '1', chainId, erc20PermitMock.address, signer1.address, signer2.address, value.toString(), nonce.toString()); + const signature = await signer1._signTypedData(data.domain, data.types, data.message); + const { v, r, s } = fromRpcSig(signature); + // spender is signer1 but in signature spender was signer2 + const permit = cutSelector(erc20PermitMock.interface.encodeFunctionData('permit', [signer1.address, signer1.address, value, defaultDeadline, v, r, s])); + await expect(permitableMock.mockPermit(erc20PermitMock.address, permit)) + .to.be.revertedWith('ERC20Permit: invalid signature'); }); it('should be permitted for IDaiLikePermit', async function () { - const permit = await getPermitLikeDai(context.holder, context.wallet.privateKey, context.daiLikePermitMock, '1', context.chainId, wallet2, true); - await context.permittableMock.mockPermit(context.daiLikePermitMock.address, permit); + const { permitableMock, daiLikePermitMock, chainId } = await loadFixture(deployTokens); + + const permit = await getPermitLikeDai(signer1, daiLikePermitMock, '1', chainId, signer2.address, true); + await permitableMock.mockPermit(daiLikePermitMock.address, permit); - const MAX_UINT128 = toBN('2').pow(toBN('128')).sub(toBN('1')); - expect(await context.daiLikePermitMock.nonces(context.owner)).to.be.bignumber.equal('1'); - expect(await context.daiLikePermitMock.allowance(context.owner, wallet2)).to.be.bignumber.equal(MAX_UINT128); + expect(await daiLikePermitMock.nonces(signer1.address)).to.be.equal('1'); + expect(await daiLikePermitMock.allowance(signer1.address, signer2.address)).to.be.equal(constants.MAX_UINT128); }); it('should not be permitted for IDaiLikePermit', async function () { - const data = buildDataLikeDai(await context.daiLikePermitMock.name(), '1', context.chainId, context.daiLikePermitMock.address, context.holder, wallet2, nonce, true); - const signature = signWithPk(context.wallet.privateKey, data); + const { permitableMock, daiLikePermitMock, chainId } = await loadFixture(deployTokens); + + const name = await daiLikePermitMock.name(); + const nonce = await daiLikePermitMock.nonces(signer1.address); + const data = buildDataLikeDai(name, '1', chainId, daiLikePermitMock.address, signer1.address, signer2.address, nonce.toString(), true); + const signature = await signer1._signTypedData(data.domain, data.types, data.message); const { v, r, s } = fromRpcSig(signature); - const payload = web3.eth.abi.encodeParameter( - 'tuple(address,address,uint256,uint256,bool,uint8,bytes32,bytes32)', - [context.holder, wallet1, nonce, defaultDeadline, true, v, r, s], - ); + // spender is signer1 but in signature spender was signer2 + const permit = cutSelector(daiLikePermitMock.interface.encodeFunctionData( + 'permit(address,address,uint256,uint256,bool,uint8,bytes32,bytes32)', + [signer1.address, signer1.address, nonce, defaultDeadline.toString(), true, v, r, s] + )); - await expect(context.permittableMock.mockPermit(context.daiLikePermitMock.address, payload)) - .to.eventually.be.rejectedWith('Dai/invalid-permit'); + await expect(permitableMock.mockPermit(daiLikePermitMock.address, permit)) + .to.be.revertedWith('Dai/invalid-permit'); }); it('should be wrong permit length', async function () { - const data = buildData(await context.erc20PermitMock.name(), '1', context.chainId, context.erc20PermitMock.address, context.owner, wallet2, value.toString(), nonce); - const signature = signWithPk(context.wallet.privateKey, data); + const { permitableMock, erc20PermitMock, chainId } = await loadFixture(deployTokens); + + const name = await erc20PermitMock.name(); + const nonce = await erc20PermitMock.nonces(signer1.address); + const data = buildData(name, '1', chainId, erc20PermitMock.address, signer1.address, signer2.address, value.toString(), nonce.toString()); + const signature = await signer1._signTypedData(data.domain, data.types, data.message); const { v, r, s } = fromRpcSig(signature); - const permit = web3.eth.abi.encodeParameter( - 'tuple(address,uint256,uint256,uint8,bytes32,bytes32)', - [wallet2, value, defaultDeadline, v, r, s], - ); + const permit = '0x' + cutSelector(erc20PermitMock.interface.encodeFunctionData('permit', [signer1.address, signer1.address, value, defaultDeadline, v, r, s])).substring(64); - await expect(context.permittableMock.mockPermit(context.erc20PermitMock.address, permit)) - .to.eventually.be.rejectedWith('SafePermitBadLength()'); + await expect(permitableMock.mockPermit(erc20PermitMock.address, permit)) + .to.be.revertedWithCustomError(permitableMock, 'SafePermitBadLength'); }); }); diff --git a/test/contracts/AddressArray.test.ts b/test/contracts/AddressArray.test.ts index 46df069e..8feece96 100644 --- a/test/contracts/AddressArray.test.ts +++ b/test/contracts/AddressArray.test.ts @@ -1,165 +1,179 @@ import { expect, constants } from '../../src/prelude'; -import types from '../../typechain-types'; +import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; +import { loadFixture } from '@nomicfoundation/hardhat-network-helpers'; +import { ethers } from 'hardhat'; -const AddressArrayMock = artifacts.require('AddressArrayMock'); +describe('AddressArray', async function () { + let signer1: SignerWithAddress; + let signer2: SignerWithAddress; + let signer3: SignerWithAddress; -contract('AddressArray', async function ([wallet1, wallet2, wallet3]) { - const initContext = async () => { - const addressArrayMock: types.AddressArrayMockInstance = undefined!; - return { addressArrayMock }; - }; - - let context: Awaited> = undefined!; - - before(async () => { - context = await initContext(); + before(async function () { + [signer1, signer2, signer3] = await ethers.getSigners(); }); - beforeEach(async function () { - context.addressArrayMock = await AddressArrayMock.new(); - }); + const deployAddressArrayMock = async () => { + const AddressArrayMock = await ethers.getContractFactory('AddressArrayMock'); + const addressArrayMock = await AddressArrayMock.deploy(); + return { addressArrayMock }; + }; describe('length', async function () { - it('should be calculate length 0', async function () { - expect(await context.addressArrayMock.length()).to.be.bignumber.equal('0'); + it('should calculate length 0', async function () { + const { addressArrayMock } = await loadFixture(deployAddressArrayMock); + expect(await addressArrayMock.length()).to.be.equal('0'); }); - it('should be calculate length 1', async function () { - await context.addressArrayMock.push(wallet1); - expect(await context.addressArrayMock.length()).to.be.bignumber.equal('1'); + it('should calculate length 1', async function () { + const { addressArrayMock } = await loadFixture(deployAddressArrayMock); + await addressArrayMock.push(signer1.address); + expect(await addressArrayMock.length()).to.be.equal('1'); }); }); describe('at', async function () { - it('should be get from empty data', async function () { - expect(await context.addressArrayMock.at(0)).to.be.equal(constants.ZERO_ADDRESS); - expect(await context.addressArrayMock.at(1)).to.be.equal(constants.ZERO_ADDRESS); + it('should get from empty array', async function () { + const { addressArrayMock } = await loadFixture(deployAddressArrayMock); + expect(await addressArrayMock.at(0)).to.be.equal(constants.ZERO_ADDRESS); + expect(await addressArrayMock.at(1)).to.be.equal(constants.ZERO_ADDRESS); }); - it('should be get from data with 1 element', async function () { - await context.addressArrayMock.push(wallet1); - expect(await context.addressArrayMock.at(0)).to.be.equal(wallet1); - expect(await context.addressArrayMock.at(1)).to.be.equal(constants.ZERO_ADDRESS); + it('should get from array with 1 element', async function () { + const { addressArrayMock } = await loadFixture(deployAddressArrayMock); + await addressArrayMock.push(signer1.address); + expect(await addressArrayMock.at(0)).to.be.equal(signer1.address); + expect(await addressArrayMock.at(1)).to.be.equal(constants.ZERO_ADDRESS); }); - it('should be get from data with several elements', async function () { - await context.addressArrayMock.push(wallet1); - await context.addressArrayMock.push(wallet2); - expect(await context.addressArrayMock.at(0)).to.be.equal(wallet1); - expect(await context.addressArrayMock.at(1)).to.be.equal(wallet2); + it('should get from array with several elements', async function () { + const { addressArrayMock } = await loadFixture(deployAddressArrayMock); + await addressArrayMock.push(signer1.address); + await addressArrayMock.push(signer2.address); + expect(await addressArrayMock.at(0)).to.be.equal(signer1.address); + expect(await addressArrayMock.at(1)).to.be.equal(signer2.address); }); }); describe('get', async function () { - it('should be get empty data', async function () { - expect(await context.addressArrayMock.get()).to.eql([]); - await context.addressArrayMock.contract.methods.get().send({ from: wallet1 }); + it('should get empty array', async function () { + const { addressArrayMock } = await loadFixture(deployAddressArrayMock); + expect(await addressArrayMock.get()).to.be.deep.equal([]); }); - it('should be get from data with 1 element', async function () { - await context.addressArrayMock.push(wallet1); - expect(await context.addressArrayMock.get()).to.eql([wallet1]); - await context.addressArrayMock.contract.methods.get().send({ from: wallet1 }); + it('should get array with 1 element', async function () { + const { addressArrayMock } = await loadFixture(deployAddressArrayMock); + await addressArrayMock.push(signer1.address); + expect(await addressArrayMock.get()).to.be.deep.equal([signer1.address]); }); - it('should be get from data with 2 elements', async function () { - await context.addressArrayMock.push(wallet1); - await context.addressArrayMock.push(wallet2); - expect(await context.addressArrayMock.get()).to.eql([wallet1, wallet2]); - await context.addressArrayMock.contract.methods.get().send({ from: wallet1 }); + it('should get array with 2 elements', async function () { + const { addressArrayMock } = await loadFixture(deployAddressArrayMock); + await addressArrayMock.push(signer1.address); + await addressArrayMock.push(signer2.address); + expect(await addressArrayMock.get()).to.be.deep.equal([signer1.address, signer2.address]); }); - it('should be get from data with several elements', async function () { - await context.addressArrayMock.push(wallet1); - await context.addressArrayMock.push(wallet2); - await context.addressArrayMock.push(wallet3); - expect(await context.addressArrayMock.get()).to.eql([wallet1, wallet2, wallet3]); - await context.addressArrayMock.contract.methods.get().send({ from: wallet1 }); + it('should get from array with 3 elements', async function () { + const { addressArrayMock } = await loadFixture(deployAddressArrayMock); + await addressArrayMock.push(signer1.address); + await addressArrayMock.push(signer2.address); + await addressArrayMock.push(signer3.address); + expect(await addressArrayMock.get()).to.be.deep.equal([signer1.address, signer2.address, signer3.address]); }); }); describe('push', async function () { - it('should be push to empty data', async function () { - const pushedIndex = await context.addressArrayMock.push.call(wallet1); - await context.addressArrayMock.push(wallet1); - expect(await context.addressArrayMock.at(pushedIndex.subn(1))).to.be.equal(wallet1); + it('should push to empty array', async function () { + const { addressArrayMock } = await loadFixture(deployAddressArrayMock); + const pushedIndex = await addressArrayMock.callStatic.push(signer1.address); + await addressArrayMock.push(signer1.address); + expect(await addressArrayMock.at(pushedIndex.toBigInt() - 1n)).to.be.equal(signer1.address); }); - it('should be push to data with 1 element', async function () { - await context.addressArrayMock.push(wallet1); - const pushedIndex = await context.addressArrayMock.push.call(wallet2); - await context.addressArrayMock.push(wallet2); - expect(await context.addressArrayMock.at(pushedIndex.subn(1))).to.be.equal(wallet2); + it('should push to array with 1 element', async function () { + const { addressArrayMock } = await loadFixture(deployAddressArrayMock); + await addressArrayMock.push(signer1.address); + const pushedIndex = await addressArrayMock.callStatic.push(signer2.address); + await addressArrayMock.push(signer2.address); + expect(await addressArrayMock.at(pushedIndex.toBigInt() - 1n)).to.be.equal(signer2.address); }); - it('should be get push to data with several elements', async function () { - await context.addressArrayMock.push(wallet1); - await context.addressArrayMock.push(wallet2); - const pushedIndex = await context.addressArrayMock.push.call(wallet3); - await context.addressArrayMock.push(wallet3); - expect(await context.addressArrayMock.at(pushedIndex.subn(1))).to.be.equal(wallet3); + it('should push to array with 2 elements', async function () { + const { addressArrayMock } = await loadFixture(deployAddressArrayMock); + await addressArrayMock.push(signer1.address); + await addressArrayMock.push(signer2.address); + const pushedIndex = await addressArrayMock.callStatic.push(signer3.address); + await addressArrayMock.push(signer3.address); + expect(await addressArrayMock.at(pushedIndex.toBigInt() - 1n)).to.be.equal(signer3.address); }); }); describe('pop', async function () { - it('should be thrown when data is empty', async function () { - await expect(context.addressArrayMock.pop()) - .to.eventually.be.rejectedWith('PopFromEmptyArray()'); + it('should throw when array is empty', async function () { + const { addressArrayMock } = await loadFixture(deployAddressArrayMock); + await expect(addressArrayMock.pop()).to.be.revertedWithCustomError(addressArrayMock, 'PopFromEmptyArray'); }); - it('should be pop in data with 1 element', async function () { - await context.addressArrayMock.push(wallet1); - await context.addressArrayMock.pop(); - expect(await context.addressArrayMock.get()).to.eql([]); + it('should pop from array with 1 element', async function () { + const { addressArrayMock } = await loadFixture(deployAddressArrayMock); + await addressArrayMock.push(signer1.address); + await addressArrayMock.pop(); + expect(await addressArrayMock.get()).to.be.deep.equal([]); }); - it('should be pop in data with several elements', async function () { - await context.addressArrayMock.push(wallet1); - await context.addressArrayMock.push(wallet2); - await context.addressArrayMock.pop(); - expect(await context.addressArrayMock.get()).to.eql([wallet1]); + it('should pop from array with 2 elements', async function () { + const { addressArrayMock } = await loadFixture(deployAddressArrayMock); + await addressArrayMock.push(signer1.address); + await addressArrayMock.push(signer2.address); + await addressArrayMock.pop(); + expect(await addressArrayMock.get()).to.be.deep.equal([signer1.address]); }); - it('should be several pops', async function () { - await context.addressArrayMock.push(wallet1); - await context.addressArrayMock.push(wallet2); - await context.addressArrayMock.push(wallet3); - await context.addressArrayMock.pop(); - expect(await context.addressArrayMock.get()).to.eql([wallet1, wallet2]); + it('should pop from array with 3 elements', async function () { + const { addressArrayMock } = await loadFixture(deployAddressArrayMock); + await addressArrayMock.push(signer1.address); + await addressArrayMock.push(signer2.address); + await addressArrayMock.push(signer3.address); + await addressArrayMock.pop(); + expect(await addressArrayMock.get()).to.be.deep.equal([signer1.address, signer2.address]); }); - it('should be thrown when pops more than elements', async function () { - await context.addressArrayMock.push(wallet1); - await context.addressArrayMock.pop(); - await expect(context.addressArrayMock.pop()) - .to.eventually.be.rejectedWith('PopFromEmptyArray()'); + it('should throw when pops more than there are elements in array', async function () { + const { addressArrayMock } = await loadFixture(deployAddressArrayMock); + await addressArrayMock.push(signer1.address); + await addressArrayMock.pop(); + await expect(addressArrayMock.pop()).to.be.revertedWithCustomError(addressArrayMock, 'PopFromEmptyArray'); }); }); describe('set', async function () { - it('should be thrown when set index less than data length', async function () { - await expect(context.addressArrayMock.set(0, wallet1)) - .to.eventually.be.rejectedWith('IndexOutOfBounds()'); + it('should throw when sets index out of bounds', async function () { + const { addressArrayMock } = await loadFixture(deployAddressArrayMock); + await expect(addressArrayMock.set(0, signer1.address)) + .to.be.revertedWithCustomError(addressArrayMock, 'IndexOutOfBounds'); }); - it('should be set to index 0 to data with 1 element', async function () { - await context.addressArrayMock.push(wallet1); - await context.addressArrayMock.set(0, wallet2); - expect(await context.addressArrayMock.get()).to.eql([wallet2]); + it('should set index 0 in array with 1 element', async function () { + const { addressArrayMock } = await loadFixture(deployAddressArrayMock); + await addressArrayMock.push(signer1.address); + await addressArrayMock.set(0, signer2.address); + expect(await addressArrayMock.get()).to.be.deep.equal([signer2.address]); }); - it('should be set to index 0 to data with several elements', async function () { - await context.addressArrayMock.push(wallet1); - await context.addressArrayMock.push(wallet2); - await context.addressArrayMock.set(0, wallet3); - expect(await context.addressArrayMock.get()).to.eql([wallet3, wallet2]); + it('should set index 0 in array with several elements', async function () { + const { addressArrayMock } = await loadFixture(deployAddressArrayMock); + await addressArrayMock.push(signer1.address); + await addressArrayMock.push(signer2.address); + await addressArrayMock.set(0, signer3.address); + expect(await addressArrayMock.get()).to.be.deep.equal([signer3.address, signer2.address]); }); - it('should be set to index non-0 to data with several elements', async function () { - await context.addressArrayMock.push(wallet1); - await context.addressArrayMock.push(wallet2); - await context.addressArrayMock.set(1, wallet3); - expect(await context.addressArrayMock.get()).to.eql([wallet1, wallet3]); + it('should set index 1 in array with several elements', async function () { + const { addressArrayMock } = await loadFixture(deployAddressArrayMock); + await addressArrayMock.push(signer1.address); + await addressArrayMock.push(signer2.address); + await addressArrayMock.set(1, signer3.address); + expect(await addressArrayMock.get()).to.be.deep.equal([signer1.address, signer3.address]); }); }); }); diff --git a/test/contracts/AddressSet.test.ts b/test/contracts/AddressSet.test.ts index 5774f259..105dd5c3 100644 --- a/test/contracts/AddressSet.test.ts +++ b/test/contracts/AddressSet.test.ts @@ -1,133 +1,148 @@ import { expect, constants } from '../../src/prelude'; -import types from '../../typechain-types'; +import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; +import { loadFixture } from '@nomicfoundation/hardhat-network-helpers'; +import { ethers } from 'hardhat'; -const AddressSetMock = artifacts.require('AddressSetMock'); +describe('AddressSet', async function () { + let signer1: SignerWithAddress; + let signer2: SignerWithAddress; + let signer3: SignerWithAddress; -contract('AddressSet', async function ([wallet1, wallet2, wallet3]) { - const initContext = async () => { - const addressSetMock: types.AddressSetMockInstance = undefined!; - return { addressSetMock }; - }; - - let context: Awaited> = undefined!; - - before(async () => { - context = await initContext(); + before(async function () { + [signer1, signer2, signer3] = await ethers.getSigners(); }); - beforeEach(async () => { - context.addressSetMock = await AddressSetMock.new(); - }); + const deployAddressSetMock = async () => { + const AddressSetMock = await ethers.getContractFactory('AddressSetMock'); + const addressSetMock = await AddressSetMock.deploy(); + return { addressSetMock }; + }; describe('length', async function () { - it('should be calculate length 0', async function () { - expect(await context.addressSetMock.length()).to.be.bignumber.equal('0'); + it('should get length 0', async function () { + const { addressSetMock } = await loadFixture(deployAddressSetMock); + expect(await addressSetMock.length()).to.be.equal('0'); }); - it('should be calculate length 1', async function () { - await context.addressSetMock.add(wallet1); - expect(await context.addressSetMock.length()).to.be.bignumber.equal('1'); + it('should get length 1', async function () { + const { addressSetMock } = await loadFixture(deployAddressSetMock); + await addressSetMock.add(signer1.address); + expect(await addressSetMock.length()).to.be.equal('1'); }); }); describe('at', async function () { - it('should be get from empty data', async function () { - expect(await context.addressSetMock.at(0)).to.be.equal(constants.ZERO_ADDRESS); - expect(await context.addressSetMock.at(1)).to.be.equal(constants.ZERO_ADDRESS); + it('should get from empty set', async function () { + const { addressSetMock } = await loadFixture(deployAddressSetMock); + expect(await addressSetMock.at(0)).to.be.equal(constants.ZERO_ADDRESS); + expect(await addressSetMock.at(1)).to.be.equal(constants.ZERO_ADDRESS); }); - it('should be get from data with 1 element', async function () { - await context.addressSetMock.add(wallet1); - expect(await context.addressSetMock.at(0)).to.be.equal(wallet1); - expect(await context.addressSetMock.at(1)).to.be.equal(constants.ZERO_ADDRESS); + it('should get from set with 1 element', async function () { + const { addressSetMock } = await loadFixture(deployAddressSetMock); + await addressSetMock.add(signer1.address); + expect(await addressSetMock.at(0)).to.be.equal(signer1.address); + expect(await addressSetMock.at(1)).to.be.equal(constants.ZERO_ADDRESS); }); - it('should be get from data with several elements', async function () { - await context.addressSetMock.add(wallet1); - await context.addressSetMock.add(wallet2); - expect(await context.addressSetMock.at(0)).to.be.equal(wallet1); - expect(await context.addressSetMock.at(1)).to.be.equal(wallet2); + it('should get from set with several elements', async function () { + const { addressSetMock } = await loadFixture(deployAddressSetMock); + await addressSetMock.add(signer1.address); + await addressSetMock.add(signer2.address); + expect(await addressSetMock.at(0)).to.be.equal(signer1.address); + expect(await addressSetMock.at(1)).to.be.equal(signer2.address); }); }); describe('contains', async function () { - it('should be not contains in empty data', async function () { - expect(await context.addressSetMock.contains(wallet1)).to.be.equal(false); - expect(await context.addressSetMock.contains(wallet2)).to.be.equal(false); - expect(await context.addressSetMock.contains(constants.ZERO_ADDRESS)).to.be.equal(false); - }); - - it('should be contains address', async function () { - await context.addressSetMock.add(wallet1); - expect(await context.addressSetMock.contains(wallet1)).to.be.equal(true); - expect(await context.addressSetMock.contains(wallet2)).to.be.equal(false); - expect(await context.addressSetMock.contains(constants.ZERO_ADDRESS)).to.be.equal(false); - }); - - it('should be contains addresses', async function () { - await context.addressSetMock.add(wallet1); - await context.addressSetMock.add(wallet2); - expect(await context.addressSetMock.contains(wallet1)).to.be.equal(true); - expect(await context.addressSetMock.contains(wallet2)).to.be.equal(true); - expect(await context.addressSetMock.contains(wallet3)).to.be.equal(false); - expect(await context.addressSetMock.contains(constants.ZERO_ADDRESS)).to.be.equal(false); + it('should not contain in empty set', async function () { + const { addressSetMock } = await loadFixture(deployAddressSetMock); + expect(await addressSetMock.contains(signer1.address)).to.be.equal(false); + expect(await addressSetMock.contains(signer2.address)).to.be.equal(false); + expect(await addressSetMock.contains(constants.ZERO_ADDRESS)).to.be.equal(false); + }); + + it('should contain 1 address', async function () { + const { addressSetMock } = await loadFixture(deployAddressSetMock); + await addressSetMock.add(signer1.address); + expect(await addressSetMock.contains(signer1.address)).to.be.equal(true); + expect(await addressSetMock.contains(signer2.address)).to.be.equal(false); + expect(await addressSetMock.contains(constants.ZERO_ADDRESS)).to.be.equal(false); + }); + + it('should contains several addresses', async function () { + const { addressSetMock } = await loadFixture(deployAddressSetMock); + await addressSetMock.add(signer1.address); + await addressSetMock.add(signer2.address); + expect(await addressSetMock.contains(signer1.address)).to.be.equal(true); + expect(await addressSetMock.contains(signer2.address)).to.be.equal(true); + expect(await addressSetMock.contains(signer3.address)).to.be.equal(false); + expect(await addressSetMock.contains(constants.ZERO_ADDRESS)).to.be.equal(false); }); }); describe('add', async function () { - it('should be add to empty data', async function () { - const isAdded = await context.addressSetMock.add.call(wallet1); - await context.addressSetMock.add(wallet1); - expect(await context.addressSetMock.contains(wallet1)).to.be.equal(isAdded); + it('should add to empty set', async function () { + const { addressSetMock } = await loadFixture(deployAddressSetMock); + const isAdded = await addressSetMock.callStatic.add(signer1.address); + await addressSetMock.add(signer1.address); + expect(await addressSetMock.contains(signer1.address)).to.be.equal(isAdded); }); - it('should not be add a double element without another elements in data', async function () { - await context.addressSetMock.add(wallet1); - expect(await context.addressSetMock.add.call(wallet1)).to.be.equal(false); + it('should not add element twice', async function () { + const { addressSetMock } = await loadFixture(deployAddressSetMock); + await addressSetMock.add(signer1.address); + expect(await addressSetMock.callStatic.add(signer1.address)).to.be.equal(false); }); - it('should be add to data with 1 element', async function () { - await context.addressSetMock.add(wallet1); - const isAdded = await context.addressSetMock.add.call(wallet2); - await context.addressSetMock.add(wallet2); - expect(await context.addressSetMock.contains(wallet2)).to.be.equal(isAdded); + it('should add to set with 1 element', async function () { + const { addressSetMock } = await loadFixture(deployAddressSetMock); + await addressSetMock.add(signer1.address); + const isAdded = await addressSetMock.callStatic.add(signer2.address); + await addressSetMock.add(signer2.address); + expect(await addressSetMock.contains(signer2.address)).to.be.equal(isAdded); }); - it('should not be add a double element with another elements in data', async function () { - await context.addressSetMock.add(wallet1); - await context.addressSetMock.add(wallet2); - expect(await context.addressSetMock.add.call(wallet2)).to.be.equal(false); + it('should not add element twice to set with 1 element', async function () { + const { addressSetMock } = await loadFixture(deployAddressSetMock); + await addressSetMock.add(signer1.address); + await addressSetMock.add(signer2.address); + expect(await addressSetMock.callStatic.add(signer2.address)).to.be.equal(false); }); }); describe('remove', async function () { - it('should not be remove from empty data', async function () { - const isRemoved = await context.addressSetMock.remove.call(wallet1); + it('should not remove from empty set', async function () { + const { addressSetMock } = await loadFixture(deployAddressSetMock); + const isRemoved = await addressSetMock.callStatic.remove(signer1.address); expect(isRemoved).to.be.equal(false); }); - it('should be remove from data', async function () { - await context.addressSetMock.add(wallet1); - const isRemoved = await context.addressSetMock.remove.call(wallet1); - await context.addressSetMock.remove(wallet1); + it('should remove from set', async function () { + const { addressSetMock } = await loadFixture(deployAddressSetMock); + await addressSetMock.add(signer1.address); + const isRemoved = await addressSetMock.callStatic.remove(signer1.address); + await addressSetMock.remove(signer1.address); expect(isRemoved).to.be.equal(true); - expect(await context.addressSetMock.contains(wallet1)).to.be.equal(false); + expect(await addressSetMock.contains(signer1.address)).to.be.equal(false); }); - it('should not be remove element which is not in data', async function () { - await context.addressSetMock.add(wallet1); - const isRemoved = await context.addressSetMock.remove.call(wallet2); + it('should not remove element which is not in set', async function () { + const { addressSetMock } = await loadFixture(deployAddressSetMock); + await addressSetMock.add(signer1.address); + const isRemoved = await addressSetMock.callStatic.remove(signer2.address); expect(isRemoved).to.be.equal(false); }); - it('should be remove from data and keep the remainder', async function () { - await context.addressSetMock.add(wallet1); - await context.addressSetMock.add(wallet2); - const isRemoved = await context.addressSetMock.remove.call(wallet1); - await context.addressSetMock.remove(wallet1); + it('should remove from set and keep other elements', async function () { + const { addressSetMock } = await loadFixture(deployAddressSetMock); + await addressSetMock.add(signer1.address); + await addressSetMock.add(signer2.address); + const isRemoved = await addressSetMock.callStatic.remove(signer1.address); + await addressSetMock.remove(signer1.address); expect(isRemoved).to.be.equal(true); - expect(await context.addressSetMock.contains(wallet1)).to.be.equal(false); - expect(await context.addressSetMock.contains(wallet2)).to.be.equal(true); + expect(await addressSetMock.contains(signer1.address)).to.be.equal(false); + expect(await addressSetMock.contains(signer2.address)).to.be.equal(true); }); }); }); diff --git a/test/contracts/ECDSA.test.ts b/test/contracts/ECDSA.test.ts index 404c1a7c..2058f09d 100644 --- a/test/contracts/ECDSA.test.ts +++ b/test/contracts/ECDSA.test.ts @@ -1,87 +1,60 @@ import { expect, constants } from '../../src/prelude'; +import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; +import { Wallet } from 'ethers'; +import { ethers } from 'hardhat'; +import { loadFixture } from '@nomicfoundation/hardhat-network-helpers'; +import { arrayify, concat } from 'ethers/lib/utils'; -const ECDSATest = artifacts.require('ECDSATest'); -const ERC1271WalletMock = artifacts.require('ERC1271WalletMock'); +describe('ECDSA', async function () { + let account: SignerWithAddress; + let randomAccount: Wallet; + + before(async () => { + [account] = await ethers.getSigners(); + randomAccount = await ethers.Wallet.createRandom(); + }); + + const deployContracts = async function () { + const ECDSATest = await ethers.getContractFactory('ECDSATest'); + const ecdsa = await ECDSATest.deploy(); + const ERC1271WalletMock = await ethers.getContractFactory('ERC1271WalletMock'); + const erc1271wallet = await ERC1271WalletMock.deploy(account.address); + const erc1271walletV0 = await ERC1271WalletMock.deploy(signerV0); + const erc1271walletV1 = await ERC1271WalletMock.deploy(signerV1); -describe('ECDSA', async () => { - const TEST_MESSAGE = '1inch-ecdsa-asm-library'; - const HASHED_TEST_MESSAGE = web3.eth.accounts.hashMessage('1inch-ecdsa-asm-library'); - const WRONG_MESSAGE = web3.utils.keccak256('Nope'); - const NON_HASH_MESSAGE = '0x' + Buffer.from('abcd').toString('hex'); - - const initContext = async (erc1271owner: string, erc1271ownerV0: string, erc1271ownerV1: string) => { - const ecdsa = await ECDSATest.new(); - const erc1271wallet = await ERC1271WalletMock.new(erc1271owner); - const erc1271walletV0 = await ERC1271WalletMock.new(erc1271ownerV0); - const erc1271walletV1 = await ERC1271WalletMock.new(erc1271ownerV1); return { ecdsa, erc1271wallet, erc1271walletV0, erc1271walletV1 }; }; + const TEST_MESSAGE = '1inch-ecdsa-asm-library'; + const HASHED_TEST_MESSAGE = ethers.utils.hashMessage('1inch-ecdsa-asm-library'); + const WRONG_MESSAGE = ethers.utils.keccak256(ethers.utils.toUtf8Bytes('Nope')); + const NON_HASH_MESSAGE = arrayify('0x' + Buffer.from('abcd').toString('hex')); + const split2 = (signature: string): [string, string] => { - const raw = web3.utils.hexToBytes(signature); - switch (raw.length) { - case 64: - return [ - web3.utils.bytesToHex(raw.slice(0, 32)), // r - web3.utils.bytesToHex(raw.slice(32, 64)), // vs - ]; - case 65: { - const v = web3.utils.toBN(raw[64]); - const s = web3.utils.toBN(web3.utils.bytesToHex(raw.slice(32, 64))); - return [ - web3.utils.bytesToHex(raw.slice(0, 32)), // r - web3.utils.toHex(s.shln(1).shrn(1).or(v.subn(27).shln(255))), // vs - ]; - } - default: - expect.fail('Invalid signature length, cannot split'); - } + const { r, _vs } = ethers.utils.splitSignature(signature); + return [r, _vs]; }; const split3 = (signature: string): [string, string, string] => { - const raw = web3.utils.hexToBytes(signature); - if (raw.length !== 65) { - expect.fail('Invalid signature length, cannot split'); - } - return [ - web3.eth.abi.encodeParameter('uint8', raw[64]), // v - web3.utils.bytesToHex(raw.slice(0, 32)), // r - web3.utils.bytesToHex(raw.slice(32, 64)), // s - ]; + const { v, r, s } = ethers.utils.splitSignature(signature); + return [v.toString(), r, s]; }; const to2098Format = (signature: string): string => { - const long = web3.utils.hexToBytes(signature); - if (long.length !== 65) { - expect.fail('Invalid signature length (expected long format)'); - } - if (long[32] >> 7 === 1) { - expect.fail('Invalid signature \'s\' value'); - } - const short = long.slice(0, 64); - short[32] |= (long[64] % 27) << 7; // set the first bit of the 32nd byte to the v parity bit - return web3.utils.bytesToHex(short); + const { compact } = ethers.utils.splitSignature(signature); + return compact; }; const from2098Format = (signature: string): string => { - const short = web3.utils.hexToBytes(signature); - if (short.length !== 64) { - expect.fail('Invalid signature length (expected short format)'); - throw new Error(''); - } - short.push((short[32] >> 7) + 27); - short[32] &= (1 << 7) - 1; // zero out the first bit of 1 the 32nd byte - return web3.utils.bytesToHex(short); + const { v, r, s } = ethers.utils.splitSignature(signature); + const ret = ethers.utils.hexConcat([r, s, arrayify(v)]); + return ret; }; - let account: string; - let context: Awaited> = undefined!; - - const randomAccount: string = web3.eth.accounts.create().address; // eslint-disable-next-line max-len const longSignature = '0x01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789'; - // Signature generated outside ganache with method web3.eth.sign(TEST_MESSAGE, account) + // Signature generated outside ganache const signerV0 = '0x70997970C51812dc3A010C7d01b50e0d17dc79C8'; // eslint-disable-next-line max-len const signatureWithoutVersionV0 = '0x064d3d0f049cc3b971476ba4bdbd5d0ccb5ac0ee7a03c2f063908ac2bdb59f944c7c5bf43804a7ff717f8c0a8749e0e5cb26ef96408313558acd130210604d9c'; @@ -91,107 +64,116 @@ describe('ECDSA', async () => { // eslint-disable-next-line max-len const invalidSignature = '0x332ce75a821c982f9127538858900d87d3ec1f9f737338ad67cad133fa48feff48e6fa0c18abc62e42820f05943e47af3e9fbe306ce74d64094bdf1691ee53e01c'; - before(async () => { - [account] = await web3.eth.getAccounts(); - context = await initContext(account, signerV0, signerV1); - }); - describe('recover', async () => { describe('with invalid signature', async () => { it('with short signature', async function () { - expect(await context.ecdsa.recover(HASHED_TEST_MESSAGE, '0x1234')).to.be.equals(constants.ZERO_ADDRESS); + const { ecdsa } = await loadFixture(deployContracts); + expect(await ecdsa.recover(HASHED_TEST_MESSAGE, '0x1234')).to.be.equals(constants.ZERO_ADDRESS); }); it('with long signature', async () => { - expect(await context.ecdsa.recover(HASHED_TEST_MESSAGE, longSignature)).to.be.equals(constants.ZERO_ADDRESS); + const { ecdsa } = await loadFixture(deployContracts); + expect(await ecdsa.recover(HASHED_TEST_MESSAGE, longSignature)).to.be.equals(constants.ZERO_ADDRESS); }); }); describe('with valid signature', async () => { - describe('using web3.eth.sign', async () => { + describe('using account.signMessage', async () => { it('returns signer address with correct signature', async () => { - const signature = await web3.eth.sign(TEST_MESSAGE, account); - expect(await context.ecdsa.recover(HASHED_TEST_MESSAGE, signature)).to.be.equals(account); + const { ecdsa } = await loadFixture(deployContracts); + const signature = await account.signMessage(TEST_MESSAGE); + expect(await ecdsa.recover(HASHED_TEST_MESSAGE, signature)).to.be.equals(account.address); }); it('returns signer address with correct signature for arbitrary length message', async () => { - const signature = await web3.eth.sign(NON_HASH_MESSAGE, account); - expect(await context.ecdsa.recover(web3.eth.accounts.hashMessage(NON_HASH_MESSAGE), signature)).to.be.equals(account); + const { ecdsa } = await loadFixture(deployContracts); + const signature = await account.signMessage(NON_HASH_MESSAGE); + expect(await ecdsa.recover(ethers.utils.hashMessage(NON_HASH_MESSAGE), signature)).to.be.equals(account.address); }); it('returns a different address', async () => { - const signature = await web3.eth.sign(TEST_MESSAGE, account); - expect(await context.ecdsa.recover(WRONG_MESSAGE, signature)).to.be.not.equals(account); + const { ecdsa } = await loadFixture(deployContracts); + const signature = await account.signMessage(TEST_MESSAGE); + expect(await ecdsa.recover(WRONG_MESSAGE, signature)).to.be.not.equals(account.address); }); it('returns zero address with invalid signature', async () => { - expect(await context.ecdsa.recover(HASHED_TEST_MESSAGE, invalidSignature)).to.be.equals(constants.ZERO_ADDRESS); + const { ecdsa } = await loadFixture(deployContracts); + expect(await ecdsa.recover(HASHED_TEST_MESSAGE, invalidSignature)).to.be.equals(constants.ZERO_ADDRESS); }); }); describe('with v0 signature', function () { it('returns zero address with 00 as version value', async function () { + const { ecdsa } = await loadFixture(deployContracts); const version = '00'; const signature = signatureWithoutVersionV0 + version; - expect(await context.ecdsa.recover(HASHED_TEST_MESSAGE, signature)).to.be.equals(constants.ZERO_ADDRESS); - expect(await context.ecdsa.recover_v_r_s(HASHED_TEST_MESSAGE, ...split3(signature))).to.be.equals(constants.ZERO_ADDRESS); + expect(await ecdsa.recover(HASHED_TEST_MESSAGE, signature)).to.be.equals(constants.ZERO_ADDRESS); + const [, r, s] = split3(signature); + expect(await ecdsa.recover_v_r_s(HASHED_TEST_MESSAGE, 0, r, s)).to.be.equals(constants.ZERO_ADDRESS); }); it('works with 27 as version value', async function () { + const { ecdsa } = await loadFixture(deployContracts); const version = '1b'; // 27 = 1b. const signature = signatureWithoutVersionV0 + version; - expect(await context.ecdsa.recover(HASHED_TEST_MESSAGE, signature)).to.be.equals(signerV0); - expect(await context.ecdsa.recover_v_r_s(HASHED_TEST_MESSAGE, ...split3(signature))).to.be.equals(signerV0); - expect(await context.ecdsa.recover_r_vs(HASHED_TEST_MESSAGE, ...split2(to2098Format(signature)))).to.equal(signerV0); + expect(await ecdsa.recover(HASHED_TEST_MESSAGE, signature)).to.be.equals(signerV0); + expect(await ecdsa.recover_v_r_s(HASHED_TEST_MESSAGE, ...split3(signature))).to.be.equals(signerV0); + expect(await ecdsa.recover_r_vs(HASHED_TEST_MESSAGE, ...split2(to2098Format(signature)))).to.equal(signerV0); }); it('returns zero address when wrong version', async function () { + const { ecdsa } = await loadFixture(deployContracts); // The last two hex digits are the signature version. // The only valid values are 0, 1, 27 and 28. - const version = '02'; - const signature = signatureWithoutVersionV0 + version; - expect(await context.ecdsa.recover(HASHED_TEST_MESSAGE, signature)).to.be.equals(constants.ZERO_ADDRESS); - expect(await context.ecdsa.recover_v_r_s(HASHED_TEST_MESSAGE, ...split3(signature))).to.be.equals(constants.ZERO_ADDRESS); + expect(await ecdsa.recover(HASHED_TEST_MESSAGE, signatureWithoutVersionV0 + '02')).to.be.equals(constants.ZERO_ADDRESS); + const [, r, s] = split3(signatureWithoutVersionV0 + '00'); + expect(await ecdsa.recover_v_r_s(HASHED_TEST_MESSAGE, 2, r, s)).to.be.equals(constants.ZERO_ADDRESS); }); it('works with short EIP2098 format', async function () { + const { ecdsa } = await loadFixture(deployContracts); const version = '1b'; // 27 = 1b. const signature = signatureWithoutVersionV0 + version; - expect(await context.ecdsa.recover(HASHED_TEST_MESSAGE, to2098Format(signature))).to.be.equals(signerV0); - expect(await context.ecdsa.recover(HASHED_TEST_MESSAGE, from2098Format(to2098Format(signature)))).to.be.equals(signerV0); + expect(await ecdsa.recover(HASHED_TEST_MESSAGE, to2098Format(signature))).to.be.equals(signerV0); + expect(await ecdsa.recover(HASHED_TEST_MESSAGE, from2098Format(to2098Format(signature)))).to.be.equals(signerV0); }); }); describe('with v1 signature', function () { it('returns zero address with 01 as version value', async function () { + const { ecdsa } = await loadFixture(deployContracts); const version = '01'; const signature = signatureWithoutVersionV1 + version; - expect(await context.ecdsa.recover(HASHED_TEST_MESSAGE, signature)).to.be.equals(constants.ZERO_ADDRESS); - expect(await context.ecdsa.recover_v_r_s(HASHED_TEST_MESSAGE, ...split3(signature))).to.be.equals(constants.ZERO_ADDRESS); + expect(await ecdsa.recover(HASHED_TEST_MESSAGE, signature)).to.be.equals(constants.ZERO_ADDRESS); + const [, r, s] = split3(signature); + expect(await ecdsa.recover_v_r_s(HASHED_TEST_MESSAGE, 1, r, s)).to.be.equals(constants.ZERO_ADDRESS); }); it('works with 28 as version value', async function () { + const { ecdsa } = await loadFixture(deployContracts); const version = '1c'; // 28 = 1c. const signature = signatureWithoutVersionV1 + version; - expect(await context.ecdsa.recover(HASHED_TEST_MESSAGE, signature)).to.be.equals(signerV1); - expect(await context.ecdsa.recover_v_r_s(HASHED_TEST_MESSAGE, ...split3(signature))).to.be.equals(signerV1); - expect(await context.ecdsa.recover_r_vs(HASHED_TEST_MESSAGE, ...split2(to2098Format(signature)))).to.equal(signerV1); + expect(await ecdsa.recover(HASHED_TEST_MESSAGE, signature)).to.be.equals(signerV1); + expect(await ecdsa.recover_v_r_s(HASHED_TEST_MESSAGE, ...split3(signature))).to.be.equals(signerV1); + expect(await ecdsa.recover_r_vs(HASHED_TEST_MESSAGE, ...split2(to2098Format(signature)))).to.equal(signerV1); }); it('returns zero address when wrong version', async function () { + const { ecdsa } = await loadFixture(deployContracts); // The last two hex digits are the signature version. // The only valid values are 0, 1, 27 and 28. - const version = '02'; - const signature = signatureWithoutVersionV1 + version; - expect(await context.ecdsa.recover(HASHED_TEST_MESSAGE, signature)).to.be.equals(constants.ZERO_ADDRESS); - expect(await context.ecdsa.recover_v_r_s(HASHED_TEST_MESSAGE, ...split3(signature))).to.be.equals(constants.ZERO_ADDRESS); + expect(await ecdsa.recover(HASHED_TEST_MESSAGE, signatureWithoutVersionV1 + '02')).to.be.equals(constants.ZERO_ADDRESS); + const [, r, s] = split3(signatureWithoutVersionV1 + '01'); + expect(await ecdsa.recover_v_r_s(HASHED_TEST_MESSAGE, 2, r, s)).to.be.equals(constants.ZERO_ADDRESS); }); it('works with short EIP2098 format', async function () { + const { ecdsa } = await loadFixture(deployContracts); const version = '1c'; // 27 = 1b. const signature = signatureWithoutVersionV1 + version; - expect(await context.ecdsa.recover(HASHED_TEST_MESSAGE, to2098Format(signature))).to.be.equals(signerV1); - expect(await context.ecdsa.recover(HASHED_TEST_MESSAGE, from2098Format(to2098Format(signature)))).to.be.equals(signerV1); + expect(await ecdsa.recover(HASHED_TEST_MESSAGE, to2098Format(signature))).to.be.equals(signerV1); + expect(await ecdsa.recover(HASHED_TEST_MESSAGE, from2098Format(to2098Format(signature)))).to.be.equals(signerV1); }); }); }); @@ -200,124 +182,138 @@ describe('ECDSA', async () => { describe('isValidSignature', async () => { describe('with invalid signature', async () => { it('with short signature', async function () { - expect(await context.ecdsa.isValidSignature(context.erc1271wallet.address, HASHED_TEST_MESSAGE, '0x1234')).to.be.equals(false); + const { ecdsa, erc1271wallet } = await loadFixture(deployContracts); + expect(await ecdsa.isValidSignature(erc1271wallet.address, HASHED_TEST_MESSAGE, '0x1234')).to.be.equals(false); }); it('with long signature', async () => { - expect(await context.ecdsa.isValidSignature(context.erc1271wallet.address, HASHED_TEST_MESSAGE, longSignature)).to.be.equals(false); + const { ecdsa, erc1271wallet } = await loadFixture(deployContracts); + expect(await ecdsa.isValidSignature(erc1271wallet.address, HASHED_TEST_MESSAGE, longSignature)).to.be.equals(false); }); }); describe('with valid signature', async () => { - describe('using web3.eth.sign', async () => { + describe('using account.signMesage', async () => { it('returns true with correct signature and only correct signer', async () => { - const signature = await web3.eth.sign(TEST_MESSAGE, account); - expect(await context.ecdsa.isValidSignature(context.erc1271wallet.address, HASHED_TEST_MESSAGE, signature)).to.be.equals(true); - expect(await context.ecdsa.isValidSignature(randomAccount, HASHED_TEST_MESSAGE, signature)).to.be.equals(false); + const { ecdsa, erc1271wallet } = await loadFixture(deployContracts); + const signature = await account.signMessage(TEST_MESSAGE); + expect(await ecdsa.isValidSignature(erc1271wallet.address, HASHED_TEST_MESSAGE, signature)).to.be.equals(true); + expect(await ecdsa.isValidSignature(randomAccount.address, HASHED_TEST_MESSAGE, signature)).to.be.equals(false); }); it('returns true with correct signature and only correct signer for arbitrary length message', async () => { - const signature = await web3.eth.sign(NON_HASH_MESSAGE, account); - expect(await context.ecdsa.isValidSignature(context.erc1271wallet.address, web3.eth.accounts.hashMessage(NON_HASH_MESSAGE), signature)).to.be.equals(true); - expect(await context.ecdsa.isValidSignature(randomAccount, web3.eth.accounts.hashMessage(NON_HASH_MESSAGE), signature)).to.be.equals(false); + const { ecdsa, erc1271wallet } = await loadFixture(deployContracts); + const signature = await account.signMessage(NON_HASH_MESSAGE); + expect(await ecdsa.isValidSignature(erc1271wallet.address, ethers.utils.hashMessage(NON_HASH_MESSAGE), signature)).to.be.equals(true); + expect(await ecdsa.isValidSignature(randomAccount.address, ethers.utils.hashMessage(NON_HASH_MESSAGE), signature)).to.be.equals(false); }); it('returns false with invalid signature', async () => { - expect(await context.ecdsa.isValidSignature(context.erc1271wallet.address, web3.eth.accounts.hashMessage(NON_HASH_MESSAGE), invalidSignature)).to.be.equals(false); + const { ecdsa, erc1271wallet } = await loadFixture(deployContracts); + expect(await ecdsa.isValidSignature(erc1271wallet.address, ethers.utils.hashMessage(NON_HASH_MESSAGE), invalidSignature)).to.be.equals(false); }); }); describe('with v0 signature', function () { it('returns false with 00 as version value', async function () { + const { ecdsa, erc1271walletV0 } = await loadFixture(deployContracts); const version = '00'; const signature = signatureWithoutVersionV0 + version; - expect(await context.ecdsa.isValidSignature(context.erc1271walletV0.address, HASHED_TEST_MESSAGE, signature)).to.be.equals(false); - expect(await context.ecdsa.isValidSignature_v_r_s(context.erc1271walletV0.address, HASHED_TEST_MESSAGE, ...split3(signature))).to.be.equals(false); + expect(await ecdsa.isValidSignature(erc1271walletV0.address, HASHED_TEST_MESSAGE, signature)).to.be.equals(false); + const [, r, s] = split3(signature); + expect(await ecdsa.isValidSignature_v_r_s(erc1271walletV0.address, HASHED_TEST_MESSAGE, 0, r, s)).to.be.equals(false); }); it('returns true with 27 as version value, and only for signer', async function () { + const { ecdsa, erc1271walletV0 } = await loadFixture(deployContracts); const version = '1b'; // 27 = 1b. const signature = signatureWithoutVersionV0 + version; - expect(await context.ecdsa.isValidSignature(context.erc1271walletV0.address, HASHED_TEST_MESSAGE, signature)).to.be.equals(true); - expect(await context.ecdsa.isValidSignature(account, HASHED_TEST_MESSAGE, signature)).to.be.equals(false); - expect(await context.ecdsa.isValidSignature_v_r_s(context.erc1271walletV0.address, HASHED_TEST_MESSAGE, ...split3(signature))).to.be.equals(true); - expect(await context.ecdsa.isValidSignature_v_r_s(account, HASHED_TEST_MESSAGE, ...split3(signature))).to.be.equals(false); - expect(await context.ecdsa.isValidSignature_r_vs(context.erc1271walletV0.address, HASHED_TEST_MESSAGE, ...split2(to2098Format(signature)))).to.equal(true); - expect(await context.ecdsa.isValidSignature_r_vs(account, HASHED_TEST_MESSAGE, ...split2(to2098Format(signature)))).to.equal(false); + expect(await ecdsa.isValidSignature(erc1271walletV0.address, HASHED_TEST_MESSAGE, signature)).to.be.equals(true); + expect(await ecdsa.isValidSignature(account.address, HASHED_TEST_MESSAGE, signature)).to.be.equals(false); + expect(await ecdsa.isValidSignature_v_r_s(erc1271walletV0.address, HASHED_TEST_MESSAGE, ...split3(signature))).to.be.equals(true); + expect(await ecdsa.isValidSignature_v_r_s(account.address, HASHED_TEST_MESSAGE, ...split3(signature))).to.be.equals(false); + expect(await ecdsa.isValidSignature_r_vs(erc1271walletV0.address, HASHED_TEST_MESSAGE, ...split2(to2098Format(signature)))).to.equal(true); + expect(await ecdsa.isValidSignature_r_vs(account.address, HASHED_TEST_MESSAGE, ...split2(to2098Format(signature)))).to.equal(false); }); it('returns false when wrong version', async function () { + const { ecdsa, erc1271walletV0 } = await loadFixture(deployContracts); // The last two hex digits are the signature version. // The only valid values are 0, 1, 27 and 28. - const version = '02'; - const signature = signatureWithoutVersionV0 + version; - expect(await context.ecdsa.isValidSignature(context.erc1271walletV0.address, HASHED_TEST_MESSAGE, signature)).to.be.equals(false); - expect(await context.ecdsa.isValidSignature_v_r_s(context.erc1271walletV0.address, HASHED_TEST_MESSAGE, ...split3(signature))).to.be.equals(false); + expect(await ecdsa.isValidSignature(erc1271walletV0.address, HASHED_TEST_MESSAGE, signatureWithoutVersionV0 + '02')).to.be.equals(false); + const [, r, s] = split3(signatureWithoutVersionV1 + '01'); + expect(await ecdsa.isValidSignature_v_r_s(erc1271walletV0.address, HASHED_TEST_MESSAGE, 2, r, s)).to.be.equals(false); }); it('returns true with short EIP2098 format, and only for signer', async function () { + const { ecdsa, erc1271walletV0 } = await loadFixture(deployContracts); const version = '1b'; // 27 = 1b. const signature = signatureWithoutVersionV0 + version; - expect(await context.ecdsa.isValidSignature(context.erc1271walletV0.address, HASHED_TEST_MESSAGE, to2098Format(signature))).to.be.equals(true); - expect(await context.ecdsa.isValidSignature(account, HASHED_TEST_MESSAGE, to2098Format(signature))).to.be.equals(false); - expect(await context.ecdsa.isValidSignature(context.erc1271walletV0.address, HASHED_TEST_MESSAGE, from2098Format(to2098Format(signature)))).to.be.equals(true); - expect(await context.ecdsa.isValidSignature(account, HASHED_TEST_MESSAGE, from2098Format(to2098Format(signature)))).to.be.equals(false); + expect(await ecdsa.isValidSignature(erc1271walletV0.address, HASHED_TEST_MESSAGE, to2098Format(signature))).to.be.equals(true); + expect(await ecdsa.isValidSignature(account.address, HASHED_TEST_MESSAGE, to2098Format(signature))).to.be.equals(false); + expect(await ecdsa.isValidSignature(erc1271walletV0.address, HASHED_TEST_MESSAGE, from2098Format(to2098Format(signature)))).to.be.equals(true); + expect(await ecdsa.isValidSignature(account.address, HASHED_TEST_MESSAGE, from2098Format(to2098Format(signature)))).to.be.equals(false); }); }); describe('with v1 signature', function () { it('returns false with 01 as version value', async function () { - const version = '01'; - const signature = signatureWithoutVersionV1 + version; - expect(await context.ecdsa.isValidSignature(context.erc1271walletV1.address, HASHED_TEST_MESSAGE, signature)).to.be.equals(false); - expect(await context.ecdsa.isValidSignature_v_r_s(context.erc1271walletV1.address, HASHED_TEST_MESSAGE, ...split3(signature))).to.be.equals(false); + const { ecdsa, erc1271walletV1 } = await loadFixture(deployContracts); + expect(await ecdsa.isValidSignature(erc1271walletV1.address, HASHED_TEST_MESSAGE, signatureWithoutVersionV1 + '01')).to.be.equals(false); + const [, r, s] = split3(signatureWithoutVersionV1 + '01'); + expect(await ecdsa.isValidSignature_v_r_s(erc1271walletV1.address, HASHED_TEST_MESSAGE, 1, r, s)).to.be.equals(false); }); it('returns true with 28 as version value, and only for signer', async function () { + const { ecdsa, erc1271walletV1 } = await loadFixture(deployContracts); const version = '1c'; // 28 = 1c. const signature = signatureWithoutVersionV1 + version; - expect(await context.ecdsa.isValidSignature(context.erc1271walletV1.address, HASHED_TEST_MESSAGE, signature)).to.be.equals(true); - expect(await context.ecdsa.isValidSignature(account, HASHED_TEST_MESSAGE, signature)).to.be.equals(false); - expect(await context.ecdsa.isValidSignature_v_r_s(context.erc1271walletV1.address, HASHED_TEST_MESSAGE, ...split3(signature))).to.be.equals(true); - expect(await context.ecdsa.isValidSignature_v_r_s(account, HASHED_TEST_MESSAGE, ...split3(signature))).to.be.equals(false); - expect(await context.ecdsa.isValidSignature_r_vs(context.erc1271walletV1.address, HASHED_TEST_MESSAGE, ...split2(to2098Format(signature)))).to.equal(true); - expect(await context.ecdsa.isValidSignature_r_vs(account, HASHED_TEST_MESSAGE, ...split2(to2098Format(signature)))).to.equal(false); + expect(await ecdsa.isValidSignature(erc1271walletV1.address, HASHED_TEST_MESSAGE, signature)).to.be.equals(true); + expect(await ecdsa.isValidSignature(account.address, HASHED_TEST_MESSAGE, signature)).to.be.equals(false); + expect(await ecdsa.isValidSignature_v_r_s(erc1271walletV1.address, HASHED_TEST_MESSAGE, ...split3(signature))).to.be.equals(true); + expect(await ecdsa.isValidSignature_v_r_s(account.address, HASHED_TEST_MESSAGE, ...split3(signature))).to.be.equals(false); + expect(await ecdsa.isValidSignature_r_vs(erc1271walletV1.address, HASHED_TEST_MESSAGE, ...split2(to2098Format(signature)))).to.equal(true); + expect(await ecdsa.isValidSignature_r_vs(account.address, HASHED_TEST_MESSAGE, ...split2(to2098Format(signature)))).to.equal(false); }); it('returns false when wrong version', async function () { + const { ecdsa, erc1271walletV1 } = await loadFixture(deployContracts); // The last two hex digits are the signature version. // The only valid values are 0, 1, 27 and 28. - const version = '02'; - const signature = signatureWithoutVersionV1 + version; - expect(await context.ecdsa.isValidSignature(context.erc1271walletV1.address, HASHED_TEST_MESSAGE, signature)).to.be.equals(false); - expect(await context.ecdsa.isValidSignature_v_r_s(context.erc1271walletV1.address, HASHED_TEST_MESSAGE, ...split3(signature))).to.be.equals(false); + expect(await ecdsa.isValidSignature(erc1271walletV1.address, HASHED_TEST_MESSAGE, signatureWithoutVersionV1 + '02')).to.be.equals(false); + const [, r, s] = split3(signatureWithoutVersionV1 + '01'); + expect(await ecdsa.isValidSignature_v_r_s(erc1271walletV1.address, HASHED_TEST_MESSAGE, 2, r, s)).to.be.equals(false); }); it('returns true with short EIP2098 format, and only for signer', async function () { + const { ecdsa, erc1271walletV1 } = await loadFixture(deployContracts); const version = '1c'; // 27 = 1b. const signature = signatureWithoutVersionV1 + version; - expect(await context.ecdsa.isValidSignature(context.erc1271walletV1.address, HASHED_TEST_MESSAGE, to2098Format(signature))).to.be.equals(true); - expect(await context.ecdsa.isValidSignature(account, HASHED_TEST_MESSAGE, to2098Format(signature))).to.be.equals(false); - expect(await context.ecdsa.isValidSignature(context.erc1271walletV1.address, HASHED_TEST_MESSAGE, from2098Format(to2098Format(signature)))).to.be.equals(true); - expect(await context.ecdsa.isValidSignature(account, HASHED_TEST_MESSAGE, from2098Format(to2098Format(signature)))).to.be.equals(false); + expect(await ecdsa.isValidSignature(erc1271walletV1.address, HASHED_TEST_MESSAGE, to2098Format(signature))).to.be.equals(true); + expect(await ecdsa.isValidSignature(account.address, HASHED_TEST_MESSAGE, to2098Format(signature))).to.be.equals(false); + expect(await ecdsa.isValidSignature(erc1271walletV1.address, HASHED_TEST_MESSAGE, from2098Format(to2098Format(signature)))).to.be.equals(true); + expect(await ecdsa.isValidSignature(account.address, HASHED_TEST_MESSAGE, from2098Format(to2098Format(signature)))).to.be.equals(false); }); }); describe('isValidSignature65', async () => { it('with matching signer and signature', async function () { - const signature = await web3.eth.sign(TEST_MESSAGE, account); - expect(await context.ecdsa.isValidSignature65(context.erc1271wallet.address, HASHED_TEST_MESSAGE, ...split2(signature))).to.be.equals(true); + const { ecdsa, erc1271wallet } = await loadFixture(deployContracts); + const signature = await account.signMessage(TEST_MESSAGE); + expect(await ecdsa.isValidSignature65(erc1271wallet.address, HASHED_TEST_MESSAGE, ...split2(signature))).to.be.equals(true); }); it('with invalid signer', async function () { - const signature = await web3.eth.sign(TEST_MESSAGE, account); - expect(await context.ecdsa.isValidSignature65(randomAccount, HASHED_TEST_MESSAGE, ...split2(signature))).to.be.equals(false); + const { ecdsa } = await loadFixture(deployContracts); + const signature = await account.signMessage(TEST_MESSAGE); + expect(await ecdsa.isValidSignature65(randomAccount.address, HASHED_TEST_MESSAGE, ...split2(signature))).to.be.equals(false); }); it('with invalid signature', async function () { - const signature = await web3.eth.sign(TEST_MESSAGE, account); - const HASHED_WRONG_MESSAGE = web3.eth.accounts.hashMessage(WRONG_MESSAGE); - expect(await context.ecdsa.isValidSignature65(context.erc1271wallet.address, HASHED_WRONG_MESSAGE, ...split2(signature))).to.be.equals(false); + const { ecdsa, erc1271wallet } = await loadFixture(deployContracts); + const signature = await account.signMessage(TEST_MESSAGE); + const HASHED_WRONG_MESSAGE = ethers.utils.hashMessage(WRONG_MESSAGE); + expect(await ecdsa.isValidSignature65(erc1271wallet.address, HASHED_WRONG_MESSAGE, ...split2(signature))).to.be.equals(false); }); }); }); @@ -326,149 +322,165 @@ describe('ECDSA', async () => { describe('recoverOrIsValidSignature', async () => { describe('with invalid signature', async () => { it('with short signature', async function () { - expect(await context.ecdsa.recoverOrIsValidSignature(account, HASHED_TEST_MESSAGE, '0x1234')).to.be.equals(false); - expect(await context.ecdsa.recoverOrIsValidSignature(context.erc1271wallet.address, HASHED_TEST_MESSAGE, '0x1234')).to.be.equals(false); + const { ecdsa, erc1271wallet } = await loadFixture(deployContracts); + expect(await ecdsa.recoverOrIsValidSignature(account.address, HASHED_TEST_MESSAGE, '0x1234')).to.be.equals(false); + expect(await ecdsa.recoverOrIsValidSignature(erc1271wallet.address, HASHED_TEST_MESSAGE, '0x1234')).to.be.equals(false); }); it('with long signature', async () => { - expect(await context.ecdsa.recoverOrIsValidSignature(account, HASHED_TEST_MESSAGE, longSignature)).to.be.equals(false); - expect(await context.ecdsa.recoverOrIsValidSignature(context.erc1271wallet.address, HASHED_TEST_MESSAGE, longSignature)).to.be.equals(false); + const { ecdsa, erc1271wallet } = await loadFixture(deployContracts); + expect(await ecdsa.recoverOrIsValidSignature(account.address, HASHED_TEST_MESSAGE, longSignature)).to.be.equals(false); + expect(await ecdsa.recoverOrIsValidSignature(erc1271wallet.address, HASHED_TEST_MESSAGE, longSignature)).to.be.equals(false); }); }); describe('with valid signature', async () => { - describe('using web3.eth.sign', async () => { + describe('using account.signMessage', async () => { it('returns true with correct signature and only correct signer', async () => { - const signature = await web3.eth.sign(TEST_MESSAGE, account); - expect(await context.ecdsa.recoverOrIsValidSignature(account, HASHED_TEST_MESSAGE, signature)).to.be.equals(true); - expect(await context.ecdsa.recoverOrIsValidSignature(randomAccount, HASHED_TEST_MESSAGE, signature)).to.be.equals(false); - expect(await context.ecdsa.recoverOrIsValidSignature(context.erc1271wallet.address, HASHED_TEST_MESSAGE, signature)).to.be.equals(true); + const { ecdsa, erc1271wallet } = await loadFixture(deployContracts); + const signature = await account.signMessage(TEST_MESSAGE); + expect(await ecdsa.recoverOrIsValidSignature(account.address, HASHED_TEST_MESSAGE, signature)).to.be.equals(true); + expect(await ecdsa.recoverOrIsValidSignature(randomAccount.address, HASHED_TEST_MESSAGE, signature)).to.be.equals(false); + expect(await ecdsa.recoverOrIsValidSignature(erc1271wallet.address, HASHED_TEST_MESSAGE, signature)).to.be.equals(true); }); it('returns true with correct signature and only correct signer for arbitrary length message', async () => { - const signature = await web3.eth.sign(NON_HASH_MESSAGE, account); - expect(await context.ecdsa.recoverOrIsValidSignature(account, web3.eth.accounts.hashMessage(NON_HASH_MESSAGE), signature)).to.be.equals(true); - expect(await context.ecdsa.recoverOrIsValidSignature(randomAccount, web3.eth.accounts.hashMessage(NON_HASH_MESSAGE), signature)).to.be.equals(false); - expect(await context.ecdsa.recoverOrIsValidSignature(context.erc1271wallet.address, web3.eth.accounts.hashMessage(NON_HASH_MESSAGE), signature)).to.be.equals(true); + const { ecdsa, erc1271wallet } = await loadFixture(deployContracts); + const signature = await account.signMessage(NON_HASH_MESSAGE); + expect(await ecdsa.recoverOrIsValidSignature(account.address, ethers.utils.hashMessage(NON_HASH_MESSAGE), signature)).to.be.equals(true); + expect(await ecdsa.recoverOrIsValidSignature(randomAccount.address, ethers.utils.hashMessage(NON_HASH_MESSAGE), signature)).to.be.equals(false); + expect(await ecdsa.recoverOrIsValidSignature(erc1271wallet.address, ethers.utils.hashMessage(NON_HASH_MESSAGE), signature)).to.be.equals(true); }); it('returns false with invalid signature', async () => { - expect(await context.ecdsa.recoverOrIsValidSignature(account, web3.eth.accounts.hashMessage(NON_HASH_MESSAGE), invalidSignature)).to.be.equals(false); - expect(await context.ecdsa.recoverOrIsValidSignature(context.erc1271wallet.address, web3.eth.accounts.hashMessage(NON_HASH_MESSAGE), invalidSignature)).to.be.equals(false); + const { ecdsa, erc1271wallet } = await loadFixture(deployContracts); + expect(await ecdsa.recoverOrIsValidSignature(account.address, ethers.utils.hashMessage(NON_HASH_MESSAGE), invalidSignature)).to.be.equals(false); + expect(await ecdsa.recoverOrIsValidSignature(erc1271wallet.address, ethers.utils.hashMessage(NON_HASH_MESSAGE), invalidSignature)).to.be.equals(false); }); }); describe('with v0 signature', function () { it('returns false with 00 as version value', async function () { + const { ecdsa, erc1271walletV0 } = await loadFixture(deployContracts); const version = '00'; const signature = signatureWithoutVersionV0 + version; - expect(await context.ecdsa.recoverOrIsValidSignature(signerV0, HASHED_TEST_MESSAGE, signature)).to.be.equals(false); - expect(await context.ecdsa.recoverOrIsValidSignature(context.erc1271walletV0.address, HASHED_TEST_MESSAGE, signature)).to.be.equals(false); - expect(await context.ecdsa.recoverOrIsValidSignature_v_r_s(signerV0, HASHED_TEST_MESSAGE, ...split3(signature))).to.be.equals(false); - expect(await context.ecdsa.recoverOrIsValidSignature_v_r_s(context.erc1271walletV0.address, HASHED_TEST_MESSAGE, ...split3(signature))).to.be.equals(false); + expect(await ecdsa.recoverOrIsValidSignature(signerV0, HASHED_TEST_MESSAGE, signature)).to.be.equals(false); + expect(await ecdsa.recoverOrIsValidSignature(erc1271walletV0.address, HASHED_TEST_MESSAGE, signature)).to.be.equals(false); + const [, r, s] = split3(signature); + expect(await ecdsa.recoverOrIsValidSignature_v_r_s(signerV0, HASHED_TEST_MESSAGE, 0, r, s)).to.be.equals(false); + expect(await ecdsa.recoverOrIsValidSignature_v_r_s(erc1271walletV0.address, HASHED_TEST_MESSAGE, 0, r, s)).to.be.equals(false); }); it('returns true with 27 as version value, and only for signer', async function () { + const { ecdsa, erc1271walletV0 } = await loadFixture(deployContracts); const version = '1b'; // 27 = 1b. const signature = signatureWithoutVersionV0 + version; - expect(await context.ecdsa.recoverOrIsValidSignature(signerV0, HASHED_TEST_MESSAGE, signature)).to.be.equals(true); - expect(await context.ecdsa.recoverOrIsValidSignature(context.erc1271walletV0.address, HASHED_TEST_MESSAGE, signature)).to.be.equals(true); - expect(await context.ecdsa.recoverOrIsValidSignature(account, HASHED_TEST_MESSAGE, signature)).to.be.equals(false); - expect(await context.ecdsa.recoverOrIsValidSignature_v_r_s(signerV0, HASHED_TEST_MESSAGE, ...split3(signature))).to.be.equals(true); - expect(await context.ecdsa.recoverOrIsValidSignature_v_r_s(context.erc1271walletV0.address, HASHED_TEST_MESSAGE, ...split3(signature))).to.be.equals(true); - expect(await context.ecdsa.recoverOrIsValidSignature_v_r_s(account, HASHED_TEST_MESSAGE, ...split3(signature))).to.be.equals(false); - expect(await context.ecdsa.recoverOrIsValidSignature_r_vs(signerV0, HASHED_TEST_MESSAGE, ...split2(to2098Format(signature)))).to.equal(true); - expect(await context.ecdsa.recoverOrIsValidSignature_r_vs(context.erc1271walletV0.address, HASHED_TEST_MESSAGE, ...split2(to2098Format(signature)))).to.equal(true); - expect(await context.ecdsa.recoverOrIsValidSignature_r_vs(account, HASHED_TEST_MESSAGE, ...split2(to2098Format(signature)))).to.equal(false); + expect(await ecdsa.recoverOrIsValidSignature(signerV0, HASHED_TEST_MESSAGE, signature)).to.be.equals(true); + expect(await ecdsa.recoverOrIsValidSignature(erc1271walletV0.address, HASHED_TEST_MESSAGE, signature)).to.be.equals(true); + expect(await ecdsa.recoverOrIsValidSignature(account.address, HASHED_TEST_MESSAGE, signature)).to.be.equals(false); + expect(await ecdsa.recoverOrIsValidSignature_v_r_s(signerV0, HASHED_TEST_MESSAGE, ...split3(signature))).to.be.equals(true); + expect(await ecdsa.recoverOrIsValidSignature_v_r_s(erc1271walletV0.address, HASHED_TEST_MESSAGE, ...split3(signature))).to.be.equals(true); + expect(await ecdsa.recoverOrIsValidSignature_v_r_s(account.address, HASHED_TEST_MESSAGE, ...split3(signature))).to.be.equals(false); + expect(await ecdsa.recoverOrIsValidSignature_r_vs(signerV0, HASHED_TEST_MESSAGE, ...split2(to2098Format(signature)))).to.equal(true); + expect(await ecdsa.recoverOrIsValidSignature_r_vs(erc1271walletV0.address, HASHED_TEST_MESSAGE, ...split2(to2098Format(signature)))).to.equal(true); + expect(await ecdsa.recoverOrIsValidSignature_r_vs(account.address, HASHED_TEST_MESSAGE, ...split2(to2098Format(signature)))).to.equal(false); }); it('returns false when wrong version', async function () { + const { ecdsa, erc1271walletV0 } = await loadFixture(deployContracts); // The last two hex digits are the signature version. // The only valid values are 0, 1, 27 and 28. - const version = '02'; - const signature = signatureWithoutVersionV0 + version; - expect(await context.ecdsa.recoverOrIsValidSignature(signerV0, HASHED_TEST_MESSAGE, signature)).to.be.equals(false); - expect(await context.ecdsa.recoverOrIsValidSignature(context.erc1271walletV0.address, HASHED_TEST_MESSAGE, signature)).to.be.equals(false); - expect(await context.ecdsa.recoverOrIsValidSignature_v_r_s(signerV0, HASHED_TEST_MESSAGE, ...split3(signature))).to.be.equals(false); - expect(await context.ecdsa.recoverOrIsValidSignature_v_r_s(context.erc1271walletV0.address, HASHED_TEST_MESSAGE, ...split3(signature))).to.be.equals(false); + expect(await ecdsa.recoverOrIsValidSignature(signerV0, HASHED_TEST_MESSAGE, signatureWithoutVersionV0 + '02')).to.be.equals(false); + expect(await ecdsa.recoverOrIsValidSignature(erc1271walletV0.address, HASHED_TEST_MESSAGE, signatureWithoutVersionV0 + '02')).to.be.equals(false); + const [, r, s] = split3(signatureWithoutVersionV0 + '00'); + expect(await ecdsa.recoverOrIsValidSignature_v_r_s(signerV0, HASHED_TEST_MESSAGE, 2, r, s)).to.be.equals(false); + expect(await ecdsa.recoverOrIsValidSignature_v_r_s(erc1271walletV0.address, HASHED_TEST_MESSAGE, 2, r, s)).to.be.equals(false); }); it('returns true with short EIP2098 format, and only for signer', async function () { + const { ecdsa, erc1271walletV0 } = await loadFixture(deployContracts); const version = '1b'; // 27 = 1b. const signature = signatureWithoutVersionV0 + version; - expect(await context.ecdsa.recoverOrIsValidSignature(signerV0, HASHED_TEST_MESSAGE, to2098Format(signature))).to.be.equals(true); - expect(await context.ecdsa.recoverOrIsValidSignature(context.erc1271walletV0.address, HASHED_TEST_MESSAGE, to2098Format(signature))).to.be.equals(true); - expect(await context.ecdsa.recoverOrIsValidSignature(account, HASHED_TEST_MESSAGE, to2098Format(signature))).to.be.equals(false); - expect(await context.ecdsa.recoverOrIsValidSignature(signerV0, HASHED_TEST_MESSAGE, from2098Format(to2098Format(signature)))).to.be.equals(true); - expect(await context.ecdsa.recoverOrIsValidSignature(context.erc1271walletV0.address, HASHED_TEST_MESSAGE, from2098Format(to2098Format(signature)))).to.be.equals(true); - expect(await context.ecdsa.recoverOrIsValidSignature(account, HASHED_TEST_MESSAGE, from2098Format(to2098Format(signature)))).to.be.equals(false); + expect(await ecdsa.recoverOrIsValidSignature(signerV0, HASHED_TEST_MESSAGE, to2098Format(signature))).to.be.equals(true); + expect(await ecdsa.recoverOrIsValidSignature(erc1271walletV0.address, HASHED_TEST_MESSAGE, to2098Format(signature))).to.be.equals(true); + expect(await ecdsa.recoverOrIsValidSignature(account.address, HASHED_TEST_MESSAGE, to2098Format(signature))).to.be.equals(false); + expect(await ecdsa.recoverOrIsValidSignature(signerV0, HASHED_TEST_MESSAGE, from2098Format(to2098Format(signature)))).to.be.equals(true); + expect(await ecdsa.recoverOrIsValidSignature(erc1271walletV0.address, HASHED_TEST_MESSAGE, from2098Format(to2098Format(signature)))).to.be.equals(true); + expect(await ecdsa.recoverOrIsValidSignature(account.address, HASHED_TEST_MESSAGE, from2098Format(to2098Format(signature)))).to.be.equals(false); }); }); describe('with v1 signature', function () { it('returns false with 01 as version value', async function () { + const { ecdsa, erc1271walletV1 } = await loadFixture(deployContracts); const version = '01'; const signature = signatureWithoutVersionV1 + version; - expect(await context.ecdsa.recoverOrIsValidSignature(signerV1, HASHED_TEST_MESSAGE, signature)).to.be.equals(false); - expect(await context.ecdsa.recoverOrIsValidSignature(context.erc1271walletV1.address, HASHED_TEST_MESSAGE, signature)).to.be.equals(false); - expect(await context.ecdsa.recoverOrIsValidSignature_v_r_s(signerV1, HASHED_TEST_MESSAGE, ...split3(signature))).to.be.equals(false); - expect(await context.ecdsa.recoverOrIsValidSignature_v_r_s(context.erc1271walletV1.address, HASHED_TEST_MESSAGE, ...split3(signature))).to.be.equals(false); + expect(await ecdsa.recoverOrIsValidSignature(signerV1, HASHED_TEST_MESSAGE, signature)).to.be.equals(false); + expect(await ecdsa.recoverOrIsValidSignature(erc1271walletV1.address, HASHED_TEST_MESSAGE, signature)).to.be.equals(false); + const [, r, s] = split3(signature); + expect(await ecdsa.recoverOrIsValidSignature_v_r_s(signerV1, HASHED_TEST_MESSAGE, 1, r, s)).to.be.equals(false); + expect(await ecdsa.recoverOrIsValidSignature_v_r_s(erc1271walletV1.address, HASHED_TEST_MESSAGE, 1, r, s)).to.be.equals(false); }); it('returns true with 28 as version value, and only for signer', async function () { + const { ecdsa, erc1271walletV1 } = await loadFixture(deployContracts); const version = '1c'; // 28 = 1c. const signature = signatureWithoutVersionV1 + version; - expect(await context.ecdsa.recoverOrIsValidSignature(signerV1, HASHED_TEST_MESSAGE, signature)).to.be.equals(true); - expect(await context.ecdsa.recoverOrIsValidSignature(context.erc1271walletV1.address, HASHED_TEST_MESSAGE, signature)).to.be.equals(true); - expect(await context.ecdsa.recoverOrIsValidSignature(account, HASHED_TEST_MESSAGE, signature)).to.be.equals(false); - expect(await context.ecdsa.recoverOrIsValidSignature_v_r_s(signerV1, HASHED_TEST_MESSAGE, ...split3(signature))).to.be.equals(true); - expect(await context.ecdsa.recoverOrIsValidSignature_v_r_s(context.erc1271walletV1.address, HASHED_TEST_MESSAGE, ...split3(signature))).to.be.equals(true); - expect(await context.ecdsa.recoverOrIsValidSignature_v_r_s(account, HASHED_TEST_MESSAGE, ...split3(signature))).to.be.equals(false); - expect(await context.ecdsa.recoverOrIsValidSignature_r_vs(signerV1, HASHED_TEST_MESSAGE, ...split2(to2098Format(signature)))).to.equal(true); - expect(await context.ecdsa.recoverOrIsValidSignature_r_vs(context.erc1271walletV1.address, HASHED_TEST_MESSAGE, ...split2(to2098Format(signature)))).to.equal(true); - expect(await context.ecdsa.recoverOrIsValidSignature_r_vs(account, HASHED_TEST_MESSAGE, ...split2(to2098Format(signature)))).to.equal(false); + expect(await ecdsa.recoverOrIsValidSignature(signerV1, HASHED_TEST_MESSAGE, signature)).to.be.equals(true); + expect(await ecdsa.recoverOrIsValidSignature(erc1271walletV1.address, HASHED_TEST_MESSAGE, signature)).to.be.equals(true); + expect(await ecdsa.recoverOrIsValidSignature(account.address, HASHED_TEST_MESSAGE, signature)).to.be.equals(false); + expect(await ecdsa.recoverOrIsValidSignature_v_r_s(signerV1, HASHED_TEST_MESSAGE, ...split3(signature))).to.be.equals(true); + expect(await ecdsa.recoverOrIsValidSignature_v_r_s(erc1271walletV1.address, HASHED_TEST_MESSAGE, ...split3(signature))).to.be.equals(true); + expect(await ecdsa.recoverOrIsValidSignature_v_r_s(account.address, HASHED_TEST_MESSAGE, ...split3(signature))).to.be.equals(false); + expect(await ecdsa.recoverOrIsValidSignature_r_vs(signerV1, HASHED_TEST_MESSAGE, ...split2(to2098Format(signature)))).to.equal(true); + expect(await ecdsa.recoverOrIsValidSignature_r_vs(erc1271walletV1.address, HASHED_TEST_MESSAGE, ...split2(to2098Format(signature)))).to.equal(true); + expect(await ecdsa.recoverOrIsValidSignature_r_vs(account.address, HASHED_TEST_MESSAGE, ...split2(to2098Format(signature)))).to.equal(false); }); it('returns false when wrong version', async function () { + const { ecdsa, erc1271walletV1 } = await loadFixture(deployContracts); // The last two hex digits are the signature version. // The only valid values are 0, 1, 27 and 28. - const version = '02'; - const signature = signatureWithoutVersionV1 + version; - expect(await context.ecdsa.recoverOrIsValidSignature(signerV1, HASHED_TEST_MESSAGE, signature)).to.be.equals(false); - expect(await context.ecdsa.recoverOrIsValidSignature(context.erc1271walletV1.address, HASHED_TEST_MESSAGE, signature)).to.be.equals(false); - expect(await context.ecdsa.recoverOrIsValidSignature_v_r_s(signerV1, HASHED_TEST_MESSAGE, ...split3(signature))).to.be.equals(false); - expect(await context.ecdsa.recoverOrIsValidSignature_v_r_s(context.erc1271walletV1.address, HASHED_TEST_MESSAGE, ...split3(signature))).to.be.equals(false); + expect(await ecdsa.recoverOrIsValidSignature(signerV1, HASHED_TEST_MESSAGE, signatureWithoutVersionV1 + '02')).to.be.equals(false); + expect(await ecdsa.recoverOrIsValidSignature(erc1271walletV1.address, HASHED_TEST_MESSAGE, signatureWithoutVersionV1 + '02')).to.be.equals(false); + const [, r, s] = split3(signatureWithoutVersionV1 + '01'); + expect(await ecdsa.recoverOrIsValidSignature_v_r_s(signerV1, HASHED_TEST_MESSAGE, 2, r, s)).to.be.equals(false); + expect(await ecdsa.recoverOrIsValidSignature_v_r_s(erc1271walletV1.address, HASHED_TEST_MESSAGE, 2, r, s)).to.be.equals(false); }); it('returns true with short EIP2098 format, and only for signer', async function () { + const { ecdsa, erc1271walletV1 } = await loadFixture(deployContracts); const version = '1c'; // 27 = 1b. const signature = signatureWithoutVersionV1 + version; - expect(await context.ecdsa.recoverOrIsValidSignature(signerV1, HASHED_TEST_MESSAGE, to2098Format(signature))).to.be.equals(true); - expect(await context.ecdsa.recoverOrIsValidSignature(context.erc1271walletV1.address, HASHED_TEST_MESSAGE, to2098Format(signature))).to.be.equals(true); - expect(await context.ecdsa.recoverOrIsValidSignature(account, HASHED_TEST_MESSAGE, to2098Format(signature))).to.be.equals(false); - expect(await context.ecdsa.recoverOrIsValidSignature(signerV1, HASHED_TEST_MESSAGE, from2098Format(to2098Format(signature)))).to.be.equals(true); - expect(await context.ecdsa.recoverOrIsValidSignature(context.erc1271walletV1.address, HASHED_TEST_MESSAGE, from2098Format(to2098Format(signature)))).to.be.equals(true); - expect(await context.ecdsa.recoverOrIsValidSignature(account, HASHED_TEST_MESSAGE, from2098Format(to2098Format(signature)))).to.be.equals(false); + expect(await ecdsa.recoverOrIsValidSignature(signerV1, HASHED_TEST_MESSAGE, to2098Format(signature))).to.be.equals(true); + expect(await ecdsa.recoverOrIsValidSignature(erc1271walletV1.address, HASHED_TEST_MESSAGE, to2098Format(signature))).to.be.equals(true); + expect(await ecdsa.recoverOrIsValidSignature(account.address, HASHED_TEST_MESSAGE, to2098Format(signature))).to.be.equals(false); + expect(await ecdsa.recoverOrIsValidSignature(signerV1, HASHED_TEST_MESSAGE, from2098Format(to2098Format(signature)))).to.be.equals(true); + expect(await ecdsa.recoverOrIsValidSignature(erc1271walletV1.address, HASHED_TEST_MESSAGE, from2098Format(to2098Format(signature)))).to.be.equals(true); + expect(await ecdsa.recoverOrIsValidSignature(account.address, HASHED_TEST_MESSAGE, from2098Format(to2098Format(signature)))).to.be.equals(false); }); }); describe('recoverOrIsValidSignature65', async () => { it('with matching signer and signature', async function () { - const signature = await web3.eth.sign(TEST_MESSAGE, account); - expect(await context.ecdsa.recoverOrIsValidSignature65(account, HASHED_TEST_MESSAGE, ...split2(signature))).to.be.equals(true); - expect(await context.ecdsa.recoverOrIsValidSignature65(context.erc1271wallet.address, HASHED_TEST_MESSAGE, ...split2(signature))).to.be.equals(true); + const { ecdsa, erc1271wallet } = await loadFixture(deployContracts); + const signature = await account.signMessage(TEST_MESSAGE); + expect(await ecdsa.recoverOrIsValidSignature65(account.address, HASHED_TEST_MESSAGE, ...split2(signature))).to.be.equals(true); + expect(await ecdsa.recoverOrIsValidSignature65(erc1271wallet.address, HASHED_TEST_MESSAGE, ...split2(signature))).to.be.equals(true); }); it('with invalid signer', async function () { - const signature = await web3.eth.sign(TEST_MESSAGE, account); - expect(await context.ecdsa.recoverOrIsValidSignature65(randomAccount, HASHED_TEST_MESSAGE, ...split2(signature))).to.be.equals(false); + const { ecdsa } = await loadFixture(deployContracts); + const signature = await account.signMessage(TEST_MESSAGE); + expect(await ecdsa.recoverOrIsValidSignature65(randomAccount.address, HASHED_TEST_MESSAGE, ...split2(signature))).to.be.equals(false); }); it('with invalid signature', async function () { - const signature = await web3.eth.sign(TEST_MESSAGE, account); - const HASHED_WRONG_MESSAGE = web3.eth.accounts.hashMessage(WRONG_MESSAGE); - expect(await context.ecdsa.recoverOrIsValidSignature65(account, HASHED_WRONG_MESSAGE, ...split2(signature))).to.be.equals(false); - expect(await context.ecdsa.recoverOrIsValidSignature65(context.erc1271wallet.address, HASHED_WRONG_MESSAGE, ...split2(signature))).to.be.equals(false); + const { ecdsa, erc1271wallet } = await loadFixture(deployContracts); + const signature = await account.signMessage(TEST_MESSAGE); + const HASHED_WRONG_MESSAGE = ethers.utils.hashMessage(WRONG_MESSAGE); + expect(await ecdsa.recoverOrIsValidSignature65(account.address, HASHED_WRONG_MESSAGE, ...split2(signature))).to.be.equals(false); + expect(await ecdsa.recoverOrIsValidSignature65(erc1271wallet.address, HASHED_WRONG_MESSAGE, ...split2(signature))).to.be.equals(false); }); }); }); @@ -476,116 +488,140 @@ describe('ECDSA', async () => { describe('toEthSignedMessageHash', async () => { it('correct hash', async function () { + const { ecdsa } = await loadFixture(deployContracts); const hashedTestMessageWithoutPrefix = HASHED_TEST_MESSAGE.substring(2); - const ethSignedMessage = web3.utils.sha3(web3.utils.toHex(`\u0019Ethereum Signed Message:\n${hashedTestMessageWithoutPrefix.length/2}`) + hashedTestMessageWithoutPrefix); - expect(await context.ecdsa.toEthSignedMessageHash(HASHED_TEST_MESSAGE)).to.be.equals(ethSignedMessage); + const msg = concat([ + ethers.utils.toUtf8Bytes('\x19Ethereum Signed Message:\n'), + ethers.utils.toUtf8Bytes(String(hashedTestMessageWithoutPrefix.length / 2)), + arrayify(hashedTestMessageWithoutPrefix, { allowMissingPrefix: true }), + ]); + const ethSignedMessage = ethers.utils.keccak256(msg); + expect(await ecdsa.toEthSignedMessageHash(HASHED_TEST_MESSAGE)).to.be.equals(ethSignedMessage); }); }); describe('toTypedDataHash', async () => { it('correct hash', async function () { + const { ecdsa } = await loadFixture(deployContracts); const domainSeparator = HASHED_TEST_MESSAGE.substring(2); const structHash = HASHED_TEST_MESSAGE.substring(2); - const typedDataHash = web3.utils.sha3(web3.utils.toHex('\x19\x01') + domainSeparator + structHash); - expect(await context.ecdsa.toTypedDataHash(HASHED_TEST_MESSAGE, HASHED_TEST_MESSAGE)).to.be.equals(typedDataHash); + const typedDataHash = ethers.utils.keccak256(concat([ + ethers.utils.toUtf8Bytes('\x19\x01'), + arrayify(domainSeparator, { allowMissingPrefix: true }), + arrayify(String(structHash), { allowMissingPrefix: true }), + ])); + expect(await ecdsa.toTypedDataHash(HASHED_TEST_MESSAGE, HASHED_TEST_MESSAGE)).to.be.equals(typedDataHash); }); }); describe('gas price', async () => { describe('recover', async () => { it('with signature', async function () { - const signature = await web3.eth.sign(TEST_MESSAGE, account); - await context.ecdsa.contract.methods.recover(HASHED_TEST_MESSAGE, signature).send({ from: account }); + const { ecdsa } = await loadFixture(deployContracts); + const signature = await account.signMessage(TEST_MESSAGE); + await account.sendTransaction(await ecdsa.populateTransaction.recover(HASHED_TEST_MESSAGE, signature)); }); it('with v0 signature', async () => { + const { ecdsa } = await loadFixture(deployContracts); const version = '1b'; // 27 = 1b. const signature = signatureWithoutVersionV0 + version; - await context.ecdsa.contract.methods.recover(HASHED_TEST_MESSAGE, signature).send({ from: account }); - await context.ecdsa.contract.methods.recover_v_r_s(HASHED_TEST_MESSAGE, ...split3(signature)).send({ from: account }); - await context.ecdsa.contract.methods.recover_r_vs(HASHED_TEST_MESSAGE, ...split2(to2098Format(signature))).send({ from: account }); + await account.sendTransaction(await ecdsa.populateTransaction.recover(HASHED_TEST_MESSAGE, signature)); + await account.sendTransaction(await ecdsa.populateTransaction.recover_v_r_s(HASHED_TEST_MESSAGE, ...split3(signature))); + await account.sendTransaction(await ecdsa.populateTransaction.recover_r_vs(HASHED_TEST_MESSAGE, ...split2(to2098Format(signature)))); }); it('with v1 signature', async () => { + const { ecdsa } = await loadFixture(deployContracts); const version = '1c'; // 28 = 1c. const signature = signatureWithoutVersionV1 + version; - await context.ecdsa.contract.methods.recover(HASHED_TEST_MESSAGE, signature).send({ from: account }); - await context.ecdsa.contract.methods.recover_v_r_s(HASHED_TEST_MESSAGE, ...split3(signature)).send({ from: account }); - await context.ecdsa.contract.methods.recover_r_vs(HASHED_TEST_MESSAGE, ...split2(to2098Format(signature))).send({ from: account }); + await account.sendTransaction(await ecdsa.populateTransaction.recover(HASHED_TEST_MESSAGE, signature)); + await account.sendTransaction(await ecdsa.populateTransaction.recover_v_r_s(HASHED_TEST_MESSAGE, ...split3(signature))); + await account.sendTransaction(await ecdsa.populateTransaction.recover_r_vs(HASHED_TEST_MESSAGE, ...split2(to2098Format(signature)))); }); }); describe('recoverOrIsValidSignature', async () => { it('with signature', async function () { - const signature = await web3.eth.sign(TEST_MESSAGE, account); - await context.ecdsa.contract.methods.recoverOrIsValidSignature(account, HASHED_TEST_MESSAGE, signature).send({ from: account }); - await context.ecdsa.contract.methods.recoverOrIsValidSignature(context.erc1271wallet.address, HASHED_TEST_MESSAGE, signature).send({ from: account }); + const { ecdsa, erc1271wallet } = await loadFixture(deployContracts); + const signature = await account.signMessage(TEST_MESSAGE); + await account.sendTransaction(await ecdsa.populateTransaction.recoverOrIsValidSignature(account.address, HASHED_TEST_MESSAGE, signature)); + await account.sendTransaction(await ecdsa.populateTransaction.recoverOrIsValidSignature(erc1271wallet.address, HASHED_TEST_MESSAGE, signature)); }); it('with v0 signature', async () => { + const { ecdsa, erc1271walletV0 } = await loadFixture(deployContracts); const version = '1b'; // 27 = 1b. const signature = signatureWithoutVersionV0 + version; - await context.ecdsa.contract.methods.recoverOrIsValidSignature(signerV0, HASHED_TEST_MESSAGE, signature).send({ from: account }); - await context.ecdsa.contract.methods.recoverOrIsValidSignature(context.erc1271walletV0.address, HASHED_TEST_MESSAGE, signature).send({ from: account }); - await context.ecdsa.contract.methods.recoverOrIsValidSignature_v_r_s(signerV0, HASHED_TEST_MESSAGE, ...split3(signature)).send({ from: account }); - await context.ecdsa.contract.methods.recoverOrIsValidSignature_v_r_s(context.erc1271walletV0.address, HASHED_TEST_MESSAGE, ...split3(signature)).send({ from: account }); - await context.ecdsa.contract.methods.recoverOrIsValidSignature_r_vs(signerV0, HASHED_TEST_MESSAGE, ...split2(to2098Format(signature))).send({ from: account }); - await context.ecdsa.contract.methods.recoverOrIsValidSignature_r_vs(context.erc1271walletV0.address, HASHED_TEST_MESSAGE, ...split2(to2098Format(signature))).send({ from: account }); + await account.sendTransaction(await ecdsa.populateTransaction.recoverOrIsValidSignature(signerV0, HASHED_TEST_MESSAGE, signature)); + await account.sendTransaction(await ecdsa.populateTransaction.recoverOrIsValidSignature(erc1271walletV0.address, HASHED_TEST_MESSAGE, signature)); + await account.sendTransaction(await ecdsa.populateTransaction.recoverOrIsValidSignature_v_r_s(signerV0, HASHED_TEST_MESSAGE, ...split3(signature))); + await account.sendTransaction(await ecdsa.populateTransaction.recoverOrIsValidSignature_v_r_s(erc1271walletV0.address, HASHED_TEST_MESSAGE, ...split3(signature))); + await account.sendTransaction(await ecdsa.populateTransaction.recoverOrIsValidSignature_r_vs(signerV0, HASHED_TEST_MESSAGE, ...split2(to2098Format(signature)))); + await account.sendTransaction(await ecdsa.populateTransaction.recoverOrIsValidSignature_r_vs(erc1271walletV0.address, HASHED_TEST_MESSAGE, ...split2(to2098Format(signature)))); }); it('with v1 signature', async () => { + const { ecdsa, erc1271walletV1 } = await loadFixture(deployContracts); const version = '1b'; // 27 = 1b. const signature = signatureWithoutVersionV0 + version; - await context.ecdsa.contract.methods.recoverOrIsValidSignature(signerV1, HASHED_TEST_MESSAGE, signature).send({ from: account }); - await context.ecdsa.contract.methods.recoverOrIsValidSignature(context.erc1271walletV1.address, HASHED_TEST_MESSAGE, signature).send({ from: account }); - await context.ecdsa.contract.methods.recoverOrIsValidSignature_v_r_s(signerV1, HASHED_TEST_MESSAGE, ...split3(signature)).send({ from: account }); - await context.ecdsa.contract.methods.recoverOrIsValidSignature_v_r_s(context.erc1271walletV1.address, HASHED_TEST_MESSAGE, ...split3(signature)).send({ from: account }); - await context.ecdsa.contract.methods.recoverOrIsValidSignature_r_vs(signerV1, HASHED_TEST_MESSAGE, ...split2(to2098Format(signature))).send({ from: account }); - await context.ecdsa.contract.methods.recoverOrIsValidSignature_r_vs(context.erc1271walletV1.address, HASHED_TEST_MESSAGE, ...split2(to2098Format(signature))).send({ from: account }); + await account.sendTransaction(await ecdsa.populateTransaction.recoverOrIsValidSignature(signerV1, HASHED_TEST_MESSAGE, signature)); + await account.sendTransaction(await ecdsa.populateTransaction.recoverOrIsValidSignature(erc1271walletV1.address, HASHED_TEST_MESSAGE, signature)); + await account.sendTransaction(await ecdsa.populateTransaction.recoverOrIsValidSignature_v_r_s(signerV1, HASHED_TEST_MESSAGE, ...split3(signature))); + await account.sendTransaction(await ecdsa.populateTransaction.recoverOrIsValidSignature_v_r_s(erc1271walletV1.address, HASHED_TEST_MESSAGE, ...split3(signature))); + await account.sendTransaction(await ecdsa.populateTransaction.recoverOrIsValidSignature_r_vs(signerV1, HASHED_TEST_MESSAGE, ...split2(to2098Format(signature)))); + await account.sendTransaction(await ecdsa.populateTransaction.recoverOrIsValidSignature_r_vs(erc1271walletV1.address, HASHED_TEST_MESSAGE, ...split2(to2098Format(signature)))); }); it('recoverOrIsValidSignature65', async () => { - const signature = await web3.eth.sign(TEST_MESSAGE, account); - await context.ecdsa.contract.methods.recoverOrIsValidSignature65(account, HASHED_TEST_MESSAGE, ...split2(signature)).send({ from: account }); - await context.ecdsa.contract.methods.recoverOrIsValidSignature65(context.erc1271wallet.address, HASHED_TEST_MESSAGE, ...split2(signature)).send({ from: account }); + const { ecdsa, erc1271wallet } = await loadFixture(deployContracts); + const signature = await account.signMessage(TEST_MESSAGE); + await account.sendTransaction(await ecdsa.populateTransaction.recoverOrIsValidSignature65(account.address, HASHED_TEST_MESSAGE, ...split2(signature))); + await account.sendTransaction(await ecdsa.populateTransaction.recoverOrIsValidSignature65(erc1271wallet.address, HASHED_TEST_MESSAGE, ...split2(signature))); }); }); describe('isValidSignature', async () => { it('with signature', async function () { - const signature = await web3.eth.sign(TEST_MESSAGE, account); - await context.ecdsa.contract.methods.isValidSignature(context.erc1271wallet.address, HASHED_TEST_MESSAGE, signature).send({ from: account }); + const { ecdsa, erc1271wallet } = await loadFixture(deployContracts); + const signature = await account.signMessage(TEST_MESSAGE); + await account.sendTransaction(await ecdsa.populateTransaction.isValidSignature(erc1271wallet.address, HASHED_TEST_MESSAGE, signature)); }); it('with v0 signature', async () => { + const { ecdsa, erc1271walletV0 } = await loadFixture(deployContracts); const version = '1b'; // 27 = 1b. const signature = signatureWithoutVersionV0 + version; - await context.ecdsa.contract.methods.isValidSignature(context.erc1271walletV0.address, HASHED_TEST_MESSAGE, signature).send({ from: account }); - await context.ecdsa.contract.methods.isValidSignature_v_r_s(context.erc1271walletV0.address, HASHED_TEST_MESSAGE, ...split3(signature)).send({ from: account }); - await context.ecdsa.contract.methods.isValidSignature_r_vs(context.erc1271walletV0.address, HASHED_TEST_MESSAGE, ...split2(to2098Format(signature))).send({ from: account }); + await account.sendTransaction(await ecdsa.populateTransaction.isValidSignature(erc1271walletV0.address, HASHED_TEST_MESSAGE, signature)); + await account.sendTransaction(await ecdsa.populateTransaction.isValidSignature_v_r_s(erc1271walletV0.address, HASHED_TEST_MESSAGE, ...split3(signature))); + await account.sendTransaction(await ecdsa.populateTransaction.isValidSignature_r_vs(erc1271walletV0.address, HASHED_TEST_MESSAGE, ...split2(to2098Format(signature)))); }); it('with v1 signature', async () => { + const { ecdsa, erc1271walletV1 } = await loadFixture(deployContracts); const version = '1b'; // 27 = 1b. const signature = signatureWithoutVersionV0 + version; - await context.ecdsa.contract.methods.isValidSignature(context.erc1271walletV1.address, HASHED_TEST_MESSAGE, signature).send({ from: account }); - await context.ecdsa.contract.methods.isValidSignature_v_r_s(context.erc1271walletV1.address, HASHED_TEST_MESSAGE, ...split3(signature)).send({ from: account }); - await context.ecdsa.contract.methods.isValidSignature_r_vs(context.erc1271walletV1.address, HASHED_TEST_MESSAGE, ...split2(to2098Format(signature))).send({ from: account }); + await account.sendTransaction(await ecdsa.populateTransaction.isValidSignature(erc1271walletV1.address, HASHED_TEST_MESSAGE, signature)); + await account.sendTransaction(await ecdsa.populateTransaction.isValidSignature_v_r_s(erc1271walletV1.address, HASHED_TEST_MESSAGE, ...split3(signature))); + await account.sendTransaction(await ecdsa.populateTransaction.isValidSignature_r_vs(erc1271walletV1.address, HASHED_TEST_MESSAGE, ...split2(to2098Format(signature)))); }); it('isValidSignature65', async () => { - const signature = await web3.eth.sign(TEST_MESSAGE, account); - await context.ecdsa.contract.methods.isValidSignature65(context.erc1271wallet.address, HASHED_TEST_MESSAGE, ...split2(signature)).send({ from: account }); + const { ecdsa, erc1271wallet } = await loadFixture(deployContracts); + const signature = await account.signMessage(TEST_MESSAGE); + await account.sendTransaction(await ecdsa.populateTransaction.isValidSignature65(erc1271wallet.address, HASHED_TEST_MESSAGE, ...split2(signature))); }); }); describe('Additional methods', async () => { it('toEthSignedMessageHash', async function () { - await context.ecdsa.contract.methods.toEthSignedMessageHash(HASHED_TEST_MESSAGE).send({ from: account }); + const { ecdsa } = await loadFixture(deployContracts); + await account.sendTransaction(await ecdsa.populateTransaction.toEthSignedMessageHash(HASHED_TEST_MESSAGE)); }); it('toTypedDataHash', async function () { - await context.ecdsa.contract.methods.toTypedDataHash(HASHED_TEST_MESSAGE, HASHED_TEST_MESSAGE).send({ from: account }); + const { ecdsa } = await loadFixture(deployContracts); + await account.sendTransaction(await ecdsa.populateTransaction.toTypedDataHash(HASHED_TEST_MESSAGE, HASHED_TEST_MESSAGE)); }); }); }); diff --git a/test/contracts/RevertReasonParser.test.ts b/test/contracts/RevertReasonParser.test.ts index 12d4d3fc..415f01fd 100644 --- a/test/contracts/RevertReasonParser.test.ts +++ b/test/contracts/RevertReasonParser.test.ts @@ -1,48 +1,50 @@ import { expect } from '../../src/prelude'; - -const RevertReasonParserTest = artifacts.require('RevertReasonParserTest'); +import { loadFixture } from '@nomicfoundation/hardhat-network-helpers'; +import { ethers } from 'hardhat'; describe('RevertReasonParser', async () => { - const initContext = async () => { - const revertReasonParserTest = await RevertReasonParserTest.new(); + const deployRevertReasonParserTest = async () => { + const RevertReasonParserTest = await ethers.getContractFactory('RevertReasonParserTest'); + const revertReasonParserTest = await RevertReasonParserTest.deploy(); return { revertReasonParserTest }; }; - let context: Awaited> = undefined!; - - before(async () => { - context = await initContext(); - }); - describe('parse', async function () { it('should be parsed as Unknown (Invalid revert reason)', async function () { - await context.revertReasonParserTest.testParseWithThrow(); + const { revertReasonParserTest } = await loadFixture(deployRevertReasonParserTest); + await revertReasonParserTest.testParseWithThrow(); }); it('should be parsed as empty Error', async function () { - await context.revertReasonParserTest.testEmptyStringRevert(); + const { revertReasonParserTest } = await loadFixture(deployRevertReasonParserTest); + await revertReasonParserTest.testEmptyStringRevert(); }); it('should be parsed as Error', async function () { - await context.revertReasonParserTest.testNonEmptyRevert(); + const { revertReasonParserTest } = await loadFixture(deployRevertReasonParserTest); + await revertReasonParserTest.testNonEmptyRevert(); }); it('should be parsed as Unknown', async function () { - await context.revertReasonParserTest.testEmptyRevert(); + const { revertReasonParserTest } = await loadFixture(deployRevertReasonParserTest); + await revertReasonParserTest.testEmptyRevert(); }); it('should be parsed as Panic', async function () { - await context.revertReasonParserTest.testAssertion(); + const { revertReasonParserTest } = await loadFixture(deployRevertReasonParserTest); + await revertReasonParserTest.testAssertion(); }); it('should be parsed as Error with long string', async function () { - await context.revertReasonParserTest.testLongStringRevert(); + const { revertReasonParserTest } = await loadFixture(deployRevertReasonParserTest); + await revertReasonParserTest.testLongStringRevert(); }); it('should be reverted in _test()', async function () { - await expect(context.revertReasonParserTest.testWithThrow()) - .to.eventually.be.rejectedWith('TestDidNotThrow()'); + const { revertReasonParserTest } = await loadFixture(deployRevertReasonParserTest); + await expect(revertReasonParserTest.testWithThrow()) + .to.be.revertedWithCustomError(revertReasonParserTest, 'TestDidNotThrow'); }); }); }); diff --git a/test/contracts/StringUtil.test.ts b/test/contracts/StringUtil.test.ts index d415ae84..783ad80e 100644 --- a/test/contracts/StringUtil.test.ts +++ b/test/contracts/StringUtil.test.ts @@ -1,6 +1,6 @@ import { expect } from '../../src/prelude'; - -const StringUtilTest = artifacts.require('StringUtilTest'); +import { loadFixture } from '@nomicfoundation/hardhat-network-helpers'; +import { ethers } from 'hardhat'; describe('StringUtil', async () => { const uint256TestValue = '0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF'; @@ -10,17 +10,12 @@ describe('StringUtil', async () => { const emptyBytes = '0x'; const singleByte = '0xaf'; - const initContext = async () => { - const stringUtilTest = await StringUtilTest.new(); + const deployStringUtilTest = async () => { + const StringUtilTest = await ethers.getContractFactory('StringUtilTest'); + const stringUtilTest = await StringUtilTest.deploy(); return { stringUtilTest }; }; - let context: Awaited> = undefined!; - - before(async () => { - context = await initContext(); - }); - describe('Validity', async () => { it('Uint 256', () => test(uint256TestValue)); @@ -35,15 +30,17 @@ describe('StringUtil', async () => { it('Single byte', () => testBytes(singleByte)); const test = async (value: string) => { - const result = await context.stringUtilTest.toHex(value, 0); - const naiveResult = await context.stringUtilTest.toHexNaive(value, 0); + const { stringUtilTest } = await loadFixture(deployStringUtilTest); + const result = await stringUtilTest.toHex(value, 0); + const naiveResult = await stringUtilTest.toHexNaive(value, 0); expect(result.toLowerCase()).to.be.equal(value.toLowerCase()); expect(result.toLowerCase()).to.be.equal(naiveResult.toLowerCase()); }; const testBytes = async (value: string) => { - const result = await context.stringUtilTest.toHexBytes(value, 0); - const naiveResult = await context.stringUtilTest.toHexNaiveBytes(value, 0); + const { stringUtilTest } = await loadFixture(deployStringUtilTest); + const result = await stringUtilTest.toHexBytes(value, 0); + const naiveResult = await stringUtilTest.toHexNaiveBytes(value, 0); expect(result.toLowerCase()).to.be.equal(value.toLowerCase()); expect(result.toLowerCase()).to.be.equal(naiveResult.toLowerCase()); }; @@ -79,19 +76,23 @@ describe('StringUtil', async () => { it('Single byte naive', () => testGasNaiveBytes(singleByte, 832)); const testGasUint256 = async (value: string, expectedGas: number) => { - await context.stringUtilTest.toHex(value, expectedGas); + const { stringUtilTest } = await loadFixture(deployStringUtilTest); + await stringUtilTest.toHex(value, expectedGas); }; const testGasBytes = async (value: string, expectedGas: number) => { - await context.stringUtilTest.toHexBytes(value, expectedGas); + const { stringUtilTest } = await loadFixture(deployStringUtilTest); + await stringUtilTest.toHexBytes(value, expectedGas); }; const testGasNaiveUint256 = async (value: string, expectedGas: number) => { - await context.stringUtilTest.toHexNaive(value, expectedGas); + const { stringUtilTest } = await loadFixture(deployStringUtilTest); + await stringUtilTest.toHexNaive(value, expectedGas); }; const testGasNaiveBytes = async (value: string, expectedGas: number) => { - await context.stringUtilTest.toHexNaiveBytes(value, expectedGas); + const { stringUtilTest } = await loadFixture(deployStringUtilTest); + await stringUtilTest.toHexNaiveBytes(value, expectedGas); }; }); }); diff --git a/test/permit.test.ts b/test/permit.test.ts index c526ce35..7bc38c65 100644 --- a/test/permit.test.ts +++ b/test/permit.test.ts @@ -1,30 +1,26 @@ import { expect } from '../src/prelude'; -import { web3 } from 'hardhat'; -import { defaultDeadline, EIP712Domain, Permit, DaiLikePermit } from '../src/permit'; +import { ethers } from 'hardhat'; +import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; +import { loadFixture } from '@nomicfoundation/hardhat-network-helpers'; +import { defaultDeadline, Permit, DaiLikePermit } from '../src/permit'; import { trim0x, buildData, buildDataLikeDai, withTarget } from '../src/permit'; -const ERC20PermitMock = artifacts.require('ERC20PermitMock'); -const DaiLikePermitMock = artifacts.require('DaiLikePermitMock'); +describe('Permit library', async function () { + let signer1: SignerWithAddress; -describe('Methods', async () => { - const initContext = async () => { - const account = web3.eth.accounts.create(); - const wallet = { - address: account.address, - privateKey: account.privateKey, - }; - - const token = await ERC20PermitMock.new('Token', 'TKN', wallet.address, '1'); - const daiLikeToken = await DaiLikePermitMock.new('DaiLikeToken', 'DLT', wallet.address, '1'); - const chainId = await web3.eth.getChainId(); - return { account, wallet, token, daiLikeToken, chainId }; - }; + before(async function () { + [signer1] = await ethers.getSigners(); + }); - let context: Awaited> = undefined!; + async function deployTokens () { + const ERC20PermitMock = await ethers.getContractFactory('ERC20PermitMock'); + const DaiLikePermitMock = await ethers.getContractFactory('DaiLikePermitMock'); - before(async () => { - context = await initContext(); - }); + const chainId = (await ethers.provider.getNetwork()).chainId; + const erc20PermitMock = await ERC20PermitMock.deploy('USDC', 'USDC', signer1.address, 100n); + const daiLikePermitMock = await DaiLikePermitMock.deploy('DAI', 'DAI', signer1.address, 100n); + return { erc20PermitMock, daiLikePermitMock, chainId }; + } it('should be trimmed', async () => { expect(trim0x('0x123456')).to.be.equal('123456'); @@ -35,22 +31,23 @@ describe('Methods', async () => { }); it('should correctly build data for permit', async () => { - const data = buildData(await context.token.name(), '1', context.chainId, context.token.address, context.wallet.address, context.wallet.address, '1', '1'); + const { erc20PermitMock, chainId } = await loadFixture(deployTokens); + + const name = await erc20PermitMock.name(); + const data = buildData(name, '1', chainId, erc20PermitMock.address, signer1.address, signer1.address, '1', '1'); expect(data).to.be.deep.equal({ - primaryType: 'Permit', types: { - EIP712Domain: EIP712Domain, Permit: Permit, }, domain: { - name: await context.token.name(), + name, version: '1', chainId: 31337, - verifyingContract: context.token.address, + verifyingContract: erc20PermitMock.address, }, message: { - owner: context.wallet.address, - spender: context.wallet.address, + owner: signer1.address, + spender: signer1.address, value: '1', nonce: '1', deadline: defaultDeadline, @@ -59,22 +56,23 @@ describe('Methods', async () => { }); it('should correctly build data for dai-like permit', async () => { - const data = buildDataLikeDai(await context.daiLikeToken.name(), '1', context.chainId, context.daiLikeToken.address, context.wallet.address, context.wallet.address, '1', true); + const { daiLikePermitMock, chainId } = await loadFixture(deployTokens); + + const name = await daiLikePermitMock.name(); + const data = buildDataLikeDai(name, '1', chainId, daiLikePermitMock.address, signer1.address, signer1.address, '1', true); expect(data).to.be.deep.equal({ - primaryType: 'Permit', types: { - EIP712Domain: EIP712Domain, Permit: DaiLikePermit, }, domain: { - name: await context.daiLikeToken.name(), + name, version: '1', chainId: 31337, - verifyingContract: context.daiLikeToken.address, + verifyingContract: daiLikePermitMock.address, }, message: { - holder: context.wallet.address, - spender: context.wallet.address, + holder: signer1.address, + spender: signer1.address, nonce: '1', allowed: true, expiry: defaultDeadline, diff --git a/test/profileEVM.test.ts b/test/profileEVM.test.ts index 10d0835c..ed178bc1 100644 --- a/test/profileEVM.test.ts +++ b/test/profileEVM.test.ts @@ -1,78 +1,91 @@ import { expect, ether } from '../src/prelude'; import { profileEVM, gasspectEVM } from '../src/profileEVM'; +import { ethers } from 'hardhat'; +import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; +import { loadFixture } from '@nomicfoundation/hardhat-network-helpers'; -const TokenMock = artifacts.require('TokenMock'); +describe('trace inspection', async function () { + let signer1: SignerWithAddress; + let signer2: SignerWithAddress; -contract('', function ([wallet1, wallet2]) { - const initContext = async () => { - const usdt = await TokenMock.new('USDT', 'USDT'); - return { usdt }; - }; - - let context: Awaited> = undefined!; - - before(async () => { - context = await initContext(); + before(async function () { + [signer1, signer2] = await ethers.getSigners(); }); - beforeEach(async function () { - for (const addr of [wallet1, wallet2]) { - await context.usdt.mint(addr, ether('1000')); - } - }); + const deployUSDT = async () => { + const TokenMock = await ethers.getContractFactory('TokenMock'); + const usdt = await TokenMock.deploy('USDT', 'USDT'); + await usdt.mint(signer1.address, ether('1000')); + await usdt.mint(signer2.address, ether('1000')); + return { usdt }; + }; describe('profileEVM', async function () { it('should be counted ERC20 Transfer', async function () { - const receipt = await context.usdt.transfer(wallet2, ether('1'), { from: wallet1 }); - expect(await profileEVM(receipt.tx, ['STATICCALL', 'CALL', 'SSTORE', 'SLOAD'])) + const { usdt } = await loadFixture(deployUSDT); + + const txn = await usdt.transfer(signer2.address, ether('1')); + expect(await profileEVM(txn.hash, ['STATICCALL', 'CALL', 'SSTORE', 'SLOAD'])) .to.be.deep.equal([0, 0, 2, 2]); }); it('should be counted ERC20 Approve', async function () { - const receipt = await context.usdt.approve(wallet2, ether('1'), { from: wallet1 }); - expect(await profileEVM(receipt.tx, ['STATICCALL', 'CALL', 'SSTORE', 'SLOAD'])) + const { usdt } = await loadFixture(deployUSDT); + + const txn = await usdt.approve(signer2.address, ether('1')); + expect(await profileEVM(txn.hash, ['STATICCALL', 'CALL', 'SSTORE', 'SLOAD'])) .to.be.deep.equal([0, 0, 1, 0]); }); }); describe('gasspectEVM', async function () { it('should be counted ERC20 Transfer', async function () { - const receipt = await context.usdt.transfer(wallet2, ether('1'), { from: wallet1 }); - expect(await gasspectEVM(receipt.tx)) + const { usdt } = await loadFixture(deployUSDT); + + const txn = await usdt.transfer(signer2.address, ether('1')); + expect(await gasspectEVM(txn.hash)) .to.be.deep.equal(['0-0-SLOAD = 2100', '0-0-SSTORE = 2900', '0-0-SLOAD = 2100', '0-0-SSTORE = 2900', '0-0-LOG3 = 1756']); }); it('should be counted ERC20 Approve', async function () { - const receipt = await context.usdt.approve(wallet2, ether('1'), { from: wallet1 }); - expect(await gasspectEVM(receipt.tx)) - .to.be.deep.equal(['0-0-SSTORE = 2200', '0-0-LOG3 = 1756']); + const { usdt } = await loadFixture(deployUSDT); + + const txn = await usdt.approve(signer2.address, ether('1')); + expect(await gasspectEVM(txn.hash)) + .to.be.deep.equal(['0-0-SSTORE_I = 22100', '0-0-LOG3 = 1756']); }); it('should be counted ERC20 Transfer with minOpGasCost = 2000', async function () { - const receipt = await context.usdt.transfer(wallet2, ether('1'), { from: wallet1 }); - expect(await gasspectEVM(receipt.tx, { minOpGasCost: 2000 })) + const { usdt } = await loadFixture(deployUSDT); + + const txn = await usdt.transfer(signer2.address, ether('1')); + expect(await gasspectEVM(txn.hash, { minOpGasCost: 2000 })) .to.be.deep.equal(['0-0-SLOAD = 2100', '0-0-SSTORE = 2900', '0-0-SLOAD = 2100', '0-0-SSTORE = 2900']); }); it('should be counted ERC20 Transfer with args', async function () { - const receipt = await context.usdt.transfer(wallet2, ether('1'), { from: wallet1 }); - expect(await gasspectEVM(receipt.tx, { args: true })) + const { usdt } = await loadFixture(deployUSDT); + + const txn = await usdt.transfer(signer2.address, ether('1')); + expect(await gasspectEVM(txn.hash, { args: true })) .to.be.deep.equal([ '0-0-SLOAD(0x723077b8a1b173adc35e5f0e7e3662fd1208212cb629f9c128551ea7168da722) = 2100', - '0-0-SSTORE(0x723077b8a1b173adc35e5f0e7e3662fd1208212cb629f9c128551ea7168da722,0x0000000000000000000000000000000000000000000001450b3737d49a300000) = 2900', + '0-0-SSTORE(0x723077b8a1b173adc35e5f0e7e3662fd1208212cb629f9c128551ea7168da722,0x00000000000000000000000000000000000000000000003627e8f712373c0000) = 2900', '0-0-SLOAD(0x14e04a66bf74771820a7400ff6cf065175b3d7eb25805a5bd1633b161af5d101) = 2100', - '0-0-SSTORE(0x14e04a66bf74771820a7400ff6cf065175b3d7eb25805a5bd1633b161af5d101,0x0000000000000000000000000000000000000000000001457a3ced71d5500000) = 2900', + '0-0-SSTORE(0x14e04a66bf74771820a7400ff6cf065175b3d7eb25805a5bd1633b161af5d101,0x00000000000000000000000000000000000000000000003643aa647986040000) = 2900', '0-0-LOG3() = 1756', ]); }); it('should be counted ERC20 Transfer with res', async function () { - const receipt = await context.usdt.transfer(wallet2, ether('1'), { from: wallet1 }); - expect(await gasspectEVM(receipt.tx, { res: true })) + const { usdt } = await loadFixture(deployUSDT); + + const txn = await usdt.transfer(signer2.address, ether('1')); + expect(await gasspectEVM(txn.hash, { res: true })) .to.be.deep.equal([ - '0-0-SLOAD:0x00000000000000000000000000000000000000000000017b4100e59a78d00000 = 2100', + '0-0-SLOAD:0x00000000000000000000000000000000000000000000003635c9adc5dea00000 = 2100', '0-0-SSTORE = 2900', - '0-0-SLOAD:0x00000000000000000000000000000000000000000000017bb0069b37b3f00000 = 2100', + '0-0-SLOAD:0x00000000000000000000000000000000000000000000003635c9adc5dea00000 = 2100', '0-0-SSTORE = 2900', '0-0-LOG3 = 1756', ]); diff --git a/test/utils.test.ts b/test/utils.test.ts index 16ab10a4..c890ebcd 100644 --- a/test/utils.test.ts +++ b/test/utils.test.ts @@ -1,20 +1,22 @@ -import { expect, time, ether, toBN } from '../src/prelude'; +import { expect, ether, time } from '../src/prelude'; import { timeIncreaseTo, fixSignature, signMessage, trackReceivedTokenAndTx, countInstructions } from '../src/utils'; import { randomHex, toHex } from 'web3-utils'; - -const TokenMock = artifacts.require('TokenMock'); +import { ethers } from 'hardhat'; +import { loadFixture } from '@nomicfoundation/hardhat-network-helpers'; +import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers'; +import { arrayify } from 'ethers/lib/utils'; describe('timeIncreaseTo', async function () { const precision = 2; async function shouldIncrease (secs: number) { const timeBefore = await time.latest(); - await timeIncreaseTo(timeBefore.addn(secs)); + await timeIncreaseTo(timeBefore + secs); const timeAfter = await time.latest(); - expect(timeAfter).to.be.bignumber.gt(timeBefore); - expect(timeAfter.sub(timeBefore)).to.be.bignumber.lte(toBN(secs).addn(precision)); - expect(timeAfter.sub(timeBefore)).to.be.bignumber.gte(toBN(secs)); + expect(timeAfter).to.be.gt(timeBefore); + expect(timeAfter - timeBefore).to.be.lte(secs +precision); + expect(timeAfter - timeBefore).to.be.gte(secs); } it('should be increased on 1000 sec', async function () { @@ -30,7 +32,7 @@ describe('timeIncreaseTo', async function () { }); it('should be thrown with increase time to a moment in the past', async function () { - await expect(shouldIncrease(-1000)).to.eventually.be.rejectedWith(/Cannot increase current time \(\d+\) to a moment in the past \(\d+\)/); + await expect(shouldIncrease(-1000)).to.be.rejectedWith(/Invalid timestamp \d+ is not larger than current timestamp \d+/); }); }); @@ -48,111 +50,124 @@ describe('fixSignature', async function () { }); }); -contract('', function ([wallet1, wallet2]) { - const initContext = async () => { - const USDT = await TokenMock.new('USDT', 'USDT'); - const USDC = await TokenMock.new('USDC', 'USDC'); - return { USDT, USDC }; - }; - - let context: Awaited> = undefined!; - - before(async () => { - context = await initContext(); - }); +describe('utils', async function () { + let signer1: SignerWithAddress; + let signer2: SignerWithAddress; - beforeEach(async function () { - for (const addr of [wallet1, wallet2]) { - for (const token of [context.USDT, context.USDC]) { - await token.mint(addr, ether('1000')); - } - } + before(async function () { + [signer1, signer2] = await ethers.getSigners(); }); describe('signMessage', async function () { it('should be signed test1', async function () { - expect(await web3.eth.sign('0x', wallet1)).equal(await signMessage(wallet1)); + expect(await signer1.signMessage('0x')).equal(await signMessage(signer1)); }); it('should be signed test2', async function () { const message = randomHex(32); - expect(await web3.eth.sign(message, wallet1)).equal(await signMessage(wallet1, message)); + expect(await signer1.signMessage(arrayify(message))).equal(await signMessage(signer1, arrayify(message))); }); it('should be signed test3', async function () { const message = toHex('Test message'); - expect(await web3.eth.sign(message, wallet1)).equal(await signMessage(wallet1, message)); + expect(await signer1.signMessage(arrayify(message))).equal(await signMessage(signer1, arrayify(message))); + }); + + it('should be signed test4', async function () { + const message = toHex('Test message'); + expect(await signer1.signMessage(message)).equal(await signMessage(signer1, message)); }); }); + async function deployUSDT () { + const TokenMock = await ethers.getContractFactory('TokenMock'); + const usdt = await TokenMock.deploy('USDT', 'USDT'); + await usdt.mint(signer1.address, ether('1000')); + return { usdt }; + } + describe('trackReceivedTokenAndTx', async function () { it('should be tracked ERC20 Transfer', async function () { + const { usdt } = await loadFixture(deployUSDT); + const [received, tx] = await trackReceivedTokenAndTx( - context.USDT, - wallet2, - () => context.USDT.transfer(wallet2, ether('1'), { from: wallet1 }), + usdt, + signer2.address, + () => usdt.transfer(signer2.address, ether('1')), ); - expect(received).to.be.bignumber.equal(ether('1')); - expect(tx.tx.length).equal(66); - expect(tx.receipt.from).equal(wallet1.toLowerCase()); - expect(tx.receipt.to).equal(context.USDT.address.toLowerCase()); - expect(tx.logs.length).equal(1); - expect(tx.logs[0].event).equal('Transfer'); + expect(received).to.be.equal(ether('1')); + expect(tx.data.length).equal(138); + expect(tx.from).equal(signer1.address); + expect(tx.to).equal(usdt.address); + const events = (await tx.wait()).events!; + expect(events.length).equal(1); + expect(events[0].event).equal('Transfer'); }); it('should be tracked ERC20 Approve', async function () { + const { usdt } = await loadFixture(deployUSDT); + const [received, tx] = await trackReceivedTokenAndTx( - context.USDT, - wallet2, - () => context.USDT.approve(wallet2, ether('1'), { from: wallet1 }), + usdt, + signer2.address, + () => usdt.approve(signer2.address, ether('1')), ); - expect(received).to.be.bignumber.equal('0'); - expect(tx.tx.length).equal(66); - expect(tx.receipt.from).equal(wallet1.toLowerCase()); - expect(tx.receipt.to).equal(context.USDT.address.toLowerCase()); - expect(tx.logs.length).equal(1); - expect(tx.logs[0].event).equal('Approval'); + expect(received).to.be.equal('0'); + expect(tx.data.length).equal(138); + expect(tx.from).equal(signer1.address); + expect(tx.to).equal(usdt.address); + const events = (await tx.wait()).events!; + expect(events.length).equal(1); + expect(events[0].event).equal('Approval'); }); }); describe('trackReceivedToken', async function () { it('should be tracked ERC20 Transfer', async function () { + const { usdt } = await loadFixture(deployUSDT); + const [received] = await trackReceivedTokenAndTx( - context.USDT, - wallet2, - () => context.USDT.transfer(wallet2, ether('1'), { from: wallet1 }), + usdt, + signer2.address, + () => usdt.transfer(signer2.address, ether('1')), ); - expect(received).to.be.bignumber.equal(ether('1')); + expect(received).to.be.equal(ether('1')); }); it('should be tracked ERC20 Approve', async function () { + const { usdt } = await loadFixture(deployUSDT); + const [received] = await trackReceivedTokenAndTx( - context.USDT, - wallet2, - () => context.USDT.approve(wallet2, ether('1'), { from: wallet1 }), + usdt, + signer2.address, + () => usdt.approve(signer2.address, ether('1')), ); - expect(received).to.be.bignumber.equal('0'); + expect(received).to.be.equal('0'); }); }); describe('countInstructions', async function () { it('should be counted ERC20 Transfer', async function () { + const { usdt } = await loadFixture(deployUSDT); + const [, tx] = await trackReceivedTokenAndTx( - context.USDT, - wallet2, - () => context.USDT.transfer(wallet2, ether('1'), { from: wallet1 }), + usdt, + signer2.address, + () => usdt.transfer(signer2.address, ether('1')), ); - expect(await countInstructions(tx.receipt.transactionHash, ['STATICCALL', 'CALL', 'SSTORE', 'SLOAD'])) + expect(await countInstructions(tx.hash, ['STATICCALL', 'CALL', 'SSTORE', 'SLOAD'])) .to.be.deep.equal([0, 0, 2, 2]); }); it('should be counted ERC20 Approve', async function () { + const { usdt } = await loadFixture(deployUSDT); + const [, tx] = await trackReceivedTokenAndTx( - context.USDT, - wallet2, - () => context.USDT.approve(wallet2, ether('1'), { from: wallet1 }), + usdt, + signer2.address, + () => usdt.approve(signer2.address, ether('1')), ); - expect(await countInstructions(tx.receipt.transactionHash, ['STATICCALL', 'CALL', 'SSTORE', 'SLOAD'])) + expect(await countInstructions(tx.hash, ['STATICCALL', 'CALL', 'SSTORE', 'SLOAD'])) .to.be.deep.equal([0, 0, 1, 0]); }); }); diff --git a/tsconfig.json b/tsconfig.json index ab5a9ac8..27e65db9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "es2018", + "target": "es2020", "module": "commonjs", "strict": true, "esModuleInterop": true, @@ -17,6 +17,6 @@ "resolveJsonModule": true, "strictNullChecks": true, "typeRoots": ["node_modules/@types"], - "lib": ["es2018", "dom", "esnext"] + "lib": ["es2020", "dom", "esnext"] } } diff --git a/yarn.lock b/yarn.lock index f5481ea0..cfa983cb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -141,7 +141,7 @@ "@ethersproject/properties" "^5.6.0" "@ethersproject/strings" "^5.6.1" -"@ethersproject/abi@^5.0.9": +"@ethersproject/abi@5.7.0", "@ethersproject/abi@^5.0.9", "@ethersproject/abi@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.7.0.tgz#b3f3e045bbbeed1af3947335c247ad625a44e449" integrity sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA== @@ -169,7 +169,7 @@ "@ethersproject/transactions" "^5.6.2" "@ethersproject/web" "^5.6.1" -"@ethersproject/abstract-provider@^5.7.0": +"@ethersproject/abstract-provider@5.7.0", "@ethersproject/abstract-provider@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz#b0a8550f88b6bf9d51f90e4795d48294630cb9ef" integrity sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw== @@ -193,7 +193,7 @@ "@ethersproject/logger" "^5.6.0" "@ethersproject/properties" "^5.6.0" -"@ethersproject/abstract-signer@^5.7.0": +"@ethersproject/abstract-signer@5.7.0", "@ethersproject/abstract-signer@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz#13f4f32117868452191a4649723cb086d2b596b2" integrity sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ== @@ -215,7 +215,7 @@ "@ethersproject/logger" "^5.6.0" "@ethersproject/rlp" "^5.6.1" -"@ethersproject/address@^5.7.0": +"@ethersproject/address@5.7.0", "@ethersproject/address@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.7.0.tgz#19b56c4d74a3b0a46bfdbb6cfcc0a153fc697f37" integrity sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA== @@ -233,7 +233,7 @@ dependencies: "@ethersproject/bytes" "^5.6.1" -"@ethersproject/base64@^5.7.0": +"@ethersproject/base64@5.7.0", "@ethersproject/base64@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.7.0.tgz#ac4ee92aa36c1628173e221d0d01f53692059e1c" integrity sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ== @@ -248,6 +248,14 @@ "@ethersproject/bytes" "^5.6.1" "@ethersproject/properties" "^5.6.0" +"@ethersproject/basex@5.7.0", "@ethersproject/basex@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/basex/-/basex-5.7.0.tgz#97034dc7e8938a8ca943ab20f8a5e492ece4020b" + integrity sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/bignumber@5.6.2", "@ethersproject/bignumber@^5.0.7", "@ethersproject/bignumber@^5.6.2": version "5.6.2" resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.6.2.tgz#72a0717d6163fab44c47bcc82e0c550ac0315d66" @@ -257,7 +265,7 @@ "@ethersproject/logger" "^5.6.0" bn.js "^5.2.1" -"@ethersproject/bignumber@^5.7.0": +"@ethersproject/bignumber@5.7.0", "@ethersproject/bignumber@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.7.0.tgz#e2f03837f268ba655ffba03a57853e18a18dc9c2" integrity sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw== @@ -273,7 +281,7 @@ dependencies: "@ethersproject/logger" "^5.6.0" -"@ethersproject/bytes@^5.7.0": +"@ethersproject/bytes@5.7.0", "@ethersproject/bytes@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.7.0.tgz#a00f6ea8d7e7534d6d87f47188af1148d71f155d" integrity sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A== @@ -287,7 +295,7 @@ dependencies: "@ethersproject/bignumber" "^5.6.2" -"@ethersproject/constants@^5.7.0": +"@ethersproject/constants@5.7.0", "@ethersproject/constants@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.7.0.tgz#df80a9705a7e08984161f09014ea012d1c75295e" integrity sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA== @@ -310,6 +318,22 @@ "@ethersproject/properties" "^5.6.0" "@ethersproject/transactions" "^5.6.2" +"@ethersproject/contracts@5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/contracts/-/contracts-5.7.0.tgz#c305e775abd07e48aa590e1a877ed5c316f8bd1e" + integrity sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg== + dependencies: + "@ethersproject/abi" "^5.7.0" + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/hash@5.6.1", "@ethersproject/hash@^5.0.4", "@ethersproject/hash@^5.6.1": version "5.6.1" resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.6.1.tgz#224572ea4de257f05b4abf8ae58b03a67e99b0f4" @@ -324,7 +348,7 @@ "@ethersproject/properties" "^5.6.0" "@ethersproject/strings" "^5.6.1" -"@ethersproject/hash@^5.7.0": +"@ethersproject/hash@5.7.0", "@ethersproject/hash@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.7.0.tgz#eb7aca84a588508369562e16e514b539ba5240a7" integrity sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g== @@ -357,6 +381,24 @@ "@ethersproject/transactions" "^5.6.2" "@ethersproject/wordlists" "^5.6.1" +"@ethersproject/hdnode@5.7.0", "@ethersproject/hdnode@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/hdnode/-/hdnode-5.7.0.tgz#e627ddc6b466bc77aebf1a6b9e47405ca5aef9cf" + integrity sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg== + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/basex" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/pbkdf2" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/wordlists" "^5.7.0" + "@ethersproject/json-wallets@5.6.1", "@ethersproject/json-wallets@^5.6.1": version "5.6.1" resolved "https://registry.yarnpkg.com/@ethersproject/json-wallets/-/json-wallets-5.6.1.tgz#3f06ba555c9c0d7da46756a12ac53483fe18dd91" @@ -376,6 +418,25 @@ aes-js "3.0.0" scrypt-js "3.0.1" +"@ethersproject/json-wallets@5.7.0", "@ethersproject/json-wallets@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz#5e3355287b548c32b368d91014919ebebddd5360" + integrity sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g== + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hdnode" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/pbkdf2" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/random" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + aes-js "3.0.0" + scrypt-js "3.0.1" + "@ethersproject/keccak256@5.6.1", "@ethersproject/keccak256@^5.0.3", "@ethersproject/keccak256@^5.6.1": version "5.6.1" resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.6.1.tgz#b867167c9b50ba1b1a92bccdd4f2d6bd168a91cc" @@ -384,7 +445,7 @@ "@ethersproject/bytes" "^5.6.1" js-sha3 "0.8.0" -"@ethersproject/keccak256@^5.7.0": +"@ethersproject/keccak256@5.7.0", "@ethersproject/keccak256@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.7.0.tgz#3186350c6e1cd6aba7940384ec7d6d9db01f335a" integrity sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg== @@ -397,7 +458,7 @@ resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.6.0.tgz#d7db1bfcc22fd2e4ab574cba0bb6ad779a9a3e7a" integrity sha512-BiBWllUROH9w+P21RzoxJKzqoqpkyM1pRnEKG69bulE9TSQD8SAIvTQqIMZmmCO8pUNkgLP1wndX1gKghSpBmg== -"@ethersproject/logger@^5.7.0": +"@ethersproject/logger@5.7.0", "@ethersproject/logger@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.7.0.tgz#6ce9ae168e74fecf287be17062b590852c311892" integrity sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig== @@ -409,7 +470,7 @@ dependencies: "@ethersproject/logger" "^5.6.0" -"@ethersproject/networks@^5.7.0": +"@ethersproject/networks@5.7.1", "@ethersproject/networks@^5.7.0": version "5.7.1" resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.7.1.tgz#118e1a981d757d45ccea6bb58d9fd3d9db14ead6" integrity sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ== @@ -424,6 +485,14 @@ "@ethersproject/bytes" "^5.6.1" "@ethersproject/sha2" "^5.6.1" +"@ethersproject/pbkdf2@5.7.0", "@ethersproject/pbkdf2@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz#d2267d0a1f6e123f3771007338c47cccd83d3102" + integrity sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + "@ethersproject/properties@5.6.0", "@ethersproject/properties@^5.0.3", "@ethersproject/properties@^5.6.0": version "5.6.0" resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.6.0.tgz#38904651713bc6bdd5bdd1b0a4287ecda920fa04" @@ -431,7 +500,7 @@ dependencies: "@ethersproject/logger" "^5.6.0" -"@ethersproject/properties@^5.7.0": +"@ethersproject/properties@5.7.0", "@ethersproject/properties@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.7.0.tgz#a6e12cb0439b878aaf470f1902a176033067ed30" integrity sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw== @@ -464,6 +533,32 @@ bech32 "1.1.4" ws "7.4.6" +"@ethersproject/providers@5.7.1": + version "5.7.1" + resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.7.1.tgz#b0799b616d5579cd1067a8ebf1fc1ec74c1e122c" + integrity sha512-vZveG/DLyo+wk4Ga1yx6jSEHrLPgmTt+dFv0dv8URpVCRf0jVhalps1jq/emN/oXnMRsC7cQgAF32DcXLL7BPQ== + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/base64" "^5.7.0" + "@ethersproject/basex" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/networks" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/random" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/web" "^5.7.0" + bech32 "1.1.4" + ws "7.4.6" + "@ethersproject/random@5.6.1", "@ethersproject/random@^5.6.1": version "5.6.1" resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.6.1.tgz#66915943981bcd3e11bbd43733f5c3ba5a790255" @@ -472,6 +567,14 @@ "@ethersproject/bytes" "^5.6.1" "@ethersproject/logger" "^5.6.0" +"@ethersproject/random@5.7.0", "@ethersproject/random@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.7.0.tgz#af19dcbc2484aae078bb03656ec05df66253280c" + integrity sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/rlp@5.6.1", "@ethersproject/rlp@^5.6.1": version "5.6.1" resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.6.1.tgz#df8311e6f9f24dcb03d59a2bac457a28a4fe2bd8" @@ -480,7 +583,7 @@ "@ethersproject/bytes" "^5.6.1" "@ethersproject/logger" "^5.6.0" -"@ethersproject/rlp@^5.7.0": +"@ethersproject/rlp@5.7.0", "@ethersproject/rlp@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.7.0.tgz#de39e4d5918b9d74d46de93af80b7685a9c21304" integrity sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w== @@ -497,6 +600,15 @@ "@ethersproject/logger" "^5.6.0" hash.js "1.1.7" +"@ethersproject/sha2@5.7.0", "@ethersproject/sha2@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.7.0.tgz#9a5f7a7824ef784f7f7680984e593a800480c9fb" + integrity sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + hash.js "1.1.7" + "@ethersproject/signing-key@5.6.2", "@ethersproject/signing-key@^5.6.2": version "5.6.2" resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.6.2.tgz#8a51b111e4d62e5a62aee1da1e088d12de0614a3" @@ -509,7 +621,7 @@ elliptic "6.5.4" hash.js "1.1.7" -"@ethersproject/signing-key@^5.7.0": +"@ethersproject/signing-key@5.7.0", "@ethersproject/signing-key@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.7.0.tgz#06b2df39411b00bc57c7c09b01d1e41cf1b16ab3" integrity sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q== @@ -533,6 +645,18 @@ "@ethersproject/sha2" "^5.6.1" "@ethersproject/strings" "^5.6.1" +"@ethersproject/solidity@5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/solidity/-/solidity-5.7.0.tgz#5e9c911d8a2acce2a5ebb48a5e2e0af20b631cb8" + integrity sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@ethersproject/strings@5.6.1", "@ethersproject/strings@^5.0.4", "@ethersproject/strings@^5.6.1": version "5.6.1" resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.6.1.tgz#dbc1b7f901db822b5cafd4ebf01ca93c373f8952" @@ -542,7 +666,7 @@ "@ethersproject/constants" "^5.6.1" "@ethersproject/logger" "^5.6.0" -"@ethersproject/strings@^5.7.0": +"@ethersproject/strings@5.7.0", "@ethersproject/strings@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.7.0.tgz#54c9d2a7c57ae8f1205c88a9d3a56471e14d5ed2" integrity sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg== @@ -566,7 +690,7 @@ "@ethersproject/rlp" "^5.6.1" "@ethersproject/signing-key" "^5.6.2" -"@ethersproject/transactions@^5.7.0": +"@ethersproject/transactions@5.7.0", "@ethersproject/transactions@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.7.0.tgz#91318fc24063e057885a6af13fdb703e1f993d3b" integrity sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ== @@ -590,6 +714,15 @@ "@ethersproject/constants" "^5.6.1" "@ethersproject/logger" "^5.6.0" +"@ethersproject/units@5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.7.0.tgz#637b563d7e14f42deeee39245275d477aae1d8b1" + integrity sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/wallet@5.6.2": version "5.6.2" resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.6.2.tgz#cd61429d1e934681e413f4bc847a5f2f87e3a03c" @@ -611,6 +744,27 @@ "@ethersproject/transactions" "^5.6.2" "@ethersproject/wordlists" "^5.6.1" +"@ethersproject/wallet@5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.7.0.tgz#4e5d0790d96fe21d61d38fb40324e6c7ef350b2d" + integrity sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA== + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/hdnode" "^5.7.0" + "@ethersproject/json-wallets" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/random" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/wordlists" "^5.7.0" + "@ethersproject/web@5.6.1", "@ethersproject/web@^5.6.1": version "5.6.1" resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.6.1.tgz#6e2bd3ebadd033e6fe57d072db2b69ad2c9bdf5d" @@ -622,7 +776,7 @@ "@ethersproject/properties" "^5.6.0" "@ethersproject/strings" "^5.6.1" -"@ethersproject/web@^5.7.0": +"@ethersproject/web@5.7.1", "@ethersproject/web@^5.7.0": version "5.7.1" resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.7.1.tgz#de1f285b373149bee5928f4eb7bcb87ee5fbb4ae" integrity sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w== @@ -644,6 +798,17 @@ "@ethersproject/properties" "^5.6.0" "@ethersproject/strings" "^5.6.1" +"@ethersproject/wordlists@5.7.0", "@ethersproject/wordlists@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/wordlists/-/wordlists-5.7.0.tgz#8fb2c07185d68c3e09eb3bfd6e779ba2774627f5" + integrity sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@humanwhocodes/config-array@^0.10.4": version "0.10.4" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.10.4.tgz#01e7366e57d2ad104feea63e72248f22015c520c" @@ -860,6 +1025,25 @@ mcl-wasm "^0.7.1" rustbn.js "~0.2.0" +"@nomicfoundation/hardhat-chai-matchers@1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-chai-matchers/-/hardhat-chai-matchers-1.0.3.tgz#a48ed0a3a58de616e4f553368d79c13a8850ebd5" + integrity sha512-qEE7Drs2HSY+krH09TXm6P9LFogs0BqbUq6wPD7nQRhmJ+p5zoDaIZjM5WL1pHqU5MpGqya3y+BdwmTYBfU5UA== + dependencies: + "@ethersproject/abi" "^5.1.2" + "@types/chai-as-promised" "^7.1.3" + chai-as-promised "^7.1.1" + chalk "^2.4.2" + deep-eql "^4.0.1" + ordinal "^1.0.3" + +"@nomicfoundation/hardhat-network-helpers@1.0.6": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-network-helpers/-/hardhat-network-helpers-1.0.6.tgz#5e2026ddde5ca539f70a2bf498528afd08bd0827" + integrity sha512-a35iVD4ycF6AoTfllAnKm96IPIzzHpgKX/ep4oKc2bsUKFfMlacWdyntgC/7d5blyCTXfFssgNAvXDZfzNWVGQ== + dependencies: + ethereumjs-util "^7.1.4" + "@nomicfoundation/solidity-analyzer-darwin-arm64@0.0.3": version "0.0.3" resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.0.3.tgz#1d49e4ac028831a3011a9f3dca60bd1963185342" @@ -926,6 +1110,11 @@ "@nomicfoundation/solidity-analyzer-win32-ia32-msvc" "0.0.3" "@nomicfoundation/solidity-analyzer-win32-x64-msvc" "0.0.3" +"@nomiclabs/hardhat-ethers@2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@nomiclabs/hardhat-ethers/-/hardhat-ethers-2.1.1.tgz#3f1d1ab49813d1bae4c035cc1adec224711e528b" + integrity sha512-Gg0IFkT/DW3vOpih4/kMjeZCLYqtfgECLeLXTs7ZDPzcK0cfoc5wKk4nq5n/izCUzdhidO/Utd6ptF9JrWwWVA== + "@nomiclabs/hardhat-truffle5@2.0.7": version "2.0.7" resolved "https://registry.yarnpkg.com/@nomiclabs/hardhat-truffle5/-/hardhat-truffle5-2.0.7.tgz#7519eadd2c6c460c2addc3d4d6efda7a8883361e" @@ -960,35 +1149,11 @@ ethers "^4.0.0-beta.1" source-map-support "^0.5.19" -"@openzeppelin/contract-loader@^0.6.2": - version "0.6.3" - resolved "https://registry.yarnpkg.com/@openzeppelin/contract-loader/-/contract-loader-0.6.3.tgz#61a7b44de327e40b7d53f39e0fb59bbf847335c3" - integrity sha512-cOFIjBjwbGgZhDZsitNgJl0Ye1rd5yu/Yx5LMgeq3u0ZYzldm4uObzHDFq4gjDdoypvyORjjJa3BlFA7eAnVIg== - dependencies: - find-up "^4.1.0" - fs-extra "^8.1.0" - "@openzeppelin/contracts@4.7.3": version "4.7.3" resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-4.7.3.tgz#939534757a81f8d69cc854c7692805684ff3111e" integrity sha512-dGRS0agJzu8ybo44pCIf3xBaPQN/65AIXNgK8+4gzKd5kbvlqyxryUYVLJv7fK98Seyd2hDZzVEHSWAh0Bt1Yw== -"@openzeppelin/test-helpers@0.5.16": - version "0.5.16" - resolved "https://registry.yarnpkg.com/@openzeppelin/test-helpers/-/test-helpers-0.5.16.tgz#2c9054f85069dfbfb5e8cef3ed781e8caf241fb3" - integrity sha512-T1EvspSfH1qQO/sgGlskLfYVBbqzJR23SZzYl/6B2JnT4EhThcI85UpvDk0BkLWKaDScQTabGHt4GzHW+3SfZg== - dependencies: - "@openzeppelin/contract-loader" "^0.6.2" - "@truffle/contract" "^4.0.35" - ansi-colors "^3.2.3" - chai "^4.2.0" - chai-bn "^0.2.1" - ethjs-abi "^0.2.1" - lodash.flatten "^4.4.0" - semver "^5.6.0" - web3 "^1.2.5" - web3-utils "^1.2.5" - "@scure/base@~1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.0.0.tgz#109fb595021de285f05a7db6806f2f48296fcee7" @@ -1144,27 +1309,7 @@ ajv "^6.10.0" debug "^4.3.1" -"@truffle/contract@^4.0.35": - version "4.5.14" - resolved "https://registry.yarnpkg.com/@truffle/contract/-/contract-4.5.14.tgz#39aceae595bca4cb554be9fa24d2d9931e4af6da" - integrity sha512-ofdH7As7d+uyG+6wlZWYoBtN/Nb1efyzooHym4du5Hck4l+EHm8brSYZsHPJrEBA8UN05jYUtBrjUuzbJ/eq0w== - dependencies: - "@ensdomains/ensjs" "^2.0.1" - "@truffle/blockchain-utils" "^0.1.3" - "@truffle/contract-schema" "^3.4.7" - "@truffle/debug-utils" "^6.0.26" - "@truffle/error" "^0.1.0" - "@truffle/interface-adapter" "^0.5.17" - bignumber.js "^7.2.1" - debug "^4.3.1" - ethers "^4.0.32" - web3 "1.5.3" - web3-core-helpers "1.5.3" - web3-core-promievent "1.5.3" - web3-eth-abi "1.5.3" - web3-utils "1.5.3" - -"@truffle/debug-utils@^6.0.22", "@truffle/debug-utils@^6.0.26": +"@truffle/debug-utils@^6.0.22": version "6.0.26" resolved "https://registry.yarnpkg.com/@truffle/debug-utils/-/debug-utils-6.0.26.tgz#12ca10f399143f7c50c0dc605843c14f75cc4f7f" integrity sha512-+wxeXLRl23rzpOf76PkUTUqbsEzS8zAgLnZKFMEyS/vkVY5CpNVIhddCQcqQcDaIn9BRcmbuB5xMYR6hs8wrSw== @@ -1181,7 +1326,7 @@ resolved "https://registry.yarnpkg.com/@truffle/error/-/error-0.1.0.tgz#5e9fed79e6cda624c926d314b280a576f8b22a36" integrity sha512-RbUfp5VreNhsa2Q4YbBjz18rOQI909pG32bghl1hulO7IpvcqTS+C3Ge5cNbiWQ1WGzy1wIeKLW0tmQtHFB7qg== -"@truffle/interface-adapter@^0.5.16", "@truffle/interface-adapter@^0.5.17": +"@truffle/interface-adapter@^0.5.16": version "0.5.17" resolved "https://registry.yarnpkg.com/@truffle/interface-adapter/-/interface-adapter-0.5.17.tgz#34e7e28930f6aa4c722f1b2ede127d379f891e70" integrity sha512-2MJ+YLAL4y2QqlWc90NKizBLpavcETTzV8EpYkYJgAM326xKrAt+N3wx3f3tgRPSsbdtiEVKf1JRXHmDYQ+xIg== @@ -1224,6 +1369,14 @@ resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e" integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ== +"@typechain/ethers-v5@10.1.0": + version "10.1.0" + resolved "https://registry.yarnpkg.com/@typechain/ethers-v5/-/ethers-v5-10.1.0.tgz#068d7dc7014502354696dab59590a7841091e951" + integrity sha512-3LIb+eUpV3mNCrjUKT5oqp8PBsZYSnVrkfk6pY/ZM0boRs2mKxjFZ7bktx42vfDye8PPz3NxtW4DL5NsNsFqlg== + dependencies: + lodash "^4.17.15" + ts-essentials "^7.0.1" + "@typechain/hardhat@6.1.3": version "6.1.3" resolved "https://registry.yarnpkg.com/@typechain/hardhat/-/hardhat-6.1.3.tgz#e6121502eb64903ab562d89e094a5506e7b86822" @@ -1231,13 +1384,6 @@ dependencies: fs-extra "^9.1.0" -"@typechain/truffle-v5@7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@typechain/truffle-v5/-/truffle-v5-7.0.0.tgz#f7ab68186de8b2ef0a3f932837f6380a6c481360" - integrity sha512-TeK3EjbWzRyvR7Ags6I05UmDnWDGOxZnfUkFEJf9e5bheipDqvaoMYThcw3AObVfYaC6VA6UdelwPRtK6BC8lg== - dependencies: - lodash "^4.17.15" - "@types/async-eventemitter@^0.2.1": version "0.2.1" resolved "https://registry.yarnpkg.com/@types/async-eventemitter/-/async-eventemitter-0.2.1.tgz#f8e6280e87e8c60b2b938624b0a3530fb3e24712" @@ -1264,7 +1410,7 @@ dependencies: "@types/node" "*" -"@types/chai-as-promised@7.1.5": +"@types/chai-as-promised@7.1.5", "@types/chai-as-promised@^7.1.3": version "7.1.5" resolved "https://registry.yarnpkg.com/@types/chai-as-promised/-/chai-as-promised-7.1.5.tgz#6e016811f6c7a64f2eed823191c3a6955094e255" integrity sha512-jStwss93SITGBwt/niYrkf2C+/1KTeZCZl1LaeezTlqppAKeoQC7jxyqYuP72sxBGKCIbw7oHgbYssIRzT5FCQ== @@ -1347,10 +1493,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.42.tgz#d7e8f22700efc94d125103075c074396b5f41f9b" integrity sha512-Q5BPGyGKcvQgAMbsr7qEGN/kIPN6zZecYYABeTDBizOsau+2NMdSVTar9UQw21A2+JyA2KRNDYaYrPB0Rpk2oQ== -"@types/node@18.7.18": - version "18.7.18" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.18.tgz#633184f55c322e4fb08612307c274ee6d5ed3154" - integrity sha512-m+6nTEOadJZuTPkKR/SYK3A2d7FZrgElol9UP1Kae90VVU4a6mxnPuLiIW1m4Cq4gZ/nWb9GrdVXJCoCazDAbg== +"@types/node@18.7.21": + version "18.7.21" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.21.tgz#63ee6688070e456325b6748dc492a7b948593871" + integrity sha512-rLFzK5bhM0YPyCoTC8bolBjMk7bwnZ8qeZUBslBfjZQou2ssJdWslx9CZ8DGM+Dx7QXQiiTVZ/6QO6kwtHkZCA== "@types/node@^10.0.3": version "10.17.60" @@ -1607,11 +1753,6 @@ ansi-colors@4.1.1: resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== -ansi-colors@^3.2.3: - version "3.2.4" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf" - integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA== - ansi-colors@^4.1.1: version "4.1.3" resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" @@ -2213,7 +2354,7 @@ cbor@^5.1.0: bignumber.js "^9.0.1" nofilter "^1.0.4" -chai-as-promised@7.1.1: +chai-as-promised@7.1.1, chai-as-promised@^7.1.1: version "7.1.1" resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-7.1.1.tgz#08645d825deb8696ee61725dbf590c012eb00ca0" integrity sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA== @@ -2225,11 +2366,6 @@ chai-bn@0.3.1: resolved "https://registry.yarnpkg.com/chai-bn/-/chai-bn-0.3.1.tgz#677cd3c0b58bae83ffe51604a811d0b3c6f41544" integrity sha512-vuzEy0Cb+k8zqi2SHOmvZdRSbKcSOJfS1Nv8+6YDJIyCzfxkTCHLNRyjRIoRJ3WJtYb/c7OHjrvLoGeyO4A/gA== -chai-bn@^0.2.1: - version "0.2.2" - resolved "https://registry.yarnpkg.com/chai-bn/-/chai-bn-0.2.2.tgz#4dcf30dbc79db2378a00781693bc749c972bf34f" - integrity sha512-MzjelH0p8vWn65QKmEq/DLBG1Hle4WeyqT79ANhXZhn/UxRWO0OogkAxi5oGGtfzwU9bZR8mvbvYdoqNVWQwFg== - chai@4.3.6, chai@^4.2.0: version "4.3.6" resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.6.tgz#ffe4ba2d9fa9d6680cc0b370adae709ec9011e9c" @@ -2847,6 +2983,13 @@ deep-eql@^3.0.1: dependencies: type-detect "^4.0.0" +deep-eql@^4.0.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.1.tgz#b1154ea8c95012d9f23f37f4eecfd2ee8e5b9323" + integrity sha512-rc6HkZswtl+KMi/IODZ8k7C/P37clC2Rf1HYI11GqdbgvggIyHjsU5MdjlTlaP6eu24c0sR3mcW2SqsVZ1sXUw== + dependencies: + type-detect "^4.0.0" + deep-extend@~0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" @@ -3632,6 +3775,42 @@ ethereumjs-wallet@1.0.2: utf8 "^3.0.0" uuid "^8.3.2" +ethers@5.7.1: + version "5.7.1" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.1.tgz#48c83a44900b5f006eb2f65d3ba6277047fd4f33" + integrity sha512-5krze4dRLITX7FpU8J4WscXqADiKmyeNlylmmDLbS95DaZpBhDe2YSwRQwKXWNyXcox7a3gBgm/MkGXV1O1S/Q== + dependencies: + "@ethersproject/abi" "5.7.0" + "@ethersproject/abstract-provider" "5.7.0" + "@ethersproject/abstract-signer" "5.7.0" + "@ethersproject/address" "5.7.0" + "@ethersproject/base64" "5.7.0" + "@ethersproject/basex" "5.7.0" + "@ethersproject/bignumber" "5.7.0" + "@ethersproject/bytes" "5.7.0" + "@ethersproject/constants" "5.7.0" + "@ethersproject/contracts" "5.7.0" + "@ethersproject/hash" "5.7.0" + "@ethersproject/hdnode" "5.7.0" + "@ethersproject/json-wallets" "5.7.0" + "@ethersproject/keccak256" "5.7.0" + "@ethersproject/logger" "5.7.0" + "@ethersproject/networks" "5.7.1" + "@ethersproject/pbkdf2" "5.7.0" + "@ethersproject/properties" "5.7.0" + "@ethersproject/providers" "5.7.1" + "@ethersproject/random" "5.7.0" + "@ethersproject/rlp" "5.7.0" + "@ethersproject/sha2" "5.7.0" + "@ethersproject/signing-key" "5.7.0" + "@ethersproject/solidity" "5.7.0" + "@ethersproject/strings" "5.7.0" + "@ethersproject/transactions" "5.7.0" + "@ethersproject/units" "5.7.0" + "@ethersproject/wallet" "5.7.0" + "@ethersproject/web" "5.7.1" + "@ethersproject/wordlists" "5.7.0" + ethers@^4.0.0-beta.1, ethers@^4.0.32, ethers@^4.0.40: version "4.0.49" resolved "https://registry.yarnpkg.com/ethers/-/ethers-4.0.49.tgz#0eb0e9161a0c8b4761be547396bbe2fb121a8894" @@ -3683,15 +3862,6 @@ ethers@^5.0.13: "@ethersproject/web" "5.6.1" "@ethersproject/wordlists" "5.6.1" -ethjs-abi@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/ethjs-abi/-/ethjs-abi-0.2.1.tgz#e0a7a93a7e81163a94477bad56ede524ab6de533" - integrity sha512-g2AULSDYI6nEJyJaEVEXtTimRY2aPC2fi7ddSy0W+LXvEVL8Fe1y76o43ecbgdUKwZD+xsmEgX1yJr1Ia3r1IA== - dependencies: - bn.js "4.11.6" - js-sha3 "0.5.5" - number-to-bn "1.7.0" - ethjs-unit@0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/ethjs-unit/-/ethjs-unit-0.1.6.tgz#c665921e476e87bce2a9d588a6fe0405b2c41699" @@ -3922,14 +4092,6 @@ find-up@^2.1.0: dependencies: locate-path "^2.0.0" -find-up@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" - integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== - dependencies: - locate-path "^5.0.0" - path-exists "^4.0.0" - flat-cache@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" @@ -4226,6 +4388,18 @@ glob@7.1.3: once "^1.3.0" path-is-absolute "^1.0.0" +glob@7.1.7: + version "7.1.7" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" + integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + glob@7.2.0: version "7.2.0" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" @@ -4249,7 +4423,7 @@ glob@^5.0.15: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.0.0, glob@^7.1.2, glob@^7.1.3, glob@^7.1.6, glob@^7.2.0: +glob@^7.0.0, glob@^7.1.2, glob@^7.1.3, glob@^7.2.0: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -5046,11 +5220,6 @@ js-sdsl@^4.1.4: resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.1.4.tgz#78793c90f80e8430b7d8dc94515b6c77d98a26a6" integrity sha512-Y2/yD55y5jteOAmY50JbUZYwk3CP3wnLPEZnlR1w9oKhITrBEtAxwuWKebFf8hMrPMgbYwFoWK/lH2sBkErELw== -js-sha3@0.5.5: - version "0.5.5" - resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.5.5.tgz#baf0c0e8c54ad5903447df96ade7a4a1bca79a4a" - integrity sha512-yLLwn44IVeunwjpDVTDZmQeVbB0h+dZpY2eO68B/Zik8hu6dH+rKeLxwua79GGIvW6xr8NBAcrtiUbYrTjEFTA== - js-sha3@0.5.7, js-sha3@^0.5.7: version "0.5.7" resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.5.7.tgz#0d4ffd8002d5333aabaf4a23eed2f6374c9f28e7" @@ -5273,13 +5442,6 @@ locate-path@^3.0.0: p-locate "^3.0.0" path-exists "^3.0.0" -locate-path@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" - integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== - dependencies: - p-locate "^4.1.0" - locate-path@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" @@ -5297,11 +5459,6 @@ lodash.camelcase@^4.3.0: resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== -lodash.flatten@^4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" - integrity sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g== - lodash.merge@^4.6.2: version "4.6.2" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" @@ -5993,6 +6150,11 @@ optionator@^0.9.1: type-check "^0.4.0" word-wrap "^1.2.3" +ordinal@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/ordinal/-/ordinal-1.0.3.tgz#1a3c7726a61728112f50944ad7c35c06ae3a0d4d" + integrity sha512-cMddMgb2QElm8G7vdaa02jhUNbTSrhsgAGUz1OokD83uJTwSUn+nKoNoKVVaRa08yF6sgfO7Maou1+bgLd9rdQ== + os-locale@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" @@ -6027,7 +6189,7 @@ p-limit@^1.1.0: dependencies: p-try "^1.0.0" -p-limit@^2.0.0, p-limit@^2.2.0: +p-limit@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== @@ -6055,13 +6217,6 @@ p-locate@^3.0.0: dependencies: p-limit "^2.0.0" -p-locate@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" - integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== - dependencies: - p-limit "^2.2.0" - p-locate@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" @@ -6317,7 +6472,7 @@ prettier@^1.14.3: resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== -prettier@^2.1.2: +prettier@^2.3.1: version "2.7.1" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64" integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== @@ -6818,7 +6973,7 @@ secp256k1@^4.0.1: node-addon-api "^2.0.0" node-gyp-build "^4.2.0" -"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0, semver@^5.7.0: +"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.5.0, semver@^5.5.1, semver@^5.7.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== @@ -7655,19 +7810,19 @@ type@^2.5.0: resolved "https://registry.yarnpkg.com/type/-/type-2.6.0.tgz#3ca6099af5981d36ca86b78442973694278a219f" integrity sha512-eiDBDOmkih5pMbo9OqsqPRGMljLodLcwd5XD5JbtNB0o89xZAwynY9EdCDsJU7LtcVCClu9DvM7/0Ep1hYX3EQ== -typechain@7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/typechain/-/typechain-7.0.1.tgz#65411991327a7031895b1d57b7e0ce7fc9c66376" - integrity sha512-4c+ecLW4mTiKwTDdofiN8ToDp7TkFC2Bzp2Pt/+qeKzkmELWzy2eDjCiv0IWHswAZhE2y9KXBhTmShzhIzD+LQ== +typechain@8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/typechain/-/typechain-8.1.0.tgz#fc4902ce596519cb2ccfd012e4ddf92a9945b569" + integrity sha512-5jToLgKTjHdI1VKqs/K8BLYy42Sr3o8bV5ojh4MnR9ExHO83cyyUdw+7+vMJCpKXUiVUvARM4qmHTFuyaCMAZQ== dependencies: "@types/prettier" "^2.1.1" - debug "^4.1.1" + debug "^4.3.1" fs-extra "^7.0.0" - glob "^7.1.6" + glob "7.1.7" js-sha3 "^0.8.0" lodash "^4.17.15" mkdirp "^1.0.4" - prettier "^2.1.2" + prettier "^2.3.1" ts-command-line-args "^2.2.0" ts-essentials "^7.0.1" @@ -8290,7 +8445,7 @@ web3-utils@1.5.3: randombytes "^2.1.0" utf8 "3.0.0" -web3-utils@1.7.3, web3-utils@^1.0.0-beta.31, web3-utils@^1.2.5: +web3-utils@1.7.3, web3-utils@^1.0.0-beta.31: version "1.7.3" resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.7.3.tgz#b214d05f124530d8694ad364509ac454d05f207c" integrity sha512-g6nQgvb/bUpVUIxJE+ezVN+rYwYmlFyMvMIRSuqpi1dk6ApDD00YNArrk7sPcZnjvxOJ76813Xs2vIN2rgh4lg== @@ -8329,7 +8484,7 @@ web3@1.5.3: web3-shh "1.5.3" web3-utils "1.5.3" -web3@^1.0.0-beta.34, web3@^1.2.5: +web3@^1.0.0-beta.34: version "1.7.3" resolved "https://registry.yarnpkg.com/web3/-/web3-1.7.3.tgz#30fe786338b2cc775881cb28c056ee5da4be65b8" integrity sha512-UgBvQnKIXncGYzsiGacaiHtm0xzQ/JtGqcSO/ddzQHYxnNuwI72j1Pb4gskztLYihizV9qPNQYHMSCiBlStI9A==