diff --git a/.github/workflows/echidna.yaml b/.github/workflows/echidna.yaml index 410be24..6e64824 100644 --- a/.github/workflows/echidna.yaml +++ b/.github/workflows/echidna.yaml @@ -48,6 +48,28 @@ jobs: crytic-args: --ignore-compile contract: CryticERC20ExternalHarness + - name: Compile ERC721 Foundry example + working-directory: tests/ERC721/foundry + run: forge build --build-info + + - name: Run Echidna against ERC721 Internal Foundry example + uses: crytic/echidna-action@v2 + with: + echidna-workdir: ./tests/ERC721/foundry + files: . + config: ./echidna-config.yaml + crytic-args: --ignore-compile + contract: CryticERC721InternalHarness + + - name: Run Echidna against ERC721 External Foundry example + uses: crytic/echidna-action@v2 + with: + echidna-workdir: ./tests/ERC721/foundry + files: . + config: ./echidna-config-ext.yaml + crytic-args: --ignore-compile + contract: CryticERC721ExternalHarness + - name: Compile ERC4646 Foundry example working-directory: tests/ERC4626/foundry run: forge build --build-info @@ -99,6 +121,30 @@ jobs: crytic-args: --ignore-compile contract: CryticERC20ExternalHarness + - name: Install dependencies and compile ERC721 example + working-directory: tests/ERC721/hardhat + run: | + npm ci + npx hardhat compile --force + + - name: Run Echidna for Internal tests + uses: crytic/echidna-action@v2 + with: + echidna-workdir: ./tests/ERC721/hardhat + files: . + config: ./tests/echidna-config.yaml + crytic-args: --ignore-compile + contract: CryticERC721InternalHarness + + - name: Run Echidna for External tests + uses: crytic/echidna-action@v2 + with: + echidna-workdir: ./tests/ERC721/hardhat + files: . + config: ./tests/echidna-config-ext.yaml + crytic-args: --ignore-compile + contract: CryticERC721ExternalHarness + - name: Install dependencies and compile ERC4626 example working-directory: tests/ERC4626/hardhat run: | diff --git a/PROPERTIES.md b/PROPERTIES.md index c24d8ae..063dd83 100644 --- a/PROPERTIES.md +++ b/PROPERTIES.md @@ -227,7 +227,7 @@ This file lists all the currently implemented Echidna property tests for ERC20, | ABDKMATH-071 | [pow_test_base_one](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1290) | One to the power of any number should be one. | | ABDKMATH-072 | [pow_test_product_same_base](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1298) | Product of powers of the same base property | | ABDKMATH-073 | [pow_test_power_of_an_exponentiation](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1310) | Power of an exponentiation property | -| ABDKMATH-074 | [pow_test_product_same_base](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1322) | Distributive property for power of a product | +| ABDKMATH-074 | [pow_test_distributive](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1322) | Distributive property for power of a product | | ABDKMATH-075 | [pow_test_values](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1336) | Power result should increase or decrease (in absolute value) depending on exponent's absolute value. | | ABDKMATH-076 | [pow_test_sign](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1352) | Power result sign should change according to the exponent sign. | | ABDKMATH-077 | [pow_test_maximum_base](https://github.com/crytic/properties/blob/main/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol#L1382) | Power edge case: Power of the maximum value should revert if exponent > 1. | diff --git a/README.md b/README.md index 611cf14..9c3c9ca 100644 --- a/README.md +++ b/README.md @@ -515,7 +515,7 @@ contract TestProperties is PropertiesAsserts { # HEVM cheat codes support -Since version 2.0.5, Echidna supports [HEVM cheat codes](https://hevm.dev/controlling-the-unit-testing-environment.html#cheat-codes). This repository contains a [`Hevm.sol`](contracts/util/Hevm.sol) contract that exposes cheat codes for easy integration into contracts under test. +Since version 2.0.5, Echidna supports [HEVM cheat codes](https://hevm.dev/ds-test-tutorial.html#supported-cheat-codes). This repository contains a [`Hevm.sol`](contracts/util/Hevm.sol) contract that exposes cheat codes for easy integration into contracts under test. Cheat codes should be used with care, since they can alter the execution environment in ways that are not expected, and may introduce false positives or false negatives. diff --git a/contracts/ERC4626/util/TestERC20Token.sol b/contracts/ERC4626/util/TestERC20Token.sol index 1072f22..8b58fb8 100644 --- a/contracts/ERC4626/util/TestERC20Token.sol +++ b/contracts/ERC4626/util/TestERC20Token.sol @@ -1,21 +1,16 @@ pragma solidity ^0.8.0; -contract TestERC20Token { - event Transfer(address indexed from, address indexed to, uint256 amount); - event Approval( - address indexed owner, - address indexed spender, - uint256 amount - ); +import {IERC20} from "../../util/IERC20.sol"; +contract TestERC20Token is IERC20 { string public name; string public symbol; - uint256 public decimals; + uint8 public decimals; uint256 public totalSupply; mapping(address => uint256) public balanceOf; mapping(address => mapping(address => uint256)) public allowance; - constructor(string memory _name, string memory _symbol, uint256 _decimals) { + constructor(string memory _name, string memory _symbol, uint8 _decimals) { name = _name; symbol = _symbol; decimals = _decimals; diff --git a/contracts/ERC721/external/properties/ERC721ExternalBasicProperties.sol b/contracts/ERC721/external/properties/ERC721ExternalBasicProperties.sol index a877ecd..de13332 100644 --- a/contracts/ERC721/external/properties/ERC721ExternalBasicProperties.sol +++ b/contracts/ERC721/external/properties/ERC721ExternalBasicProperties.sol @@ -48,6 +48,7 @@ abstract contract CryticERC721ExternalBasicProperties is CryticERC721ExternalTes require(selfBalance > 0); require(target != address(this)); require(target != msg.sender); + require(target != address(0)); uint tokenId = token.tokenOfOwnerByIndex(msg.sender, 0); @@ -65,6 +66,7 @@ abstract contract CryticERC721ExternalBasicProperties is CryticERC721ExternalTes require(selfBalance > 0); require(target != address(this)); require(target != msg.sender); + require(target != address(0)); uint tokenId = token.tokenOfOwnerByIndex(msg.sender, 0); hevm.prank(msg.sender); diff --git a/contracts/ERC721/external/properties/ERC721ExternalMintableProperties.sol b/contracts/ERC721/external/properties/ERC721ExternalMintableProperties.sol index 3010202..ba55418 100644 --- a/contracts/ERC721/external/properties/ERC721ExternalMintableProperties.sol +++ b/contracts/ERC721/external/properties/ERC721ExternalMintableProperties.sol @@ -7,29 +7,31 @@ abstract contract CryticERC721ExternalMintableProperties is CryticERC721External //////////////////////////////////////// // Properties - // mint increases the total supply - function test_ERC721_external_mintIncreasesSupply() public virtual { + // mint increases the total supply. + function test_ERC721_external_mintIncreasesSupply(uint256 amount) public virtual { require(token.isMintableOrBurnable()); + uint256 selfBalance = token.balanceOf(address(this)); uint256 oldTotalSupply = token.totalSupply(); - try token._customMint(address(this)) { - assertEq(oldTotalSupply + 1, token.totalSupply(), "Total supply was not correctly increased"); - assertEq(selfBalance + 1, token.balanceOf(address(this)), "Receiver supply was not correctly increased"); + try token._customMint(address(this), amount) { + assertEq(oldTotalSupply + amount, token.totalSupply(), "Total supply was not correctly increased"); + assertEq(selfBalance + amount, token.balanceOf(address(this)), "Receiver supply was not correctly increased"); } catch { assertWithMsg(false, "Minting unexpectedly reverted"); } } - // mint creates a fresh token - function test_ERC721_external_mintCreatesFreshToken() public virtual { + // mint creates a fresh token. + function test_ERC721_external_mintCreatesFreshToken(uint256 amount) public virtual { require(token.isMintableOrBurnable()); + uint256 selfBalance = token.balanceOf(address(this)); - try token._customMint(address(this)) { + try token._customMint(address(this), amount) { uint256 tokenId = token.tokenOfOwnerByIndex(address(this), selfBalance); assertWithMsg(token.ownerOf(tokenId) == address(this), "Token ID was not minted to receiver"); assertWithMsg(!token.usedId(tokenId), "Token ID minted is not new"); - assertEq(selfBalance + 1, token.balanceOf(address(this)), "Receiver supply was not correctly increased"); + assertEq(selfBalance + amount, token.balanceOf(address(this)), "Receiver supply was not correctly increased"); } catch { assertWithMsg(false, "Minting unexpectedly reverted"); } diff --git a/contracts/ERC721/external/test/ERC721Compliant.sol b/contracts/ERC721/external/test/ERC721Compliant.sol index 18e87e8..b886cee 100644 --- a/contracts/ERC721/external/test/ERC721Compliant.sol +++ b/contracts/ERC721/external/test/ERC721Compliant.sol @@ -18,8 +18,10 @@ contract ERC721Compliant is ERC721, ERC721Enumerable, IERC721Internal { _burn(tokenId); } - function _customMint(address to) public virtual { - _mint(to, counter++); + function _customMint(address to, uint256 amount) public virtual { + for(uint256 i; i < amount; i++) { + _mint(to, counter++); + } } // The following functions are overrides required by Solidity. diff --git a/contracts/ERC721/external/util/ERC721IncorrectBasic.sol b/contracts/ERC721/external/util/ERC721IncorrectBasic.sol index 6c19de2..46ddd70 100644 --- a/contracts/ERC721/external/util/ERC721IncorrectBasic.sol +++ b/contracts/ERC721/external/util/ERC721IncorrectBasic.sol @@ -66,8 +66,10 @@ contract ERC721IncorrectBasic is Context, ERC165, IERC721, IERC721Metadata { _mint(to, counter++); } - function _customMint(address to) external { - mint(to); + function _customMint(address to, uint256 amount) external { + for(uint256 i; i < amount; i++) { + mint(to); + } } /** diff --git a/contracts/ERC721/external/util/ERC721IncorrectBurnable.sol b/contracts/ERC721/external/util/ERC721IncorrectBurnable.sol index c20de44..bb3537a 100644 --- a/contracts/ERC721/external/util/ERC721IncorrectBurnable.sol +++ b/contracts/ERC721/external/util/ERC721IncorrectBurnable.sol @@ -72,8 +72,10 @@ contract ERC721IncorrectBurnable is Context, ERC165, IERC721, IERC721Metadata { _burn(tokenId); } - function _customMint(address to) external { - mint(to); + function _customMint(address to, uint256 amount) external { + for(uint256 i; i < amount; i++) { + mint(to); + } } /** diff --git a/contracts/ERC721/external/util/ERC721IncorrectMintable.sol b/contracts/ERC721/external/util/ERC721IncorrectMintable.sol index 071d276..c313b53 100644 --- a/contracts/ERC721/external/util/ERC721IncorrectMintable.sol +++ b/contracts/ERC721/external/util/ERC721IncorrectMintable.sol @@ -69,8 +69,10 @@ contract ERC721IncorrectMintable is Context, ERC165, IERC721, IERC721Metadata { _mint(to, id); } - function _customMint(address to) external { - mint(to); + function _customMint(address to, uint256 amount) external { + for(uint256 i; i < amount; i++) { + mint(to); + } } /** diff --git a/contracts/ERC721/internal/properties/ERC721BasicProperties.sol b/contracts/ERC721/internal/properties/ERC721BasicProperties.sol index af7eb3e..edadea0 100644 --- a/contracts/ERC721/internal/properties/ERC721BasicProperties.sol +++ b/contracts/ERC721/internal/properties/ERC721BasicProperties.sol @@ -50,6 +50,7 @@ abstract contract CryticERC721BasicProperties is CryticERC721TestBase { require(selfBalance > 0); require(target != address(this)); require(target != msg.sender); + require(target != address(0)); uint tokenId = tokenOfOwnerByIndex(msg.sender, 0); hevm.prank(msg.sender); @@ -67,6 +68,7 @@ abstract contract CryticERC721BasicProperties is CryticERC721TestBase { require(selfBalance > 0); require(target != address(this)); require(target != msg.sender); + require(target != address(0)); uint tokenId = tokenOfOwnerByIndex(msg.sender, 0); hevm.prank(msg.sender); diff --git a/contracts/ERC721/internal/properties/ERC721MintableProperties.sol b/contracts/ERC721/internal/properties/ERC721MintableProperties.sol index ec259ef..2b424df 100644 --- a/contracts/ERC721/internal/properties/ERC721MintableProperties.sol +++ b/contracts/ERC721/internal/properties/ERC721MintableProperties.sol @@ -7,24 +7,26 @@ abstract contract CryticERC721MintableProperties is CryticERC721TestBase { //////////////////////////////////////// // Properties - // mint increases the total supply - function test_ERC721_mintIncreasesSupply() public virtual { + // mint increases the total supply. + function test_ERC721_mintIncreasesSupply(uint256 amount) public virtual { require(isMintableOrBurnable); + uint256 selfBalance = balanceOf(msg.sender); uint256 oldTotalSupply = totalSupply(); - _customMint(msg.sender); + _customMint(msg.sender, amount); - assertEq(oldTotalSupply + 1, totalSupply(), "Total supply was not correctly increased"); - assertEq(selfBalance + 1, balanceOf(msg.sender), "Receiver supply was not correctly increased"); + assertEq(oldTotalSupply + amount, totalSupply(), "Total supply was not correctly increased"); + assertEq(selfBalance + amount, balanceOf(msg.sender), "Receiver supply was not correctly increased"); } - // mint creates a fresh token - function test_ERC721_mintCreatesFreshToken() public virtual { + // mint creates a fresh token. + function test_ERC721_mintCreatesFreshToken(uint256 amount) public virtual { require(isMintableOrBurnable); + uint256 selfBalance = balanceOf(msg.sender); - _customMint(msg.sender); + _customMint(msg.sender, amount); - assertEq(selfBalance + 1, balanceOf(msg.sender), "Receiver supply was not correctly increased"); + assertEq(selfBalance + amount, balanceOf(msg.sender), "Receiver supply was not correctly increased"); uint256 tokenId = tokenOfOwnerByIndex(msg.sender, selfBalance); assertWithMsg(ownerOf(tokenId) == msg.sender, "Token ID was not minted to receiver"); @@ -32,5 +34,5 @@ abstract contract CryticERC721MintableProperties is CryticERC721TestBase { } // Wrappers - function _customMint(address to) internal virtual; + function _customMint(address to, uint256 amount) internal virtual; } diff --git a/contracts/ERC721/internal/test/standard/ERC721BasicTests.sol b/contracts/ERC721/internal/test/standard/ERC721BasicTests.sol index 9202c5a..f7381ad 100644 --- a/contracts/ERC721/internal/test/standard/ERC721BasicTests.sol +++ b/contracts/ERC721/internal/test/standard/ERC721BasicTests.sol @@ -86,8 +86,10 @@ contract ERC721BasicTestsInternal is CryticERC721BasicProperties { return super.supportsInterface(interfaceId); } - function _customMint(address to) internal virtual { - mint(to); + function _customMint(address to, uint256 amount) internal virtual { + for(uint256 i; i < amount; i++) { + mint(to); + } } } diff --git a/contracts/ERC721/internal/test/standard/ERC721Compliant.sol b/contracts/ERC721/internal/test/standard/ERC721Compliant.sol index d14ca70..0d15662 100644 --- a/contracts/ERC721/internal/test/standard/ERC721Compliant.sol +++ b/contracts/ERC721/internal/test/standard/ERC721Compliant.sol @@ -41,7 +41,9 @@ contract ERC721Compliant is CryticERC721InternalPropertyTests { return super.supportsInterface(interfaceId); } - function _customMint(address to) internal virtual override { - mint(to); + function _customMint(address to, uint256 amount) internal virtual override { + for(uint256 i; i < amount; i++) { + mint(to); + } } } \ No newline at end of file diff --git a/contracts/ERC721/internal/test/standard/ERC721MintableTests.sol b/contracts/ERC721/internal/test/standard/ERC721MintableTests.sol index d6af5ed..fc93c12 100644 --- a/contracts/ERC721/internal/test/standard/ERC721MintableTests.sol +++ b/contracts/ERC721/internal/test/standard/ERC721MintableTests.sol @@ -88,8 +88,10 @@ contract ERC721MintableTestsInternal is CryticERC721MintableProperties { return super.supportsInterface(interfaceId); } - function _customMint(address to) internal virtual override { - mint(to); + function _customMint(address to, uint256 amount) internal virtual override { + for(uint256 i; i < amount; i++) { + mint(to); + } } } diff --git a/contracts/ERC721/util/IERC721Internal.sol b/contracts/ERC721/util/IERC721Internal.sol index 09ddd44..f8771a4 100644 --- a/contracts/ERC721/util/IERC721Internal.sol +++ b/contracts/ERC721/util/IERC721Internal.sol @@ -7,5 +7,5 @@ interface IERC721Internal is IERC721, IERC721Enumerable { function isMintableOrBurnable() external returns (bool); function burn(uint256 tokenId) external; function usedId(uint256 tokenId) external view returns (bool); - function _customMint(address to) external; + function _customMint(address to, uint256 amount) external; } \ No newline at end of file diff --git a/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol b/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol index 3246adc..efa58fd 100644 --- a/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol +++ b/contracts/Math/ABDKMath64x64/ABDKMath64x64PropertyTests.sol @@ -1079,8 +1079,8 @@ contract CryticABDKMath64x64Properties { function inv_test_minimum() public view { int128 inv_minimum; - try this.inv(MAX_64x64) { - inv_minimum = this.inv(MAX_64x64); + try this.inv(MIN_64x64) { + inv_minimum = this.inv(MIN_64x64); assert(equal_within_precision(abs(inv_minimum), ZERO_FP, 10)); } catch { // Unexpected, the function must not revert @@ -1312,9 +1312,9 @@ contract CryticABDKMath64x64Properties { assert(equal_within_precision(x_a_b, x_ab, 2)); } - // Test for power of a product + // Test for distributive property for power of a product // (x * y) ** a == x ** a * y ** a - function pow_test_product_same_base( + function pow_test_distributive( int128 x, int128 y, uint256 a diff --git a/contracts/util/Hevm.sol b/contracts/util/Hevm.sol index c227580..8a7a92c 100644 --- a/contracts/util/Hevm.sol +++ b/contracts/util/Hevm.sol @@ -8,17 +8,24 @@ interface IHevm { // Set block.number to newNumber function roll(uint256 newNumber) external; + // Add the condition b to the assumption base for the current branch + // This function is almost identical to require + function assume(bool b) external; + + // Sets the eth balance of usr to amt + function deal(address usr, uint256 amt) external; + // Loads a storage slot from an address function load(address where, bytes32 slot) external returns (bytes32); // Stores a value to an address' storage slot function store(address where, bytes32 slot, bytes32 value) external; - // Signs data (privateKey, digest) => (r, v, s) + // Signs data (privateKey, digest) => (v, r, s) function sign( uint256 privateKey, bytes32 digest - ) external returns (uint8 r, bytes32 v, bytes32 s); + ) external returns (uint8 v, bytes32 r, bytes32 s); // Gets address for a given private key function addr(uint256 privateKey) external returns (address addr); @@ -30,6 +37,18 @@ interface IHevm { // Performs the next smart contract call with specified `msg.sender` function prank(address newSender) external; + + // Creates a new fork with the given endpoint and the latest block and returns the identifier of the fork + function createFork(string calldata urlOrAlias) external returns (uint256); + + // Takes a fork identifier created by createFork and sets the corresponding forked state as active + function selectFork(uint256 forkId) external; + + // Returns the identifier of the current fork + function activeFork() external returns (uint256); + + // Labels the address in traces + function label(address addr, string calldata label) external; } IHevm constant hevm = IHevm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); diff --git a/tests/ERC721/foundry/test/CryticTest.sol b/tests/ERC721/foundry/test/CryticTest.sol index 9e76d56..e4e4bbc 100644 --- a/tests/ERC721/foundry/test/CryticTest.sol +++ b/tests/ERC721/foundry/test/CryticTest.sol @@ -6,19 +6,13 @@ contract CryticERC721InternalHarness is ExampleToken, CryticERC721BasicPropertie using Address for address; constructor() { - maxSupply = 100; isMintableOrBurnable = true; - hasMaxSupply = false; safeReceiver = new MockReceiver(true); unsafeReceiver = new MockReceiver(false); } - function _customMint(uint256 amount) internal virtual { - mint(msg.sender, amount); - } - - function _customMaxSupply() internal virtual view returns (uint256) { - return maxSupply; + function _customMint(address to, uint256 amount) internal virtual { + mint(to, amount); } // The following functions are overrides required by Solidity. diff --git a/tests/ERC721/hardhat/contracts/CryticTest.sol b/tests/ERC721/hardhat/contracts/CryticTest.sol index afb735b..b8b7ae4 100644 --- a/tests/ERC721/hardhat/contracts/CryticTest.sol +++ b/tests/ERC721/hardhat/contracts/CryticTest.sol @@ -1,24 +1,18 @@ pragma solidity ^0.8.0; -import "@crytic/properties/ERC721/internal/properties/ERC721BasicProperties.sol"; +import "@crytic/properties/contracts/ERC721/internal/properties/ERC721BasicProperties.sol"; import "./ExampleToken.sol"; contract CryticERC721InternalHarness is ExampleToken, CryticERC721BasicProperties { using Address for address; constructor() { - maxSupply = 100; isMintableOrBurnable = true; - hasMaxSupply = false; safeReceiver = new MockReceiver(true); unsafeReceiver = new MockReceiver(false); } - function _customMint(uint256 amount) internal virtual { - mint(msg.sender, amount); - } - - function _customMaxSupply() internal virtual view returns (uint256) { - return maxSupply; + function _customMint(address to, uint256 amount) internal virtual { + mint(to, amount); } // The following functions are overrides required by Solidity. diff --git a/tests/ERC721/hardhat/contracts/CryticTestExt.sol b/tests/ERC721/hardhat/contracts/CryticTestExt.sol index 89c6a0b..0f5cd33 100644 --- a/tests/ERC721/hardhat/contracts/CryticTestExt.sol +++ b/tests/ERC721/hardhat/contracts/CryticTestExt.sol @@ -1,8 +1,8 @@ pragma solidity ^0.8.0; import "./ExampleToken.sol"; -import {IERC721Internal} from "@crytic/properties/ERC721/util/IERC721Internal.sol"; -import {CryticERC721ExternalBasicProperties} from "@crytic/properties/ERC721/external/properties/ERC721xternalBasicProperties.sol"; -import {MockReceiver} from "properties/ERC721/external/util/MockReceiver.sol"; +import {IERC721Internal} from "@crytic/properties/contracts/ERC721/util/IERC721Internal.sol"; +import {CryticERC721ExternalBasicProperties} from "@crytic/properties/contracts/ERC721/external/properties/ERC721ExternalBasicProperties.sol"; +import {MockReceiver} from "@crytic/properties/contracts/ERC721/external/util/MockReceiver.sol"; contract CryticERC721ExternalHarness is CryticERC721ExternalBasicProperties { diff --git a/tests/ERC721/hardhat/yarn.lock b/tests/ERC721/hardhat/yarn.lock index 0018d21..647aefd 100644 --- a/tests/ERC721/hardhat/yarn.lock +++ b/tests/ERC721/hardhat/yarn.lock @@ -7,6 +7,9 @@ "version" "0.0.1" dependencies: "@openzeppelin/contracts" "^4.7.3" + "markdown-link-check" "^3.11.0" + "prettier" "^2.8.7" + "prettier-plugin-solidity" "^1.1.3" "solmate" "^6.6.1" "@ethersproject/abi@^5.1.2":