From 23c3a866549a7f4607bbb3da84dde18d5d0be71b Mon Sep 17 00:00:00 2001 From: Jan-Felix Date: Wed, 26 Apr 2023 16:35:18 +0200 Subject: [PATCH 01/41] upgrade to latest account-abstraction contracts --- contracts/base/Account.sol | 25 +++++++------------------ package.json | 2 +- yarn.lock | 10 +++++----- 3 files changed, 13 insertions(+), 24 deletions(-) diff --git a/contracts/base/Account.sol b/contracts/base/Account.sol index 2bfd107..55ae73f 100644 --- a/contracts/base/Account.sol +++ b/contracts/base/Account.sol @@ -14,22 +14,22 @@ abstract contract Account is BaseAccount { // return value in case of signature validation success, with no time-range. uint256 private constant SIG_VALIDATION_SUCCEEDED = 0; - uint256 private _nonce = 0; - /** - * @dev Hard-code the ERC4337 entry point contract address for gas efficiency + * @dev Hard-code the ERC4337 entry point contract address so it cannot be changed by anyone */ IEntryPoint private constant _entryPoint = IEntryPoint(0x0576a174D229E3cFA37253523E645A78A0C91B57); /// @inheritdoc BaseAccount - function nonce() public view virtual override returns (uint256) { - return _nonce; + function entryPoint() public view virtual override returns (IEntryPoint) { + return _entryPoint; } /// @inheritdoc BaseAccount - function entryPoint() public view virtual override returns (IEntryPoint) { - return _entryPoint; + function _validateNonce(uint256 nonce) internal view virtual override { + // First 192 bits are the sequence key, remaining 64 bits are the sequence number + // We only use the nonce sequence with key 0, so no out-of-order nonce is possible. + require(nonce < type(uint64).max, "Invalid nonce"); } /** @@ -59,15 +59,4 @@ abstract contract Account is BaseAccount { bytes32 hash, bytes memory signature ) public view virtual returns (bytes4 magicValue); - - /** - * @dev Validate the current nonce matches the UserOperation nonce, then increment nonce to prevent replay of this user operation. - * Called only if initCode is empty (since "nonce" field is used as "salt" on account creation) - * @param userOp The user operation to validate. - */ - function _validateAndUpdateNonce( - UserOperation calldata userOp - ) internal virtual override { - require(_nonce++ == userOp.nonce, "Invalid nonce"); - } } diff --git a/package.json b/package.json index 7ae6871..319651f 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ }, "homepage": "https://github.com/gnosis/mech#readme", "devDependencies": { - "@account-abstraction/contracts": "^0.5.0", + "@account-abstraction/contracts": "^0.6.0", "@ambire/signature-validator": "^1.1.0", "@ethersproject/abi": "^5.7.0", "@ethersproject/bytes": "^5.7.0", diff --git a/yarn.lock b/yarn.lock index 47a14a0..72422be 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5,10 +5,10 @@ __metadata: version: 6 cacheKey: 8 -"@account-abstraction/contracts@npm:^0.5.0": - version: 0.5.0 - resolution: "@account-abstraction/contracts@npm:0.5.0" - checksum: 792a82e9ac3dac2d0c6b92133998b567acfc980aea6bb6d51377d95039a2a4c8cbd764c02ebe4d16ea7f7e18ff0724a0ae41970ba2b1bbcaf89e9bf875806ec5 +"@account-abstraction/contracts@npm:^0.6.0": + version: 0.6.0 + resolution: "@account-abstraction/contracts@npm:0.6.0" + checksum: 745e838e2cb04c89a9c0df11d022c1d604b1e440c9cd65c2014edd9b1056809fec2e363b42ec09883d49dbe09f9597d8339c90d57763a1621fb515edf5fef35d languageName: node linkType: hard @@ -14042,7 +14042,7 @@ __metadata: version: 0.0.0-use.local resolution: "mech-contracts@workspace:." dependencies: - "@account-abstraction/contracts": ^0.5.0 + "@account-abstraction/contracts": ^0.6.0 "@ambire/signature-validator": ^1.1.0 "@ethersproject/abi": ^5.7.0 "@ethersproject/bytes": ^5.7.0 From f76da227fe7a5b82be06bdec7ed0dc752155a02b Mon Sep 17 00:00:00 2001 From: Jan-Felix Date: Wed, 10 May 2023 09:40:30 +0200 Subject: [PATCH 02/41] fix package json --- sdk/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/package.json b/sdk/package.json index 81150ec..94e8b66 100644 --- a/sdk/package.json +++ b/sdk/package.json @@ -13,8 +13,8 @@ "build/**/*" ], "main": "build/cjs/sdk/index.js", - "typings": "build/cjs/sdk/index.d.ts", "module": "build/esm/sdk/index.js", + "types": "build/cjs/sdk/index.d.ts", "repository": { "type": "git", "url": "git+https://github.com/gnosis/mech.git" From 41702933d44b4e6a712b69225e48d4cddc108872 Mon Sep 17 00:00:00 2001 From: Jan-Felix Date: Wed, 10 May 2023 10:02:30 +0200 Subject: [PATCH 03/41] adjust tests --- contracts/ZodiacMech.sol | 12 ---- test/Account.ts | 47 +-------------- test/ZodiacMech.ts | 120 +++++++++++++++++++-------------------- 3 files changed, 61 insertions(+), 118 deletions(-) diff --git a/contracts/ZodiacMech.sol b/contracts/ZodiacMech.sol index a053bd2..2165e94 100644 --- a/contracts/ZodiacMech.sol +++ b/contracts/ZodiacMech.sol @@ -46,18 +46,6 @@ contract ZodiacMech is SafeStorage, Mech, IAvatar { } } - function nonce() public view override returns (uint256) { - // Here we use the nonce variable of the SafeStorage contract rather than that of the Mech contract. - // This is for keeping the nonce sequence of Safes that got upgraded to ZodiacMechs. - return safeNonce; - } - - function _validateAndUpdateNonce( - UserOperation calldata userOp - ) internal override { - require(safeNonce++ == userOp.nonce, "Invalid nonce"); - } - function isOperator(address signer) public view override returns (bool) { return isModuleEnabled(signer); } diff --git a/test/Account.ts b/test/Account.ts index 9e68c13..465a872 100644 --- a/test/Account.ts +++ b/test/Account.ts @@ -98,30 +98,6 @@ describe("Account base contract", () => { ).to.equal(0) }) - it("increments the nonce on successful validation", async () => { - const { mech1, alice, entryPointSigner } = await loadFixture(deployMech1) - - expect(await mech1.nonce()).to.equal(0) - - const userOp = await signUserOp( - await fillUserOp( - { - callData: BURN_1_ETH, - }, - mech1 - ), - alice - ) - - expect( - await mech1 - .connect(entryPointSigner) - .validateUserOp(userOp, getUserOpHash(userOp), 0) - ).to.not.be.reverted - - expect(await mech1.nonce()).to.equal(1) - }) - it("returns 1 for any other ECDSA signature", async () => { const { mech1, bob, entryPointSigner } = await loadFixture(deployMech1) @@ -142,27 +118,6 @@ describe("Account base contract", () => { ).to.equal(1) }) - it("reverts if it has a valid signature but a wrong nonce", async () => { - const { mech1, alice, entryPointSigner } = await loadFixture(deployMech1) - - const userOp = await signUserOp( - await fillUserOp( - { - callData: BURN_1_ETH, - nonce: 99, - }, - mech1 - ), - alice - ) - - await expect( - mech1 - .connect(entryPointSigner) - .validateUserOp(userOp, getUserOpHash(userOp), 0) - ).to.be.revertedWith("Invalid nonce") - }) - it("sends the pre-fund to sender if the user op has valid signature", async () => { const { mech1, alice, entryPointSigner } = await loadFixture(deployMech1) @@ -210,7 +165,7 @@ export const fillUserOp = async ( verificationGasLimit: 100000, paymasterAndData: "0x", ...op, - nonce: op.nonce === undefined ? await account.nonce() : op.nonce, + nonce: op.nonce || 0, }) export const signUserOp = async ( diff --git a/test/ZodiacMech.ts b/test/ZodiacMech.ts index 1c8a4d8..a02e2df 100644 --- a/test/ZodiacMech.ts +++ b/test/ZodiacMech.ts @@ -301,64 +301,64 @@ describe("ZodiacMech contract", () => { }) }) - describe("nonce storage", async () => { - it("reads the nonce from Safe's storage slot and increments it on successful validation", async () => { - const { mech1, alice } = await loadFixture(deployMech1) - - // set safeNonce storage slot to 99 - const nonceEncoded = defaultAbiCoder.encode(["uint256"], [99]) - const nonceSlot = "0x5" // see SafeStorage.sol - await network.provider.request({ - method: "hardhat_setStorageAt", - params: [mech1.address, nonceSlot, nonceEncoded], - }) - - // validate that the nonce is read from that slot - expect(await mech1.nonce()).to.equal(99) - - // prepare ERC4337 entry point - await network.provider.request({ - method: "hardhat_impersonateAccount", - params: [entryPoint], - }) - const entryPointSigner = await ethers.getSigner(entryPoint) - await alice.sendTransaction({ - to: entryPoint, - value: parseEther("1.0"), - }) - - // fund mech1 with 1 ETH - await alice.sendTransaction({ - to: mech1.address, - value: parseEther("1.0"), - }) - - const BURN_1_ETH = mech1.interface.encodeFunctionData("exec", [ - ZERO_ADDRESS, - parseEther("1.0"), - "0x", - 0, - 0, - ]) - - const userOp = await signUserOp( - await fillUserOp( - { - callData: BURN_1_ETH, - }, - mech1 - ), - alice - ) - - // call validateUserOp so that the nonce is incremented - expect( - await mech1 - .connect(entryPointSigner) - .validateUserOp(userOp, getUserOpHash(userOp), 0) - ).to.not.be.reverted - - expect(await mech1.nonce()).to.equal(100) - }) - }) + // describe("nonce storage", async () => { + // it("reads the nonce from Safe's storage slot and increments it on successful validation", async () => { + // const { mech1, alice } = await loadFixture(deployMech1) + + // // set safeNonce storage slot to 99 + // const nonceEncoded = defaultAbiCoder.encode(["uint256"], [99]) + // const nonceSlot = "0x5" // see SafeStorage.sol + // await network.provider.request({ + // method: "hardhat_setStorageAt", + // params: [mech1.address, nonceSlot, nonceEncoded], + // }) + + // // validate that the nonce is read from that slot + // expect(await mech1.nonce()).to.equal(99) + + // // prepare ERC4337 entry point + // await network.provider.request({ + // method: "hardhat_impersonateAccount", + // params: [entryPoint], + // }) + // const entryPointSigner = await ethers.getSigner(entryPoint) + // await alice.sendTransaction({ + // to: entryPoint, + // value: parseEther("1.0"), + // }) + + // // fund mech1 with 1 ETH + // await alice.sendTransaction({ + // to: mech1.address, + // value: parseEther("1.0"), + // }) + + // const BURN_1_ETH = mech1.interface.encodeFunctionData("exec", [ + // ZERO_ADDRESS, + // parseEther("1.0"), + // "0x", + // 0, + // 0, + // ]) + + // const userOp = await signUserOp( + // await fillUserOp( + // { + // callData: BURN_1_ETH, + // }, + // mech1 + // ), + // alice + // ) + + // // call validateUserOp so that the nonce is incremented + // expect( + // await mech1 + // .connect(entryPointSigner) + // .validateUserOp(userOp, getUserOpHash(userOp), 0) + // ).to.not.be.reverted + + // expect(await mech1.nonce()).to.equal(100) + // }) + // }) }) From 4e7cf06f47aff543426d680cdb7e7ecb19be0252 Mon Sep 17 00:00:00 2001 From: Jan-Felix Date: Wed, 10 May 2023 16:32:21 +0200 Subject: [PATCH 04/41] trial to fix vercel routes --- vercel.json | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 vercel.json diff --git a/vercel.json b/vercel.json new file mode 100644 index 0000000..3a48e56 --- /dev/null +++ b/vercel.json @@ -0,0 +1,3 @@ +{ + "rewrites": [{ "source": "/(.*)", "destination": "/" }] +} From 217223d977489328363c67392e09a1814f5c8f59 Mon Sep 17 00:00:00 2001 From: Jan-Felix Date: Thu, 11 May 2023 10:09:56 +0200 Subject: [PATCH 05/41] fix deploy script for gnosis chain --- .env.example | 3 ++- hardhat.config.ts | 20 +++++++++++++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/.env.example b/.env.example index 1f26355..7581d74 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,4 @@ MNEMONIC= INFURA_KEY= -ETHERSCAN_API_KEY= \ No newline at end of file +ETHERSCAN_API_KEY= +GNOSISSCAN_API_KEY= \ No newline at end of file diff --git a/hardhat.config.ts b/hardhat.config.ts index 9b1b92e..76bd3ff 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -6,7 +6,8 @@ import dotenv from "dotenv" import { HardhatUserConfig, HttpNetworkUserConfig } from "hardhat/types" dotenv.config() -const { INFURA_KEY, MNEMONIC, ETHERSCAN_API_KEY } = process.env +const { INFURA_KEY, MNEMONIC, ETHERSCAN_API_KEY, GNOSISSCAN_API_KEY } = + process.env const DEFAULT_MNEMONIC = "candy maple cake sugar pudding cream honey rich smooth crumble sweet treat" @@ -44,7 +45,7 @@ let config: HardhatUserConfig = { ...sharedNetworkConfig, url: `https://goerli.infura.io/v3/${INFURA_KEY}`, }, - xdai: { + gnosis: { ...sharedNetworkConfig, url: "https://rpc.gnosischain.com/", }, @@ -54,7 +55,20 @@ let config: HardhatUserConfig = { }, }, etherscan: { - apiKey: ETHERSCAN_API_KEY, + apiKey: { + mainnet: ETHERSCAN_API_KEY, + gnosis: GNOSISSCAN_API_KEY, + } as Record, + customChains: [ + { + network: "gnosis", + chainId: 100, + urls: { + apiURL: "https://api.gnosisscan.io/api", + browserURL: "https://www.gnosisscan.io", + }, + }, + ], }, // verify: { // etherscan: { From 6e53bb01f1b5625eb4b92ae2488505e11c4990bd Mon Sep 17 00:00:00 2001 From: Jan-Felix Date: Tue, 30 May 2023 15:09:35 +0200 Subject: [PATCH 06/41] implement IERC6551Account --- contracts/interfaces/IMech.sol | 3 ++- package.json | 1 + yarn.lock | 8 ++++++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/contracts/interfaces/IMech.sol b/contracts/interfaces/IMech.sol index 4570f6d..a994c9f 100644 --- a/contracts/interfaces/IMech.sol +++ b/contracts/interfaces/IMech.sol @@ -4,10 +4,11 @@ pragma solidity ^0.8.12; import "@openzeppelin/contracts/interfaces/IERC1271.sol"; import "@gnosis.pm/safe-contracts/contracts/common/Enum.sol"; import "@account-abstraction/contracts/interfaces/IAccount.sol"; +import "@erc6551/reference/src/interfaces/IERC6551Account.sol"; import "./IFactoryFriendly.sol"; -interface IMech is IAccount, IERC1271, IFactoryFriendly { +interface IMech is IAccount, IERC6551Account, IERC1271, IFactoryFriendly { /// @dev Executes either a delegatecall or a call with provided parameters /// @param to Destination address. /// @param value Ether value. diff --git a/package.json b/package.json index 319651f..c269e27 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "devDependencies": { "@account-abstraction/contracts": "^0.6.0", "@ambire/signature-validator": "^1.1.0", + "@erc6551/reference": "https://github.com/erc6551/reference", "@ethersproject/abi": "^5.7.0", "@ethersproject/bytes": "^5.7.0", "@ethersproject/providers": "^5.7.2", diff --git a/yarn.lock b/yarn.lock index 72422be..bfc60f3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1741,6 +1741,13 @@ __metadata: languageName: node linkType: hard +"@erc6551/reference@https://github.com/erc6551/reference": + version: 0.0.1 + resolution: "@erc6551/reference@https://github.com/erc6551/reference.git#commit=d79a49e99fee1154a2023bd164850c5d0c34c208" + checksum: dadd486de350f02ecf68809cb6130fb29029c2230fa44aa212a1ae473e0a1155e24220b50467bb1274539bda16205b947eb2c7904cba5ded918a274ba2043123 + languageName: node + linkType: hard + "@esbuild/android-arm@npm:0.15.13": version: 0.15.13 resolution: "@esbuild/android-arm@npm:0.15.13" @@ -14044,6 +14051,7 @@ __metadata: dependencies: "@account-abstraction/contracts": ^0.6.0 "@ambire/signature-validator": ^1.1.0 + "@erc6551/reference": "https://github.com/erc6551/reference" "@ethersproject/abi": ^5.7.0 "@ethersproject/bytes": ^5.7.0 "@ethersproject/providers": ^5.7.2 From 3d6d79dc4c261fb4e85a9504e38e263b2b0e28b2 Mon Sep 17 00:00:00 2001 From: Jan-Felix Date: Wed, 7 Jun 2023 12:55:49 +0200 Subject: [PATCH 07/41] restructure contract inheritance hierarchy --- ...C1155Mech.sol => ERC1155ThresholdMech.sol} | 5 +- contracts/ERC1155TokenboundMech.sol | 90 +++++++++++++++++++ contracts/ERC721Mech.sol | 41 --------- contracts/ERC721TokenboundMech.sol | 52 +++++++++++ contracts/base/ImmutableStorage.sol | 54 ----------- contracts/base/Mech.sol | 2 + contracts/base/ThresholdMech.sol | 11 +++ contracts/base/TokenboundMech.sol | 41 +++++++++ contracts/interfaces/IMech.sol | 3 +- contracts/libraries/WriteOnce.sol | 86 ------------------ ...ERC1155Mech.ts => ERC1155ThresholdMech.ts} | 20 +++-- ...{ERC721Mech.ts => ERC721TokenboundMech.ts} | 10 ++- test/ImmutableStorage.ts | 47 ---------- yarn.lock | 8 ++ 14 files changed, 225 insertions(+), 245 deletions(-) rename contracts/{ERC1155Mech.sol => ERC1155ThresholdMech.sol} (96%) create mode 100644 contracts/ERC1155TokenboundMech.sol delete mode 100644 contracts/ERC721Mech.sol create mode 100644 contracts/ERC721TokenboundMech.sol delete mode 100644 contracts/base/ImmutableStorage.sol create mode 100644 contracts/base/ThresholdMech.sol create mode 100644 contracts/base/TokenboundMech.sol delete mode 100644 contracts/libraries/WriteOnce.sol rename test/{ERC1155Mech.ts => ERC1155ThresholdMech.ts} (87%) rename test/{ERC721Mech.ts => ERC721TokenboundMech.ts} (90%) delete mode 100644 test/ImmutableStorage.ts diff --git a/contracts/ERC1155Mech.sol b/contracts/ERC1155ThresholdMech.sol similarity index 96% rename from contracts/ERC1155Mech.sol rename to contracts/ERC1155ThresholdMech.sol index a265247..0d607b7 100644 --- a/contracts/ERC1155Mech.sol +++ b/contracts/ERC1155ThresholdMech.sol @@ -2,13 +2,12 @@ pragma solidity ^0.8.12; import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol"; -import "./base/Mech.sol"; -import "./base/ImmutableStorage.sol"; +import "./base/ThresholdMech.sol"; /** * @dev A Mech that is operated by the holder of a defined set of minimum ERC1155 token balances */ -contract ERC1155Mech is Mech, ImmutableStorage { +contract ERC1155ThresholdMech is ThresholdMech { /// @param _token Address of the token contract /// @param _tokenIds The token IDs /// @param _minBalances The minimum balances required for each token ID diff --git a/contracts/ERC1155TokenboundMech.sol b/contracts/ERC1155TokenboundMech.sol new file mode 100644 index 0000000..d8d8a0c --- /dev/null +++ b/contracts/ERC1155TokenboundMech.sol @@ -0,0 +1,90 @@ +//SPDX-License-Identifier: LGPL-3.0 +pragma solidity ^0.8.12; + +import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol"; +import "./base/TokenboundMech.sol"; + +/** + * @dev A Mech that is operated by the holder of a defined set of minimum ERC1155 token balances + */ +contract ERC1155TokenboundMech is TokenboundMech { + /// @param _token Address of the token contract + /// @param _tokenIds The token IDs + /// @param _minBalances The minimum balances required for each token ID + constructor( + address _token, + uint256[] memory _tokenIds, + uint256[] memory _minBalances, + uint256 _minTotalBalance + ) { + bytes memory initParams = abi.encode( + _token, + _tokenIds, + _minBalances, + _minTotalBalance + ); + setUp(initParams); + } + + function setUp(bytes memory initParams) public override { + require(readImmutable().length == 0, "Already initialized"); + (, uint256[] memory _tokenIds, uint256[] memory _minBalances, ) = abi + .decode(initParams, (address, uint256[], uint256[], uint256)); + require(_tokenIds.length > 0, "No token IDs provided"); + require(_tokenIds.length == _minBalances.length, "Length mismatch"); + + writeImmutable(initParams); + } + + function token() public view returns (IERC1155) { + address _token = abi.decode(readImmutable(), (address)); + return IERC1155(_token); + } + + function tokenIds(uint256 index) public view returns (uint256) { + (, uint256[] memory _tokenIds) = abi.decode( + readImmutable(), + (address, uint256[]) + ); + return _tokenIds[index]; + } + + function minBalances(uint256 index) public view returns (uint256) { + (, , uint256[] memory _minBalances) = abi.decode( + readImmutable(), + (address, uint256[], uint256[]) + ); + return _minBalances[index]; + } + + function minTotalBalance() public view returns (uint256) { + (, , , uint256 _minTotalBalance) = abi.decode( + readImmutable(), + (address, uint256[], uint256[], uint256) + ); + return _minTotalBalance; + } + + function isOperator(address signer) public view override returns (bool) { + ( + address _token, + uint256[] memory _tokenIds, + uint256[] memory _minBalances, + uint256 _minTotalBalance + ) = abi.decode( + readImmutable(), + (address, uint256[], uint256[], uint256) + ); + + uint256 balanceSum = 0; + for (uint256 i = 0; i < _tokenIds.length; i++) { + uint256 balance = IERC1155(_token).balanceOf(signer, _tokenIds[i]); + if (balance < _minBalances[i]) { + return false; + } + balanceSum += balance; + } + + return balanceSum >= _minTotalBalance; + } +} diff --git a/contracts/ERC721Mech.sol b/contracts/ERC721Mech.sol deleted file mode 100644 index 5b76b79..0000000 --- a/contracts/ERC721Mech.sol +++ /dev/null @@ -1,41 +0,0 @@ -//SPDX-License-Identifier: LGPL-3.0 -pragma solidity ^0.8.12; - -import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; -import "./base/Mech.sol"; -import "./base/ImmutableStorage.sol"; - -/** - * @dev A Mech that is operated by the holder of an ERC721 non-fungible token - */ -contract ERC721Mech is Mech, ImmutableStorage { - /// @param _token Address of the token contract - /// @param _tokenId The token ID - constructor(address _token, uint256 _tokenId) { - bytes memory initParams = abi.encode(_token, _tokenId); - setUp(initParams); - } - - function setUp(bytes memory initParams) public override { - require(readImmutable().length == 0, "Already initialized"); - writeImmutable(initParams); - } - - function token() public view returns (IERC721) { - address _token = abi.decode(readImmutable(), (address)); - return IERC721(_token); - } - - function tokenId() public view returns (uint256) { - (, uint256 _tokenId) = abi.decode(readImmutable(), (address, uint256)); - return _tokenId; - } - - function isOperator(address signer) public view override returns (bool) { - (address _token, uint256 _tokenId) = abi.decode( - readImmutable(), - (address, uint256) - ); - return IERC721(_token).ownerOf(_tokenId) == signer; - } -} diff --git a/contracts/ERC721TokenboundMech.sol b/contracts/ERC721TokenboundMech.sol new file mode 100644 index 0000000..71edb86 --- /dev/null +++ b/contracts/ERC721TokenboundMech.sol @@ -0,0 +1,52 @@ +//SPDX-License-Identifier: LGPL-3.0 +pragma solidity ^0.8.12; + +import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; +import "@erc6551/reference/src/interfaces/IERC6551Account.sol"; +import "@erc6551/reference/src/lib/ERC6551AccountLib.sol"; + +import "./base/Mech.sol"; + +/** + * @dev A Mech that is operated by the holder of an ERC721 non-fungible token, implements the ERC6551 standard + */ +contract ERC721Mech is Mech, IERC6551Account { + /// @param _token Address of the token contract + /// @param _tokenId The token ID + constructor(address _token, uint256 _tokenId) { + bytes memory initParams = abi.encode(_token, _tokenId); + setUp(initParams); + } + + function setUp(bytes memory initParams) public override { + require(readImmutable().length == 0, "Already initialized"); + writeImmutable(initParams); + } + + function isOperator(address signer) public view override returns (bool) { + return owner() == signer && signer != address(0); + } + + function executeCall( + address to, + uint256 value, + bytes calldata data + ) external payable returns (bytes memory) { + return exec(to, value, data, Enum.Operation.Call, 0); + }; + + function token() + external + view + returns (uint256 chainId, address tokenContract, uint256 tokenId) + { + return ERC6551AccountLib.token(); + } + + function owner() external view returns (address) { + (uint256 chainId, address tokenContract, uint256 tokenId) = this.token(); + if (chainId != block.chainid) return address(0); + + return IERC721(tokenContract).ownerOf(tokenId); + }; +} diff --git a/contracts/base/ImmutableStorage.sol b/contracts/base/ImmutableStorage.sol deleted file mode 100644 index aee95a2..0000000 --- a/contracts/base/ImmutableStorage.sol +++ /dev/null @@ -1,54 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.12; - -import "hardhat/console.sol"; -import "../libraries/WriteOnce.sol"; - -contract ImmutableStorage { - /** - * @return The address the data is written to - */ - function storageLocation() internal view returns (address) { - // calculates the address of the contract created through the first create() call made by this contract - // see: https://ethereum.stackexchange.com/a/761 - return - address( - uint160( - uint256( - keccak256( - abi.encodePacked( - bytes1(0xd6), - bytes1(0x94), - address(this), - bytes1(0x01) // contracts start with nonce 1 (EIP-161) - ) - ) - ) - ) - ); - } - - /** - * Stores `data` and validates that it's written to the expected storage location - * @param data to be written - */ - function writeImmutable(bytes memory data) internal { - bytes memory initCode = WriteOnce.creationCodeFor(data); - address createdAt; - - // Deploy contract using create - assembly { - createdAt := create(0, add(initCode, 32), mload(initCode)) - } - - require(createdAt == storageLocation(), "Write failed"); - } - - /** - * Reads the code at the storage location as data - * @return data stored at the storage location - */ - function readImmutable() internal view returns (bytes memory) { - return WriteOnce.valueStoredAt(storageLocation()); - } -} diff --git a/contracts/base/Mech.sol b/contracts/base/Mech.sol index e6c2726..1759e3b 100644 --- a/contracts/base/Mech.sol +++ b/contracts/base/Mech.sol @@ -15,6 +15,8 @@ abstract contract Mech is IMech, Account, Receiver { // bytes4(keccak256("isValidSignature(bytes32,bytes)") bytes4 internal constant EIP1271_MAGICVALUE = 0x1626ba7e; + receive() external payable override {} + /** * @dev Modifier to make a function callable only by the mech operator or the ERC4337 entry point contract */ diff --git a/contracts/base/ThresholdMech.sol b/contracts/base/ThresholdMech.sol new file mode 100644 index 0000000..b34d5fb --- /dev/null +++ b/contracts/base/ThresholdMech.sol @@ -0,0 +1,11 @@ +//SPDX-License-Identifier: LGPL-3.0 +pragma solidity ^0.8.12; + +import "./Mech.sol"; + +/** + * @dev A Mech that is operated by anyone hitting the configured threshold + */ +abstract contract ThresholdMech is Mech { + +} diff --git a/contracts/base/TokenboundMech.sol b/contracts/base/TokenboundMech.sol new file mode 100644 index 0000000..43242ee --- /dev/null +++ b/contracts/base/TokenboundMech.sol @@ -0,0 +1,41 @@ +//SPDX-License-Identifier: LGPL-3.0 +pragma solidity ^0.8.12; + +import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; +import "@erc6551/reference/src/interfaces/IERC6551Account.sol"; +import "@erc6551/reference/src/lib/ERC6551AccountLib.sol"; + +import "./Mech.sol"; + +/** + * @dev A Mech that is operated by the holder of a designated token, implements the ERC6551 standard + */ +abstract contract TokenboundMech is Mech, IERC6551Account { + function isOperator(address signer) public view override returns (bool) { + return owner() == signer && signer != address(0); + } + + function executeCall( + address to, + uint256 value, + bytes calldata data + ) external payable returns (bytes memory) { + return exec(to, value, data, Enum.Operation.Call, 0); + }; + + function token() + external + view + returns (uint256 chainId, address tokenContract, uint256 tokenId) + { + return ERC6551AccountLib.token(); + } + + function owner() public view returns (address); + + // required by ERC-6551, even though their account (https://github.com/tokenbound/contracts/blob/main/src/Account.sol) does not use it but a time-locking mechanism + // TODO adopt whatever ERC-6551 will settle on + function nonce() external view returns (uint256) { + return 0 + }; +} diff --git a/contracts/interfaces/IMech.sol b/contracts/interfaces/IMech.sol index a994c9f..4570f6d 100644 --- a/contracts/interfaces/IMech.sol +++ b/contracts/interfaces/IMech.sol @@ -4,11 +4,10 @@ pragma solidity ^0.8.12; import "@openzeppelin/contracts/interfaces/IERC1271.sol"; import "@gnosis.pm/safe-contracts/contracts/common/Enum.sol"; import "@account-abstraction/contracts/interfaces/IAccount.sol"; -import "@erc6551/reference/src/interfaces/IERC6551Account.sol"; import "./IFactoryFriendly.sol"; -interface IMech is IAccount, IERC6551Account, IERC1271, IFactoryFriendly { +interface IMech is IAccount, IERC1271, IFactoryFriendly { /// @dev Executes either a delegatecall or a call with provided parameters /// @param to Destination address. /// @param value Ether value. diff --git a/contracts/libraries/WriteOnce.sol b/contracts/libraries/WriteOnce.sol deleted file mode 100644 index 88b37b9..0000000 --- a/contracts/libraries/WriteOnce.sol +++ /dev/null @@ -1,86 +0,0 @@ -// SPDX-License-Identifier: MIT - -// Forked from https://github.com/0xsequence/sstore2/blob/master/contracts/utils/Bytecode.sol -// MIT License -// Copyright (c) [2018] [Ismael Ramos Silvan] -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -pragma solidity ^0.8.12; - -library WriteOnce { - /** - * @notice Generate a creation code that results on a contract with `00${_value}` as bytecode - * @param data The value to store in the bytecode - * @return creationCode (constructor) for new contract - */ - function creationCodeFor( - bytes memory data - ) internal pure returns (bytes memory) { - /* - 0x00 0x63 0x63XXXXXX PUSH4 _value.length size - 0x01 0x80 0x80 DUP1 size size - 0x02 0x60 0x600e PUSH1 14 14 size size - 0x03 0x60 0x6000 PUSH1 00 0 14 size size - 0x04 0x39 0x39 CODECOPY size - 0x05 0x60 0x6000 PUSH1 00 0 size - 0x06 0xf3 0xf3 RETURN - - */ - - // Prepend 00 so the created contract can't be called - return - abi.encodePacked( - hex"63", - uint32(data.length + 1), - hex"80_60_0E_60_00_39_60_00_F3", - hex"00", - data - ); - } - - /** - * @notice Returns the size of the code on a given address - * @param _addr Address that may or may not contain code - * @return size of the code on the given `_addr` - */ - function codeSize(address _addr) internal view returns (uint256 size) { - assembly { - size := extcodesize(_addr) - } - } - - /** - * @notice Returns the value stored in the bytecode of the given address - * @param _addr Address that may or may not contain code - * @return _value The value stored in the bytecode of the given address - * - * Forked from: https://gist.github.com/KardanovIR/fe98661df9338c842b4a30306d507fbd - **/ - function valueStoredAt( - address _addr - ) internal view returns (bytes memory _value) { - uint256 size = codeSize(_addr); - if (size <= 1) return bytes(""); - size--; // remove 00 byte we prepend when writing - - unchecked { - assembly { - // allocate output byte array - this could also be done without assembly - // by using o_code = new bytes(size) - _value := mload(0x40) - // new "memory end" including padding - mstore( - 0x40, - add(_value, and(add(add(size, 0x20), 0x1f), not(0x1f))) - ) - // store length in memory - mstore(_value, size) - // actually retrieve the code, this needs assembly - // start at offset 1 to skip over 00 byte we prepend when writing - extcodecopy(_addr, add(_value, 0x20), 1, size) - } - } - } -} diff --git a/test/ERC1155Mech.ts b/test/ERC1155ThresholdMech.ts similarity index 87% rename from test/ERC1155Mech.ts rename to test/ERC1155ThresholdMech.ts index 5ffae1a..8d4e873 100644 --- a/test/ERC1155Mech.ts +++ b/test/ERC1155ThresholdMech.ts @@ -7,17 +7,19 @@ import { ethers } from "hardhat" // Using this simplifies your tests and makes them run faster, by taking // advantage or Hardhat Network's snapshot functionality. -describe("ERC1155Mech contract", () => { +describe("ERC115ThresholdMech contract", () => { // We define a fixture to reuse the same setup in every test. We use // loadFixture to run this setup once, snapshot that state, and reset Hardhat // Network to that snapshot in every test. async function deployMech1() { const TestToken = await ethers.getContractFactory("ERC1155Token") - const ERC1155Mech = await ethers.getContractFactory("ERC1155Mech") + const ERC1155ThresholdMech = await ethers.getContractFactory( + "ERC1155ThresholdMech" + ) const [, alice, bob] = await ethers.getSigners() const testToken = await TestToken.deploy() - const mech1 = await ERC1155Mech.deploy( + const mech1 = await ERC1155ThresholdMech.deploy( testToken.address, [1, 2, 3], [1, 2, 3], @@ -27,7 +29,7 @@ describe("ERC1155Mech contract", () => { await mech1.deployed() // Fixtures can return anything you consider useful for your tests - return { ERC1155Mech, testToken, mech1, alice, bob } + return { ERC1155ThresholdMech, testToken, mech1, alice, bob } } describe("deployment", () => { @@ -48,9 +50,9 @@ describe("ERC1155Mech contract", () => { }) it("reverts if tokenIds and minBalances are not of same length", async () => { - const { testToken, ERC1155Mech } = await loadFixture(deployMech1) + const { testToken, ERC1155ThresholdMech } = await loadFixture(deployMech1) await expect( - ERC1155Mech.deploy(testToken.address, [1, 2, 3], [1, 2], 0) + ERC1155ThresholdMech.deploy(testToken.address, [1, 2, 3], [1, 2], 0) ).to.be.revertedWith("Length mismatch") }) @@ -97,8 +99,10 @@ describe("ERC1155Mech contract", () => { }) it("returns false if the minimum total balance threshold is not met", async () => { - const { testToken, ERC1155Mech, alice } = await loadFixture(deployMech1) - const mech = await ERC1155Mech.deploy( + const { testToken, ERC1155ThresholdMech, alice } = await loadFixture( + deployMech1 + ) + const mech = await ERC1155ThresholdMech.deploy( testToken.address, [1, 2], [1, 1], diff --git a/test/ERC721Mech.ts b/test/ERC721TokenboundMech.ts similarity index 90% rename from test/ERC721Mech.ts rename to test/ERC721TokenboundMech.ts index d283c23..0283acd 100644 --- a/test/ERC721Mech.ts +++ b/test/ERC721TokenboundMech.ts @@ -7,22 +7,24 @@ import { ethers } from "hardhat" // Using this simplifies your tests and makes them run faster, by taking // advantage or Hardhat Network's snapshot functionality. -describe("ERC721Mech contract", () => { +describe("ERC721TokenboundMech contract", () => { // We define a fixture to reuse the same setup in every test. We use // loadFixture to run this setup once, snapshot that state, and reset Hardhat // Network to that snapshot in every test. async function deployMech1() { const TestToken = await ethers.getContractFactory("ERC721Token") - const ERC721Mech = await ethers.getContractFactory("ERC721Mech") + const ERC721TokenboundMech = await ethers.getContractFactory( + "ERC721TokenboundMech" + ) const [, alice, bob] = await ethers.getSigners() const testToken = await TestToken.deploy() - const mech1 = await ERC721Mech.deploy(testToken.address, 1) + const mech1 = await ERC721TokenboundMech.deploy(testToken.address, 1) await mech1.deployed() // Fixtures can return anything you consider useful for your tests - return { ERC721Mech, testToken, mech1, alice, bob } + return { ERC721TokenboundMech, testToken, mech1, alice, bob } } describe("deployment", () => { diff --git a/test/ImmutableStorage.ts b/test/ImmutableStorage.ts deleted file mode 100644 index 42bde27..0000000 --- a/test/ImmutableStorage.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { defaultAbiCoder } from "@ethersproject/abi" -import { loadFixture } from "@nomicfoundation/hardhat-network-helpers" -import { expect } from "chai" -import { ethers } from "hardhat" - -describe("ImmutableStorage base contract", () => { - // We define a fixture to reuse the same setup in every test. We use - // loadFixture to run this setup once, snapshot that state, and reset Hardhat - // Network to that snapshot in every test. - async function deployTestContract() { - const ImmutableStorageTest = await ethers.getContractFactory( - "ImmutableStorageTest" - ) - const contract = await ImmutableStorageTest.deploy() - - return { ImmutableStorageTest, contract } - } - - describe("writeImmutable()", () => { - it("can be called once and never again", async () => { - const { contract } = await loadFixture(deployTestContract) - - await contract.write(defaultAbiCoder.encode(["uint256"], [1])) - - await expect( - contract.write(defaultAbiCoder.encode(["uint256"], [2])) - ).to.be.revertedWith("Write failed") - }) - }) - - describe("readImmutable()", () => { - it("returns empty bytes if nothing has been stored yet", async () => { - const { contract } = await loadFixture(deployTestContract) - - expect(await contract.read()).to.equal("0x") - }) - - it("returns the stored value", async () => { - const { contract } = await loadFixture(deployTestContract) - - const bytes = defaultAbiCoder.encode(["uint256"], [1]) - await contract.write(bytes) - - expect(await contract.read()).to.equal(bytes) - }) - }) -}) diff --git a/yarn.lock b/yarn.lock index bfc60f3..6dac921 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14082,6 +14082,7 @@ __metadata: hardhat: ^2.12.5 hardhat-deploy: ^0.11.22 hardhat-gas-reporter: ^1.0.9 + openzeppelin-contracts: ^4.0.0 prettier: ^2.8.3 prettier-plugin-solidity: ^1.1.1 rimraf: ^4.1.2 @@ -15117,6 +15118,13 @@ __metadata: languageName: node linkType: hard +"openzeppelin-contracts@npm:^4.0.0": + version: 4.0.0 + resolution: "openzeppelin-contracts@npm:4.0.0" + checksum: 977df75157505a9687700714b0c3741a5d57b535ecab141e07fe00adb70f8922ff5ca7cd221ada4c284506899f8ad3d2b8cd1321cfff8460a1e0121170c7a456 + languageName: node + linkType: hard + "optionator@npm:^0.8.1": version: 0.8.3 resolution: "optionator@npm:0.8.3" From 203d1d234d45cf1f668147f59692ef037a8939e4 Mon Sep 17 00:00:00 2001 From: Jan-Felix Date: Wed, 7 Jun 2023 15:20:07 +0200 Subject: [PATCH 08/41] add mech factory --- README.md | 17 +-- contracts/MechFactory.sol | 60 +++++++++ contracts/libraries/MinimalProxyStore.sol | 151 ++++++++++++++++++++++ 3 files changed, 220 insertions(+), 8 deletions(-) create mode 100644 contracts/MechFactory.sol create mode 100644 contracts/libraries/MinimalProxyStore.sol diff --git a/README.md b/README.md index ba3f2ca..6c469f5 100644 --- a/README.md +++ b/README.md @@ -8,11 +8,13 @@ Smart account with programmable ownership #### Transferrable ownership -- [ERC721Mech.sol](contracts/ERC721Mech.sol): allow the holder of a designated ERC-721 NFT to sign transactions on behalf of the Mech +- [ERC721TokenboundMech.sol](contracts/ERC721TokenboundMech.sol): allow the holder of a designated ERC-721 NFT to sign transactions on behalf of the Mech +- [ERC1155TokenboundMech.sol](contracts/ERC721TokenboundMech.sol): allow the holder of a designated ERC-1155 NFT to sign transactions on behalf of the Mech #### Threshold ownership -- [ERC1155Mech.sol](contracts/ERC1155Mech.sol): allow holders of a minimum balance of ERC-1155 tokens to sign transactions on behalf of the Mech +- [ERC20ThresholdMech.sol](contracts/ERC20ThresholdMech.sol): allow holders of a minimum balance of an ERC-20 token to sign transactions on behalf of the Mech +- [ERC1155ThresholdMech.sol](contracts/ERC1155ThresholdMech.sol): allow holders of a minimum balance of ERC-1155 tokens to sign transactions on behalf of the Mech #### Programmable ownership @@ -69,7 +71,7 @@ Integration tests are run on a mainnet fork and cover the interaction of mech co ### EIP-4337 account -Mechs implement the EIP-4337 [Account](contracts/base/Account.sol) interface meaning they allow bundlers to execute account-abstracted user operations from the Mech's address. +Mech implements the EIP-4337 [Account](contracts/base/Account.sol) interface meaning they allow bundlers to execute account-abstracted user operations from the Mech's address. For this purpose the EIP-4337 entry point contract first calls the Mech's `validateUserOp()` function for checking if a user operation has a valid signature by the mech operator. The entry point then calls the `exec` function, or any other function using the `onlyOperator` modifier, to trigger execution. @@ -95,18 +97,17 @@ An EIP-1271 signature will be considered valid if it meets the following conditi ### Deterministic deployment -The idea for the ERC721 and ERC1155 mechs is that the mech instance for the designated tokens is deployed to a deterministic address. +The idea for the ERC721 and ERC1155 versions of mech is that the mech instance for the designated tokens is deployed to a deterministic address. This enables counterfactually funding the mech account (own token to unlock treasure) or granting access for it (use token as key card). The deterministic deployment is implemented via Zodiac's [ModuleProxyFactory](https://github.com/gnosis/zodiac/blob/master/contracts/factory/ModuleProxyFactory.sol), through which each mech instance is deployed as an ERC-1167 minimal proxy. -### Immutable storage +### EIP-1167 minimal proxies with context The holder of the token gains full control over the mech account and can write to its storage without any restrictions via delegate calls. Since tokens are transferrable this is problematic, as a past owner could mess with storage to change the mech's behavior in ways that future owners wouldn't expect. -That's why the ERC721 and ERC1155 versions of the mech avoid using storage but hard-code their configuration in bytecode. +That's why the ERC721 and ERC1155 versions of mech avoid using storage but instead solely rely on the immutable data in their own bytecode. -To achieve this, Mech sub contracts can extend [ImmutableStorage](contracts/base/ImmutableStorage.sol) which allows writing data to the bytecode at a deterministic address once. -Note that using Solidity's `immutable` keyword is not an option for proxy contracts, since immutable fields can only be written to from the constructor which won't be invoked for proxy instances. +To achieve this, mechs are deployed through a version of a EIP-1167 proxy factory that allows appending arbitrary bytes to the minimal proxy bytecode. ### Migrate a Safe to a ZodiacMech diff --git a/contracts/MechFactory.sol b/contracts/MechFactory.sol new file mode 100644 index 0000000..8ebc00a --- /dev/null +++ b/contracts/MechFactory.sol @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: LGPL-3.0-only +pragma solidity >=0.8.0; + +import "./libraries/MinimalProxyStore.sol"; + +contract MechFactory { + event MechCreated( + address indexed proxy, + address indexed masterCopy, + bytes context + ); + + /// `target` can not be zero. + error ZeroAddress(address target); + + /// `target` has no code deployed. + error TargetHasNoCode(address target); + + /// `target` is already taken. + error TakenAddress(address target); + + /// @notice Initialization failed. + error FailedInitialization(); + + function createProxy( + address target, + bytes memory context, + uint256 saltNonce + ) internal returns (address result) { + if (address(target) == address(0)) revert ZeroAddress(target); + if (address(target).code.length == 0) revert TargetHasNoCode(target); + + bytes32 salt = keccak256( + abi.encodePacked(keccak256(context), saltNonce) + ); + address proxy = MinimalProxyStore.cloneDeterministic( + target, + context, + salt + ); + + emit MechCreated(proxy, target, context); + + return proxy; + } + + function deployMech( + address masterCopy, + bytes memory context, + bytes memory initialCall, + uint256 saltNonce + ) public returns (address proxy) { + proxy = createProxy(masterCopy, context, saltNonce); + + if (initialCall.length > 0) { + (bool success, ) = proxy.call(initialCall); + if (!success) revert FailedInitialization(); + } + } +} diff --git a/contracts/libraries/MinimalProxyStore.sol b/contracts/libraries/MinimalProxyStore.sol new file mode 100644 index 0000000..02e038f --- /dev/null +++ b/contracts/libraries/MinimalProxyStore.sol @@ -0,0 +1,151 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +import "@openzeppelin/contracts/utils/Create2.sol"; + +/** + * @title A library for deploying EIP-1167 minimal proxy contracts with embedded constant data + * @author Jayden Windle (jaydenwindle) + */ +library MinimalProxyStore { + error CreateError(); + + // error ContextOverflow(); + + /** + * @dev Returns bytecode for a minmal proxy with additional context data appended to it + * + * @param implementation the implementation this proxy will delegate to + * @param context the data to be appended to the proxy + * @return the generated bytecode + */ + function getBytecode( + address implementation, + bytes memory context + ) internal pure returns (bytes memory) { + return + abi.encodePacked( + hex"3d61", // RETURNDATASIZE, PUSH2 + uint16(0x2d + context.length + 1), // size of minimal proxy (45 bytes) + size of context + stop byte + hex"8060", // DUP1, PUSH1 + uint8(0x0a + 1), // default offset (0x0a) + 1 byte because we increased size from uint8 to uint16 + hex"3d3981f3363d3d373d3d3d363d73", // standard EIP1167 implementation + implementation, // implementation address + hex"5af43d82803e903d91602b57fd5bf3", // standard EIP1167 implementation + hex"00", // stop byte (prevents context from executing as code) + context // appended context data + ); + } + + /** + * @dev Fetches the context data stored in a deployed proxy + * + * @param instance the proxy to query context data for + * @return context the queried context data + */ + function getContext( + address instance + ) internal view returns (bytes memory context) { + uint256 instanceCodeLength = instance.code.length; + uint256 start = 46; + uint256 size = instanceCodeLength - start; + + assembly { + // allocate output byte array - this could also be done without assembly + // by using o_code = new bytes(size) + context := mload(0x40) + // new "memory end" including padding + mstore( + 0x40, + add(context, and(add(add(size, 0x20), 0x1f), not(0x1f))) + ) + // store length in memory + mstore(context, size) + // actually retrieve the code, this needs assembly + extcodecopy(instance, add(context, 0x20), start, size) + } + } + + /** + * @dev Deploys and returns the address of a clone with stored context data that mimics the behaviour of `implementation`. + * + * This function uses the create opcode, which should never revert. + * + * @param implementation the implementation to delegate to + * @param context context data to be stored in the proxy + * @return instance the address of the deployed proxy + */ + function clone( + address implementation, + bytes memory context + ) internal returns (address instance) { + // Generate bytecode for proxy + bytes memory code = getBytecode(implementation, context); + + // Deploy contract using create + assembly { + instance := create(0, add(code, 32), mload(code)) + } + + // If address is zero, deployment failed + if (instance == address(0)) revert CreateError(); + } + + /** + * @dev Deploys and returns the address of a clone with stored context data that mimics the behaviour of `implementation`. + * + * This function uses the create2 opcode and a `salt` to deterministically deploy + * the clone. Using the same `implementation` and `salt` multiple time will revert, since + * the clones cannot be deployed twice at the same address. + * + * @param implementation the implementation to delegate to + * @param context context data to be stored in the proxy + * @return instance the address of the deployed proxy + */ + function cloneDeterministic( + address implementation, + bytes memory context, + bytes32 salt + ) internal returns (address instance) { + bytes memory code = getBytecode(implementation, context); + + // Deploy contract using create2 + assembly { + instance := create2(0, add(code, 32), mload(code), salt) + } + + // If address is zero, deployment failed + if (instance == address(0)) revert CreateError(); + } + + /** + * @dev Computes the address of a clone deployed using {MinimalProxyStore-cloneDeterministic}. + */ + function predictDeterministicAddress( + address implementation, + bytes memory context, + bytes32 salt, + address deployer + ) internal pure returns (address predicted) { + bytes memory code = getBytecode(implementation, context); + + return Create2.computeAddress(salt, keccak256(code), deployer); + } + + /** + * @dev Computes the address of a clone deployed using {MinimalProxyStore-cloneDeterministic}. + */ + function predictDeterministicAddress( + address implementation, + bytes memory context, + bytes32 salt + ) internal view returns (address predicted) { + return + predictDeterministicAddress( + implementation, + context, + salt, + address(this) + ); + } +} From 1f67b0c192fb96c25b6184ea2acb3e83f3345575 Mon Sep 17 00:00:00 2001 From: Jan-Felix Date: Mon, 12 Jun 2023 10:57:00 +0200 Subject: [PATCH 09/41] refactor contracts --- README.md | 13 ++-- contracts/ERC1155ThresholdMech.sol | 94 +++++++---------------- contracts/ERC1155TokenboundMech.sol | 85 ++------------------ contracts/ERC721TokenboundMech.sol | 47 ++---------- contracts/MechFactory.sol | 1 + contracts/ZodiacMech.sol | 2 +- contracts/base/Mech.sol | 2 - contracts/base/Receiver.sol | 2 +- contracts/base/TokenboundMech.sol | 27 ++++--- contracts/interfaces/IFactoryFriendly.sol | 7 -- contracts/interfaces/IMech.sol | 4 +- contracts/test/ImmutableStorageTest.sol | 14 ---- 12 files changed, 69 insertions(+), 229 deletions(-) delete mode 100644 contracts/interfaces/IFactoryFriendly.sol delete mode 100644 contracts/test/ImmutableStorageTest.sol diff --git a/README.md b/README.md index 6c469f5..f8fdc4c 100644 --- a/README.md +++ b/README.md @@ -6,15 +6,15 @@ Smart account with programmable ownership -#### Transferrable ownership +#### Token-bound ownership -- [ERC721TokenboundMech.sol](contracts/ERC721TokenboundMech.sol): allow the holder of a designated ERC-721 NFT to sign transactions on behalf of the Mech -- [ERC1155TokenboundMech.sol](contracts/ERC721TokenboundMech.sol): allow the holder of a designated ERC-1155 NFT to sign transactions on behalf of the Mech +- [ERC721TokenboundMech.sol](contracts/ERC721TokenboundMech.sol): allow the holder of a designated ERC-721 NFT to operate the Mech +- [ERC1155TokenboundMech.sol](contracts/ERC721TokenboundMech.sol): allow the holder of a designated ERC-1155 NFT to operate the Mech #### Threshold ownership -- [ERC20ThresholdMech.sol](contracts/ERC20ThresholdMech.sol): allow holders of a minimum balance of an ERC-20 token to sign transactions on behalf of the Mech -- [ERC1155ThresholdMech.sol](contracts/ERC1155ThresholdMech.sol): allow holders of a minimum balance of ERC-1155 tokens to sign transactions on behalf of the Mech +- [ERC20ThresholdMech.sol](contracts/ERC20ThresholdMech.sol): allow holders of a minimum balance of an ERC-20 token to operate the Mech +- [ERC1155ThresholdMech.sol](contracts/ERC1155ThresholdMech.sol): allow holders of a minimum balances of designated ERC-1155 tokens to operate the Mech #### Programmable ownership @@ -97,8 +97,9 @@ An EIP-1271 signature will be considered valid if it meets the following conditi ### Deterministic deployment -The idea for the ERC721 and ERC1155 versions of mech is that the mech instance for the designated tokens is deployed to a deterministic address. +The idea for the token-bound versions of mech is that the mech instance for a designated token is deployed to a deterministic address. This enables counterfactually funding the mech account (own token to unlock treasure) or granting access for it (use token as key card). + The deterministic deployment is implemented via Zodiac's [ModuleProxyFactory](https://github.com/gnosis/zodiac/blob/master/contracts/factory/ModuleProxyFactory.sol), through which each mech instance is deployed as an ERC-1167 minimal proxy. ### EIP-1167 minimal proxies with context diff --git a/contracts/ERC1155ThresholdMech.sol b/contracts/ERC1155ThresholdMech.sol index 0d607b7..daff205 100644 --- a/contracts/ERC1155ThresholdMech.sol +++ b/contracts/ERC1155ThresholdMech.sol @@ -3,88 +3,46 @@ pragma solidity ^0.8.12; import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol"; import "./base/ThresholdMech.sol"; +import "./libraries/MinimalProxyStore.sol"; /** - * @dev A Mech that is operated by the holder of a defined set of minimum ERC1155 token balances + * @dev A Mech that is operated by any holder of a defined set of minimum ERC1155 token balances */ contract ERC1155ThresholdMech is ThresholdMech { - /// @param _token Address of the token contract - /// @param _tokenIds The token IDs - /// @param _minBalances The minimum balances required for each token ID - constructor( - address _token, - uint256[] memory _tokenIds, - uint256[] memory _minBalances, - uint256 _minTotalBalance - ) { - bytes memory initParams = abi.encode( - _token, - _tokenIds, - _minBalances, - _minTotalBalance - ); - setUp(initParams); - } - - function setUp(bytes memory initParams) public override { - require(readImmutable().length == 0, "Already initialized"); - (, uint256[] memory _tokenIds, uint256[] memory _minBalances, ) = abi - .decode(initParams, (address, uint256[], uint256[], uint256)); - require(_tokenIds.length > 0, "No token IDs provided"); - require(_tokenIds.length == _minBalances.length, "Length mismatch"); - - writeImmutable(initParams); - } - - function token() public view returns (IERC1155) { - address _token = abi.decode(readImmutable(), (address)); - return IERC1155(_token); - } - - function tokenIds(uint256 index) public view returns (uint256) { - (, uint256[] memory _tokenIds) = abi.decode( - readImmutable(), - (address, uint256[]) - ); - return _tokenIds[index]; - } - - function minBalances(uint256 index) public view returns (uint256) { - (, , uint256[] memory _minBalances) = abi.decode( - readImmutable(), - (address, uint256[], uint256[]) - ); - return _minBalances[index]; - } - - function minTotalBalance() public view returns (uint256) { - (, , , uint256 _minTotalBalance) = abi.decode( - readImmutable(), - (address, uint256[], uint256[], uint256) - ); - return _minTotalBalance; + function threshold() + public + view + returns ( + address token, + uint256[] memory tokenIds, + uint256[] memory minBalances, + uint256 minTotalBalance + ) + { + return + abi.decode( + MinimalProxyStore.getContext(address(this)), + (address, uint256[], uint256[], uint256) + ); } function isOperator(address signer) public view override returns (bool) { ( - address _token, - uint256[] memory _tokenIds, - uint256[] memory _minBalances, - uint256 _minTotalBalance - ) = abi.decode( - readImmutable(), - (address, uint256[], uint256[], uint256) - ); + address token, + uint256[] memory tokenIds, + uint256[] memory minBalances, + uint256 minTotalBalance + ) = this.threshold(); uint256 balanceSum = 0; - for (uint256 i = 0; i < _tokenIds.length; i++) { - uint256 balance = IERC1155(_token).balanceOf(signer, _tokenIds[i]); - if (balance < _minBalances[i]) { + for (uint256 i = 0; i < tokenIds.length; i++) { + uint256 balance = IERC1155(token).balanceOf(signer, tokenIds[i]); + if (balance < minBalances[i]) { return false; } balanceSum += balance; } - return balanceSum >= _minTotalBalance; + return balanceSum >= minTotalBalance; } } diff --git a/contracts/ERC1155TokenboundMech.sol b/contracts/ERC1155TokenboundMech.sol index d8d8a0c..d95fdb4 100644 --- a/contracts/ERC1155TokenboundMech.sol +++ b/contracts/ERC1155TokenboundMech.sol @@ -5,86 +5,17 @@ import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol"; import "./base/TokenboundMech.sol"; /** - * @dev A Mech that is operated by the holder of a defined set of minimum ERC1155 token balances + * @dev A Mech that is operated by the holder of a designated ERC1155 token */ contract ERC1155TokenboundMech is TokenboundMech { - /// @param _token Address of the token contract - /// @param _tokenIds The token IDs - /// @param _minBalances The minimum balances required for each token ID - constructor( - address _token, - uint256[] memory _tokenIds, - uint256[] memory _minBalances, - uint256 _minTotalBalance - ) { - bytes memory initParams = abi.encode( - _token, - _tokenIds, - _minBalances, - _minTotalBalance - ); - setUp(initParams); - } - - function setUp(bytes memory initParams) public override { - require(readImmutable().length == 0, "Already initialized"); - (, uint256[] memory _tokenIds, uint256[] memory _minBalances, ) = abi - .decode(initParams, (address, uint256[], uint256[], uint256)); - require(_tokenIds.length > 0, "No token IDs provided"); - require(_tokenIds.length == _minBalances.length, "Length mismatch"); - - writeImmutable(initParams); - } - - function token() public view returns (IERC1155) { - address _token = abi.decode(readImmutable(), (address)); - return IERC1155(_token); - } - - function tokenIds(uint256 index) public view returns (uint256) { - (, uint256[] memory _tokenIds) = abi.decode( - readImmutable(), - (address, uint256[]) - ); - return _tokenIds[index]; - } - - function minBalances(uint256 index) public view returns (uint256) { - (, , uint256[] memory _minBalances) = abi.decode( - readImmutable(), - (address, uint256[], uint256[]) - ); - return _minBalances[index]; - } - - function minTotalBalance() public view returns (uint256) { - (, , , uint256 _minTotalBalance) = abi.decode( - readImmutable(), - (address, uint256[], uint256[], uint256) - ); - return _minTotalBalance; - } - function isOperator(address signer) public view override returns (bool) { - ( - address _token, - uint256[] memory _tokenIds, - uint256[] memory _minBalances, - uint256 _minTotalBalance - ) = abi.decode( - readImmutable(), - (address, uint256[], uint256[], uint256) - ); - - uint256 balanceSum = 0; - for (uint256 i = 0; i < _tokenIds.length; i++) { - uint256 balance = IERC1155(_token).balanceOf(signer, _tokenIds[i]); - if (balance < _minBalances[i]) { - return false; - } - balanceSum += balance; - } + (uint256 chainId, address tokenContract, uint256 tokenId) = this + .token(); + if (chainId != block.chainid) return false; + return IERC1155(tokenContract).balanceOf(signer, tokenId) > 0; + } - return balanceSum >= _minTotalBalance; + function owner() public view virtual override returns (address) { + return address(0); } } diff --git a/contracts/ERC721TokenboundMech.sol b/contracts/ERC721TokenboundMech.sol index 71edb86..3f4c6e0 100644 --- a/contracts/ERC721TokenboundMech.sol +++ b/contracts/ERC721TokenboundMech.sol @@ -2,51 +2,18 @@ pragma solidity ^0.8.12; import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; -import "@erc6551/reference/src/interfaces/IERC6551Account.sol"; -import "@erc6551/reference/src/lib/ERC6551AccountLib.sol"; -import "./base/Mech.sol"; +import "./base/TokenboundMech.sol"; /** - * @dev A Mech that is operated by the holder of an ERC721 non-fungible token, implements the ERC6551 standard + * @dev A Mech that is operated by the holder of an ERC721 non-fungible token */ -contract ERC721Mech is Mech, IERC6551Account { - /// @param _token Address of the token contract - /// @param _tokenId The token ID - constructor(address _token, uint256 _tokenId) { - bytes memory initParams = abi.encode(_token, _tokenId); - setUp(initParams); - } - - function setUp(bytes memory initParams) public override { - require(readImmutable().length == 0, "Already initialized"); - writeImmutable(initParams); - } - - function isOperator(address signer) public view override returns (bool) { - return owner() == signer && signer != address(0); - } - - function executeCall( - address to, - uint256 value, - bytes calldata data - ) external payable returns (bytes memory) { - return exec(to, value, data, Enum.Operation.Call, 0); - }; - - function token() - external - view - returns (uint256 chainId, address tokenContract, uint256 tokenId) - { - return ERC6551AccountLib.token(); - } - - function owner() external view returns (address) { - (uint256 chainId, address tokenContract, uint256 tokenId) = this.token(); +contract ERC721TokenboundMech is TokenboundMech { + function owner() public view override returns (address) { + (uint256 chainId, address tokenContract, uint256 tokenId) = this + .token(); if (chainId != block.chainid) return address(0); return IERC721(tokenContract).ownerOf(tokenId); - }; + } } diff --git a/contracts/MechFactory.sol b/contracts/MechFactory.sol index 8ebc00a..90932b3 100644 --- a/contracts/MechFactory.sol +++ b/contracts/MechFactory.sol @@ -33,6 +33,7 @@ contract MechFactory { bytes32 salt = keccak256( abi.encodePacked(keccak256(context), saltNonce) ); + address proxy = MinimalProxyStore.cloneDeterministic( target, context, diff --git a/contracts/ZodiacMech.sol b/contracts/ZodiacMech.sol index 2165e94..c2746a0 100644 --- a/contracts/ZodiacMech.sol +++ b/contracts/ZodiacMech.sol @@ -31,7 +31,7 @@ contract ZodiacMech is SafeStorage, Mech, IAvatar { } /// @dev This function can be called whenever no modules are enabled, meaning anyone could come and call setUp() then. We keep this behavior to not brick the mech in that case. - function setUp(bytes memory initParams) public override { + function setUp(bytes memory initParams) public { require( modules[address(SENTINEL_MODULES)] == address(0), "Already initialized" diff --git a/contracts/base/Mech.sol b/contracts/base/Mech.sol index 1759e3b..e6c2726 100644 --- a/contracts/base/Mech.sol +++ b/contracts/base/Mech.sol @@ -15,8 +15,6 @@ abstract contract Mech is IMech, Account, Receiver { // bytes4(keccak256("isValidSignature(bytes32,bytes)") bytes4 internal constant EIP1271_MAGICVALUE = 0x1626ba7e; - receive() external payable override {} - /** * @dev Modifier to make a function callable only by the mech operator or the ERC4337 entry point contract */ diff --git a/contracts/base/Receiver.sol b/contracts/base/Receiver.sol index fdd349a..6ef7cd8 100644 --- a/contracts/base/Receiver.sol +++ b/contracts/base/Receiver.sol @@ -13,7 +13,7 @@ contract Receiver is ERC777TokensRecipient, ERC721TokenReceiver { - receive() external payable {} + receive() external payable virtual {} function onERC1155Received( address, diff --git a/contracts/base/TokenboundMech.sol b/contracts/base/TokenboundMech.sol index 43242ee..3d3f914 100644 --- a/contracts/base/TokenboundMech.sol +++ b/contracts/base/TokenboundMech.sol @@ -1,17 +1,18 @@ //SPDX-License-Identifier: LGPL-3.0 pragma solidity ^0.8.12; -import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import "@erc6551/reference/src/interfaces/IERC6551Account.sol"; -import "@erc6551/reference/src/lib/ERC6551AccountLib.sol"; import "./Mech.sol"; +import "../libraries/MinimalProxyStore.sol"; /** - * @dev A Mech that is operated by the holder of a designated token, implements the ERC6551 standard + * @dev A Mech that is operated by the holder of a designated token, implements the ERC6551 standard and is deployed through the ERC6551 registry */ abstract contract TokenboundMech is Mech, IERC6551Account { - function isOperator(address signer) public view override returns (bool) { + function isOperator( + address signer + ) public view virtual override returns (bool) { return owner() == signer && signer != address(0); } @@ -21,21 +22,27 @@ abstract contract TokenboundMech is Mech, IERC6551Account { bytes calldata data ) external payable returns (bytes memory) { return exec(to, value, data, Enum.Operation.Call, 0); - }; + } function token() external view returns (uint256 chainId, address tokenContract, uint256 tokenId) { - return ERC6551AccountLib.token(); + return + abi.decode( + MinimalProxyStore.getContext(address(this)), + (uint256, address, uint256) + ); } - function owner() public view returns (address); + function owner() public view virtual returns (address); // required by ERC-6551, even though their account (https://github.com/tokenbound/contracts/blob/main/src/Account.sol) does not use it but a time-locking mechanism // TODO adopt whatever ERC-6551 will settle on - function nonce() external view returns (uint256) { - return 0 - }; + function nonce() external pure returns (uint256) { + return 0; + } + + receive() external payable override(Receiver, IERC6551Account) {} } diff --git a/contracts/interfaces/IFactoryFriendly.sol b/contracts/interfaces/IFactoryFriendly.sol deleted file mode 100644 index ef6ced1..0000000 --- a/contracts/interfaces/IFactoryFriendly.sol +++ /dev/null @@ -1,7 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-only -pragma solidity ^0.8.12; - -/// @dev Interface for contracts that can be used as master copies for minimal proxies deployed through Zodiac's ModuleProxyFactory -interface IFactoryFriendly { - function setUp(bytes memory initializeParams) external; -} diff --git a/contracts/interfaces/IMech.sol b/contracts/interfaces/IMech.sol index 4570f6d..b012a3b 100644 --- a/contracts/interfaces/IMech.sol +++ b/contracts/interfaces/IMech.sol @@ -5,9 +5,7 @@ import "@openzeppelin/contracts/interfaces/IERC1271.sol"; import "@gnosis.pm/safe-contracts/contracts/common/Enum.sol"; import "@account-abstraction/contracts/interfaces/IAccount.sol"; -import "./IFactoryFriendly.sol"; - -interface IMech is IAccount, IERC1271, IFactoryFriendly { +interface IMech is IAccount, IERC1271 { /// @dev Executes either a delegatecall or a call with provided parameters /// @param to Destination address. /// @param value Ether value. diff --git a/contracts/test/ImmutableStorageTest.sol b/contracts/test/ImmutableStorageTest.sol deleted file mode 100644 index 02fd38f..0000000 --- a/contracts/test/ImmutableStorageTest.sol +++ /dev/null @@ -1,14 +0,0 @@ -//SPDX-License-Identifier: LGPL-3.0 -pragma solidity ^0.8.12; - -import "../base/ImmutableStorage.sol"; - -contract ImmutableStorageTest is ImmutableStorage { - function read() public view returns (bytes memory data) { - return readImmutable(); - } - - function write(bytes memory data) public { - writeImmutable(data); - } -} From de98decd558292d9be38422dee26bfd903f348ad Mon Sep 17 00:00:00 2001 From: Jan-Felix Date: Mon, 12 Jun 2023 10:57:08 +0200 Subject: [PATCH 10/41] add erc20 threshold mech --- contracts/ERC20ThresholdMech.sol | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 contracts/ERC20ThresholdMech.sol diff --git a/contracts/ERC20ThresholdMech.sol b/contracts/ERC20ThresholdMech.sol new file mode 100644 index 0000000..4e91150 --- /dev/null +++ b/contracts/ERC20ThresholdMech.sol @@ -0,0 +1,29 @@ +//SPDX-License-Identifier: LGPL-3.0 +pragma solidity ^0.8.12; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "./base/ThresholdMech.sol"; +import "./libraries/MinimalProxyStore.sol"; + +/** + * @dev A Mech that is operated by any holder of a minimum ERC20 token balance + */ +contract ERC20ThresholdMech is ThresholdMech { + function threshold() + public + view + returns (address token, uint256 minBalance) + { + return + abi.decode( + MinimalProxyStore.getContext(address(this)), + (address, uint256) + ); + } + + function isOperator(address signer) public view override returns (bool) { + (address token, uint256 minBalance) = this.threshold(); + + return IERC20(token).balanceOf(signer) >= minBalance; + } +} From c74914988279109bbc38cfe4d70a903ff976879b Mon Sep 17 00:00:00 2001 From: Jan-Felix Date: Mon, 12 Jun 2023 11:03:15 +0200 Subject: [PATCH 11/41] cleanup --- README.md | 6 ++++-- contracts/libraries/MinimalProxyStore.sol | 2 -- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index f8fdc4c..c4eb106 100644 --- a/README.md +++ b/README.md @@ -69,12 +69,14 @@ Integration tests are run on a mainnet fork and cover the interaction of mech co ## How it works -### EIP-4337 account +### EIP-4337 account abstraction Mech implements the EIP-4337 [Account](contracts/base/Account.sol) interface meaning they allow bundlers to execute account-abstracted user operations from the Mech's address. For this purpose the EIP-4337 entry point contract first calls the Mech's `validateUserOp()` function for checking if a user operation has a valid signature by the mech operator. The entry point then calls the `exec` function, or any other function using the `onlyOperator` modifier, to trigger execution. +### EIP-6551 token-bound account + ### EIP-1271 signatures [Mech](contracts/base/Mech.sol) implements the EIP-1271 interface. @@ -97,7 +99,7 @@ An EIP-1271 signature will be considered valid if it meets the following conditi ### Deterministic deployment -The idea for the token-bound versions of mech is that the mech instance for a designated token is deployed to a deterministic address. +The idea for the token-bound versions of mech is that the mech instance for a designated token is deployed to an address that can be deterministically derived from the token contract address and token ID. This enables counterfactually funding the mech account (own token to unlock treasure) or granting access for it (use token as key card). The deterministic deployment is implemented via Zodiac's [ModuleProxyFactory](https://github.com/gnosis/zodiac/blob/master/contracts/factory/ModuleProxyFactory.sol), through which each mech instance is deployed as an ERC-1167 minimal proxy. diff --git a/contracts/libraries/MinimalProxyStore.sol b/contracts/libraries/MinimalProxyStore.sol index 02e038f..7a59bcc 100644 --- a/contracts/libraries/MinimalProxyStore.sol +++ b/contracts/libraries/MinimalProxyStore.sol @@ -10,8 +10,6 @@ import "@openzeppelin/contracts/utils/Create2.sol"; library MinimalProxyStore { error CreateError(); - // error ContextOverflow(); - /** * @dev Returns bytecode for a minmal proxy with additional context data appended to it * From e26424392cf0a05e4cbdb9d2aac9d7d398982cdc Mon Sep 17 00:00:00 2001 From: Jan-Felix Date: Mon, 12 Jun 2023 11:53:58 +0200 Subject: [PATCH 12/41] update docs --- README.md | 24 ++++++++++++++++++++++-- contracts/interfaces/IMech.sol | 6 ++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c4eb106..d950118 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,22 @@ Smart account with programmable ownership - [ZodiacMech.sol](contracts/ZodiacMech.sol): allow enabled [zodiac](https://github.com/gnosis/zodiac) modules to sign transactions on behalf of the Mech - [Mech.sol](contracts/base/Mech.sol): implement custom ownership terms by extending this abstract contract +## Mech interface + +Mech implements the [EIP-4337](https://eips.ethereum.org/EIPS/eip-4337) account interface, [EIP-1271](https://eips.ethereum.org/EIPS/eip-1271), and the following functions: + +### `isOperator(address signer)` + +Returns true if `signer` is allowed to operate the Mech. +Sub classes implement this function for defining the specific operator criteria. + +### `exec(address to, uint256 value, bytes data, Enum.Operation operation, uint256 txGas)` + +Allows the operator to make the Mech execute a transaction. + +- `operation: 0` for a regular call +- `operation: 1` for a delegate call + ## Contribute The repo is structured as a monorepo with `mech-contracts` as the container package exporting the contract sources and artifacts. @@ -75,8 +91,6 @@ Mech implements the EIP-4337 [Account](contracts/base/Account.sol) interface mea For this purpose the EIP-4337 entry point contract first calls the Mech's `validateUserOp()` function for checking if a user operation has a valid signature by the mech operator. The entry point then calls the `exec` function, or any other function using the `onlyOperator` modifier, to trigger execution. -### EIP-6551 token-bound account - ### EIP-1271 signatures [Mech](contracts/base/Mech.sol) implements the EIP-1271 interface. @@ -104,6 +118,11 @@ This enables counterfactually funding the mech account (own token to unlock trea The deterministic deployment is implemented via Zodiac's [ModuleProxyFactory](https://github.com/gnosis/zodiac/blob/master/contracts/factory/ModuleProxyFactory.sol), through which each mech instance is deployed as an ERC-1167 minimal proxy. +### EIP-6551 token-bound account + +The token-bound versions of Mech adopts the [EIP-6551](https://eips.ethereum.org/EIPS/eip-6551) standard. +This means that these kinds of mechs are deployed through the official 6551 account registry, so they are deployed to the canonical address and detected by compatible tools. + ### EIP-1167 minimal proxies with context The holder of the token gains full control over the mech account and can write to its storage without any restrictions via delegate calls. @@ -111,6 +130,7 @@ Since tokens are transferrable this is problematic, as a past owner could mess w That's why the ERC721 and ERC1155 versions of mech avoid using storage but instead solely rely on the immutable data in their own bytecode. To achieve this, mechs are deployed through a version of a EIP-1167 proxy factory that allows appending arbitrary bytes to the minimal proxy bytecode. +The same mechanism is implemented by the 6551 account registry. ### Migrate a Safe to a ZodiacMech diff --git a/contracts/interfaces/IMech.sol b/contracts/interfaces/IMech.sol index b012a3b..2b043c8 100644 --- a/contracts/interfaces/IMech.sol +++ b/contracts/interfaces/IMech.sol @@ -6,6 +6,12 @@ import "@gnosis.pm/safe-contracts/contracts/common/Enum.sol"; import "@account-abstraction/contracts/interfaces/IAccount.sol"; interface IMech is IAccount, IERC1271 { + /** + * @dev Return if the passed address is authorized to sign on behalf of the mech, must be implemented by the child contract + * @param signer The address to check + */ + function isOperator(address signer) external view returns (bool); + /// @dev Executes either a delegatecall or a call with provided parameters /// @param to Destination address. /// @param value Ether value. From 06d0971ca66836084507325d324b03c6af18a374 Mon Sep 17 00:00:00 2001 From: Jan-Felix Date: Wed, 14 Jun 2023 10:15:50 +0100 Subject: [PATCH 13/41] adjust all deploy functions and migrate them to viem --- TODO.md | 5 + contracts/MechFactory.sol | 14 +- sdk/constants.ts | 23 ++- sdk/deploy/deployERC1155Mech.ts | 164 -------------------- sdk/deploy/deployERC1155ThresholdMech.ts | 156 +++++++++++++++++++ sdk/deploy/deployERC1155TokenboundMech.ts | 129 ++++++++++++++++ sdk/deploy/deployERC721Mech.ts | 139 ----------------- sdk/deploy/deployERC721TokenboundMech.ts | 129 ++++++++++++++++ sdk/deploy/deployZodiacMech.ts | 176 ++++++++++------------ sdk/deploy/factory.ts | 82 ++++++++++ sdk/package.json | 3 +- test/deterministicDeployment.ts | 3 +- yarn.lock | 126 +++++++++++++++- 13 files changed, 724 insertions(+), 425 deletions(-) delete mode 100644 sdk/deploy/deployERC1155Mech.ts create mode 100644 sdk/deploy/deployERC1155ThresholdMech.ts create mode 100644 sdk/deploy/deployERC1155TokenboundMech.ts delete mode 100644 sdk/deploy/deployERC721Mech.ts create mode 100644 sdk/deploy/deployERC721TokenboundMech.ts create mode 100644 sdk/deploy/factory.ts diff --git a/TODO.md b/TODO.md index 80ce2c1..59ead04 100644 --- a/TODO.md +++ b/TODO.md @@ -5,3 +5,8 @@ - check what the Safe indexer requires to pick up ZodiacMechs - more requirements listed here: https://www.notion.so/Simpler-safe-mastercopy-dd8cf22626794b4aade600e1aa16da0e - ZodiacMech should allow updating the ERC4337 entrypoint + +## SDK + +- get rid of zodiac dep +- migrate to viem diff --git a/contracts/MechFactory.sol b/contracts/MechFactory.sol index 90932b3..ad013db 100644 --- a/contracts/MechFactory.sol +++ b/contracts/MechFactory.sol @@ -6,7 +6,7 @@ import "./libraries/MinimalProxyStore.sol"; contract MechFactory { event MechCreated( address indexed proxy, - address indexed masterCopy, + address indexed mastercopy, bytes context ); @@ -25,15 +25,11 @@ contract MechFactory { function createProxy( address target, bytes memory context, - uint256 saltNonce + bytes32 salt ) internal returns (address result) { if (address(target) == address(0)) revert ZeroAddress(target); if (address(target).code.length == 0) revert TargetHasNoCode(target); - bytes32 salt = keccak256( - abi.encodePacked(keccak256(context), saltNonce) - ); - address proxy = MinimalProxyStore.cloneDeterministic( target, context, @@ -46,12 +42,12 @@ contract MechFactory { } function deployMech( - address masterCopy, + address mastercopy, bytes memory context, bytes memory initialCall, - uint256 saltNonce + bytes32 salt ) public returns (address proxy) { - proxy = createProxy(masterCopy, context, saltNonce); + proxy = createProxy(mastercopy, context, salt); if (initialCall.length > 0) { (bool success, ) = proxy.call(initialCall); diff --git a/sdk/constants.ts b/sdk/constants.ts index 1a7d443..18ef2e5 100644 --- a/sdk/constants.ts +++ b/sdk/constants.ts @@ -1,12 +1,21 @@ -export const MODULE_PROXY_FACTORY_ADDRESS = - "0x000000000000aDdB49795b0f9bA5BC298cDda236" +export const MECH_FACTORY_ADDRESS = + "0x000000000000000000000000000000000000eeee" as const // TODO get MechFactory deployed to a nice vanity address -export const DEFAULT_SALT = - "0x0000000000000000000000000000000000000000000000000000000000000000" +export const ERC6551_REGISTRY_ADDRESS = + "0x0000000000000000000000000000000000006551" as const // TODO export const ERC2470_SINGLETON_FACTORY_ADDRESS = - "0xce0042b868300000d44a59004da54a005ffdcf9f" + "0xce0042b868300000d44a59004da54a005ffdcf9f" as const + +export const ZERO_ADDRESS = + "0x0000000000000000000000000000000000000000" as const + +export const DEFAULT_SALT = + "0x0000000000000000000000000000000000000000000000000000000000000000" as const -export const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000" +export const SENTINEL_MODULES = + "0x0000000000000000000000000000000000000001" as const -export const SENTINEL_MODULES = "0x0000000000000000000000000000000000000001" +export const ERC6551_REGISTRY_ABI = [ + "createAccount(address implementation, uint256 chainId, address tokenContract, uint256 tokenId, uint256 salt, bytes initData) returns (address)", +] diff --git a/sdk/deploy/deployERC1155Mech.ts b/sdk/deploy/deployERC1155Mech.ts deleted file mode 100644 index 9a6e8fd..0000000 --- a/sdk/deploy/deployERC1155Mech.ts +++ /dev/null @@ -1,164 +0,0 @@ -import { defaultAbiCoder } from "@ethersproject/abi" -import { JsonRpcProvider, JsonRpcSigner } from "@ethersproject/providers" -import { - deployAndSetUpCustomModule, - deployMastercopyWithInitData, - SupportedNetworks, -} from "@gnosis.pm/zodiac" -import { BigNumberish } from "ethers" -import { - getCreate2Address, - keccak256, - solidityKeccak256, -} from "ethers/lib/utils" - -import { - ERC1155Mech__factory, - IFactoryFriendly__factory, -} from "../../typechain-types" -import { - DEFAULT_SALT, - ERC2470_SINGLETON_FACTORY_ADDRESS, - MODULE_PROXY_FACTORY_ADDRESS, - ZERO_ADDRESS, -} from "../constants" - -export const calculateERC1155MechAddress = ( - /** Address of the ERC1155 token contract */ - token: string, - /** IDs of the tokens */ - tokenIds: BigNumberish[], - /** minimum balances of the tokens */ - minBalances: BigNumberish[], - /** minimum total balance over all tokens */ - minTotalBalance: BigNumberish, - salt: string = DEFAULT_SALT -) => { - const initData = - IFactoryFriendly__factory.createInterface().encodeFunctionData("setUp", [ - defaultAbiCoder.encode( - ["address", "uint256[]", "uint256[]", "uint256"], - [token, tokenIds, minBalances, minTotalBalance] - ), - ]) - - // ERC-1167 minimal proxy bytecode - const byteCode = - "0x602d8060093d393df3363d3d373d3d3d363d73" + - calculateERC1155MechMastercopyAddress().toLowerCase().slice(2) + - "5af43d82803e903d91602b57fd5bf3" - - return getCreate2Address( - MODULE_PROXY_FACTORY_ADDRESS, - solidityKeccak256( - ["bytes32", "uint256"], - [solidityKeccak256(["bytes"], [initData]), salt] - ), - keccak256(byteCode) - ) -} - -export const ERC1155_MASTERCOPY_INIT_DATA = [ZERO_ADDRESS, [0], [0], 0] - -export const calculateERC1155MechMastercopyAddress = () => { - const initData = defaultAbiCoder.encode( - ["address", "uint256[]", "uint256[]", "uint256"], - ERC1155_MASTERCOPY_INIT_DATA - ) - return getCreate2Address( - ERC2470_SINGLETON_FACTORY_ADDRESS, - DEFAULT_SALT, - keccak256(ERC1155Mech__factory.bytecode + initData.slice(2)) - ) -} - -export const makeERC1155MechDeployTransaction = ( - /** Address of the ERC1155 token contract */ - token: string, - /** IDs of the tokens */ - tokenIds: BigNumberish[], - /** minimum balances of the tokens */ - minBalances: BigNumberish[], - /** minimum total balance over all tokens */ - minTotalBalance: BigNumberish, - chainId: number, - salt: string = DEFAULT_SALT -) => { - const { transaction } = deployAndSetUpCustomModule( - calculateERC1155MechMastercopyAddress(), - ERC1155Mech__factory.abi, - { - types: ["address", "uint256[]", "uint256[]", "uint256"], - values: [token, tokenIds, minBalances, minTotalBalance], - }, - new JsonRpcProvider(undefined, chainId), // this provider instance is never really be used in deployAndSetUpCustomModule() - chainId, - salt - ) - - return transaction -} - -export const deployERC1155Mech = async ( - /** Address of the ERC1155 token contract */ - token: string, - /** IDs of the tokens */ - tokenIds: BigNumberish[], - /** minimum balances of the tokens */ - minBalances: BigNumberish[], - /** minimum total balance over all tokens */ - minTotalBalance: BigNumberish, - signer: JsonRpcSigner, - salt: string = DEFAULT_SALT -) => { - // make sure the mech does not already exist - const deterministicAddress = calculateERC1155MechAddress( - token, - tokenIds, - minBalances, - minTotalBalance, - salt - ) - if ((await signer.provider.getCode(deterministicAddress)) !== "0x") { - throw new Error( - `A mech with the same token and token ID already exists at ${deterministicAddress}` - ) - } - - const { chainId } = signer.provider.network - // make sure the network is supported - if (!Object.values(SupportedNetworks).includes(chainId)) { - throw new Error(`Network #${chainId} is not supported yet.`) - } - - // make sure the mastercopy is deployed - const mastercopyAddress = calculateERC1155MechMastercopyAddress() - if ((await signer.provider.getCode(mastercopyAddress)) === "0x") { - throw new Error( - `ERC1155Mech mastercopy is not deployed on network #${chainId} yet. Please deploy it first.` - ) - } - - const transaction = makeERC1155MechDeployTransaction( - token, - tokenIds, - minBalances, - minTotalBalance, - signer.provider.network.chainId, - salt - ) - - return signer.sendTransaction(transaction) -} - -export const deployERC1155MechMastercopy = async (signer: JsonRpcSigner) => { - const initData = defaultAbiCoder.encode( - ["address", "uint256[]", "uint256[]", "uint256"], - ERC1155_MASTERCOPY_INIT_DATA - ) - return await deployMastercopyWithInitData( - signer, - ERC1155Mech__factory.bytecode + initData.slice(2), - DEFAULT_SALT - ) -} diff --git a/sdk/deploy/deployERC1155ThresholdMech.ts b/sdk/deploy/deployERC1155ThresholdMech.ts new file mode 100644 index 0000000..d4465e2 --- /dev/null +++ b/sdk/deploy/deployERC1155ThresholdMech.ts @@ -0,0 +1,156 @@ +import { + encodeAbiParameters, + encodeFunctionData, + getCreate2Address, + WalletClient, +} from "viem" + +import { + ERC1155ThresholdMech__factory, + MechFactory__factory, +} from "../../typechain-types" +import { + DEFAULT_SALT, + ERC2470_SINGLETON_FACTORY_ADDRESS, + MECH_FACTORY_ADDRESS, + ZERO_ADDRESS, +} from "../constants" + +import { deployMastercopy, mechProxyBytecode } from "./factory" + +export const calculateERC1155ThresholdMechAddress = ({ + token, + tokenIds, + minBalances, + minTotalBalance, + salt = DEFAULT_SALT, +}: { + /** Address of the ERC1155 token contract */ + token: `0x${string}` + /** IDs of the tokens */ + tokenIds: bigint[] + /** minimum balances of the tokens */ + minBalances: bigint[] + /** minimum total balance over all tokens */ + minTotalBalance: bigint + salt: `0x${string}` +}) => { + const context = encodeAbiParameters( + [ + { type: "address" }, + { type: "uint256[]" }, + { type: "uint256[]" }, + { type: "uint256" }, + ], + [token, tokenIds, minBalances, minTotalBalance] + ) + + return getCreate2Address({ + bytecode: mechProxyBytecode( + calculateERC1155ThresholdMechMastercopyAddress(), + context + ), + from: MECH_FACTORY_ADDRESS, + salt, + }) +} + +export const ERC1155_MASTERCOPY_INIT_DATA = [ZERO_ADDRESS, [0], [0], 0] + +export const calculateERC1155ThresholdMechMastercopyAddress = () => { + return getCreate2Address({ + bytecode: ERC1155ThresholdMech__factory.bytecode, + from: ERC2470_SINGLETON_FACTORY_ADDRESS, + salt: DEFAULT_SALT, + }) +} + +export const makeERC1155ThresholdMechDeployTransaction = ({ + token, + tokenIds, + minBalances, + minTotalBalance, + salt = DEFAULT_SALT, +}: { + /** Address of the ERC1155 token contract */ + token: `0x${string}` + /** IDs of the tokens */ + tokenIds: bigint[] + /** minimum balances of the tokens */ + minBalances: bigint[] + /** minimum total balance over all tokens */ + minTotalBalance: bigint + salt: `0x${string}` +}) => { + const context = encodeAbiParameters( + [ + { type: "address" }, + { type: "uint256[]" }, + { type: "uint256[]" }, + { type: "uint256" }, + ], + [token, tokenIds, minBalances, minTotalBalance] + ) + + return { + to: MECH_FACTORY_ADDRESS, + data: encodeFunctionData({ + abi: MechFactory__factory.abi, + functionName: "deployMech", + args: [ + calculateERC1155ThresholdMechMastercopyAddress(), + context, + "0x", + salt, + ], + }), + } +} + +export const deployERC1155ThresholdMech = async ( + walletClient: WalletClient, + { + token, + tokenIds, + minBalances, + minTotalBalance, + salt = DEFAULT_SALT, + }: { + /** Address of the ERC1155 token contract */ + token: `0x${string}` + /** IDs of the tokens */ + tokenIds: bigint[] + /** minimum balances of the tokens */ + minBalances: bigint[] + /** minimum total balance over all tokens */ + minTotalBalance: bigint + salt: `0x${string}` + } +) => { + const { chain, account } = walletClient + if (!chain) throw new Error("No chain defined in walletClient") + if (!account) throw new Error("No account defined in walletClient") + + const transaction = makeERC1155ThresholdMechDeployTransaction({ + token, + tokenIds, + minBalances, + minTotalBalance, + salt, + }) + + return walletClient.sendTransaction({ + ...transaction, + account, + chain, + }) +} + +export const deployERC1155ThresholdMechMastercopy = async ( + walletClient: WalletClient +) => { + return await deployMastercopy( + walletClient, + ERC1155ThresholdMech__factory.bytecode + ) +} diff --git a/sdk/deploy/deployERC1155TokenboundMech.ts b/sdk/deploy/deployERC1155TokenboundMech.ts new file mode 100644 index 0000000..797905f --- /dev/null +++ b/sdk/deploy/deployERC1155TokenboundMech.ts @@ -0,0 +1,129 @@ +import { + encodeAbiParameters, + encodeFunctionData, + getCreate2Address, + WalletClient, +} from "viem" + +import { ERC1155TokenboundMech__factory } from "../../typechain-types" +import { + DEFAULT_SALT, + ERC2470_SINGLETON_FACTORY_ADDRESS, + ERC6551_REGISTRY_ABI, + ERC6551_REGISTRY_ADDRESS, +} from "../constants" + +import { deployMastercopy, mechProxyBytecode } from "./factory" + +export const calculateERC1155TokenboundMechAddress = ({ + chainId, + token, + tokenId, + salt = DEFAULT_SALT, +}: { + /** Address of the ERC1155 token contract */ + chainId: number + /** Address of the ERC1155 token contract */ + token: `0x${string}` + /** ID of the ERC1155 token */ + tokenId: bigint + salt: `0x${string}` +}) => { + const context = encodeAbiParameters( + [{ type: "uint256" }, { type: "address" }, { type: "uint256" }], + [BigInt(chainId), token, tokenId] + ) + + return getCreate2Address({ + bytecode: mechProxyBytecode( + calculateERC1155TokenboundMechMastercopyAddress(), + context + ), + from: ERC6551_REGISTRY_ADDRESS, + salt, + }) +} + +export const calculateERC1155TokenboundMechMastercopyAddress = () => { + return getCreate2Address({ + bytecode: ERC1155TokenboundMech__factory.bytecode, + from: ERC2470_SINGLETON_FACTORY_ADDRESS, + salt: DEFAULT_SALT, + }) +} + +export const makeERC1155TokenboundMechDeployTransaction = ({ + chainId, + token, + tokenId, + salt = DEFAULT_SALT, +}: { + /** ID of the chain the token lives on */ + chainId: number + /** Address of the ERC1155 token contract */ + token: `0x${string}` + /** ID of the ERC1155 token */ + tokenId: bigint + salt: string +}) => { + return { + to: ERC6551_REGISTRY_ADDRESS, + data: encodeFunctionData({ + abi: ERC6551_REGISTRY_ABI, + functionName: "createAccount", + args: [ + calculateERC1155TokenboundMechMastercopyAddress(), + chainId, + token, + tokenId, + salt, + ], + }), + } +} + +export const deployERC1155TokenboundMech = async ( + walletClient: WalletClient, + { + chainId, + token, + tokenId, + salt = DEFAULT_SALT, + }: { + /** ID of the chain the token lives on, default to the current chain of walletClient */ + chainId?: number + /** Address of the ERC1155 token contract */ + token: `0x${string}` + /** ID of the ERC1155 token */ + tokenId: bigint + salt: `0x${string}` + } +) => { + const { chain, account } = walletClient + if (!chain) throw new Error("No chain defined in walletClient") + if (!account) throw new Error("No account defined in walletClient") + + const tokenChainId = chainId ?? chain.id + + const transaction = makeERC1155TokenboundMechDeployTransaction({ + chainId: tokenChainId, + token, + tokenId, + salt, + }) + + return walletClient.sendTransaction({ + ...transaction, + account, + chain, + }) +} + +export const deployERC1155TokenboundMechMastercopy = async ( + walletClient: WalletClient +) => { + return await deployMastercopy( + walletClient, + ERC1155TokenboundMech__factory.bytecode + ) +} diff --git a/sdk/deploy/deployERC721Mech.ts b/sdk/deploy/deployERC721Mech.ts deleted file mode 100644 index 4a4c173..0000000 --- a/sdk/deploy/deployERC721Mech.ts +++ /dev/null @@ -1,139 +0,0 @@ -import { defaultAbiCoder } from "@ethersproject/abi" -import { JsonRpcProvider, JsonRpcSigner } from "@ethersproject/providers" -import { - deployAndSetUpCustomModule, - deployMastercopyWithInitData, - SupportedNetworks, -} from "@gnosis.pm/zodiac" -import { BigNumberish } from "ethers" -import { - getCreate2Address, - keccak256, - solidityKeccak256, -} from "ethers/lib/utils" - -import { - ERC721Mech__factory, - IFactoryFriendly__factory, -} from "../../typechain-types" -import { - DEFAULT_SALT, - ERC2470_SINGLETON_FACTORY_ADDRESS, - MODULE_PROXY_FACTORY_ADDRESS, - ZERO_ADDRESS, -} from "../constants" - -export const calculateERC721MechAddress = ( - /** Address of the ERC721 token contract */ - token: string, - /** ID of the ERC721 token */ - tokenId: BigNumberish, - salt: string = DEFAULT_SALT -) => { - const initData = - IFactoryFriendly__factory.createInterface().encodeFunctionData("setUp", [ - defaultAbiCoder.encode(["address", "uint256"], [token, tokenId]), - ]) - - // ERC-1167 minimal proxy bytecode - const byteCode = - "0x602d8060093d393df3363d3d373d3d3d363d73" + - calculateERC721MechMastercopyAddress().toLowerCase().slice(2) + - "5af43d82803e903d91602b57fd5bf3" - - return getCreate2Address( - MODULE_PROXY_FACTORY_ADDRESS, - solidityKeccak256( - ["bytes32", "uint256"], - [solidityKeccak256(["bytes"], [initData]), salt] - ), - keccak256(byteCode) - ) -} - -export const ERC721_MASTERCOPY_INIT_DATA = [ZERO_ADDRESS, 0] - -export const calculateERC721MechMastercopyAddress = () => { - const initData = defaultAbiCoder.encode( - ["address", "uint256"], - ERC721_MASTERCOPY_INIT_DATA - ) - return getCreate2Address( - ERC2470_SINGLETON_FACTORY_ADDRESS, - DEFAULT_SALT, - keccak256(ERC721Mech__factory.bytecode + initData.slice(2)) - ) -} - -export const makeERC721MechDeployTransaction = ( - /** Address of the ERC721 token contract */ - token: string, - /** ID of the ERC721 token */ - tokenId: BigNumberish, - chainId: number, - salt: string = DEFAULT_SALT -) => { - const { transaction } = deployAndSetUpCustomModule( - calculateERC721MechMastercopyAddress(), - ERC721Mech__factory.abi, - { - types: ["address", "uint256"], - values: [token, tokenId], - }, - new JsonRpcProvider(undefined, chainId), // this provider instance is never really be used in deployAndSetUpCustomModule() - chainId, - salt - ) - - return transaction -} - -export const deployERC721Mech = async ( - /** Address of the ERC721 token contract */ - token: string, - /** ID of the ERC721 token */ - tokenId: BigNumberish, - signer: JsonRpcSigner, - salt: string = DEFAULT_SALT -) => { - // make sure the mech does not already exist - const deterministicAddress = calculateERC721MechAddress(token, tokenId, salt) - if ((await signer.provider.getCode(deterministicAddress)) !== "0x") { - throw new Error( - `A mech with the same token and token ID already exists at ${deterministicAddress}` - ) - } - const { chainId } = signer.provider.network - // make sure the network is supported - if (!Object.values(SupportedNetworks).includes(chainId)) { - throw new Error(`Network #${chainId} is not supported yet.`) - } - // make sure the mastercopy is deployed - const mastercopyAddress = calculateERC721MechMastercopyAddress() - if ((await signer.provider.getCode(mastercopyAddress)) === "0x") { - throw new Error( - `ERC721Mech mastercopy is not deployed on network #${chainId} yet. Please deploy it first.` - ) - } - - const transaction = makeERC721MechDeployTransaction( - token, - tokenId, - signer.provider.network.chainId, - salt - ) - - return signer.sendTransaction(transaction) -} - -export const deployERC721MechMastercopy = async (signer: JsonRpcSigner) => { - const initData = defaultAbiCoder.encode( - ["address", "uint256"], - ERC721_MASTERCOPY_INIT_DATA - ) - return await deployMastercopyWithInitData( - signer, - ERC721Mech__factory.bytecode + initData.slice(2), - DEFAULT_SALT - ) -} diff --git a/sdk/deploy/deployERC721TokenboundMech.ts b/sdk/deploy/deployERC721TokenboundMech.ts new file mode 100644 index 0000000..6f8a11f --- /dev/null +++ b/sdk/deploy/deployERC721TokenboundMech.ts @@ -0,0 +1,129 @@ +import { + encodeAbiParameters, + encodeFunctionData, + getCreate2Address, + WalletClient, +} from "viem" + +import { ERC721TokenboundMech__factory } from "../../typechain-types" +import { + DEFAULT_SALT, + ERC2470_SINGLETON_FACTORY_ADDRESS, + ERC6551_REGISTRY_ABI, + ERC6551_REGISTRY_ADDRESS, +} from "../constants" + +import { deployMastercopy, mechProxyBytecode } from "./factory" + +export const calculateERC721TokenboundMechAddress = ({ + chainId, + token, + tokenId, + salt = DEFAULT_SALT, +}: { + /** Address of the ERC721 token contract */ + chainId: number + /** Address of the ERC721 token contract */ + token: `0x${string}` + /** ID of the ERC721 token */ + tokenId: bigint + salt: `0x${string}` +}) => { + const context = encodeAbiParameters( + [{ type: "uint256" }, { type: "address" }, { type: "uint256" }], + [BigInt(chainId), token, tokenId] + ) + + return getCreate2Address({ + bytecode: mechProxyBytecode( + calculateERC721TokenboundMechMastercopyAddress(), + context + ), + from: ERC6551_REGISTRY_ADDRESS, + salt, + }) +} + +export const calculateERC721TokenboundMechMastercopyAddress = () => { + return getCreate2Address({ + bytecode: ERC721TokenboundMech__factory.bytecode, + from: ERC2470_SINGLETON_FACTORY_ADDRESS, + salt: DEFAULT_SALT, + }) +} + +export const makeERC721TokenboundMechDeployTransaction = ({ + chainId, + token, + tokenId, + salt = DEFAULT_SALT, +}: { + /** ID of the chain the token lives on */ + chainId: number + /** Address of the ERC721 token contract */ + token: `0x${string}` + /** ID of the ERC721 token */ + tokenId: bigint + salt: string +}) => { + return { + to: ERC6551_REGISTRY_ADDRESS, + data: encodeFunctionData({ + abi: ERC6551_REGISTRY_ABI, + functionName: "createAccount", + args: [ + calculateERC721TokenboundMechMastercopyAddress(), + chainId, + token, + tokenId, + salt, + ], + }), + } +} + +export const deployERC721TokenboundMech = async ( + walletClient: WalletClient, + { + chainId, + token, + tokenId, + salt = DEFAULT_SALT, + }: { + /** ID of the chain the token lives on, default to the current chain of walletClient */ + chainId?: number + /** Address of the ERC721 token contract */ + token: `0x${string}` + /** ID of the ERC721 token */ + tokenId: bigint + salt: `0x${string}` + } +) => { + const { chain, account } = walletClient + if (!chain) throw new Error("No chain defined in walletClient") + if (!account) throw new Error("No account defined in walletClient") + + const tokenChainId = chainId ?? chain.id + + const transaction = makeERC721TokenboundMechDeployTransaction({ + chainId: tokenChainId, + token, + tokenId, + salt, + }) + + return walletClient.sendTransaction({ + ...transaction, + account, + chain, + }) +} + +export const deployERC721TokenboundMechMastercopy = async ( + walletClient: WalletClient +) => { + return await deployMastercopy( + walletClient, + ERC721TokenboundMech__factory.bytecode + ) +} diff --git a/sdk/deploy/deployZodiacMech.ts b/sdk/deploy/deployZodiacMech.ts index 1f041ae..024cebf 100644 --- a/sdk/deploy/deployZodiacMech.ts +++ b/sdk/deploy/deployZodiacMech.ts @@ -1,133 +1,117 @@ -import { defaultAbiCoder } from "@ethersproject/abi" -import { JsonRpcProvider, JsonRpcSigner } from "@ethersproject/providers" -import { - deployAndSetUpCustomModule, - deployMastercopyWithInitData, - SupportedNetworks, -} from "@gnosis.pm/zodiac" import { + concat, + encodeAbiParameters, + encodeFunctionData, getCreate2Address, keccak256, - solidityKeccak256, -} from "ethers/lib/utils" + WalletClient, +} from "viem" import { - IFactoryFriendly__factory, + MechFactory__factory, ZodiacMech__factory, } from "../../typechain-types" import { DEFAULT_SALT, ERC2470_SINGLETON_FACTORY_ADDRESS, - MODULE_PROXY_FACTORY_ADDRESS, + MECH_FACTORY_ADDRESS, } from "../constants" +import { deployMastercopy, mechProxyBytecode } from "./factory" + export const calculateZodiacMechAddress = ( /** Addresses of the Zodiac modules */ - modules: string[], - salt: string = DEFAULT_SALT + modules: `0x${string}`[], + salt: `0x${string}` = DEFAULT_SALT ) => { - const initData = - IFactoryFriendly__factory.createInterface().encodeFunctionData("setUp", [ - defaultAbiCoder.encode(["address[]"], [modules]), - ]) - - // ERC-1167 minimal proxy bytecode - const byteCode = - "0x602d8060093d393df3363d3d373d3d3d363d73" + - calculateZodiacMechMastercopyAddress().toLowerCase().slice(2) + - "5af43d82803e903d91602b57fd5bf3" + const initData = ZodiacMech__factory.createInterface().encodeFunctionData( + "setUp", + [encodeAbiParameters([{ type: "address[]" }], [modules])] + ) as `0x${string}` - return getCreate2Address( - MODULE_PROXY_FACTORY_ADDRESS, - solidityKeccak256( - ["bytes32", "uint256"], - [solidityKeccak256(["bytes"], [initData]), salt] + return getCreate2Address({ + bytecode: mechProxyBytecode( + calculateZodiacMechMastercopyAddress(), + new Uint8Array(0) ), - keccak256(byteCode) - ) + from: MECH_FACTORY_ADDRESS, + salt: keccak256(concat([keccak256(initData), salt])), + }) } -export const ZODIAC_MASTERCOPY_INIT_DATA = [[]] +const MASTERCOPY_INIT_DATA = [] as const export const calculateZodiacMechMastercopyAddress = () => { - const initData = defaultAbiCoder.encode( - ["address[]"], - ZODIAC_MASTERCOPY_INIT_DATA - ) - return getCreate2Address( - ERC2470_SINGLETON_FACTORY_ADDRESS, - DEFAULT_SALT, - keccak256(ZodiacMech__factory.bytecode + initData.slice(2)) + const initData = encodeAbiParameters( + [{ type: "address[]" }], + [MASTERCOPY_INIT_DATA] ) + return getCreate2Address({ + bytecode: (ZodiacMech__factory.bytecode + + initData.slice(2)) as `0x${string}`, + from: ERC2470_SINGLETON_FACTORY_ADDRESS, + salt: DEFAULT_SALT, + }) } -export const makeZodiacMechDeployTransaction = ( +export const makeZodiacMechDeployTransaction = ({ + modules, + salt = DEFAULT_SALT, +}: { /** Addresses of the Zodiac modules */ - modules: string[], - provider: JsonRpcProvider, - salt: string = DEFAULT_SALT -) => { - const { chainId } = provider.network - - const { transaction } = deployAndSetUpCustomModule( - calculateZodiacMechMastercopyAddress(), - ZodiacMech__factory.abi, - { - types: ["address[]"], - values: [modules], - }, - provider, - chainId, - salt - ) + modules: `0x${string}`[] + salt: `0x${string}` +}) => { + const initCall = encodeFunctionData({ + abi: ZodiacMech__factory.abi, + functionName: "setUp", + args: [encodeAbiParameters([{ type: "address[]" }], [modules])], + }) - return transaction + return { + to: MECH_FACTORY_ADDRESS, + data: encodeFunctionData({ + abi: MechFactory__factory.abi, + functionName: "deployMech", + args: [calculateZodiacMechMastercopyAddress(), "0x", initCall, salt], + }), + } } export const deployZodiacMech = async ( - /** Addresses of the Zodiac modules */ - modules: string[], - signer: JsonRpcSigner, - salt: string = DEFAULT_SALT -) => { - // make sure the mech does not already exist - const deterministicAddress = calculateZodiacMechAddress(modules, salt) - if ((await signer.provider.getCode(deterministicAddress)) !== "0x") { - throw new Error( - `A mech with the same set of modules and salt already exists at ${deterministicAddress}` - ) - } - - const { chainId } = signer.provider.network - // make sure the network is supported - if (!Object.values(SupportedNetworks).includes(chainId)) { - throw new Error(`Network #${chainId} is not supported yet.`) - } - // make sure the mastercopy is deployed - const mastercopyAddress = calculateZodiacMechMastercopyAddress() - if ((await signer.provider.getCode(mastercopyAddress)) === "0x") { - throw new Error( - `ZodiacMech mastercopy is not deployed on network #${chainId} yet. Please deploy it first.` - ) + walletClient: WalletClient, + { + modules, + salt = DEFAULT_SALT, + }: { + /** Addresses of the Zodiac modules */ + modules: `0x${string}`[] + salt?: `0x${string}` } +) => { + const { chain, account } = walletClient + if (!chain) throw new Error("No chain defined in walletClient") + if (!account) throw new Error("No account defined in walletClient") - const transaction = makeZodiacMechDeployTransaction( - modules, - signer.provider, - salt - ) + const transaction = makeZodiacMechDeployTransaction({ modules, salt }) - return signer.sendTransaction(transaction) + return walletClient.sendTransaction({ + ...transaction, + account, + chain, + }) } -export const deployZodiacMechMastercopy = async (signer: JsonRpcSigner) => { - const initData = defaultAbiCoder.encode( - ["address[]"], - ZODIAC_MASTERCOPY_INIT_DATA +export const deployZodiacMechMastercopy = async ( + walletClient: WalletClient +) => { + const initData = encodeAbiParameters( + [{ type: "address[]" }], + [MASTERCOPY_INIT_DATA] ) - return await deployMastercopyWithInitData( - signer, - ZodiacMech__factory.bytecode + initData.slice(2), - DEFAULT_SALT + + return await deployMastercopy( + walletClient, + concat([ZodiacMech__factory.bytecode, initData]) ) } diff --git a/sdk/deploy/factory.ts b/sdk/deploy/factory.ts new file mode 100644 index 0000000..52fb5ac --- /dev/null +++ b/sdk/deploy/factory.ts @@ -0,0 +1,82 @@ +import { + concat, + encodeAbiParameters, + getContract, + parseEther, + size, + WalletClient, +} from "viem" + +import { MechFactory__factory } from "../../typechain-types" +import { ERC2470_SINGLETON_FACTORY_ADDRESS } from "../constants" + +export const mechProxyBytecode = ( + implementation: `0x${string}`, + context: `0x${string}` | Uint8Array +) => { + if (implementation.length !== 42) { + throw new Error(`Invalid implementation address: ${implementation}`) + } + + return concat([ + "0x3d61", // RETURNDATASIZE, PUSH2 + encodeAbiParameters([{ type: "uint16" }], [0x2d + size(context) + 1]), // size of minimal proxy (45 bytes) + size of context + stop byte + "0x8060", // DUP1, PUSH1 + encodeAbiParameters([{ type: "uint8" }], [0x0a + 1]), // default offset (0x0a) + 1 byte because we increased size from uint8 to uint16 + "0x3d3981f3363d3d373d3d3d363d73", // standard EIP1167 implementation + implementation, // implementation address + "0x5af43d82803e903d91602b57fd5bf3", // standard EIP1167 implementation + "0x00", // stop byte (prevents context from executing as code) + context, // appended context data + ]) +} + +/** + * Deploy a mastercopy via the ERC-2470 singleton factory. + */ +export const deployMastercopy = async ( + walletClient: WalletClient, + bytecode: `0x${string}` +) => { + const singletonFactory = getContract({ + address: ERC2470_SINGLETON_FACTORY_ADDRESS, + abi: [ + "function deploy(bytes memory _initCode, bytes32 _salt) public returns (address payable createdContract)", + ], + walletClient, + }) + + await singletonFactory.write.deploy([bytecode]) +} + +/** + * Deploy MechFactory via the ERC-2470 singleton factory. + */ +export const deployMechFactory = async (walletClient: WalletClient) => { + await deployMastercopy(walletClient, MechFactory__factory.bytecode) +} + +/** + * Deploy the ERC-2470 singleton factory on networks where it doesn't exist yet. + */ +export const deployERC2470SingletonFactory = async ( + walletClient: WalletClient +) => { + if (!walletClient.account) { + throw new Error("walletClient.account is undefined") + } + + await walletClient.sendTransaction({ + account: walletClient.account, + chain: walletClient.chain, + to: "0xBb6e024b9cFFACB947A71991E386681B1Cd1477D", + value: parseEther("0.0247"), + }) + + await walletClient.request({ + method: "eth_sendRawTransaction", + params: [ + "0xf9016c8085174876e8008303c4d88080b90154608060405234801561001057600080fd5b50610134806100206000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c80634af63f0214602d575b600080fd5b60cf60048036036040811015604157600080fd5b810190602081018135640100000000811115605b57600080fd5b820183602082011115606c57600080fd5b80359060200191846001830284011164010000000083111715608d57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550509135925060eb915050565b604080516001600160a01b039092168252519081900360200190f35b6000818351602085016000f5939250505056fea26469706673582212206b44f8a82cb6b156bfcc3dc6aadd6df4eefd204bc928a4397fd15dacf6d5320564736f6c634300060200331b83247000822470", + ], + }) +} diff --git a/sdk/package.json b/sdk/package.json index 94e8b66..8363a21 100644 --- a/sdk/package.json +++ b/sdk/package.json @@ -36,7 +36,8 @@ "@safe-global/safe-core-sdk": "^3.3.1", "@types/chai": "^4.3.4", "@types/node": "^18.11.18", - "ethers": "^5.7.2" + "ethers": "^5.7.2", + "viem": "^1.0.5" }, "packageManager": "yarn@3.4.1" } diff --git a/test/deterministicDeployment.ts b/test/deterministicDeployment.ts index 7c19b26..152f410 100644 --- a/test/deterministicDeployment.ts +++ b/test/deterministicDeployment.ts @@ -30,7 +30,8 @@ import { } from "../typechain-types" describe("deterministic deployment", () => { - async function deployModuleFactoryAndMastercopy() { + /** deploy ERC2470 singleton factory, ZodiacFactory, and ERC6551 registry */ + async function deployFactories() { const [signer, alice] = await hre.ethers.getSigners() const deployer = hre.ethers.provider.getSigner(signer.address) const moduleProxyFactoryAddress = await deployModuleFactory(deployer) diff --git a/yarn.lock b/yarn.lock index 6dac921..50726f0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -19,6 +19,13 @@ __metadata: languageName: node linkType: hard +"@adraffy/ens-normalize@npm:1.9.0": + version: 1.9.0 + resolution: "@adraffy/ens-normalize@npm:1.9.0" + checksum: a8d47f85db7a0bba01227fae8781a3245a4517875503d6848a47ca29e7f7da271742a2f93b55afc1b9201e74eda1fd1f1e6e79e70f967359fd7f6ec3d45bf243 + languageName: node + linkType: hard + "@ambire/signature-validator@npm:^1.1.0": version: 1.1.0 resolution: "@ambire/signature-validator@npm:1.1.0" @@ -2789,6 +2796,15 @@ __metadata: languageName: node linkType: hard +"@noble/curves@npm:1.0.0, @noble/curves@npm:~1.0.0": + version: 1.0.0 + resolution: "@noble/curves@npm:1.0.0" + dependencies: + "@noble/hashes": 1.3.0 + checksum: 6bcef44d626c640dc8961819d68dd67dffb907e3b973b7c27efe0ecdd9a5c6ce62c7b9e3dfc930c66605dced7f1ec0514d191c09a2ce98d6d52b66e3315ffa79 + languageName: node + linkType: hard + "@noble/ed25519@npm:^1.7.0": version: 1.7.3 resolution: "@noble/ed25519@npm:1.7.3" @@ -2803,6 +2819,20 @@ __metadata: languageName: node linkType: hard +"@noble/hashes@npm:1.3.0": + version: 1.3.0 + resolution: "@noble/hashes@npm:1.3.0" + checksum: d7ddb6d7c60f1ce1f87facbbef5b724cdea536fc9e7f59ae96e0fc9de96c8f1a2ae2bdedbce10f7dcc621338dfef8533daa73c873f2b5c87fa1a4e05a95c2e2e + languageName: node + linkType: hard + +"@noble/hashes@npm:~1.3.0": + version: 1.3.1 + resolution: "@noble/hashes@npm:1.3.1" + checksum: 7fdefc0f7a0c1ec27acc6ff88841793e3f93ec4ce6b8a6a12bfc0dd70ae6b7c4c82fe305fdfeda1735d5ad4a9eebe761e6693b3d355689c559e91242f4bc95b1 + languageName: node + linkType: hard + "@noble/secp256k1@npm:1.7.1, @noble/secp256k1@npm:^1.6.3, @noble/secp256k1@npm:~1.7.0": version: 1.7.1 resolution: "@noble/secp256k1@npm:1.7.1" @@ -3445,6 +3475,17 @@ __metadata: languageName: node linkType: hard +"@scure/bip32@npm:1.3.0": + version: 1.3.0 + resolution: "@scure/bip32@npm:1.3.0" + dependencies: + "@noble/curves": ~1.0.0 + "@noble/hashes": ~1.3.0 + "@scure/base": ~1.1.0 + checksum: 6eae997f9bdf41fe848134898960ac48e645fa10e63d579be965ca331afd0b7c1b8ebac170770d237ab4099dafc35e5a82995384510025ccf2abe669f85e8918 + languageName: node + linkType: hard + "@scure/bip39@npm:1.1.1": version: 1.1.1 resolution: "@scure/bip39@npm:1.1.1" @@ -3455,6 +3496,16 @@ __metadata: languageName: node linkType: hard +"@scure/bip39@npm:1.2.0": + version: 1.2.0 + resolution: "@scure/bip39@npm:1.2.0" + dependencies: + "@noble/hashes": ~1.3.0 + "@scure/base": ~1.1.0 + checksum: 980d761f53e63de04a9e4db840eb13bfb1bd1b664ecb04a71824c12c190f4972fd84146f3ed89b2a8e4c6bd2c17c15f8b592b7ac029e903323b0f9e2dae6916b + languageName: node + linkType: hard + "@sentry/core@npm:5.30.0": version: 5.30.0 resolution: "@sentry/core@npm:5.30.0" @@ -4764,6 +4815,18 @@ __metadata: languageName: node linkType: hard +"@wagmi/chains@npm:1.1.0": + version: 1.1.0 + resolution: "@wagmi/chains@npm:1.1.0" + peerDependencies: + typescript: ">=5.0.4" + peerDependenciesMeta: + typescript: + optional: true + checksum: 3359df95f61120450dbe526f29860c60a9dc795dcfa5e6b2133b0b7662708f0d3998e99fae7f8337e3a92d97fcfa0e9900d88721d820dd3a8bf43832cedd8a64 + languageName: node + linkType: hard + "@wagmi/cli@npm:^0.1.3": version: 0.1.10 resolution: "@wagmi/cli@npm:0.1.10" @@ -5719,6 +5782,19 @@ __metadata: languageName: node linkType: hard +"abitype@npm:0.8.7": + version: 0.8.7 + resolution: "abitype@npm:0.8.7" + peerDependencies: + typescript: ">=5.0.4" + zod: ^3 >=3.19.1 + peerDependenciesMeta: + zod: + optional: true + checksum: 4351466808969bcc73e5c535c3d96bb687ee2be0bccd48eba024c47e6cc248f0c8bd368f9e42dab35d39923e63b1349ade470f72812de27127968caf1a1426c9 + languageName: node + linkType: hard + "abitype@npm:^0.3.0": version: 0.3.0 resolution: "abitype@npm:0.3.0" @@ -12524,6 +12600,15 @@ __metadata: languageName: node linkType: hard +"isomorphic-ws@npm:5.0.0": + version: 5.0.0 + resolution: "isomorphic-ws@npm:5.0.0" + peerDependencies: + ws: "*" + checksum: e20eb2aee09ba96247465fda40c6d22c1153394c0144fa34fe6609f341af4c8c564f60ea3ba762335a7a9c306809349f9b863c8beedf2beea09b299834ad5398 + languageName: node + linkType: hard + "isomorphic-ws@npm:^4.0.1": version: 4.0.1 resolution: "isomorphic-ws@npm:4.0.1" @@ -14082,7 +14167,6 @@ __metadata: hardhat: ^2.12.5 hardhat-deploy: ^0.11.22 hardhat-gas-reporter: ^1.0.9 - openzeppelin-contracts: ^4.0.0 prettier: ^2.8.3 prettier-plugin-solidity: ^1.1.1 rimraf: ^4.1.2 @@ -14106,6 +14190,7 @@ __metadata: ethers: ^5.7.2 rimraf: ^4.1.2 typescript: ^4.9.4 + viem: ^1.0.5 languageName: unknown linkType: soft @@ -15118,13 +15203,6 @@ __metadata: languageName: node linkType: hard -"openzeppelin-contracts@npm:^4.0.0": - version: 4.0.0 - resolution: "openzeppelin-contracts@npm:4.0.0" - checksum: 977df75157505a9687700714b0c3741a5d57b535ecab141e07fe00adb70f8922ff5ca7cd221ada4c284506899f8ad3d2b8cd1321cfff8460a1e0121170c7a456 - languageName: node - linkType: hard - "optionator@npm:^0.8.1": version: 0.8.3 resolution: "optionator@npm:0.8.3" @@ -20073,6 +20151,23 @@ __metadata: languageName: node linkType: hard +"viem@npm:^1.0.5": + version: 1.0.5 + resolution: "viem@npm:1.0.5" + dependencies: + "@adraffy/ens-normalize": 1.9.0 + "@noble/curves": 1.0.0 + "@noble/hashes": 1.3.0 + "@scure/bip32": 1.3.0 + "@scure/bip39": 1.2.0 + "@wagmi/chains": 1.1.0 + abitype: 0.8.7 + isomorphic-ws: 5.0.0 + ws: 8.12.0 + checksum: fe222bdf2a36eed3f84c2bb1a05ce6c516b28817496f15a99555f326b3b922f151669d6ef5fb8a914349016fce34b9a47dc372547e2f521caa8015604b389ad3 + languageName: node + linkType: hard + "w3c-hr-time@npm:^1.0.2": version: 1.0.2 resolution: "w3c-hr-time@npm:1.0.2" @@ -20938,6 +21033,21 @@ __metadata: languageName: node linkType: hard +"ws@npm:8.12.0": + version: 8.12.0 + resolution: "ws@npm:8.12.0" + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ">=5.0.2" + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + checksum: 818ff3f8749c172a95a114cceb8b89cedd27e43a82d65c7ad0f7882b1e96a2ee6709e3746a903c3fa88beec0c8bae9a9fcd75f20858b32a166dfb7519316a5d7 + languageName: node + linkType: hard + "ws@npm:^7.4.0, ws@npm:^7.4.5, ws@npm:^7.4.6, ws@npm:^7.5.1": version: 7.5.9 resolution: "ws@npm:7.5.9" From b608faabad8014a2c5b67d5c45c7ee51eecf69d2 Mon Sep 17 00:00:00 2001 From: Jan-Felix Date: Tue, 20 Jun 2023 10:38:57 +0200 Subject: [PATCH 14/41] add hierarchy graph --- README.md | 6 +- docs/mech-hierarchy.excalidraw | 1269 ++++++++++++++++++++++++++++++++ docs/mech-hierarchy.png | Bin 0 -> 136890 bytes docs/mech-hierarchy.svg | 17 + 4 files changed, 1289 insertions(+), 3 deletions(-) create mode 100644 docs/mech-hierarchy.excalidraw create mode 100644 docs/mech-hierarchy.png create mode 100644 docs/mech-hierarchy.svg diff --git a/README.md b/README.md index d950118..2e18eb6 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,8 @@ Smart account with programmable ownership - [ZodiacMech.sol](contracts/ZodiacMech.sol): allow enabled [zodiac](https://github.com/gnosis/zodiac) modules to sign transactions on behalf of the Mech - [Mech.sol](contracts/base/Mech.sol): implement custom ownership terms by extending this abstract contract +![mech hierarchy](docs/mech-hierarchy.png) + ## Mech interface Mech implements the [EIP-4337](https://eips.ethereum.org/EIPS/eip-4337) account interface, [EIP-1271](https://eips.ethereum.org/EIPS/eip-1271), and the following functions: @@ -116,12 +118,10 @@ An EIP-1271 signature will be considered valid if it meets the following conditi The idea for the token-bound versions of mech is that the mech instance for a designated token is deployed to an address that can be deterministically derived from the token contract address and token ID. This enables counterfactually funding the mech account (own token to unlock treasure) or granting access for it (use token as key card). -The deterministic deployment is implemented via Zodiac's [ModuleProxyFactory](https://github.com/gnosis/zodiac/blob/master/contracts/factory/ModuleProxyFactory.sol), through which each mech instance is deployed as an ERC-1167 minimal proxy. - ### EIP-6551 token-bound account The token-bound versions of Mech adopts the [EIP-6551](https://eips.ethereum.org/EIPS/eip-6551) standard. -This means that these kinds of mechs are deployed through the official 6551 account registry, so they are deployed to the canonical address and detected by compatible tools. +This means that these kinds of mechs are deployed through the official 6551 account registry, so they are deployed to their canonical addresses and can be detected by compatible tools. ### EIP-1167 minimal proxies with context diff --git a/docs/mech-hierarchy.excalidraw b/docs/mech-hierarchy.excalidraw new file mode 100644 index 0000000..1336476 --- /dev/null +++ b/docs/mech-hierarchy.excalidraw @@ -0,0 +1,1269 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://excalidraw.com", + "elements": [ + { + "type": "rectangle", + "version": 70, + "versionNonce": 1498118490, + "isDeleted": false, + "id": "Qd9BZ5uJod3PiAHYKKnvK", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1158.5, + "y": 289.5, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 167, + "height": 83, + "seed": 1414607686, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "N1C--aI5OeMY2meQvHngJ" + }, + { + "id": "Ac4x7mSQSeiBzk-erYTMF", + "type": "arrow" + } + ], + "updated": 1687249969036, + "link": null, + "locked": false + }, + { + "id": "N1C--aI5OeMY2meQvHngJ", + "type": "text", + "x": 1173.4599914550781, + "y": 318.5, + "width": 137.08001708984375, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 2064977222, + "version": 45, + "versionNonce": 2006428870, + "isDeleted": false, + "boundElements": null, + "updated": 1687249880558, + "link": null, + "locked": false, + "text": "4337 Account", + "fontSize": 20, + "fontFamily": 1, + "textAlign": "center", + "verticalAlign": "middle", + "baseline": 18, + "containerId": "Qd9BZ5uJod3PiAHYKKnvK", + "originalText": "4337 Account", + "lineHeight": 1.25, + "isFrameName": false + }, + { + "type": "rectangle", + "version": 229, + "versionNonce": 1895193286, + "isDeleted": false, + "id": "Kt9ecuU0T6YziwMxORpi2", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 726.25, + "y": 289.5, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 167, + "height": 83, + "seed": 397358470, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "JvF1O6TcKXZfoMCAecrFJ" + }, + { + "id": "G1IDUtHnT88HeC00m-AXa", + "type": "arrow" + }, + { + "id": "3xF5i-0zFL2jLfHOzUX1P", + "type": "arrow" + }, + { + "id": "eposn4gkhhG1veHDC9XFh", + "type": "arrow" + }, + { + "id": "Ac4x7mSQSeiBzk-erYTMF", + "type": "arrow" + } + ], + "updated": 1687249965251, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 208, + "versionNonce": 580383578, + "isDeleted": false, + "id": "JvF1O6TcKXZfoMCAecrFJ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 786.6599998474121, + "y": 318.5, + "strokeColor": "#343a40", + "backgroundColor": "transparent", + "width": 46.18000030517578, + "height": 25, + "seed": 1484428486, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1687249952985, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "Mech", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "Kt9ecuU0T6YziwMxORpi2", + "originalText": "Mech", + "lineHeight": 1.25, + "baseline": 18 + }, + { + "type": "rectangle", + "version": 357, + "versionNonce": 1887120858, + "isDeleted": false, + "id": "EP0vhCSYGfHck97YH-xoL", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 511.5, + "y": 488, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 167, + "height": 83, + "seed": 1966364762, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "kGJ6q15_dBJ7QIs5U15SN" + }, + { + "id": "eposn4gkhhG1veHDC9XFh", + "type": "arrow" + }, + { + "id": "qDjCrIWFuavGMz4gqjl3v", + "type": "arrow" + }, + { + "id": "wEyfkGDmhk1mtJ_8R8RzR", + "type": "arrow" + } + ], + "updated": 1687249977937, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 352, + "versionNonce": 1446753094, + "isDeleted": false, + "id": "kGJ6q15_dBJ7QIs5U15SN", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 548.0200004577637, + "y": 517, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 93.95999908447266, + "height": 25, + "seed": 1350319386, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1687249880559, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "Threshold", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "EP0vhCSYGfHck97YH-xoL", + "originalText": "Threshold", + "lineHeight": 1.25, + "baseline": 18 + }, + { + "type": "rectangle", + "version": 346, + "versionNonce": 1249555654, + "isDeleted": false, + "id": "ySuuzFZh2ir5U4fU09Ov6", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 941.5, + "y": 488, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 167, + "height": 83, + "seed": 1584732954, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "jS0Yx4OABjmV3IpNHK2uD" + }, + { + "id": "3xF5i-0zFL2jLfHOzUX1P", + "type": "arrow" + }, + { + "id": "x8h2ozCdnWr9fPeldYKMP", + "type": "arrow" + }, + { + "id": "ujPJ-Hr9B2-vmWhgspcOl", + "type": "arrow" + } + ], + "updated": 1687249977937, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 353, + "versionNonce": 338778758, + "isDeleted": false, + "id": "jS0Yx4OABjmV3IpNHK2uD", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 969.7500038146973, + "y": 517, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 110.49999237060547, + "height": 25, + "seed": 1108781018, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1687249880559, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "Tokenbound", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "ySuuzFZh2ir5U4fU09Ov6", + "originalText": "Tokenbound", + "lineHeight": 1.25, + "baseline": 18 + }, + { + "type": "rectangle", + "version": 187, + "versionNonce": 927752858, + "isDeleted": false, + "id": "JzQHCBVbil3RJ6YGCYDLa", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1158.5, + "y": 488, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 167, + "height": 83, + "seed": 1668926362, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "kaaqWYn0_SHG_UKvpPic_" + } + ], + "updated": 1687249977937, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 165, + "versionNonce": 728766918, + "isDeleted": false, + "id": "kaaqWYn0_SHG_UKvpPic_", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1177.389991760254, + "y": 517, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 129.2200164794922, + "height": 25, + "seed": 338774106, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1687249880559, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "6551 Account", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "JzQHCBVbil3RJ6YGCYDLa", + "originalText": "6551 Account", + "lineHeight": 1.25, + "baseline": 18 + }, + { + "type": "rectangle", + "version": 511, + "versionNonce": 378260890, + "isDeleted": false, + "id": "fkYBlyRqtorTL1ENJpcZQ", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 726.25, + "y": 488, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 167, + "height": 83, + "seed": 1593457434, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "kay7uRInPleLcf4mqUAvC" + }, + { + "id": "qDjCrIWFuavGMz4gqjl3v", + "type": "arrow" + } + ], + "updated": 1687249880559, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 520, + "versionNonce": 1125445894, + "isDeleted": false, + "id": "kay7uRInPleLcf4mqUAvC", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 776.6699981689453, + "y": 517, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 66.16000366210938, + "height": 25, + "seed": 888653786, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1687249880559, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "Zodiac", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "fkYBlyRqtorTL1ENJpcZQ", + "originalText": "Zodiac", + "lineHeight": 1.25, + "baseline": 18 + }, + { + "id": "G1IDUtHnT88HeC00m-AXa", + "type": "arrow", + "x": 809.6633959850747, + "y": 489, + "width": 0, + "height": 115.5, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "seed": 1363388250, + "version": 512, + "versionNonce": 1650615514, + "isDeleted": false, + "boundElements": null, + "updated": 1687249957032, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0, + -115.5 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": { + "elementId": "Kt9ecuU0T6YziwMxORpi2", + "focus": 0.001037173831441224, + "gap": 1 + }, + "startArrowhead": null, + "endArrowhead": "triangle" + }, + { + "type": "arrow", + "version": 1213, + "versionNonce": 815861318, + "isDeleted": false, + "id": "3xF5i-0zFL2jLfHOzUX1P", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1025.9133959850747, + "y": 487, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 214.91339598507466, + "height": 111, + "seed": 762674970, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1687249975182, + "link": "", + "locked": false, + "startBinding": { + "elementId": "ySuuzFZh2ir5U4fU09Ov6", + "focus": 0.010938874072750394, + "gap": 1 + }, + "endBinding": { + "elementId": "Kt9ecuU0T6YziwMxORpi2", + "focus": -0.014970059880239521, + "gap": 3.5 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "triangle", + "points": [ + [ + 0, + 0 + ], + [ + 0, + -47 + ], + [ + -214.91339598507466, + -50 + ], + [ + -214.91339598507466, + -111 + ] + ] + }, + { + "type": "arrow", + "version": 1281, + "versionNonce": 168689562, + "isDeleted": false, + "id": "eposn4gkhhG1veHDC9XFh", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 594.4575924337465, + "y": 486.98224264141163, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 214.91339598507466, + "height": 111.5477285690605, + "seed": 1804348186, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1687249975181, + "link": "", + "locked": false, + "startBinding": { + "elementId": "EP0vhCSYGfHck97YH-xoL", + "focus": -0.006495898997047583, + "gap": 1.0177573585883692 + }, + "endBinding": { + "elementId": "Kt9ecuU0T6YziwMxORpi2", + "focus": 0.004539060852440905, + "gap": 2.934514072351135 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "triangle", + "points": [ + [ + 0, + 0 + ], + [ + 0, + -47.547728569060496 + ], + [ + 214.91339598507466, + -50.547728569060496 + ], + [ + 214.91339598507466, + -111.5477285690605 + ] + ] + }, + { + "type": "arrow", + "version": 645, + "versionNonce": 1281259098, + "isDeleted": false, + "id": "Ac4x7mSQSeiBzk-erYTMF", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 895, + "y": 331.2405029751235, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 262, + "height": 0, + "seed": 2100566234, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1687249957033, + "link": null, + "locked": false, + "startBinding": { + "elementId": "Kt9ecuU0T6YziwMxORpi2", + "focus": 0.005795252412614232, + "gap": 1.75 + }, + "endBinding": { + "elementId": "Qd9BZ5uJod3PiAHYKKnvK", + "focus": -0.005795252412614232, + "gap": 1.5 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "triangle", + "points": [ + [ + 0, + 0 + ], + [ + 262, + 0 + ] + ] + }, + { + "type": "arrow", + "version": 799, + "versionNonce": 150950426, + "isDeleted": false, + "id": "Jzb_M87c0iZIujMrhS8DM", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1107.9999997615814, + "y": 529.3070919532981, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 52, + "height": 0, + "seed": 1265998214, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1687249880559, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "triangle", + "points": [ + [ + 0, + 0 + ], + [ + 52, + 0 + ] + ] + }, + { + "type": "rectangle", + "version": 705, + "versionNonce": 115995782, + "isDeleted": false, + "id": "EXgclQrPXRWS3yBwcMY_P", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 411.55555531713696, + "y": 656.0833339691162, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 167, + "height": 83, + "seed": 861009414, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "2ZILoPx5A87qAY0sIXFL1" + }, + { + "id": "qDjCrIWFuavGMz4gqjl3v", + "type": "arrow" + } + ], + "updated": 1687249880559, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 710, + "versionNonce": 742522586, + "isDeleted": false, + "id": "2ZILoPx5A87qAY0sIXFL1", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 461.09555241796704, + "y": 685.0833339691162, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 67.92000579833984, + "height": 25, + "seed": 1659979078, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1687249880559, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "ERC20", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "EXgclQrPXRWS3yBwcMY_P", + "originalText": "ERC20", + "lineHeight": 1.25, + "baseline": 18 + }, + { + "type": "rectangle", + "version": 779, + "versionNonce": 805663686, + "isDeleted": false, + "id": "tmkH2xuhmAF0sXW0jY4qH", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 610.0370367986184, + "y": 656.0833339691162, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 167, + "height": 83, + "seed": 910749914, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "p6s3JKky5qS-knm7KSY0D" + }, + { + "id": "wEyfkGDmhk1mtJ_8R8RzR", + "type": "arrow" + } + ], + "updated": 1687249880559, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 788, + "versionNonce": 1410405274, + "isDeleted": false, + "id": "p6s3JKky5qS-knm7KSY0D", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 655.7970351201516, + "y": 685.0833339691162, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 75.4800033569336, + "height": 25, + "seed": 610911642, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1687249880559, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "ERC1155", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "tmkH2xuhmAF0sXW0jY4qH", + "originalText": "ERC1155", + "lineHeight": 1.25, + "baseline": 18 + }, + { + "type": "rectangle", + "version": 955, + "versionNonce": 1300664582, + "isDeleted": false, + "id": "2c1lVUWxftqhZNv88TyC5", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 846.5185182800999, + "y": 656.0833339691162, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 167, + "height": 83, + "seed": 222976282, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "jqbDIWQm_D5YnqOm9Z6ZR" + }, + { + "id": "x8h2ozCdnWr9fPeldYKMP", + "type": "arrow" + } + ], + "updated": 1687249895419, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 965, + "versionNonce": 1556170138, + "isDeleted": false, + "id": "jqbDIWQm_D5YnqOm9Z6ZR", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 894.8485201111546, + "y": 685.0833339691162, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 70.33999633789062, + "height": 25, + "seed": 529802714, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1687249989739, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "ERC721", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "2c1lVUWxftqhZNv88TyC5", + "originalText": "ERC721", + "lineHeight": 1.25, + "baseline": 18 + }, + { + "type": "rectangle", + "version": 893, + "versionNonce": 2087618438, + "isDeleted": false, + "id": "cjqOxNQpQ_zpGwBphnsTk", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1044.9999997615814, + "y": 656.0833339691162, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 167, + "height": 83, + "seed": 143022746, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "boundElements": [ + { + "type": "text", + "id": "T9S8DdITVkWI8ie7JIS9V" + }, + { + "id": "ujPJ-Hr9B2-vmWhgspcOl", + "type": "arrow" + } + ], + "updated": 1687249895419, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 902, + "versionNonce": 2076210458, + "isDeleted": false, + "id": "T9S8DdITVkWI8ie7JIS9V", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1090.7599980831146, + "y": 685.0833339691162, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 75.4800033569336, + "height": 25, + "seed": 651425626, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1687249880559, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 1, + "text": "ERC1155", + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "cjqOxNQpQ_zpGwBphnsTk", + "originalText": "ERC1155", + "lineHeight": 1.25, + "baseline": 18 + }, + { + "type": "arrow", + "version": 1461, + "versionNonce": 1703337734, + "isDeleted": false, + "id": "qDjCrIWFuavGMz4gqjl3v", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 494.17816011326846, + "y": 653.3865026444197, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 100.90899630558232, + "height": 81.38650264441969, + "seed": 1570652614, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1687249975181, + "link": "", + "locked": false, + "startBinding": { + "elementId": "EXgclQrPXRWS3yBwcMY_P", + "focus": -0.010507726992437157, + "gap": 2.696831324696518 + }, + "endBinding": { + "elementId": "EP0vhCSYGfHck97YH-xoL", + "focus": -0.014733526463525423, + "gap": 1 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "triangle", + "points": [ + [ + 0, + 0 + ], + [ + 0, + -41.547728569060496 + ], + [ + 99.82183964831296, + -41.547728569060496 + ], + [ + 100.90899630558232, + -81.38650264441969 + ] + ] + }, + { + "type": "arrow", + "version": 1564, + "versionNonce": 1109326938, + "isDeleted": false, + "id": "wEyfkGDmhk1mtJ_8R8RzR", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 696.1042085606559, + "y": 654.2045002406462, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 100.91339598507477, + "height": 81.54772856906061, + "seed": 1612632218, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1687249975182, + "link": "", + "locked": false, + "startBinding": { + "elementId": "tmkH2xuhmAF0sXW0jY4qH", + "focus": 0.030744572000449822, + "gap": 1.8788337284699992 + }, + "endBinding": { + "elementId": "EP0vhCSYGfHck97YH-xoL", + "focus": 0.011660871820403415, + "gap": 1.6567716715856022 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "triangle", + "points": [ + [ + 0, + 0 + ], + [ + 0, + -41.54772856906055 + ], + [ + -99.82183964831309, + -41.54772856906055 + ], + [ + -100.91339598507477, + -81.54772856906061 + ] + ] + }, + { + "type": "arrow", + "version": 1530, + "versionNonce": 1886544154, + "isDeleted": false, + "id": "x8h2ozCdnWr9fPeldYKMP", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 930.7731009751593, + "y": 655.2220637400633, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 100.91339598507454, + "height": 81.5477285690605, + "seed": 1805001414, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1687249975182, + "link": "", + "locked": false, + "startBinding": { + "elementId": "2c1lVUWxftqhZNv88TyC5", + "focus": 0.009036918503705534, + "gap": 1 + }, + "endBinding": { + "elementId": "ySuuzFZh2ir5U4fU09Ov6", + "focus": -0.09324984264576391, + "gap": 2.674335171002781 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "triangle", + "points": [ + [ + 0, + 0 + ], + [ + 0, + -41.547728569060496 + ], + [ + 99.82183964831296, + -41.547728569060496 + ], + [ + 100.91339598507454, + -81.5477285690605 + ] + ] + }, + { + "type": "arrow", + "version": 1633, + "versionNonce": 1328764294, + "isDeleted": false, + "id": "ujPJ-Hr9B2-vmWhgspcOl", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1132.6991494225467, + "y": 656.0400613362899, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "width": 100.91339598507466, + "height": 81.54772856906061, + "seed": 696487878, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1687249975182, + "link": "", + "locked": false, + "startBinding": { + "elementId": "cjqOxNQpQ_zpGwBphnsTk", + "focus": 0.05028921749659047, + "gap": 1 + }, + "endBinding": { + "elementId": "ySuuzFZh2ir5U4fU09Ov6", + "focus": -0.06567172735635796, + "gap": 3.4923327672293 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "triangle", + "points": [ + [ + 0, + 0 + ], + [ + 0, + -41.54772856906055 + ], + [ + -99.82183964831309, + -41.54772856906055 + ], + [ + -100.91339598507466, + -81.54772856906061 + ] + ] + } + ], + "appState": { + "gridSize": null, + "viewBackgroundColor": "#ffffff" + }, + "files": {} +} \ No newline at end of file diff --git a/docs/mech-hierarchy.png b/docs/mech-hierarchy.png new file mode 100644 index 0000000000000000000000000000000000000000..1540a9cf23975f424b2b3466f54005092b06046a GIT binary patch literal 136890 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 literal 0 HcmV?d00001 diff --git a/docs/mech-hierarchy.svg b/docs/mech-hierarchy.svg new file mode 100644 index 0000000..8aa97a6 --- /dev/null +++ b/docs/mech-hierarchy.svg @@ -0,0 +1,17 @@ + + + + + + + + 4337 AccountMechThresholdTokenbound6551 AccountZodiacERC20ERC1155ERC721ERC1155 \ No newline at end of file From 139d356a922999f6407e9ea71e1c44dc1a91f084 Mon Sep 17 00:00:00 2001 From: Jan-Felix Date: Thu, 13 Jul 2023 10:23:46 +0200 Subject: [PATCH 15/41] adding exports --- sdk/deploy/index.ts | 6 +- test/deterministicDeployment.ts | 113 ++++++++++++++++++-------------- 2 files changed, 68 insertions(+), 51 deletions(-) diff --git a/sdk/deploy/index.ts b/sdk/deploy/index.ts index 5bde912..a2c9a07 100644 --- a/sdk/deploy/index.ts +++ b/sdk/deploy/index.ts @@ -1,3 +1,5 @@ -export * from "./deployERC721Mech" -export * from "./deployERC1155Mech" +export * from "./deployERC721TokenboundMech" +export * from "./deployERC1155TokenboundMech" +export * from "./deployERC1155ThresholdMech" export * from "./deployZodiacMech" +export * from "./factory" diff --git a/test/deterministicDeployment.ts b/test/deterministicDeployment.ts index 152f410..c82bb2d 100644 --- a/test/deterministicDeployment.ts +++ b/test/deterministicDeployment.ts @@ -1,59 +1,62 @@ import { defaultAbiCoder } from "@ethersproject/abi" -import { deployModuleFactory } from "@gnosis.pm/zodiac" import { loadFixture } from "@nomicfoundation/hardhat-network-helpers" import { expect } from "chai" import hre, { ethers } from "hardhat" +import { createWalletClient, http } from "viem" +import { hardhat } from "viem/chains" // We use `loadFixture` to share common setups (or fixtures) between tests. // Using this simplifies your tests and makes them run faster, by taking // advantage or Hardhat Network's snapshot functionality. import { - calculateERC1155MechAddress, - calculateERC1155MechMastercopyAddress, - calculateERC721MechAddress, - calculateERC721MechMastercopyAddress, + calculateERC1155ThresholdMechAddress, + calculateERC1155ThresholdMechMastercopyAddress, + calculateERC721TokenboundMechAddress, + calculateERC721TokenboundMechMastercopyAddress, calculateZodiacMechAddress, calculateZodiacMechMastercopyAddress, - deployERC1155Mech, - deployERC1155MechMastercopy, - deployERC721Mech, - deployERC721MechMastercopy, + deployERC1155ThresholdMech, + deployERC1155ThresholdMechMastercopy, + deployERC721TokenboundMech, + deployERC721TokenboundMechMastercopy, + deployMechFactory, deployZodiacMech, deployZodiacMechMastercopy, } from "../sdk" import { SENTINEL_MODULES, ZERO_ADDRESS } from "../sdk/constants" -import { - ERC1155Mech__factory, - ERC721Mech__factory, - ZodiacMech__factory, -} from "../typechain-types" +import { deployERC2470SingletonFactory } from "../sdk/deploy/factory" +import { ZodiacMech__factory } from "../typechain-types" describe("deterministic deployment", () => { - /** deploy ERC2470 singleton factory, ZodiacFactory, and ERC6551 registry */ + /** deploy ERC2470 singleton factory, MechFactory, and ERC6551 registry */ async function deployFactories() { const [signer, alice] = await hre.ethers.getSigners() const deployer = hre.ethers.provider.getSigner(signer.address) - const moduleProxyFactoryAddress = await deployModuleFactory(deployer) - if (moduleProxyFactoryAddress === ZERO_ADDRESS) { - throw new Error("Module proxy factory address is already deployed") - } + + const walletClient = createWalletClient({ + chain: hardhat, + account: signer.address as `0x${string}`, + transport: http(), + }) + + await deployERC2470SingletonFactory(walletClient) + await deployMechFactory(walletClient) const mastercopyAddresses = { - erc721: await deployERC721MechMastercopy(deployer), - erc1155: await deployERC1155MechMastercopy(deployer), + erc721: await deployERC721TokenboundMechMastercopy(deployer), + erc1155: await deployERC1155ThresholdMechMastercopy(deployer), zodiac: await deployZodiacMechMastercopy(deployer), } return { - moduleProxyFactoryAddress, mastercopyAddresses, deployer, alice, } } - describe("deployERC721Mech()", () => { + describe.only("deployERC721TokenboundMech()", () => { it("correctly initializes the mech proxy instance", async () => { const { alice, deployer } = await loadFixture( deployModuleFactoryAndMastercopy @@ -62,38 +65,44 @@ describe("deterministic deployment", () => { const TestToken = await ethers.getContractFactory("ERC721Token") const testToken = await TestToken.deploy() - await deployERC721Mech(testToken.address, 1, deployer) - const mechAddress = calculateERC721MechAddress(testToken.address, 1) - const mech = ERC721Mech__factory.connect(mechAddress, alice) + await deployERC721TokenboundMech(testToken.address, 1, deployer) + const mechAddress = calculateERC721TokenboundMechAddress( + testToken.address, + 1 + ) + const mech = ERC721TokenboundMech__factory.connect(mechAddress, alice) expect(await mech.token()).to.equal(testToken.address) expect(await mech.tokenId()).to.equal(1) }) }) - describe("calculateERC721MechMastercopyAddress", () => { - it("returns the address of the ERC721Mech mastercopy", async () => { + describe("calculateERC721TokenboundMechMastercopyAddress", () => { + it("returns the address of the ERC721TokenboundMech mastercopy", async () => { const { mastercopyAddresses } = await loadFixture( deployModuleFactoryAndMastercopy ) - expect(calculateERC721MechMastercopyAddress()).to.equal( + expect(calculateERC721TokenboundMechMastercopyAddress()).to.equal( mastercopyAddresses.erc721 ) }) }) - describe("calculateERC721MechAddress()", () => { + describe("calculateERC721TokenboundMechAddress()", () => { it("returns the address of the mech for a given NFT", async () => { await loadFixture(deployModuleFactoryAndMastercopy) const TestToken = await ethers.getContractFactory("ERC721Token") const testToken = await TestToken.deploy() - const calculatedAddress = calculateERC721MechAddress(testToken.address, 1) + const calculatedAddress = calculateERC721TokenboundMechAddress( + testToken.address, + 1 + ) expect(await ethers.provider.getCode(calculatedAddress)).to.equal("0x") - await deployERC721Mech( + await deployERC721TokenboundMech( testToken.address, 1, hre.ethers.provider.getSigner() @@ -105,13 +114,13 @@ describe("deterministic deployment", () => { }) }) - describe("deployERC721MechMastercopy()", () => { + describe("deployERC721TokenboundMechMastercopy()", () => { it("initializes the mastercopy", async () => { const { mastercopyAddresses, deployer } = await loadFixture( deployModuleFactoryAndMastercopy ) - const mech = ERC721Mech__factory.connect( + const mech = ERC721TokenboundMech__factory.connect( mastercopyAddresses.erc721, deployer ) @@ -127,7 +136,7 @@ describe("deterministic deployment", () => { const { mastercopyAddresses, deployer } = await loadFixture( deployModuleFactoryAndMastercopy ) - const mech = ERC721Mech__factory.connect( + const mech = ERC721TokenboundMech__factory.connect( mastercopyAddresses.erc721, deployer ) @@ -135,9 +144,9 @@ describe("deterministic deployment", () => { }) }) - ///// ERC1155Mech + ///// ERC1155ThresholdMech - describe("deployERC1155Mech()", () => { + describe("deployERC1155ThresholdMech()", () => { it("correctly initializes the mech proxy instance", async () => { const { alice, deployer } = await loadFixture( deployModuleFactoryAndMastercopy @@ -146,14 +155,20 @@ describe("deterministic deployment", () => { const TestToken = await ethers.getContractFactory("ERC1155Token") const testToken = await TestToken.deploy() - await deployERC1155Mech(testToken.address, [1, 2], [10, 20], 0, deployer) - const mechAddress = calculateERC1155MechAddress( + await deployERC1155ThresholdMech( + testToken.address, + [1, 2], + [10, 20], + 0, + deployer + ) + const mechAddress = calculateERC1155ThresholdMechAddress( testToken.address, [1, 2], [10, 20], 0 ) - const mech = ERC1155Mech__factory.connect(mechAddress, alice) + const mech = ERC1155ThresholdMech__factory.connect(mechAddress, alice) expect(await mech.token()).to.equal(testToken.address) expect(await mech.tokenIds(0)).to.equal(1) @@ -163,26 +178,26 @@ describe("deterministic deployment", () => { }) }) - describe("calculateERC1155MechMastercopyAddress", () => { - it("returns the address of the ERC1155Mech mastercopy", async () => { + describe("calculateERC1155ThresholdMechMastercopyAddress", () => { + it("returns the address of the ERC1155ThresholdMech mastercopy", async () => { const { mastercopyAddresses } = await loadFixture( deployModuleFactoryAndMastercopy ) - expect(calculateERC1155MechMastercopyAddress()).to.equal( + expect(calculateERC1155ThresholdMechMastercopyAddress()).to.equal( mastercopyAddresses.erc1155 ) }) }) - describe("calculateERC1155MechAddress()", () => { + describe("calculateERC1155ThresholdMechAddress()", () => { it("returns the address of the mech for a given NFT", async () => { await loadFixture(deployModuleFactoryAndMastercopy) const TestToken = await ethers.getContractFactory("ERC1155Token") const testToken = await TestToken.deploy() - const calculatedAddress = calculateERC1155MechAddress( + const calculatedAddress = calculateERC1155ThresholdMechAddress( testToken.address, [1], [1], @@ -191,7 +206,7 @@ describe("deterministic deployment", () => { expect(await ethers.provider.getCode(calculatedAddress)).to.equal("0x") - await deployERC1155Mech( + await deployERC1155ThresholdMech( testToken.address, [1], [1], @@ -205,13 +220,13 @@ describe("deterministic deployment", () => { }) }) - describe("deployERC1155MechMastercopy()", () => { + describe("deployERC1155ThresholdMechMastercopy()", () => { it("initializes the mastercopy with zero address and threshold [0, 0]", async () => { const { mastercopyAddresses, deployer } = await loadFixture( deployModuleFactoryAndMastercopy ) - const mech = ERC1155Mech__factory.connect( + const mech = ERC1155ThresholdMech__factory.connect( mastercopyAddresses.erc1155, deployer ) @@ -225,7 +240,7 @@ describe("deterministic deployment", () => { const { mastercopyAddresses, deployer } = await loadFixture( deployModuleFactoryAndMastercopy ) - const mech = ERC1155Mech__factory.connect( + const mech = ERC1155ThresholdMech__factory.connect( mastercopyAddresses.erc1155, deployer ) From 52484d905b94a04b029e0217bc866ed46df11b12 Mon Sep 17 00:00:00 2001 From: Jan-Felix Date: Fri, 18 Aug 2023 15:07:23 +0200 Subject: [PATCH 16/41] fixes after merge --- sdk/src/deploy/deployERC1155ThresholdMech.ts | 2 +- sdk/src/deploy/deployERC1155TokenboundMech.ts | 2 +- sdk/src/deploy/deployERC721TokenboundMech.ts | 2 +- sdk/src/deploy/factory.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sdk/src/deploy/deployERC1155ThresholdMech.ts b/sdk/src/deploy/deployERC1155ThresholdMech.ts index d4465e2..4ed4232 100644 --- a/sdk/src/deploy/deployERC1155ThresholdMech.ts +++ b/sdk/src/deploy/deployERC1155ThresholdMech.ts @@ -8,7 +8,7 @@ import { import { ERC1155ThresholdMech__factory, MechFactory__factory, -} from "../../typechain-types" +} from "../../../typechain-types" import { DEFAULT_SALT, ERC2470_SINGLETON_FACTORY_ADDRESS, diff --git a/sdk/src/deploy/deployERC1155TokenboundMech.ts b/sdk/src/deploy/deployERC1155TokenboundMech.ts index 797905f..1d1451f 100644 --- a/sdk/src/deploy/deployERC1155TokenboundMech.ts +++ b/sdk/src/deploy/deployERC1155TokenboundMech.ts @@ -5,7 +5,7 @@ import { WalletClient, } from "viem" -import { ERC1155TokenboundMech__factory } from "../../typechain-types" +import { ERC1155TokenboundMech__factory } from "../../../typechain-types" import { DEFAULT_SALT, ERC2470_SINGLETON_FACTORY_ADDRESS, diff --git a/sdk/src/deploy/deployERC721TokenboundMech.ts b/sdk/src/deploy/deployERC721TokenboundMech.ts index 6f8a11f..75d0a41 100644 --- a/sdk/src/deploy/deployERC721TokenboundMech.ts +++ b/sdk/src/deploy/deployERC721TokenboundMech.ts @@ -5,7 +5,7 @@ import { WalletClient, } from "viem" -import { ERC721TokenboundMech__factory } from "../../typechain-types" +import { ERC721TokenboundMech__factory } from "../../../typechain-types" import { DEFAULT_SALT, ERC2470_SINGLETON_FACTORY_ADDRESS, diff --git a/sdk/src/deploy/factory.ts b/sdk/src/deploy/factory.ts index 52fb5ac..3c3e498 100644 --- a/sdk/src/deploy/factory.ts +++ b/sdk/src/deploy/factory.ts @@ -7,7 +7,7 @@ import { WalletClient, } from "viem" -import { MechFactory__factory } from "../../typechain-types" +import { MechFactory__factory } from "../../../typechain-types" import { ERC2470_SINGLETON_FACTORY_ADDRESS } from "../constants" export const mechProxyBytecode = ( From cdab142f3b3fa615551cc3c42d46a6088c0313ef Mon Sep 17 00:00:00 2001 From: Jan-Felix Date: Fri, 18 Aug 2023 15:27:25 +0200 Subject: [PATCH 17/41] upgrade deps --- frontend/package.json | 20 +- package.json | 58 +-- sdk/package.json | 16 +- yarn.lock | 871 ++++++++++++++++++++++++++---------------- 4 files changed, 580 insertions(+), 385 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index 41f7703..7735ef9 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -3,14 +3,14 @@ "version": "1.0.0", "private": true, "devDependencies": { - "@types/react": "^18.0.0", - "@types/react-dom": "^18.0.0", + "@types/react": "^18.2.20", + "@types/react-dom": "^18.2.7", "@walletconnect/client": "^1.8.0", - "@walletconnect/core": "^2.7.3", + "@walletconnect/core": "^2.10.0", "@walletconnect/utils": "^1.8.0", - "@walletconnect/web3wallet": "^1.7.1", - "@web3modal/ethereum": "^2.7.0", - "@web3modal/react": "^2.7.0", + "@walletconnect/web3wallet": "^1.9.0", + "@web3modal/ethereum": "^2.7.1", + "@web3modal/react": "^2.7.1", "@web3modal/standalone": "^2.4.3", "buffer": "^6.0.3", "clsx": "^1.2.1", @@ -21,12 +21,12 @@ "mech-sdk": "workspace:^", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-router-dom": "^6.8.0", + "react-router-dom": "^6.15.0", "react-scripts": "5.0.1", "typescript": "^4.9.5", - "typescript-plugin-css-modules": "^4.1.1", - "viem": "^0.3.24", - "wagmi": "^1.0.4" + "typescript-plugin-css-modules": "^4.2.3", + "viem": "^1.6.0", + "wagmi": "^1.3.10" }, "scripts": { "start": "react-scripts start", diff --git a/package.json b/package.json index d9d12fa..a498531 100644 --- a/package.json +++ b/package.json @@ -43,46 +43,46 @@ "homepage": "https://github.com/gnosis/mech#readme", "devDependencies": { "@account-abstraction/contracts": "^0.6.0", - "@ambire/signature-validator": "^1.1.0", - "@erc6551/reference": "https://github.com/erc6551/reference", + "@ambire/signature-validator": "^1.3.1", + "@erc6551/reference": "https://github.com/erc6551/reference.git#commit=df75cd1bab5fb8e320940783df5f14c6d8aaa0f2", "@ethersproject/abi": "^5.7.0", "@ethersproject/bytes": "^5.7.0", "@ethersproject/providers": "^5.7.2", - "@nomicfoundation/hardhat-chai-matchers": "^1.0.5", - "@nomicfoundation/hardhat-network-helpers": "^1.0.7", - "@nomicfoundation/hardhat-toolbox": "^2.0.0", - "@nomiclabs/hardhat-ethers": "^2.2.1", - "@nomiclabs/hardhat-etherscan": "^3.1.4", - "@typechain/ethers-v5": "^10.2.0", - "@typechain/hardhat": "^6.1.5", + "@nomicfoundation/hardhat-chai-matchers": "^1.0.6", + "@nomicfoundation/hardhat-network-helpers": "^1.0.8", + "@nomicfoundation/hardhat-toolbox": "^2.0.2", + "@nomiclabs/hardhat-ethers": "^2.2.3", + "@nomiclabs/hardhat-etherscan": "^3.1.7", + "@typechain/ethers-v5": "^10.2.1", + "@typechain/hardhat": "^6.1.6", "@types/mocha": "^10.0.1", - "@typescript-eslint/eslint-plugin": "^5.9.0", - "@typescript-eslint/parser": "^5.9.0", + "@typescript-eslint/eslint-plugin": "^5.62.0", + "@typescript-eslint/parser": "^5.62.0", "chai": "^4.3.7", - "dotenv": "^16.0.3", - "eslint": "^8.6.0", - "eslint-config-prettier": "^8.3.0", + "dotenv": "^16.3.1", + "eslint": "^8.47.0", + "eslint-config-prettier": "^8.10.0", "eslint-plugin-eslint-comments": "^3.2.0", - "eslint-plugin-import": "^2.25.4", - "eslint-plugin-prettier": "^4.0.0", - "hardhat": "^2.12.5", - "hardhat-deploy": "^0.11.22", + "eslint-plugin-import": "^2.28.0", + "eslint-plugin-prettier": "^4.2.1", + "hardhat": "^2.17.1", + "hardhat-deploy": "^0.11.36", "hardhat-gas-reporter": "^1.0.9", - "prettier": "^2.8.3", - "prettier-plugin-solidity": "^1.1.1", - "rimraf": "^4.1.2", - "solidity-coverage": "^0.8.2", + "prettier": "^2.8.8", + "prettier-plugin-solidity": "^1.1.3", + "rimraf": "^4.4.1", + "solidity-coverage": "^0.8.4", "ts-node": "^10.9.1", - "typechain": "^8.1.1", - "typescript": "^4.9.4" + "typechain": "^8.3.1", + "typescript": "^4.9.5" }, "dependencies": { "@gnosis.pm/safe-contracts": "^1.3.0", - "@gnosis.pm/zodiac": "^3.0.0", - "@openzeppelin/contracts": "^4.8.1", - "@safe-global/safe-core-sdk": "^3.3.1", - "@types/chai": "^4.3.4", - "@types/node": "^18.11.18", + "@gnosis.pm/zodiac": "^3.3.7", + "@openzeppelin/contracts": "^4.9.3", + "@safe-global/safe-core-sdk": "^3.3.5", + "@types/chai": "^4.3.5", + "@types/node": "^18.17.5", "ethers": "^5.7.2" }, "resolutions": { diff --git a/sdk/package.json b/sdk/package.json index 0fd92f1..5ad2c1f 100644 --- a/sdk/package.json +++ b/sdk/package.json @@ -31,18 +31,18 @@ }, "homepage": "https://github.com/gnosis/mech#readme", "devDependencies": { - "rimraf": "^4.1.2", - "typescript": "^4.9.4" + "rimraf": "^4.4.1", + "typescript": "^4.9.5" }, "dependencies": { "@gnosis.pm/safe-contracts": "^1.3.0", - "@gnosis.pm/zodiac": "^3.0.0", - "@openzeppelin/contracts": "^4.8.1", - "@safe-global/safe-core-sdk": "^3.3.1", - "@types/chai": "^4.3.4", - "@types/node": "^18.11.18", + "@gnosis.pm/zodiac": "^3.3.7", + "@openzeppelin/contracts": "^4.9.3", + "@safe-global/safe-core-sdk": "^3.3.5", + "@types/chai": "^4.3.5", + "@types/node": "^18.17.5", "ethers": "^5.7.2", - "viem": "^1.0.5" + "viem": "^1.6.0" }, "packageManager": "yarn@3.6.1" } diff --git a/yarn.lock b/yarn.lock index f09c2d0..6795044 100644 --- a/yarn.lock +++ b/yarn.lock @@ -40,7 +40,7 @@ __metadata: languageName: node linkType: hard -"@ambire/signature-validator@npm:^1.1.0": +"@ambire/signature-validator@npm:^1.3.1": version: 1.3.1 resolution: "@ambire/signature-validator@npm:1.3.1" dependencies: @@ -1933,10 +1933,10 @@ __metadata: languageName: node linkType: hard -"@erc6551/reference@https://github.com/erc6551/reference": - version: 0.0.1 - resolution: "@erc6551/reference@https://github.com/erc6551/reference.git#commit=d79a49e99fee1154a2023bd164850c5d0c34c208" - checksum: dadd486de350f02ecf68809cb6130fb29029c2230fa44aa212a1ae473e0a1155e24220b50467bb1274539bda16205b947eb2c7904cba5ded918a274ba2043123 +"@erc6551/reference@https://github.com/erc6551/reference.git#commit=df75cd1bab5fb8e320940783df5f14c6d8aaa0f2": + version: 0.2.0 + resolution: "@erc6551/reference@https://github.com/erc6551/reference.git#commit=df75cd1bab5fb8e320940783df5f14c6d8aaa0f2" + checksum: dd351b2be6b1fa25bf427ee6bc24e65e5ce678924cfbda9264ce34140129d8186bc54596a0f1a47287264f8c9b4e84e1310edf9273ab9a2916fd6659932eb543 languageName: node linkType: hard @@ -1958,6 +1958,13 @@ __metadata: languageName: node linkType: hard +"@eslint-community/regexpp@npm:^4.6.1": + version: 4.6.2 + resolution: "@eslint-community/regexpp@npm:4.6.2" + checksum: a3c341377b46b54fa228f455771b901d1a2717f95d47dcdf40199df30abc000ba020f747f114f08560d119e979d882a94cf46cfc51744544d54b00319c0f2724 + languageName: node + linkType: hard + "@eslint/eslintrc@npm:^2.1.0": version: 2.1.0 resolution: "@eslint/eslintrc@npm:2.1.0" @@ -1975,6 +1982,23 @@ __metadata: languageName: node linkType: hard +"@eslint/eslintrc@npm:^2.1.2": + version: 2.1.2 + resolution: "@eslint/eslintrc@npm:2.1.2" + dependencies: + ajv: ^6.12.4 + debug: ^4.3.2 + espree: ^9.6.0 + globals: ^13.19.0 + ignore: ^5.2.0 + import-fresh: ^3.2.1 + js-yaml: ^4.1.0 + minimatch: ^3.1.2 + strip-json-comments: ^3.1.1 + checksum: bc742a1e3b361f06fedb4afb6bf32cbd27171292ef7924f61c62f2aed73048367bcc7ac68f98c06d4245cd3fabc43270f844e3c1699936d4734b3ac5398814a7 + languageName: node + linkType: hard + "@eslint/js@npm:8.44.0": version: 8.44.0 resolution: "@eslint/js@npm:8.44.0" @@ -1982,6 +2006,13 @@ __metadata: languageName: node linkType: hard +"@eslint/js@npm:^8.47.0": + version: 8.47.0 + resolution: "@eslint/js@npm:8.47.0" + checksum: 0ef57fe27b6d4c305b33f3b2d2fee1ab397a619006f1d6f4ce5ee4746b8f03d11a4e098805a7d78601ca534cf72917d37f0ac19896c992a32e26299ecb9f9de1 + languageName: node + linkType: hard + "@ethersproject/abi@npm:5.7.0, @ethersproject/abi@npm:^5.0.0-beta.146, @ethersproject/abi@npm:^5.0.9, @ethersproject/abi@npm:^5.1.2, @ethersproject/abi@npm:^5.7.0": version: 5.7.0 resolution: "@ethersproject/abi@npm:5.7.0" @@ -2400,16 +2431,16 @@ __metadata: languageName: node linkType: hard -"@gnosis.pm/zodiac@npm:^3.0.0": - version: 3.3.4 - resolution: "@gnosis.pm/zodiac@npm:3.3.4" +"@gnosis.pm/zodiac@npm:^3.3.7": + version: 3.3.7 + resolution: "@gnosis.pm/zodiac@npm:3.3.7" dependencies: "@gnosis.pm/mock-contract": ^4.0.0 "@gnosis.pm/safe-contracts": 1.3.0 "@openzeppelin/contracts": ^4.8.1 "@openzeppelin/contracts-upgradeable": ^4.8.1 ethers: ^5.7.1 - checksum: c3ce67811f1265c27c12fa1c2cfdbb03b01ad5b964e41b07326cbc549f6f6e0baaf2eac0661d80867fd0c4e8d10dfe03ad0d388f191f97cd4b97ccf8d8081bba + checksum: ae90aa4542d13a3bc86b67dc63a8b26ed74f481b3464fd27094627bd88d54db26aebe1f10de5fcc67e86b667b1a258b14a52df6ed644759a2e7b016071ed6b9b languageName: node linkType: hard @@ -3003,7 +3034,7 @@ __metadata: languageName: node linkType: hard -"@noble/curves@npm:^1.0.0": +"@noble/curves@npm:1.1.0, @noble/curves@npm:^1.0.0": version: 1.1.0 resolution: "@noble/curves@npm:1.1.0" dependencies: @@ -3225,7 +3256,7 @@ __metadata: languageName: node linkType: hard -"@nomicfoundation/hardhat-chai-matchers@npm:^1.0.5": +"@nomicfoundation/hardhat-chai-matchers@npm:^1.0.6": version: 1.0.6 resolution: "@nomicfoundation/hardhat-chai-matchers@npm:1.0.6" dependencies: @@ -3243,7 +3274,7 @@ __metadata: languageName: node linkType: hard -"@nomicfoundation/hardhat-network-helpers@npm:^1.0.7": +"@nomicfoundation/hardhat-network-helpers@npm:^1.0.8": version: 1.0.8 resolution: "@nomicfoundation/hardhat-network-helpers@npm:1.0.8" dependencies: @@ -3254,7 +3285,7 @@ __metadata: languageName: node linkType: hard -"@nomicfoundation/hardhat-toolbox@npm:^2.0.0": +"@nomicfoundation/hardhat-toolbox@npm:^2.0.2": version: 2.0.2 resolution: "@nomicfoundation/hardhat-toolbox@npm:2.0.2" peerDependencies: @@ -3390,7 +3421,7 @@ __metadata: languageName: node linkType: hard -"@nomiclabs/hardhat-ethers@npm:^2.2.1": +"@nomiclabs/hardhat-ethers@npm:^2.2.3": version: 2.2.3 resolution: "@nomiclabs/hardhat-ethers@npm:2.2.3" peerDependencies: @@ -3400,7 +3431,7 @@ __metadata: languageName: node linkType: hard -"@nomiclabs/hardhat-etherscan@npm:^3.1.4": +"@nomiclabs/hardhat-etherscan@npm:^3.1.7": version: 3.1.7 resolution: "@nomiclabs/hardhat-etherscan@npm:3.1.7" dependencies: @@ -3443,6 +3474,13 @@ __metadata: languageName: node linkType: hard +"@openzeppelin/contracts@npm:^4.9.3": + version: 4.9.3 + resolution: "@openzeppelin/contracts@npm:4.9.3" + checksum: 4932063e733b35fa7669b9fe2053f69b062366c5c208b0c6cfa1ac451712100c78acff98120c3a4b88d94154c802be05d160d71f37e7d74cadbe150964458838 + languageName: node + linkType: hard + "@pedrouid/environment@npm:^1.0.1": version: 1.0.1 resolution: "@pedrouid/environment@npm:1.0.1" @@ -3496,10 +3534,10 @@ __metadata: languageName: node linkType: hard -"@remix-run/router@npm:1.7.1": - version: 1.7.1 - resolution: "@remix-run/router@npm:1.7.1" - checksum: d13ad7e0b3b35379f8fdec1eec4f515325b618e431915e12fb9f1cd812ee959add0e7045edcb229ba17888ecfc787869b64e6cb4153ae3be148887e234b6ffac +"@remix-run/router@npm:1.8.0": + version: 1.8.0 + resolution: "@remix-run/router@npm:1.8.0" + checksum: f754f02d3b4fc86791b88acf16065000609e2324b9436027844a76831c7107c0994067cb83abdd6093c282bd518a5c89b5e02aead585782978586e3a04534428 languageName: node linkType: hard @@ -3612,9 +3650,9 @@ __metadata: languageName: node linkType: hard -"@safe-global/safe-core-sdk@npm:^3.3.1": - version: 3.3.4 - resolution: "@safe-global/safe-core-sdk@npm:3.3.4" +"@safe-global/safe-core-sdk@npm:^3.3.5": + version: 3.3.5 + resolution: "@safe-global/safe-core-sdk@npm:3.3.5" dependencies: "@ethersproject/solidity": ^5.7.0 "@safe-global/safe-core-sdk-types": ^1.9.2 @@ -3623,7 +3661,8 @@ __metadata: ethereumjs-util: ^7.1.5 semver: ^7.3.8 web3-utils: ^1.8.1 - checksum: c995aab2f1a5b75d80fbd4ef23a4cd24ebd4d65af0f99933d734f1e526d52a7e9bd8bd70ec3f4394a79a6b2d23d7bd75043d4406c516fbe6e0fb608b65a60c75 + zksync-web3: ^0.14.3 + checksum: 5a2cb9b61c90fee9edc88222017fecc1db55dca52c0f5cda462da4e9905ff5a398382eb9df2c29b76860fa9ff8322da4267662ebc02010b41495a9d3eacca6af languageName: node linkType: hard @@ -3971,7 +4010,7 @@ __metadata: languageName: node linkType: hard -"@stablelib/random@npm:1.0.2, @stablelib/random@npm:^1.0.1, @stablelib/random@npm:^1.0.2": +"@stablelib/random@npm:^1.0.1, @stablelib/random@npm:^1.0.2": version: 1.0.2 resolution: "@stablelib/random@npm:1.0.2" dependencies: @@ -4268,7 +4307,7 @@ __metadata: languageName: node linkType: hard -"@typechain/ethers-v5@npm:^10.2.0": +"@typechain/ethers-v5@npm:^10.2.1": version: 10.2.1 resolution: "@typechain/ethers-v5@npm:10.2.1" dependencies: @@ -4284,7 +4323,7 @@ __metadata: languageName: node linkType: hard -"@typechain/hardhat@npm:^6.1.5": +"@typechain/hardhat@npm:^6.1.6": version: 6.1.6 resolution: "@typechain/hardhat@npm:6.1.6" dependencies: @@ -4387,7 +4426,7 @@ __metadata: languageName: node linkType: hard -"@types/chai@npm:*, @types/chai@npm:^4.3.4": +"@types/chai@npm:*, @types/chai@npm:^4.3.5": version: 4.3.5 resolution: "@types/chai@npm:4.3.5" checksum: c8f26a88c6b5b53a3275c7f5ff8f107028e3cbb9ff26795fff5f3d9dea07106a54ce9e2dce5e40347f7c4cc35657900aaf0c83934a25a1ae12e61e0f5516e431 @@ -4642,10 +4681,10 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:^18.11.18": - version: 18.16.19 - resolution: "@types/node@npm:18.16.19" - checksum: 63c31f09616508aa7135380a4c79470a897b75f9ff3a70eb069e534dfabdec3f32fb0f9df5939127f1086614d980ddea0fa5e8cc29a49103c4f74cd687618aaf +"@types/node@npm:^18.17.5": + version: 18.17.5 + resolution: "@types/node@npm:18.17.5" + checksum: b8c658a99234b99425243c324b641ed7b9ceb6bee6b06421fdc9bb7c58f9a5552e353225cc549e6982462ac384abe1985022ed76e2e4728797f59b21f659ca2b languageName: node linkType: hard @@ -4725,7 +4764,7 @@ __metadata: languageName: node linkType: hard -"@types/react-dom@npm:^18.0.0": +"@types/react-dom@npm:^18.2.7": version: 18.2.7 resolution: "@types/react-dom@npm:18.2.7" dependencies: @@ -4734,7 +4773,7 @@ __metadata: languageName: node linkType: hard -"@types/react@npm:*, @types/react@npm:^18.0.0": +"@types/react@npm:*": version: 18.2.14 resolution: "@types/react@npm:18.2.14" dependencies: @@ -4745,6 +4784,17 @@ __metadata: languageName: node linkType: hard +"@types/react@npm:^18.2.20": + version: 18.2.20 + resolution: "@types/react@npm:18.2.20" + dependencies: + "@types/prop-types": "*" + "@types/scheduler": "*" + csstype: ^3.0.2 + checksum: 30f699c60e5e4bfef273ce64d320651cdd60f5c6a08361c6c7eca8cebcccda1ac953d2ee57c9f321b5ae87f8a62c72b6d35ca42df0e261d337849952daab2141 + languageName: node + linkType: hard + "@types/readable-stream@npm:^2.3.13": version: 2.3.15 resolution: "@types/readable-stream@npm:2.3.15" @@ -4856,7 +4906,7 @@ __metadata: languageName: node linkType: hard -"@types/ws@npm:^8.5.5": +"@types/ws@npm:^8.5.4, @types/ws@npm:^8.5.5": version: 8.5.5 resolution: "@types/ws@npm:8.5.5" dependencies: @@ -4890,7 +4940,7 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:^5.5.0, @typescript-eslint/eslint-plugin@npm:^5.9.0": +"@typescript-eslint/eslint-plugin@npm:^5.5.0, @typescript-eslint/eslint-plugin@npm:^5.62.0": version: 5.62.0 resolution: "@typescript-eslint/eslint-plugin@npm:5.62.0" dependencies: @@ -4925,7 +4975,7 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/parser@npm:^5.5.0, @typescript-eslint/parser@npm:^5.9.0": +"@typescript-eslint/parser@npm:^5.5.0, @typescript-eslint/parser@npm:^5.62.0": version: 5.62.0 resolution: "@typescript-eslint/parser@npm:5.62.0" dependencies: @@ -5022,70 +5072,58 @@ __metadata: languageName: node linkType: hard -"@wagmi/chains@npm:1.0.0": - version: 1.0.0 - resolution: "@wagmi/chains@npm:1.0.0" - peerDependencies: - typescript: ">=5.0.4" - peerDependenciesMeta: - typescript: - optional: true - checksum: b2e6b84946a276804948819b378ecf55b0cd3be762721f9b2cc5e82359d2053ab3b7b7edb6e32453c8fd001b4107a61a792c481f83f9edf04483666dfe910747 - languageName: node - linkType: hard - -"@wagmi/chains@npm:1.1.0": - version: 1.1.0 - resolution: "@wagmi/chains@npm:1.1.0" +"@wagmi/chains@npm:1.2.0": + version: 1.2.0 + resolution: "@wagmi/chains@npm:1.2.0" peerDependencies: typescript: ">=5.0.4" peerDependenciesMeta: typescript: optional: true - checksum: 3359df95f61120450dbe526f29860c60a9dc795dcfa5e6b2133b0b7662708f0d3998e99fae7f8337e3a92d97fcfa0e9900d88721d820dd3a8bf43832cedd8a64 + checksum: adac1caf245820bb50292bf2509be195e8efb3b349dc2ac0e0ed7370993b5fed93db57deaf4d27192b20e8418e9f10cdc7a59bd0a6ce1ac0447e61af76efe423 languageName: node linkType: hard -"@wagmi/chains@npm:1.2.0": - version: 1.2.0 - resolution: "@wagmi/chains@npm:1.2.0" +"@wagmi/chains@npm:1.6.0": + version: 1.6.0 + resolution: "@wagmi/chains@npm:1.6.0" peerDependencies: typescript: ">=5.0.4" peerDependenciesMeta: typescript: optional: true - checksum: adac1caf245820bb50292bf2509be195e8efb3b349dc2ac0e0ed7370993b5fed93db57deaf4d27192b20e8418e9f10cdc7a59bd0a6ce1ac0447e61af76efe423 + checksum: 6c3d477936622f763b9e44c4a66c080020f1119165c8f6b840c51f5822880fedd5031036461d4b28df5cf1ae19cb12e139e4a4b3c129b475f0363fd9c4c8bb0d languageName: node linkType: hard -"@wagmi/chains@npm:1.5.0": - version: 1.5.0 - resolution: "@wagmi/chains@npm:1.5.0" +"@wagmi/chains@npm:1.7.0": + version: 1.7.0 + resolution: "@wagmi/chains@npm:1.7.0" peerDependencies: typescript: ">=5.0.4" peerDependenciesMeta: typescript: optional: true - checksum: 01605859fa22580b418a17fc57cfe8da6a65973e390a691be7f7c3f94c5469504b21e9dc29f296d20b48f756fe4d08088dacb82216327d6173d4be5899f865c8 + checksum: 24e930d2432def5d7cbba1d390622d2cb02f002c45d3806e5a95a814af058eb483a234cc1ad5eef650bc926641b6f31e795fb3941b25de585b58dd31407a4980 languageName: node linkType: hard -"@wagmi/connectors@npm:2.6.6": - version: 2.6.6 - resolution: "@wagmi/connectors@npm:2.6.6" +"@wagmi/connectors@npm:2.7.0": + version: 2.7.0 + resolution: "@wagmi/connectors@npm:2.7.0" dependencies: "@coinbase/wallet-sdk": ^3.6.6 "@ledgerhq/connect-kit-loader": ^1.1.0 "@safe-global/safe-apps-provider": ^0.17.1 "@safe-global/safe-apps-sdk": ^8.0.0 - "@walletconnect/ethereum-provider": 2.9.0 + "@walletconnect/ethereum-provider": 2.9.2 "@walletconnect/legacy-provider": ^2.0.0 - "@walletconnect/modal": 2.5.9 - "@walletconnect/utils": 2.9.0 + "@walletconnect/modal": 2.6.1 + "@walletconnect/utils": 2.9.2 abitype: 0.8.7 eventemitter3: ^4.0.7 peerDependencies: - "@wagmi/chains": ">=1.3.0" + "@wagmi/chains": ">=1.7.0" typescript: ">=5.0.4" viem: ">=0.3.35" peerDependenciesMeta: @@ -5093,16 +5131,16 @@ __metadata: optional: true typescript: optional: true - checksum: a7806bb43ecd5a63420812b531e7e82de59004898595709aed1af6d11b869edf99407024661048e8828710c1ce81898641ebcc64c0c83d255b05b59882e585a1 + checksum: be422a00ada744042b5945d725eef60cfa37f79a8cfe81e4a77c8ecf77acddd20a0970c8dabad737d86244e9e3fc5275f99df057d636ab1e1b5443cce6bf1ced languageName: node linkType: hard -"@wagmi/core@npm:1.3.7": - version: 1.3.7 - resolution: "@wagmi/core@npm:1.3.7" +"@wagmi/core@npm:1.3.9": + version: 1.3.9 + resolution: "@wagmi/core@npm:1.3.9" dependencies: - "@wagmi/chains": 1.5.0 - "@wagmi/connectors": 2.6.6 + "@wagmi/chains": 1.7.0 + "@wagmi/connectors": 2.7.0 abitype: 0.8.7 eventemitter3: ^4.0.7 zustand: ^4.3.1 @@ -5112,28 +5150,28 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 081325b2ff1af99580d9474a03eb03746c2f384302a59abf0a4c4c561a95150a59a0a400c80af368a710f8b1ba204527d8cccfca8fd60e775ca8eaec25af5fdd + checksum: 80cb7c3a064174ba275af91b691c8fc1861ec0fcee063b9ce21f2d3ca84e742c57aabab2850dc3af274286e2df07523339bb2c5bdece21664aa722bc9468e71d languageName: node linkType: hard -"@walletconnect/auth-client@npm:2.1.0": - version: 2.1.0 - resolution: "@walletconnect/auth-client@npm:2.1.0" +"@walletconnect/auth-client@npm:2.1.1": + version: 2.1.1 + resolution: "@walletconnect/auth-client@npm:2.1.1" dependencies: "@ethersproject/hash": ^5.7.0 "@ethersproject/transactions": ^5.7.0 - "@stablelib/random": 1.0.2 + "@stablelib/random": ^1.0.2 "@stablelib/sha256": ^1.0.1 - "@walletconnect/core": ^2.7.2 + "@walletconnect/core": ^2.9.0 "@walletconnect/events": ^1.0.1 - "@walletconnect/heartbeat": ^1.2.0 - "@walletconnect/jsonrpc-utils": ^1.0.7 + "@walletconnect/heartbeat": ^1.2.1 + "@walletconnect/jsonrpc-utils": ^1.0.8 "@walletconnect/logger": ^2.0.1 "@walletconnect/time": ^1.0.2 - "@walletconnect/utils": ^2.7.2 + "@walletconnect/utils": ^2.9.0 events: ^3.3.0 isomorphic-unfetch: ^3.1.0 - checksum: 07697136a85af037e24b0b8a32de97fa55b2a851b3d6c03c44fc96f8c0ae457eb4a4cef7891b95b8464c2b2ecd93841eda3657e2f4572773c87d4240ccb1ff72 + checksum: 8597b88efa20318a1fd1ba0708f10daf889f20308e3a3c755d51b4021c5b071b69ef8894b177c37721fd30876cae0f44a52d043e02b1dc927abf777cb712ff04 languageName: node linkType: hard @@ -5162,50 +5200,50 @@ __metadata: languageName: node linkType: hard -"@walletconnect/core@npm:2.7.0": - version: 2.7.0 - resolution: "@walletconnect/core@npm:2.7.0" +"@walletconnect/core@npm:2.10.0, @walletconnect/core@npm:^2.10.0, @walletconnect/core@npm:^2.9.0": + version: 2.10.0 + resolution: "@walletconnect/core@npm:2.10.0" dependencies: "@walletconnect/heartbeat": 1.2.1 - "@walletconnect/jsonrpc-provider": ^1.0.12 - "@walletconnect/jsonrpc-utils": ^1.0.7 - "@walletconnect/jsonrpc-ws-connection": ^1.0.11 + "@walletconnect/jsonrpc-provider": 1.0.13 + "@walletconnect/jsonrpc-types": 1.0.3 + "@walletconnect/jsonrpc-utils": 1.0.8 + "@walletconnect/jsonrpc-ws-connection": 1.0.13 "@walletconnect/keyvaluestorage": ^1.0.2 "@walletconnect/logger": ^2.0.1 "@walletconnect/relay-api": ^1.0.9 "@walletconnect/relay-auth": ^1.0.4 "@walletconnect/safe-json": ^1.0.2 "@walletconnect/time": ^1.0.2 - "@walletconnect/types": 2.7.0 - "@walletconnect/utils": 2.7.0 + "@walletconnect/types": 2.10.0 + "@walletconnect/utils": 2.10.0 events: ^3.3.0 lodash.isequal: 4.5.0 uint8arrays: ^3.1.0 - checksum: 86017de59ef2fd48638897878aad109cb43b2bf40ec4c172972389e6569eb3228fe662ae022e345f38432b890d0b39059cc5fda3f3607f8e9024b587b26a5d70 + checksum: 5ad207b07ef651d143a9305e8f3a96b8c50e186b7144387c8e54d826d24cf7fdc86ab333e44b2c2d8bf1c4aa48744586cb69b783ae64c86c3dc5355750f17bf2 languageName: node linkType: hard -"@walletconnect/core@npm:2.9.0, @walletconnect/core@npm:^2.7.2, @walletconnect/core@npm:^2.7.3": - version: 2.9.0 - resolution: "@walletconnect/core@npm:2.9.0" +"@walletconnect/core@npm:2.7.0": + version: 2.7.0 + resolution: "@walletconnect/core@npm:2.7.0" dependencies: "@walletconnect/heartbeat": 1.2.1 - "@walletconnect/jsonrpc-provider": 1.0.13 - "@walletconnect/jsonrpc-types": 1.0.3 - "@walletconnect/jsonrpc-utils": 1.0.8 - "@walletconnect/jsonrpc-ws-connection": 1.0.12 + "@walletconnect/jsonrpc-provider": ^1.0.12 + "@walletconnect/jsonrpc-utils": ^1.0.7 + "@walletconnect/jsonrpc-ws-connection": ^1.0.11 "@walletconnect/keyvaluestorage": ^1.0.2 "@walletconnect/logger": ^2.0.1 "@walletconnect/relay-api": ^1.0.9 "@walletconnect/relay-auth": ^1.0.4 "@walletconnect/safe-json": ^1.0.2 "@walletconnect/time": ^1.0.2 - "@walletconnect/types": 2.9.0 - "@walletconnect/utils": 2.9.0 + "@walletconnect/types": 2.7.0 + "@walletconnect/utils": 2.7.0 events: ^3.3.0 lodash.isequal: 4.5.0 uint8arrays: ^3.1.0 - checksum: c2cba1746e9679bd03e55ecfbf8c0339d3122ee31e87e8a690778263ff5c8c371ab5301445da2139711e6522d33946e9fbf640e5238241b2b2e7a394b23c2a00 + checksum: 86017de59ef2fd48638897878aad109cb43b2bf40ec4c172972389e6569eb3228fe662ae022e345f38432b890d0b39059cc5fda3f3607f8e9024b587b26a5d70 languageName: node linkType: hard @@ -5286,7 +5324,7 @@ __metadata: languageName: node linkType: hard -"@walletconnect/heartbeat@npm:1.2.1, @walletconnect/heartbeat@npm:^1.2.0": +"@walletconnect/heartbeat@npm:1.2.1, @walletconnect/heartbeat@npm:^1.2.1": version: 1.2.1 resolution: "@walletconnect/heartbeat@npm:1.2.1" dependencies: @@ -5352,20 +5390,7 @@ __metadata: languageName: node linkType: hard -"@walletconnect/jsonrpc-ws-connection@npm:1.0.12": - version: 1.0.12 - resolution: "@walletconnect/jsonrpc-ws-connection@npm:1.0.12" - dependencies: - "@walletconnect/jsonrpc-utils": ^1.0.6 - "@walletconnect/safe-json": ^1.0.2 - events: ^3.3.0 - tslib: 1.14.1 - ws: ^7.5.1 - checksum: 937811d8d9d56064b2c1676e2d3f00cb4c0aaba2e359391ff93d83836b5e9fd2215fe6e9d435504df99924575f4c796f1e382a40c492f9b6b0da846aef674e05 - languageName: node - linkType: hard - -"@walletconnect/jsonrpc-ws-connection@npm:^1.0.11": +"@walletconnect/jsonrpc-ws-connection@npm:1.0.13, @walletconnect/jsonrpc-ws-connection@npm:^1.0.11": version: 1.0.13 resolution: "@walletconnect/jsonrpc-ws-connection@npm:1.0.13" dependencies: @@ -5476,35 +5501,34 @@ __metadata: languageName: node linkType: hard -"@walletconnect/modal-core@npm:2.5.9": - version: 2.5.9 - resolution: "@walletconnect/modal-core@npm:2.5.9" +"@walletconnect/modal-core@npm:2.6.1": + version: 2.6.1 + resolution: "@walletconnect/modal-core@npm:2.6.1" dependencies: - buffer: 6.0.3 - valtio: 1.10.6 - checksum: dfcb0b7a50febafe08fd80fec2b31b86722a27aedad8ee0656af895e2c8b1a2c8a91c7bb5f968bea5b8de9ab7fc908c6f52cef194f949e37da597acd0f1a263b + valtio: 1.11.0 + checksum: 3c1dcb865cc0737bb0e77b7103bde7167e64a8790c628427814b825dafa133c7cb3baf5184314de35a2dbd743a3b0978ef4abc86c3bb63d051f8368e3bdba67a languageName: node linkType: hard -"@walletconnect/modal-ui@npm:2.5.9": - version: 2.5.9 - resolution: "@walletconnect/modal-ui@npm:2.5.9" +"@walletconnect/modal-ui@npm:2.6.1": + version: 2.6.1 + resolution: "@walletconnect/modal-ui@npm:2.6.1" dependencies: - "@walletconnect/modal-core": 2.5.9 - lit: 2.7.5 + "@walletconnect/modal-core": 2.6.1 + lit: 2.7.6 motion: 10.16.2 qrcode: 1.5.3 - checksum: c0050715734b532f75b81c3abb75c6cce513b1481c9cec66f648aa698ddd3af4ec70978a0976b06843229e6f7ea14cc927432dc66cfe53967db7d96c9437f692 + checksum: 34408c784659564ef57fe59227f5f0a307ec34dc9e73c6c7b72e4c03054024ffbbf1d4ed73425a2606c978aaa3518629eba61adf3fc31263d80a4c13cf1c77d2 languageName: node linkType: hard -"@walletconnect/modal@npm:2.5.9": - version: 2.5.9 - resolution: "@walletconnect/modal@npm:2.5.9" +"@walletconnect/modal@npm:2.6.1": + version: 2.6.1 + resolution: "@walletconnect/modal@npm:2.6.1" dependencies: - "@walletconnect/modal-core": 2.5.9 - "@walletconnect/modal-ui": 2.5.9 - checksum: ba52f4210c238644a2c4d6fbfc1692d7f49e4fa4a85e793aa79c299e9e4d16c0555fcf08bb94726186256aec1e43abb3d7297a61020abe7211f6faac1163dddd + "@walletconnect/modal-core": 2.6.1 + "@walletconnect/modal-ui": 2.6.1 + checksum: f48107abe4594b3a6849a4eae1a3fb9fb37ded25ef390c084e9098ceed58ace1bcb723abfa15027b462d75226a907bbbfc1d48e1414f882b5d7f83903da617bb languageName: node linkType: hard @@ -5560,37 +5584,37 @@ __metadata: languageName: node linkType: hard -"@walletconnect/sign-client@npm:2.7.0": - version: 2.7.0 - resolution: "@walletconnect/sign-client@npm:2.7.0" +"@walletconnect/sign-client@npm:2.10.0": + version: 2.10.0 + resolution: "@walletconnect/sign-client@npm:2.10.0" dependencies: - "@walletconnect/core": 2.7.0 + "@walletconnect/core": 2.10.0 "@walletconnect/events": ^1.0.1 "@walletconnect/heartbeat": 1.2.1 - "@walletconnect/jsonrpc-utils": ^1.0.7 + "@walletconnect/jsonrpc-utils": 1.0.8 "@walletconnect/logger": ^2.0.1 "@walletconnect/time": ^1.0.2 - "@walletconnect/types": 2.7.0 - "@walletconnect/utils": 2.7.0 + "@walletconnect/types": 2.10.0 + "@walletconnect/utils": 2.10.0 events: ^3.3.0 - checksum: 85f6ca56d481616202cedec6e9c8af39e21d7d1ad9c021d54a4831d6b9cf71d684a00049474f8368a09c75c4b9425006d73fbfd6d8ac99f3ec23038b01522564 + checksum: 2d9f30ad8b656b7942add2cba9f7a6b04928ecb058440b9dc1701e74c605e961b518cfef6bee249e7477d1033c05a3e16977b10ed658030bf3be0d135b09afd8 languageName: node linkType: hard -"@walletconnect/sign-client@npm:2.9.0": - version: 2.9.0 - resolution: "@walletconnect/sign-client@npm:2.9.0" +"@walletconnect/sign-client@npm:2.7.0": + version: 2.7.0 + resolution: "@walletconnect/sign-client@npm:2.7.0" dependencies: - "@walletconnect/core": 2.9.0 + "@walletconnect/core": 2.7.0 "@walletconnect/events": ^1.0.1 "@walletconnect/heartbeat": 1.2.1 - "@walletconnect/jsonrpc-utils": 1.0.8 + "@walletconnect/jsonrpc-utils": ^1.0.7 "@walletconnect/logger": ^2.0.1 "@walletconnect/time": ^1.0.2 - "@walletconnect/types": 2.9.0 - "@walletconnect/utils": 2.9.0 + "@walletconnect/types": 2.7.0 + "@walletconnect/utils": 2.7.0 events: ^3.3.0 - checksum: fe35b9b15c62efc9702fd34e883f95dcdbda954ff27b628d2d3d3eb7cb904b0fd6ec9c33b64c314305ba7a4b669d37769e7b9e9a723a0a2cb6b57d6a45aa6171 + checksum: 85f6ca56d481616202cedec6e9c8af39e21d7d1ad9c021d54a4831d6b9cf71d684a00049474f8368a09c75c4b9425006d73fbfd6d8ac99f3ec23038b01522564 languageName: node linkType: hard @@ -5614,6 +5638,20 @@ __metadata: languageName: node linkType: hard +"@walletconnect/types@npm:2.10.0": + version: 2.10.0 + resolution: "@walletconnect/types@npm:2.10.0" + dependencies: + "@walletconnect/events": ^1.0.1 + "@walletconnect/heartbeat": 1.2.1 + "@walletconnect/jsonrpc-types": 1.0.3 + "@walletconnect/keyvaluestorage": ^1.0.2 + "@walletconnect/logger": ^2.0.1 + events: ^3.3.0 + checksum: b32006f192578e28cb5c1dbd757a47ff077e25ac3ea9c9d8fd95b174e47f7f8a76386db5aef52623cf6d349c9816d5cff752095af8d35d79a44a2a26a019839d + languageName: node + linkType: hard + "@walletconnect/types@npm:2.7.0": version: 2.7.0 resolution: "@walletconnect/types@npm:2.7.0" @@ -5628,9 +5666,9 @@ __metadata: languageName: node linkType: hard -"@walletconnect/types@npm:2.9.0": - version: 2.9.0 - resolution: "@walletconnect/types@npm:2.9.0" +"@walletconnect/types@npm:2.9.2": + version: 2.9.2 + resolution: "@walletconnect/types@npm:2.9.2" dependencies: "@walletconnect/events": ^1.0.1 "@walletconnect/heartbeat": 1.2.1 @@ -5638,7 +5676,7 @@ __metadata: "@walletconnect/keyvaluestorage": ^1.0.2 "@walletconnect/logger": ^2.0.1 events: ^3.3.0 - checksum: 147bec3c89cd7194e6df7e3a59560c46bf5b0b8ef58e81f387b3bfeecaa3aecb04b4ac2dbffe11fe671ffdf2f1222178b2fac256ced39e9b3b56c21411362872 + checksum: 81d523cf337f456190b87242ae7843e09f0b1d84127c1138d73420a5cc8e7b05f7f1722dfeaa2ecd12be25331e3896c733e0327221bc51eb6bae192e43b4a99f languageName: node linkType: hard @@ -5667,6 +5705,28 @@ __metadata: languageName: node linkType: hard +"@walletconnect/utils@npm:2.10.0, @walletconnect/utils@npm:^2.9.0": + version: 2.10.0 + resolution: "@walletconnect/utils@npm:2.10.0" + dependencies: + "@stablelib/chacha20poly1305": 1.0.1 + "@stablelib/hkdf": 1.0.1 + "@stablelib/random": ^1.0.2 + "@stablelib/sha256": 1.0.1 + "@stablelib/x25519": ^1.0.3 + "@walletconnect/relay-api": ^1.0.9 + "@walletconnect/safe-json": ^1.0.2 + "@walletconnect/time": ^1.0.2 + "@walletconnect/types": 2.10.0 + "@walletconnect/window-getters": ^1.0.1 + "@walletconnect/window-metadata": ^1.0.1 + detect-browser: 5.3.0 + query-string: 7.1.3 + uint8arrays: ^3.1.0 + checksum: a1a99e062ce758d28cbbe286efd1fe47f98b5c936a429d2c42700135eb8672b747fdde08384ad5dbf3ec394a7fd7837bbe6d3be0f80445b949f336923517cfc2 + languageName: node + linkType: hard + "@walletconnect/utils@npm:2.7.0": version: 2.7.0 resolution: "@walletconnect/utils@npm:2.7.0" @@ -5690,9 +5750,9 @@ __metadata: languageName: node linkType: hard -"@walletconnect/utils@npm:2.9.0, @walletconnect/utils@npm:^2.7.2": - version: 2.9.0 - resolution: "@walletconnect/utils@npm:2.9.0" +"@walletconnect/utils@npm:2.9.2": + version: 2.9.2 + resolution: "@walletconnect/utils@npm:2.9.2" dependencies: "@stablelib/chacha20poly1305": 1.0.1 "@stablelib/hkdf": 1.0.1 @@ -5702,13 +5762,13 @@ __metadata: "@walletconnect/relay-api": ^1.0.9 "@walletconnect/safe-json": ^1.0.2 "@walletconnect/time": ^1.0.2 - "@walletconnect/types": 2.9.0 + "@walletconnect/types": 2.9.2 "@walletconnect/window-getters": ^1.0.1 "@walletconnect/window-metadata": ^1.0.1 detect-browser: 5.3.0 query-string: 7.1.3 uint8arrays: ^3.1.0 - checksum: 83592e6b793d16ddcaa7d904cc1a420b1a7240c9a5263a8ff7d7304f7f1194a2f98e1a69f68b10628e1178541c135d722d3844509678a88f6660c03a076eb755 + checksum: 9caf05fa6f7c95945e675845e305220fc1e7832ae595a9ff39799195d2d5865972914f74a8768044473f45450e98db685a0ff965a09d9cd0220cfdc391279eab languageName: node linkType: hard @@ -5727,19 +5787,19 @@ __metadata: languageName: node linkType: hard -"@walletconnect/web3wallet@npm:^1.7.1": - version: 1.8.6 - resolution: "@walletconnect/web3wallet@npm:1.8.6" +"@walletconnect/web3wallet@npm:^1.9.0": + version: 1.9.0 + resolution: "@walletconnect/web3wallet@npm:1.9.0" dependencies: - "@walletconnect/auth-client": 2.1.0 - "@walletconnect/core": 2.9.0 + "@walletconnect/auth-client": 2.1.1 + "@walletconnect/core": 2.10.0 "@walletconnect/jsonrpc-provider": 1.0.13 "@walletconnect/jsonrpc-utils": 1.0.8 "@walletconnect/logger": 2.0.1 - "@walletconnect/sign-client": 2.9.0 - "@walletconnect/types": 2.9.0 - "@walletconnect/utils": 2.9.0 - checksum: 6c4b3e60dfd439ea339dda48f625edef5bf5d3aea8af6ea254dd02d21ec67eead76a53c9bf55a856855c875fc87bb13f1ea61ee5fb1bba9a0240d1e009d850a1 + "@walletconnect/sign-client": 2.10.0 + "@walletconnect/types": 2.10.0 + "@walletconnect/utils": 2.10.0 + checksum: 63380d2b1862a5d0f4b763cf418e4394249b52af8377d15b6a882f4e1fc51b9955a2c1767ac0ceb07a5fcb766629856d269e14e1a52cd3eeea16818baea32bfe languageName: node linkType: hard @@ -5788,35 +5848,35 @@ __metadata: languageName: node linkType: hard -"@web3modal/core@npm:2.7.0": - version: 2.7.0 - resolution: "@web3modal/core@npm:2.7.0" +"@web3modal/core@npm:2.7.1": + version: 2.7.1 + resolution: "@web3modal/core@npm:2.7.1" dependencies: - valtio: 1.10.7 - checksum: 6509518cb44bce65edcc5d071b7b3105ced1a5e3298f5ad7b4e76aa6ec8134e34906f4ae475ac079c75fbe1cce9ebb8cea369449c1d9575deb13e86044f57f33 + valtio: 1.11.0 + checksum: 5f41bf44047e48a717b04167b482dc12d48ac5c4af5acc183c1dbfb400d945eb6139e894ecfd9875541c587d3323e219026328d260d01d50c3116f9ff373ec85 languageName: node linkType: hard -"@web3modal/ethereum@npm:^2.7.0": - version: 2.7.0 - resolution: "@web3modal/ethereum@npm:2.7.0" +"@web3modal/ethereum@npm:^2.7.1": + version: 2.7.1 + resolution: "@web3modal/ethereum@npm:2.7.1" peerDependencies: "@wagmi/core": ">=1" viem: ">=1" - checksum: c99bbf6ee6385478bc5870f244bb41070fc8d3a3e3f57f1fae338e4154b21cef5169963d52d8a85e569c9801e97a0ac5460275d518a2fe3b8f5a86ae79e98ceb + checksum: 272aca6b3d4647183b3bcd2ab126101b7b42bc70d13ebb744d8386ddb00105bdc6f31ca0feb2e339179fc66b95865836d24f31c3d3f5c0e0c0a636c66329f6d8 languageName: node linkType: hard -"@web3modal/react@npm:^2.7.0": - version: 2.7.0 - resolution: "@web3modal/react@npm:2.7.0" +"@web3modal/react@npm:^2.7.1": + version: 2.7.1 + resolution: "@web3modal/react@npm:2.7.1" dependencies: - "@web3modal/core": 2.7.0 - "@web3modal/ui": 2.7.0 + "@web3modal/core": 2.7.1 + "@web3modal/ui": 2.7.1 peerDependencies: react: ">=17" react-dom: ">=17" - checksum: 9eb7ac3c601f5c6e312c26957e2dadad805305e7740336e7245a386ee0cfb28727c758a35ce88fa3564c2a80d53680be10d82beea841b8146350ea6eef4417f1 + checksum: 14793cf61ccea770b0b07a999d4f667f712fd24748eed0a664c5a43df493b87b6fc7f3001daa580cecd1c00ef85102257548209bffdf270ffba1fc8c21ce064f languageName: node linkType: hard @@ -5842,15 +5902,15 @@ __metadata: languageName: node linkType: hard -"@web3modal/ui@npm:2.7.0": - version: 2.7.0 - resolution: "@web3modal/ui@npm:2.7.0" +"@web3modal/ui@npm:2.7.1": + version: 2.7.1 + resolution: "@web3modal/ui@npm:2.7.1" dependencies: - "@web3modal/core": 2.7.0 + "@web3modal/core": 2.7.1 lit: 2.7.6 motion: 10.16.2 qrcode: 1.5.3 - checksum: d02ebc7f2058f013749ecba043d0e8840303fc7876315e9cc49f342cddfe9265e30ca04682fcfc70a5f48af4fdd4bc7f7877b16b4d50587952c453fdb5ba42c8 + checksum: 1bb8fa415f7b22a4e9da75d55bab80e7a36429ed2f686f4c4ee55379cd41205a17913dc30a82e374d74238111cd37ed5e737d00b6b62f6aff5fffefc2336a9fc languageName: node linkType: hard @@ -6078,12 +6138,18 @@ __metadata: languageName: node linkType: hard -"abort-controller@npm:^3.0.0": - version: 3.0.0 - resolution: "abort-controller@npm:3.0.0" - dependencies: - event-target-shim: ^5.0.0 - checksum: 170bdba9b47b7e65906a28c8ce4f38a7a369d78e2271706f020849c1bfe0ee2067d4261df8bbb66eb84f79208fd5b710df759d64191db58cfba7ce8ef9c54b75 +"abitype@npm:0.9.3": + version: 0.9.3 + resolution: "abitype@npm:0.9.3" + peerDependencies: + typescript: ">=5.0.4" + zod: ^3 >=3.19.1 + peerDependenciesMeta: + typescript: + optional: true + zod: + optional: true + checksum: f97c5a118180563b9ed8b97da492a82d3ce53dcd7d96c87764e90dbe84c04ae72dd5703d1ed5a54601033ab1772b8a235a1b5aadaf7aad6c4b5fdad7fd3a69a7 languageName: node linkType: hard @@ -6584,6 +6650,19 @@ __metadata: languageName: node linkType: hard +"array.prototype.findlastindex@npm:^1.2.2": + version: 1.2.2 + resolution: "array.prototype.findlastindex@npm:1.2.2" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.1.4 + es-abstract: ^1.20.4 + es-shim-unscopables: ^1.0.0 + get-intrinsic: ^1.1.3 + checksum: 8a166359f69a2a751c843f26b9c8cd03d0dc396a92cdcb85f4126b5f1cecdae5b2c0c616a71ea8aff026bde68165b44950b3664404bb73db0673e288495ba264 + languageName: node + linkType: hard + "array.prototype.flat@npm:^1.3.1": version: 1.3.1 resolution: "array.prototype.flat@npm:1.3.1" @@ -8989,7 +9068,7 @@ __metadata: languageName: node linkType: hard -"dotenv@npm:^16.0.3": +"dotenv@npm:^16.0.3, dotenv@npm:^16.3.1": version: 16.3.1 resolution: "dotenv@npm:16.3.1" checksum: 15d75e7279018f4bafd0ee9706593dd14455ddb71b3bcba9c52574460b7ccaf67d5cf8b2c08a5af1a9da6db36c956a04a1192b101ee102a3e0cf8817bbcf3dfd @@ -9460,14 +9539,14 @@ __metadata: languageName: node linkType: hard -"eslint-config-prettier@npm:^8.3.0": - version: 8.8.0 - resolution: "eslint-config-prettier@npm:8.8.0" +"eslint-config-prettier@npm:^8.10.0": + version: 8.10.0 + resolution: "eslint-config-prettier@npm:8.10.0" peerDependencies: eslint: ">=7.0.0" bin: eslint-config-prettier: bin/cli.js - checksum: 1e94c3882c4d5e41e1dcfa2c368dbccbfe3134f6ac7d40101644d3bfbe3eb2f2ffac757f3145910b5eacf20c0e85e02b91293d3126d770cbf3dc390b3564681c + checksum: 153266badd477e49b0759816246b2132f1dbdb6c7f313ca60a9af5822fd1071c2bc5684a3720d78b725452bbac04bb130878b2513aea5e72b1b792de5a69fec8 languageName: node linkType: hard @@ -9506,7 +9585,7 @@ __metadata: languageName: node linkType: hard -"eslint-module-utils@npm:^2.7.4": +"eslint-module-utils@npm:^2.7.4, eslint-module-utils@npm:^2.8.0": version: 2.8.0 resolution: "eslint-module-utils@npm:2.8.0" dependencies: @@ -9544,7 +9623,7 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-import@npm:^2.25.3, eslint-plugin-import@npm:^2.25.4": +"eslint-plugin-import@npm:^2.25.3": version: 2.27.5 resolution: "eslint-plugin-import@npm:2.27.5" dependencies: @@ -9569,6 +9648,34 @@ __metadata: languageName: node linkType: hard +"eslint-plugin-import@npm:^2.28.0": + version: 2.28.0 + resolution: "eslint-plugin-import@npm:2.28.0" + dependencies: + array-includes: ^3.1.6 + array.prototype.findlastindex: ^1.2.2 + array.prototype.flat: ^1.3.1 + array.prototype.flatmap: ^1.3.1 + debug: ^3.2.7 + doctrine: ^2.1.0 + eslint-import-resolver-node: ^0.3.7 + eslint-module-utils: ^2.8.0 + has: ^1.0.3 + is-core-module: ^2.12.1 + is-glob: ^4.0.3 + minimatch: ^3.1.2 + object.fromentries: ^2.0.6 + object.groupby: ^1.0.0 + object.values: ^1.1.6 + resolve: ^1.22.3 + semver: ^6.3.1 + tsconfig-paths: ^3.14.2 + peerDependencies: + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 + checksum: f9eba311b93ca1bb89311856b1f7285bd79e0181d7eb70fe115053ff77e2235fea749b30f538b78927dc65769340b5be61f4c9581d1c82bcdcccb2061f440ad1 + languageName: node + linkType: hard + "eslint-plugin-jest@npm:^25.3.0": version: 25.7.0 resolution: "eslint-plugin-jest@npm:25.7.0" @@ -9612,7 +9719,7 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-prettier@npm:^4.0.0": +"eslint-plugin-prettier@npm:^4.2.1": version: 4.2.1 resolution: "eslint-plugin-prettier@npm:4.2.1" dependencies: @@ -9692,6 +9799,16 @@ __metadata: languageName: node linkType: hard +"eslint-scope@npm:^7.2.2": + version: 7.2.2 + resolution: "eslint-scope@npm:7.2.2" + dependencies: + esrecurse: ^4.3.0 + estraverse: ^5.2.0 + checksum: ec97dbf5fb04b94e8f4c5a91a7f0a6dd3c55e46bfc7bbcd0e3138c3a76977570e02ed89a1810c778dcd72072ff0e9621ba1379b4babe53921d71e2e4486fda3e + languageName: node + linkType: hard + "eslint-visitor-keys@npm:^2.1.0": version: 2.1.0 resolution: "eslint-visitor-keys@npm:2.1.0" @@ -9706,6 +9823,13 @@ __metadata: languageName: node linkType: hard +"eslint-visitor-keys@npm:^3.4.3": + version: 3.4.3 + resolution: "eslint-visitor-keys@npm:3.4.3" + checksum: 36e9ef87fca698b6fd7ca5ca35d7b2b6eeaaf106572e2f7fd31c12d3bfdaccdb587bba6d3621067e5aece31c8c3a348b93922ab8f7b2cbc6aaab5e1d89040c60 + languageName: node + linkType: hard + "eslint-webpack-plugin@npm:^3.1.1": version: 3.2.0 resolution: "eslint-webpack-plugin@npm:3.2.0" @@ -9722,7 +9846,7 @@ __metadata: languageName: node linkType: hard -"eslint@npm:^8.3.0, eslint@npm:^8.6.0": +"eslint@npm:^8.3.0": version: 8.44.0 resolution: "eslint@npm:8.44.0" dependencies: @@ -9771,6 +9895,53 @@ __metadata: languageName: node linkType: hard +"eslint@npm:^8.47.0": + version: 8.47.0 + resolution: "eslint@npm:8.47.0" + dependencies: + "@eslint-community/eslint-utils": ^4.2.0 + "@eslint-community/regexpp": ^4.6.1 + "@eslint/eslintrc": ^2.1.2 + "@eslint/js": ^8.47.0 + "@humanwhocodes/config-array": ^0.11.10 + "@humanwhocodes/module-importer": ^1.0.1 + "@nodelib/fs.walk": ^1.2.8 + ajv: ^6.12.4 + chalk: ^4.0.0 + cross-spawn: ^7.0.2 + debug: ^4.3.2 + doctrine: ^3.0.0 + escape-string-regexp: ^4.0.0 + eslint-scope: ^7.2.2 + eslint-visitor-keys: ^3.4.3 + espree: ^9.6.1 + esquery: ^1.4.2 + esutils: ^2.0.2 + fast-deep-equal: ^3.1.3 + file-entry-cache: ^6.0.1 + find-up: ^5.0.0 + glob-parent: ^6.0.2 + globals: ^13.19.0 + graphemer: ^1.4.0 + ignore: ^5.2.0 + imurmurhash: ^0.1.4 + is-glob: ^4.0.0 + is-path-inside: ^3.0.3 + js-yaml: ^4.1.0 + json-stable-stringify-without-jsonify: ^1.0.1 + levn: ^0.4.1 + lodash.merge: ^4.6.2 + minimatch: ^3.1.2 + natural-compare: ^1.4.0 + optionator: ^0.9.3 + strip-ansi: ^6.0.1 + text-table: ^0.2.0 + bin: + eslint: bin/eslint.js + checksum: 1988617f703eadc5c7540468d54dc8e5171cf2bb9483f6172799cd1ff54a9a5e4470f003784e8cef92687eaa14de37172732787040e67817581a20bcb9c15970 + languageName: node + linkType: hard + "espree@npm:^9.6.0": version: 9.6.0 resolution: "espree@npm:9.6.0" @@ -9782,6 +9953,17 @@ __metadata: languageName: node linkType: hard +"espree@npm:^9.6.1": + version: 9.6.1 + resolution: "espree@npm:9.6.1" + dependencies: + acorn: ^8.9.0 + acorn-jsx: ^5.3.2 + eslint-visitor-keys: ^3.4.1 + checksum: eb8c149c7a2a77b3f33a5af80c10875c3abd65450f60b8af6db1bfcfa8f101e21c1e56a561c6dc13b848e18148d43469e7cd208506238554fb5395a9ea5a1ab9 + languageName: node + linkType: hard + "esprima@npm:2.7.x, esprima@npm:^2.7.1": version: 2.7.3 resolution: "esprima@npm:2.7.3" @@ -10109,13 +10291,6 @@ __metadata: languageName: node linkType: hard -"event-target-shim@npm:^5.0.0": - version: 5.0.1 - resolution: "event-target-shim@npm:5.0.1" - checksum: 1ffe3bb22a6d51bdeb6bf6f7cf97d2ff4a74b017ad12284cc9e6a279e727dc30a5de6bb613e5596ff4dc3e517841339ad09a7eec44266eccb1aa201a30448166 - languageName: node - linkType: hard - "eventemitter3@npm:4.0.4": version: 4.0.4 resolution: "eventemitter3@npm:4.0.4" @@ -10695,14 +10870,14 @@ __metadata: version: 0.0.0-use.local resolution: "frontend@workspace:frontend" dependencies: - "@types/react": ^18.0.0 - "@types/react-dom": ^18.0.0 + "@types/react": ^18.2.20 + "@types/react-dom": ^18.2.7 "@walletconnect/client": ^1.8.0 - "@walletconnect/core": ^2.7.3 + "@walletconnect/core": ^2.10.0 "@walletconnect/utils": ^1.8.0 - "@walletconnect/web3wallet": ^1.7.1 - "@web3modal/ethereum": ^2.7.0 - "@web3modal/react": ^2.7.0 + "@walletconnect/web3wallet": ^1.9.0 + "@web3modal/ethereum": ^2.7.1 + "@web3modal/react": ^2.7.1 "@web3modal/standalone": ^2.4.3 buffer: ^6.0.3 clsx: ^1.2.1 @@ -10713,12 +10888,12 @@ __metadata: mech-sdk: "workspace:^" react: ^18.2.0 react-dom: ^18.2.0 - react-router-dom: ^6.8.0 + react-router-dom: ^6.15.0 react-scripts: 5.0.1 typescript: ^4.9.5 - typescript-plugin-css-modules: ^4.1.1 - viem: ^0.3.24 - wagmi: ^1.0.4 + typescript-plugin-css-modules: ^4.2.3 + viem: ^1.6.0 + wagmi: ^1.3.10 languageName: unknown linkType: soft @@ -11289,9 +11464,9 @@ __metadata: languageName: node linkType: hard -"hardhat-deploy@npm:^0.11.22": - version: 0.11.34 - resolution: "hardhat-deploy@npm:0.11.34" +"hardhat-deploy@npm:^0.11.36": + version: 0.11.36 + resolution: "hardhat-deploy@npm:0.11.36" dependencies: "@ethersproject/abi": ^5.7.0 "@ethersproject/abstract-signer": ^5.7.0 @@ -11317,7 +11492,7 @@ __metadata: murmur-128: ^0.2.1 qs: ^6.9.4 zksync-web3: ^0.14.3 - checksum: 3c4bcd657a80e4f22c1f8bcee021e5277060849ce4180cbc721e0c2d625f2f98de8ebbfad23875d32eeaf06d88bdba06cb43ab29359cb9531e8bb7851a98ead1 + checksum: 138fa0c22aec9367bd9cf2ff1ca03c2ee8c4c90c7d30ab20da86537533fd2ec53480af4cf6ce985528f3291a260baeb4ef584dbcaba5c0d64ccf27f0dea9a084 languageName: node linkType: hard @@ -11334,9 +11509,9 @@ __metadata: languageName: node linkType: hard -"hardhat@npm:^2.12.5": - version: 2.16.1 - resolution: "hardhat@npm:2.16.1" +"hardhat@npm:^2.17.1": + version: 2.17.1 + resolution: "hardhat@npm:2.17.1" dependencies: "@ethersproject/abi": ^5.1.2 "@metamask/eth-sig-util": ^4.0.0 @@ -11354,7 +11529,6 @@ __metadata: "@sentry/node": ^5.18.1 "@types/bn.js": ^5.1.0 "@types/lru-cache": ^5.1.0 - abort-controller: ^3.0.0 adm-zip: ^0.4.16 aggregate-error: ^3.0.0 ansi-escapes: ^4.3.0 @@ -11397,7 +11571,7 @@ __metadata: optional: true bin: hardhat: internal/cli/bootstrap.js - checksum: 32508ab6463efd796e8805150c182a9b974fcec8e4ab362a95f8bab2b4baf24c4feb48bbee1f3a7165a934f5257e1d3fcfea5764f261404aec23a88066341e48 + checksum: 4986fd535d82e6c6c9e50627daf95b68b97c850dd57fb5b31ac62945c6bcecd2e48e3dbce1d3dec324a01bf903c9cd13c095cc68c3a68cf586880b4b05125254 languageName: node linkType: hard @@ -12097,6 +12271,15 @@ __metadata: languageName: node linkType: hard +"is-core-module@npm:^2.12.1, is-core-module@npm:^2.13.0": + version: 2.13.0 + resolution: "is-core-module@npm:2.13.0" + dependencies: + has: ^1.0.3 + checksum: 053ab101fb390bfeb2333360fd131387bed54e476b26860dc7f5a700bbf34a0ec4454f7c8c4d43e8a0030957e4b3db6e16d35e1890ea6fb654c833095e040355 + languageName: node + linkType: hard + "is-date-object@npm:^1.0.1, is-date-object@npm:^1.0.5": version: 1.0.5 resolution: "is-date-object@npm:1.0.5" @@ -13979,45 +14162,45 @@ __metadata: resolution: "mech-contracts@workspace:." dependencies: "@account-abstraction/contracts": ^0.6.0 - "@ambire/signature-validator": ^1.1.0 - "@erc6551/reference": "https://github.com/erc6551/reference" + "@ambire/signature-validator": ^1.3.1 + "@erc6551/reference": "https://github.com/erc6551/reference.git#commit=df75cd1bab5fb8e320940783df5f14c6d8aaa0f2" "@ethersproject/abi": ^5.7.0 "@ethersproject/bytes": ^5.7.0 "@ethersproject/providers": ^5.7.2 "@gnosis.pm/safe-contracts": ^1.3.0 - "@gnosis.pm/zodiac": ^3.0.0 - "@nomicfoundation/hardhat-chai-matchers": ^1.0.5 - "@nomicfoundation/hardhat-network-helpers": ^1.0.7 - "@nomicfoundation/hardhat-toolbox": ^2.0.0 - "@nomiclabs/hardhat-ethers": ^2.2.1 - "@nomiclabs/hardhat-etherscan": ^3.1.4 - "@openzeppelin/contracts": ^4.8.1 - "@safe-global/safe-core-sdk": ^3.3.1 - "@typechain/ethers-v5": ^10.2.0 - "@typechain/hardhat": ^6.1.5 - "@types/chai": ^4.3.4 + "@gnosis.pm/zodiac": ^3.3.7 + "@nomicfoundation/hardhat-chai-matchers": ^1.0.6 + "@nomicfoundation/hardhat-network-helpers": ^1.0.8 + "@nomicfoundation/hardhat-toolbox": ^2.0.2 + "@nomiclabs/hardhat-ethers": ^2.2.3 + "@nomiclabs/hardhat-etherscan": ^3.1.7 + "@openzeppelin/contracts": ^4.9.3 + "@safe-global/safe-core-sdk": ^3.3.5 + "@typechain/ethers-v5": ^10.2.1 + "@typechain/hardhat": ^6.1.6 + "@types/chai": ^4.3.5 "@types/mocha": ^10.0.1 - "@types/node": ^18.11.18 - "@typescript-eslint/eslint-plugin": ^5.9.0 - "@typescript-eslint/parser": ^5.9.0 + "@types/node": ^18.17.5 + "@typescript-eslint/eslint-plugin": ^5.62.0 + "@typescript-eslint/parser": ^5.62.0 chai: ^4.3.7 - dotenv: ^16.0.3 - eslint: ^8.6.0 - eslint-config-prettier: ^8.3.0 + dotenv: ^16.3.1 + eslint: ^8.47.0 + eslint-config-prettier: ^8.10.0 eslint-plugin-eslint-comments: ^3.2.0 - eslint-plugin-import: ^2.25.4 - eslint-plugin-prettier: ^4.0.0 + eslint-plugin-import: ^2.28.0 + eslint-plugin-prettier: ^4.2.1 ethers: ^5.7.2 - hardhat: ^2.12.5 - hardhat-deploy: ^0.11.22 + hardhat: ^2.17.1 + hardhat-deploy: ^0.11.36 hardhat-gas-reporter: ^1.0.9 - prettier: ^2.8.3 - prettier-plugin-solidity: ^1.1.1 - rimraf: ^4.1.2 - solidity-coverage: ^0.8.2 + prettier: ^2.8.8 + prettier-plugin-solidity: ^1.1.3 + rimraf: ^4.4.1 + solidity-coverage: ^0.8.4 ts-node: ^10.9.1 - typechain: ^8.1.1 - typescript: ^4.9.4 + typechain: ^8.3.1 + typescript: ^4.9.5 languageName: unknown linkType: soft @@ -14026,15 +14209,15 @@ __metadata: resolution: "mech-sdk@workspace:sdk" dependencies: "@gnosis.pm/safe-contracts": ^1.3.0 - "@gnosis.pm/zodiac": ^3.0.0 - "@openzeppelin/contracts": ^4.8.1 - "@safe-global/safe-core-sdk": ^3.3.1 - "@types/chai": ^4.3.4 - "@types/node": ^18.11.18 + "@gnosis.pm/zodiac": ^3.3.7 + "@openzeppelin/contracts": ^4.9.3 + "@safe-global/safe-core-sdk": ^3.3.5 + "@types/chai": ^4.3.5 + "@types/node": ^18.17.5 ethers: ^5.7.2 - rimraf: ^4.1.2 - typescript: ^4.9.4 - viem: ^1.0.5 + rimraf: ^4.4.1 + typescript: ^4.9.5 + viem: ^1.6.0 languageName: unknown linkType: soft @@ -14939,6 +15122,18 @@ __metadata: languageName: node linkType: hard +"object.groupby@npm:^1.0.0": + version: 1.0.0 + resolution: "object.groupby@npm:1.0.0" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.2.0 + es-abstract: ^1.21.2 + get-intrinsic: ^1.2.1 + checksum: 64b00b287d57580111c958e7ff375c9b61811fa356f2cf0d35372d43cab61965701f00fac66c19fd8f49c4dfa28744bee6822379c69a73648ad03e09fcdeae70 + languageName: node + linkType: hard + "object.hasown@npm:^1.1.2": version: 1.1.2 resolution: "object.hasown@npm:1.1.2" @@ -16357,7 +16552,7 @@ __metadata: languageName: node linkType: hard -"prettier-plugin-solidity@npm:^1.1.1": +"prettier-plugin-solidity@npm:^1.1.3": version: 1.1.3 resolution: "prettier-plugin-solidity@npm:1.1.3" dependencies: @@ -16370,7 +16565,7 @@ __metadata: languageName: node linkType: hard -"prettier@npm:^2.3.1, prettier@npm:^2.8.3": +"prettier@npm:^2.3.1, prettier@npm:^2.8.8": version: 2.8.8 resolution: "prettier@npm:2.8.8" bin: @@ -16792,27 +16987,27 @@ __metadata: languageName: node linkType: hard -"react-router-dom@npm:^6.8.0": - version: 6.14.1 - resolution: "react-router-dom@npm:6.14.1" +"react-router-dom@npm:^6.15.0": + version: 6.15.0 + resolution: "react-router-dom@npm:6.15.0" dependencies: - "@remix-run/router": 1.7.1 - react-router: 6.14.1 + "@remix-run/router": 1.8.0 + react-router: 6.15.0 peerDependencies: react: ">=16.8" react-dom: ">=16.8" - checksum: 6ddda481edb2c614671bcaf24b0ca07ca00215f1d0350ede43a03ba24c3401a537dfe4a9f5e108a512c2703e4a8ce99a3301c15caf16012b67b248b1a055d69a + checksum: 95301837e293654f00934de6a4bdb27bfb06f613503e4cce7a93f19384793729832e7479d50faf3b9457d149014d4df40a3ee3a5193d7e3a3caadb7aaa6ec0f9 languageName: node linkType: hard -"react-router@npm:6.14.1": - version: 6.14.1 - resolution: "react-router@npm:6.14.1" +"react-router@npm:6.15.0": + version: 6.15.0 + resolution: "react-router@npm:6.15.0" dependencies: - "@remix-run/router": 1.7.1 + "@remix-run/router": 1.8.0 peerDependencies: react: ">=16.8" - checksum: 16f3d108e0f833bfee447192e3f40bd6731b8b11d42ca6925443ec8aeb157a889fe8ece67baf690f75f0d146d0a212656f9216fcc2df6fd3a2bd263108ed0abb + checksum: 345b29277e13997f2625f0037f537eaf1955bb9f44ebfea80dd3ff83fc06273f7b64e1be944bfc75945fd2af5af917874133a8a93ed5ecaca523be8f045ae166 languageName: node linkType: hard @@ -17286,6 +17481,19 @@ __metadata: languageName: node linkType: hard +"resolve@npm:^1.22.3": + version: 1.22.4 + resolution: "resolve@npm:1.22.4" + dependencies: + is-core-module: ^2.13.0 + path-parse: ^1.0.7 + supports-preserve-symlinks-flag: ^1.0.0 + bin: + resolve: bin/resolve + checksum: 23f25174c2736ce24c6d918910e0d1f89b6b38fefa07a995dff864acd7863d59a7f049e691f93b4b2ee29696303390d921552b6d1b841ed4a8101f517e1d0124 + languageName: node + linkType: hard + "resolve@npm:^2.0.0-next.4": version: 2.0.0-next.4 resolution: "resolve@npm:2.0.0-next.4" @@ -17328,6 +17536,19 @@ __metadata: languageName: node linkType: hard +"resolve@patch:resolve@^1.22.3#~builtin": + version: 1.22.4 + resolution: "resolve@patch:resolve@npm%3A1.22.4#~builtin::version=1.22.4&hash=c3c19d" + dependencies: + is-core-module: ^2.13.0 + path-parse: ^1.0.7 + supports-preserve-symlinks-flag: ^1.0.0 + bin: + resolve: bin/resolve + checksum: c45f2545fdc4d21883861b032789e20aa67a2f2692f68da320cc84d5724cd02f2923766c5354b3210897e88f1a7b3d6d2c7c22faeead8eed7078e4c783a444bc + languageName: node + linkType: hard + "resolve@patch:resolve@^2.0.0-next.4#~builtin": version: 2.0.0-next.4 resolution: "resolve@patch:resolve@npm%3A2.0.0-next.4#~builtin::version=2.0.0-next.4&hash=c3c19d" @@ -17393,7 +17614,7 @@ __metadata: languageName: node linkType: hard -"rimraf@npm:^4.1.2": +"rimraf@npm:^4.4.1": version: 4.4.1 resolution: "rimraf@npm:4.4.1" dependencies: @@ -18064,7 +18285,7 @@ __metadata: languageName: node linkType: hard -"solidity-coverage@npm:^0.8.2": +"solidity-coverage@npm:^0.8.4": version: 0.8.4 resolution: "solidity-coverage@npm:0.8.4" dependencies: @@ -19325,7 +19546,7 @@ __metadata: languageName: node linkType: hard -"tsconfig-paths@npm:^3.14.1": +"tsconfig-paths@npm:^3.14.1, tsconfig-paths@npm:^3.14.2": version: 3.14.2 resolution: "tsconfig-paths@npm:3.14.2" dependencies: @@ -19487,9 +19708,9 @@ __metadata: languageName: node linkType: hard -"typechain@npm:^8.1.1": - version: 8.2.0 - resolution: "typechain@npm:8.2.0" +"typechain@npm:^8.3.1": + version: 8.3.1 + resolution: "typechain@npm:8.3.1" dependencies: "@types/prettier": ^2.1.1 debug: ^4.3.1 @@ -19505,7 +19726,7 @@ __metadata: typescript: ">=4.3.0" bin: typechain: dist/cli/cli.js - checksum: 8591d333fda0e31172f4d9e0a8e23c24eee446ce3719989bd48e63f84a975917bb2f853ecaf616193ad7f3964e7c42fe3b1fc5abb69f4446794f465505f6c1a7 + checksum: c1e11ab1452d0c83be0c34a8b900b156b0c6654b95f7e7bb18dd98c0decd6009ffa1316e393f4e8def187af1bea3e931a13503815cc37155c0c945b7ae5b5215 languageName: node linkType: hard @@ -19549,7 +19770,7 @@ __metadata: languageName: node linkType: hard -"typescript-plugin-css-modules@npm:^4.1.1": +"typescript-plugin-css-modules@npm:^4.2.3": version: 4.2.3 resolution: "typescript-plugin-css-modules@npm:4.2.3" dependencies: @@ -19575,7 +19796,7 @@ __metadata: languageName: node linkType: hard -"typescript@npm:^4.9.4, typescript@npm:^4.9.5": +"typescript@npm:^4.9.5": version: 4.9.5 resolution: "typescript@npm:4.9.5" bin: @@ -19585,7 +19806,7 @@ __metadata: languageName: node linkType: hard -"typescript@patch:typescript@^4.9.4#~builtin, typescript@patch:typescript@^4.9.5#~builtin": +"typescript@patch:typescript@^4.9.5#~builtin": version: 4.9.5 resolution: "typescript@patch:typescript@npm%3A4.9.5#~builtin::version=4.9.5&hash=289587" bin: @@ -19918,24 +20139,9 @@ __metadata: languageName: node linkType: hard -"valtio@npm:1.10.6": - version: 1.10.6 - resolution: "valtio@npm:1.10.6" - dependencies: - proxy-compare: 2.5.1 - use-sync-external-store: 1.2.0 - peerDependencies: - react: ">=16.8" - peerDependenciesMeta: - react: - optional: true - checksum: 0e738aa204c479c8f8c89c0a7478d6784c28ddd712be529fdc5c421d3ec28157fec2fb022a75cd4f45b8c4b470fbc64a27032adba6ed9936bdad989256222adf - languageName: node - linkType: hard - -"valtio@npm:1.10.7": - version: 1.10.7 - resolution: "valtio@npm:1.10.7" +"valtio@npm:1.11.0": + version: 1.11.0 + resolution: "valtio@npm:1.11.0" dependencies: proxy-compare: 2.5.1 use-sync-external-store: 1.2.0 @@ -19944,7 +20150,7 @@ __metadata: peerDependenciesMeta: react: optional: true - checksum: fec3aa06e494d8230e5074a2da1077835c0940e383a411935f92e27db2d75ca28d53b63cb815b07dca0edb4bb4c3b6beabd6bec475be70bf26c03b04bd201058 + checksum: 77e42f5841054ba3e41b456fbb96b679eaeb6d9dbb46b7ce9aee6acf1352de73969858dea837a706c969ca908155d6cb97966e33be10b69b097744dd99b5174a languageName: node linkType: hard @@ -19966,23 +20172,6 @@ __metadata: languageName: node linkType: hard -"viem@npm:^0.3.24": - version: 0.3.50 - resolution: "viem@npm:0.3.50" - dependencies: - "@adraffy/ens-normalize": 1.9.0 - "@noble/curves": 1.0.0 - "@noble/hashes": 1.3.0 - "@scure/bip32": 1.3.0 - "@scure/bip39": 1.2.0 - "@wagmi/chains": 1.0.0 - abitype: 0.8.7 - isomorphic-ws: 5.0.0 - ws: 8.12.0 - checksum: b8bb1fe5fea4d503f722a30876b3811a205df3e7ae16443eb1ebd237a2a6b600ec3cf622143d79ef12a5f24fc9d4c77892d29728ef88643710f0a79a41abc470 - languageName: node - linkType: hard - "viem@npm:^1.0.0": version: 1.2.14 resolution: "viem@npm:1.2.14" @@ -20005,20 +20194,26 @@ __metadata: languageName: node linkType: hard -"viem@npm:^1.0.5": - version: 1.0.5 - resolution: "viem@npm:1.0.5" +"viem@npm:^1.6.0": + version: 1.6.0 + resolution: "viem@npm:1.6.0" dependencies: "@adraffy/ens-normalize": 1.9.0 - "@noble/curves": 1.0.0 + "@noble/curves": 1.1.0 "@noble/hashes": 1.3.0 "@scure/bip32": 1.3.0 "@scure/bip39": 1.2.0 - "@wagmi/chains": 1.1.0 - abitype: 0.8.7 + "@types/ws": ^8.5.4 + "@wagmi/chains": 1.6.0 + abitype: 0.9.3 isomorphic-ws: 5.0.0 ws: 8.12.0 - checksum: fe222bdf2a36eed3f84c2bb1a05ce6c516b28817496f15a99555f326b3b922f151669d6ef5fb8a914349016fce34b9a47dc372547e2f521caa8015604b389ad3 + peerDependencies: + typescript: ">=5.0.4" + peerDependenciesMeta: + typescript: + optional: true + checksum: b01301645bc00d438318bea86fca63321e1a7e29a857a451207caaced89afb1472a219b8e62d4c42ef10cf8ef5d8fa945b0c1a2a2fdef5af08aa2ff3ae9aa250 languageName: node linkType: hard @@ -20040,14 +20235,14 @@ __metadata: languageName: node linkType: hard -"wagmi@npm:^1.0.4": - version: 1.3.8 - resolution: "wagmi@npm:1.3.8" +"wagmi@npm:^1.3.10": + version: 1.3.10 + resolution: "wagmi@npm:1.3.10" dependencies: "@tanstack/query-sync-storage-persister": ^4.27.1 "@tanstack/react-query": ^4.28.0 "@tanstack/react-query-persist-client": ^4.28.0 - "@wagmi/core": 1.3.7 + "@wagmi/core": 1.3.9 abitype: 0.8.7 use-sync-external-store: ^1.2.0 peerDependencies: @@ -20057,7 +20252,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 88c67ec3cdb7ba444d5bb13ce99854f0fd6c79e9a93a795ccbd31012d3a212e812d2c7f0a5af5f7b6520fc40617bce2e382ae16b81fe7d3961ddd439aaedb561 + checksum: ed329b9e8e7c1263312b028967980a3e47764586f154fc1040eb03fc48b9e1742b5de9eca962efcad04ea24b3440c846b439f4a35ca0849a56183783564e80f7 languageName: node linkType: hard From 98c79c1b0578c19295857c15a00bdad469fba8ec Mon Sep 17 00:00:00 2001 From: Jan-Felix Date: Mon, 21 Aug 2023 11:50:39 +0200 Subject: [PATCH 18/41] 6551 updates and prevent ownership cycles --- contracts/ERC1155TokenboundMech.sol | 63 ++++++++++++++++++++++++++++- contracts/ERC721TokenboundMech.sol | 30 ++++++++++++-- contracts/base/Receiver.sol | 6 +-- contracts/base/TokenboundMech.sol | 37 ++++++++--------- 4 files changed, 110 insertions(+), 26 deletions(-) diff --git a/contracts/ERC1155TokenboundMech.sol b/contracts/ERC1155TokenboundMech.sol index d95fdb4..7c0d4dd 100644 --- a/contracts/ERC1155TokenboundMech.sol +++ b/contracts/ERC1155TokenboundMech.sol @@ -15,7 +15,66 @@ contract ERC1155TokenboundMech is TokenboundMech { return IERC1155(tokenContract).balanceOf(signer, tokenId) > 0; } - function owner() public view virtual override returns (address) { - return address(0); + function onERC1155Received( + address operator, + address from, + uint256 receivedTokenId, + uint256 value, + bytes calldata + ) external view override returns (bytes4) { + ( + uint256 chainId, + address boundTokenContract, + uint256 boundTokenId + ) = this.token(); + + if ( + chainId == block.chainid && + msg.sender == boundTokenContract && + receivedTokenId == boundTokenId + ) { + // We block the transfer only if the sender has no balance left after the transfer. + // Note: ERC-1155 prescribes that balances are updated BEFORE the call to onERC1155Received. + if ( + IERC1155(boundTokenContract).balanceOf(from, boundTokenId) == 0 + ) { + revert OwnershipCycle(); + } + } + + return 0xf23a6e61; + } + + function onERC1155BatchReceived( + address operator, + address from, + uint256[] calldata ids, + uint256[] calldata values, + bytes calldata + ) external view override returns (bytes4) { + ( + uint256 chainId, + address boundTokenContract, + uint256 boundTokenId + ) = this.token(); + + if (chainId == block.chainid && msg.sender == boundTokenContract) { + // We block the transfer only if the sender has no balance left after the transfer. + // Note: ERC-1155 prescribes that balances are updated BEFORE the call to onERC1155BatchReceived. + for (uint256 i = 0; i < ids.length; i++) { + if (ids[i] == boundTokenId) { + if ( + IERC1155(boundTokenContract).balanceOf( + from, + boundTokenId + ) == 0 + ) { + revert OwnershipCycle(); + } + } + } + } + + return 0xbc197c81; } } diff --git a/contracts/ERC721TokenboundMech.sol b/contracts/ERC721TokenboundMech.sol index 3f4c6e0..365d842 100644 --- a/contracts/ERC721TokenboundMech.sol +++ b/contracts/ERC721TokenboundMech.sol @@ -9,11 +9,35 @@ import "./base/TokenboundMech.sol"; * @dev A Mech that is operated by the holder of an ERC721 non-fungible token */ contract ERC721TokenboundMech is TokenboundMech { - function owner() public view override returns (address) { + function isOperator(address signer) public view override returns (bool) { (uint256 chainId, address tokenContract, uint256 tokenId) = this .token(); - if (chainId != block.chainid) return address(0); + if (chainId != block.chainid) return false; + return + IERC721(tokenContract).ownerOf(tokenId) == signer && + signer != address(0); + } + + function onERC721Received( + address operator, + address from, + uint256 receivedTokenId, + bytes calldata + ) external view override returns (bytes4) { + ( + uint256 chainId, + address boundTokenContract, + uint256 boundTokenId + ) = this.token(); + + if ( + chainId == block.chainid && + msg.sender == boundTokenContract && + receivedTokenId == boundTokenId + ) { + revert OwnershipCycle(); + } - return IERC721(tokenContract).ownerOf(tokenId); + return 0x150b7a02; } } diff --git a/contracts/base/Receiver.sol b/contracts/base/Receiver.sol index 6ef7cd8..0af79b0 100644 --- a/contracts/base/Receiver.sol +++ b/contracts/base/Receiver.sol @@ -21,7 +21,7 @@ contract Receiver is uint256, uint256, bytes calldata - ) external pure override returns (bytes4) { + ) external view override returns (bytes4) { return 0xf23a6e61; } @@ -31,7 +31,7 @@ contract Receiver is uint256[] calldata, uint256[] calldata, bytes calldata - ) external pure override returns (bytes4) { + ) external view override returns (bytes4) { return 0xbc197c81; } @@ -40,7 +40,7 @@ contract Receiver is address, uint256, bytes calldata - ) external pure override returns (bytes4) { + ) external view override returns (bytes4) { return 0x150b7a02; } diff --git a/contracts/base/TokenboundMech.sol b/contracts/base/TokenboundMech.sol index 3d3f914..4e67733 100644 --- a/contracts/base/TokenboundMech.sol +++ b/contracts/base/TokenboundMech.sol @@ -10,18 +10,11 @@ import "../libraries/MinimalProxyStore.sol"; * @dev A Mech that is operated by the holder of a designated token, implements the ERC6551 standard and is deployed through the ERC6551 registry */ abstract contract TokenboundMech is Mech, IERC6551Account { - function isOperator( - address signer - ) public view virtual override returns (bool) { - return owner() == signer && signer != address(0); - } + error OwnershipCycle(); - function executeCall( - address to, - uint256 value, - bytes calldata data - ) external payable returns (bytes memory) { - return exec(to, value, data, Enum.Operation.Call, 0); + /// @dev Returns the current account nonce + function state() external view returns (uint256) { + return entryPoint().getNonce(address(this), 0); } function token() @@ -36,13 +29,21 @@ abstract contract TokenboundMech is Mech, IERC6551Account { ); } - function owner() public view virtual returns (address); + receive() external payable override(Receiver, IERC6551Account) {} - // required by ERC-6551, even though their account (https://github.com/tokenbound/contracts/blob/main/src/Account.sol) does not use it but a time-locking mechanism - // TODO adopt whatever ERC-6551 will settle on - function nonce() external pure returns (uint256) { - return 0; + /** + * @dev EIP-6551 compatibility: Returns a magic value indicating whether a given signer is authorized to act on behalf + * of the account + * @param signer The address to check signing authorization for + * @return magicValue Magic value indicating whether the signer is valid + */ + function isValidSigner( + address signer, + bytes calldata + ) external view returns (bytes4 magicValue) { + return + isOperator(signer) + ? IERC6551Account.isValidSigner.selector + : bytes4(0); } - - receive() external payable override(Receiver, IERC6551Account) {} } From eb19c39c5b9854e78fde16db1f57f60d63e9bf57 Mon Sep 17 00:00:00 2001 From: Jan-Felix Date: Mon, 21 Aug 2023 14:25:29 +0200 Subject: [PATCH 19/41] fine-tune execution interface --- README.md | 9 ++++-- contracts/ERC1155TokenboundMech.sol | 8 ++--- contracts/ERC721TokenboundMech.sol | 4 +-- contracts/base/Mech.sol | 31 ++++++++++++++++--- contracts/base/Receiver.sol | 6 ++-- contracts/base/TokenboundMech.sol | 2 +- contracts/interfaces/IMech.sol | 22 ++++++++++--- contracts/test/ERC1155Token.sol | 2 +- frontend/package.json | 6 ++-- integrationTest/SafeMigration.ts | 4 +-- sdk/package.json | 4 +-- sdk/src/{exec => execute}/index.ts | 0 .../{exec => execute}/makeExecTransaction.ts | 4 +-- sdk/src/index.ts | 2 +- test/Account.ts | 4 +-- test/Mech.ts | 20 ++++++------ test/Receiver.ts | 3 +- test/ZodiacMech.ts | 2 +- 18 files changed, 88 insertions(+), 45 deletions(-) rename sdk/src/{exec => execute}/index.ts (100%) rename sdk/src/{exec => execute}/makeExecTransaction.ts (93%) diff --git a/README.md b/README.md index 2e18eb6..a0196ee 100644 --- a/README.md +++ b/README.md @@ -32,13 +32,18 @@ Mech implements the [EIP-4337](https://eips.ethereum.org/EIPS/eip-4337) account Returns true if `signer` is allowed to operate the Mech. Sub classes implement this function for defining the specific operator criteria. -### `exec(address to, uint256 value, bytes data, Enum.Operation operation, uint256 txGas)` +### `execute(address to, uint256 value, bytes data, Enum.Operation operation)` Allows the operator to make the Mech execute a transaction. - `operation: 0` for a regular call - `operation: 1` for a delegate call +### `execute(address to, uint256 value, bytes data, Enum.Operation operation, uint256 txGas)` + +Allows the operator to make the Mech execute a transaction restricting the gas amount made available to the direct execution of the internal meta transaction. +Any remaining transaction gas must only be spent for surrounding checks of the operator criteria. + ## Contribute The repo is structured as a monorepo with `mech-contracts` as the container package exporting the contract sources and artifacts. @@ -91,7 +96,7 @@ Integration tests are run on a mainnet fork and cover the interaction of mech co Mech implements the EIP-4337 [Account](contracts/base/Account.sol) interface meaning they allow bundlers to execute account-abstracted user operations from the Mech's address. For this purpose the EIP-4337 entry point contract first calls the Mech's `validateUserOp()` function for checking if a user operation has a valid signature by the mech operator. -The entry point then calls the `exec` function, or any other function using the `onlyOperator` modifier, to trigger execution. +The entry point then calls the `execute` function, or any other function using the `onlyOperator` modifier, to trigger execution. ### EIP-1271 signatures diff --git a/contracts/ERC1155TokenboundMech.sol b/contracts/ERC1155TokenboundMech.sol index 7c0d4dd..e76cda1 100644 --- a/contracts/ERC1155TokenboundMech.sol +++ b/contracts/ERC1155TokenboundMech.sol @@ -16,10 +16,10 @@ contract ERC1155TokenboundMech is TokenboundMech { } function onERC1155Received( - address operator, + address, address from, uint256 receivedTokenId, - uint256 value, + uint256, bytes calldata ) external view override returns (bytes4) { ( @@ -46,10 +46,10 @@ contract ERC1155TokenboundMech is TokenboundMech { } function onERC1155BatchReceived( - address operator, + address, address from, uint256[] calldata ids, - uint256[] calldata values, + uint256[] calldata, bytes calldata ) external view override returns (bytes4) { ( diff --git a/contracts/ERC721TokenboundMech.sol b/contracts/ERC721TokenboundMech.sol index 365d842..f9f9f86 100644 --- a/contracts/ERC721TokenboundMech.sol +++ b/contracts/ERC721TokenboundMech.sol @@ -19,8 +19,8 @@ contract ERC721TokenboundMech is TokenboundMech { } function onERC721Received( - address operator, - address from, + address, + address, uint256 receivedTokenId, bytes calldata ) external view override returns (bytes4) { diff --git a/contracts/base/Mech.sol b/contracts/base/Mech.sol index e6c2726..64b8a12 100644 --- a/contracts/base/Mech.sol +++ b/contracts/base/Mech.sol @@ -93,7 +93,7 @@ abstract contract Mech is IMech, Account, Receiver { function _exec( address to, uint256 value, - bytes memory data, + bytes calldata data, Enum.Operation operation, uint256 txGas ) internal returns (bool success, bytes memory returnData) { @@ -111,13 +111,13 @@ abstract contract Mech is IMech, Account, Receiver { /// @param operation Operation type of transaction. /// @param txGas Gas to send for executing the meta transaction, if 0 all left will be sent /// @return returnData Return data of the call - function exec( + function execute( address to, uint256 value, - bytes memory data, + bytes calldata data, Enum.Operation operation, uint256 txGas - ) public onlyOperator returns (bytes memory returnData) { + ) public payable onlyOperator returns (bytes memory returnData) { bool success; (success, returnData) = _exec( to, @@ -135,6 +135,29 @@ abstract contract Mech is IMech, Account, Receiver { } } + /// @dev Allows the mech operator to execute arbitrary transactions + /// @param to Destination address of transaction. + /// @param value Ether value of transaction. + /// @param data Data payload of transaction. + /// @param operation Operation type of transaction. + /// @return returnData Return data of the call + function execute( + address to, + uint256 value, + bytes calldata data, + Enum.Operation operation + ) external payable returns (bytes memory returnData) { + bool success; + (success, returnData) = _exec(to, value, data, operation, gasleft()); + + if (!success) { + // solhint-disable-next-line no-inline-assembly + assembly { + revert(add(returnData, 0x20), mload(returnData)) + } + } + } + /** * @dev Divides bytes signature into `uint8 v, bytes32 r, bytes32 s`. * @param signature The signature bytes diff --git a/contracts/base/Receiver.sol b/contracts/base/Receiver.sol index 0af79b0..b4c183b 100644 --- a/contracts/base/Receiver.sol +++ b/contracts/base/Receiver.sol @@ -21,7 +21,7 @@ contract Receiver is uint256, uint256, bytes calldata - ) external view override returns (bytes4) { + ) external view virtual override returns (bytes4) { return 0xf23a6e61; } @@ -31,7 +31,7 @@ contract Receiver is uint256[] calldata, uint256[] calldata, bytes calldata - ) external view override returns (bytes4) { + ) external view virtual override returns (bytes4) { return 0xbc197c81; } @@ -40,7 +40,7 @@ contract Receiver is address, uint256, bytes calldata - ) external view override returns (bytes4) { + ) external view virtual override returns (bytes4) { return 0x150b7a02; } diff --git a/contracts/base/TokenboundMech.sol b/contracts/base/TokenboundMech.sol index 4e67733..ba4ab36 100644 --- a/contracts/base/TokenboundMech.sol +++ b/contracts/base/TokenboundMech.sol @@ -32,7 +32,7 @@ abstract contract TokenboundMech is Mech, IERC6551Account { receive() external payable override(Receiver, IERC6551Account) {} /** - * @dev EIP-6551 compatibility: Returns a magic value indicating whether a given signer is authorized to act on behalf + * @dev Returns a magic value indicating whether a given signer is authorized to act on behalf * of the account * @param signer The address to check signing authorization for * @return magicValue Magic value indicating whether the signer is valid diff --git a/contracts/interfaces/IMech.sol b/contracts/interfaces/IMech.sol index 2b043c8..0a49a24 100644 --- a/contracts/interfaces/IMech.sol +++ b/contracts/interfaces/IMech.sol @@ -2,10 +2,11 @@ pragma solidity ^0.8.12; import "@openzeppelin/contracts/interfaces/IERC1271.sol"; +import "@erc6551/reference/src/interfaces/IERC6551Executable.sol"; import "@gnosis.pm/safe-contracts/contracts/common/Enum.sol"; import "@account-abstraction/contracts/interfaces/IAccount.sol"; -interface IMech is IAccount, IERC1271 { +interface IMech is IAccount, IERC1271 /*, IERC6551Executable */ { /** * @dev Return if the passed address is authorized to sign on behalf of the mech, must be implemented by the child contract * @param signer The address to check @@ -17,13 +18,26 @@ interface IMech is IAccount, IERC1271 { /// @param value Ether value. /// @param data Data payload. /// @param operation Operation type. + /// @return returnData bytes The return data of the call + function execute( + address to, + uint256 value, + bytes calldata data, + Enum.Operation operation + ) external payable returns (bytes memory returnData); + + /// @dev Executes either a delegatecall or a call with provided parameters, with a specified gas limit for the meta transaction + /// @param to Destination address. + /// @param value Ether value. + /// @param data Data payload. + /// @param operation Operation type. /// @param txGas Gas to send for executing the meta transaction, if 0 all left will be sent /// @return returnData bytes The return data of the call - function exec( + function execute( address to, uint256 value, - bytes memory data, + bytes calldata data, Enum.Operation operation, uint256 txGas - ) external returns (bytes memory returnData); + ) external payable returns (bytes memory returnData); } diff --git a/contracts/test/ERC1155Token.sol b/contracts/test/ERC1155Token.sol index d286716..0e1bb7a 100644 --- a/contracts/test/ERC1155Token.sol +++ b/contracts/test/ERC1155Token.sol @@ -8,7 +8,7 @@ contract ERC1155Token is ERC1155("ERC1155Token") { address recipient, uint256 id, uint256 amount, - bytes memory data + bytes calldata data ) public { _mint(recipient, id, amount, data); } diff --git a/frontend/package.json b/frontend/package.json index 7735ef9..dd635bd 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -23,9 +23,9 @@ "react-dom": "^18.2.0", "react-router-dom": "^6.15.0", "react-scripts": "5.0.1", - "typescript": "^4.9.5", - "typescript-plugin-css-modules": "^4.2.3", - "viem": "^1.6.0", + "typescript": "^5.1.6", + "typescript-plugin-css-modules": "^5.0.1", + "viem": "^1.6.4", "wagmi": "^1.3.10" }, "scripts": { diff --git a/integrationTest/SafeMigration.ts b/integrationTest/SafeMigration.ts index f79dac8..d4be5db 100644 --- a/integrationTest/SafeMigration.ts +++ b/integrationTest/SafeMigration.ts @@ -40,7 +40,7 @@ describe("Safe migration", () => { // sanity check making sure the Gnosis DAO Safe is configured as expected expect(await safe.isModuleEnabled(enabledModule)).to.be.true - await expect(zodiacMech.exec(ZERO_ADDRESS, parseEther("1.0"), "0x", 0, 0)) + await expect(zodiacMech.execute(ZERO_ADDRESS, parseEther("1.0"), "0x", 0)) .to.be.reverted // deploy ZodiacMech mastercopy @@ -76,7 +76,7 @@ describe("Safe migration", () => { // make sure the Safe is now a ZodiacMech await expect( - zodiacMech.exec(ZERO_ADDRESS, parseEther("1.0"), "0x", 0, 0) + zodiacMech.execute(ZERO_ADDRESS, parseEther("1.0"), "0x", 0) ).to.changeEtherBalance(safeAddress, parseEther("-1.0")) // the enabled modules did not change diff --git a/sdk/package.json b/sdk/package.json index 5ad2c1f..2cadc89 100644 --- a/sdk/package.json +++ b/sdk/package.json @@ -32,7 +32,7 @@ "homepage": "https://github.com/gnosis/mech#readme", "devDependencies": { "rimraf": "^4.4.1", - "typescript": "^4.9.5" + "typescript": "^5.1.6" }, "dependencies": { "@gnosis.pm/safe-contracts": "^1.3.0", @@ -42,7 +42,7 @@ "@types/chai": "^4.3.5", "@types/node": "^18.17.5", "ethers": "^5.7.2", - "viem": "^1.6.0" + "viem": "^1.6.4" }, "packageManager": "yarn@3.6.1" } diff --git a/sdk/src/exec/index.ts b/sdk/src/execute/index.ts similarity index 100% rename from sdk/src/exec/index.ts rename to sdk/src/execute/index.ts diff --git a/sdk/src/exec/makeExecTransaction.ts b/sdk/src/execute/makeExecTransaction.ts similarity index 93% rename from sdk/src/exec/makeExecTransaction.ts rename to sdk/src/execute/makeExecTransaction.ts index 1628e1d..20af5a4 100644 --- a/sdk/src/exec/makeExecTransaction.ts +++ b/sdk/src/execute/makeExecTransaction.ts @@ -15,7 +15,7 @@ interface TransactionRequest { nonce?: number } -export const makeExecTransaction = ( +export const makeExecuteTransaction = ( mechAddress: `0x${string}`, transaction: TransactionRequest ) => { @@ -36,7 +36,7 @@ export const makeExecTransaction = ( // gas for mech's onlyOperator modifier still needs to be calculated (can't be fixed, since it depends on external ERC721 ownerOf() function) gasLimit: undefined, - data: IMech.encodeFunctionData("exec", [ + data: IMech.encodeFunctionData("execute()", [ to || "", value || 0, data || "0x", diff --git a/sdk/src/index.ts b/sdk/src/index.ts index b1ee202..8e175de 100644 --- a/sdk/src/index.ts +++ b/sdk/src/index.ts @@ -1,3 +1,3 @@ export * from "./deploy" -export * from "./exec" +export * from "./execute" export * from "./sign" diff --git a/test/Account.ts b/test/Account.ts index 7e0947d..67e48f1 100644 --- a/test/Account.ts +++ b/test/Account.ts @@ -55,8 +55,8 @@ describe("Account base contract", () => { } const BURN_1_ETH = Mech__factory.createInterface().encodeFunctionData( - "exec", - [ZERO_ADDRESS, parseEther("1.0"), "0x", 0, 0] + "execute", + [ZERO_ADDRESS, parseEther("1.0"), "0x", 0] ) describe("validateUserOp()", () => { diff --git a/test/Mech.ts b/test/Mech.ts index d19a4e9..8840335 100644 --- a/test/Mech.ts +++ b/test/Mech.ts @@ -158,7 +158,7 @@ describe("Mech base contract", () => { }) }) - describe("exec()", () => { + describe("execute()", () => { it("reverts if called when the connected token ID is not valid", async () => { const { mech1, testToken, alice } = await loadFixture(deployMech1) @@ -173,7 +173,7 @@ describe("Mech base contract", () => { ) await expect( - mech1.exec(testToken.address, 0, testTx.data as string, 0, 0) + mech1.execute(testToken.address, 0, testTx.data as string, 0) ).to.be.revertedWith("ERC721: invalid token ID") }) @@ -193,7 +193,7 @@ describe("Mech base contract", () => { // call exec() from deployer who is not an operator await expect( - mech1.exec(testToken.address, 0, testTx.data as string, 0, 0) + mech1.execute(testToken.address, 0, testTx.data as string, 0) ).to.be.revertedWith( "Only callable by the mech operator or the entry point contract" ) @@ -212,7 +212,9 @@ describe("Mech base contract", () => { ) await expect( - mech1.connect(alice).exec(testToken.address, 0, revertingTxData, 0, 0) + mech1 + .connect(alice) + .execute(testToken.address, 0, revertingTxData, 0, 0) ).to.be.revertedWith("ERC721: caller is not token owner or approved") }) @@ -227,7 +229,7 @@ describe("Mech base contract", () => { const result = await mech1 .connect(alice) - .callStatic.exec(testToken.address, 0, callData, 0, 0) + .callStatic.execute(testToken.address, 0, callData, 0) const decoded = testToken.interface.decodeFunctionResult( "ownerOf", result @@ -249,12 +251,12 @@ describe("Mech base contract", () => { // this should revert because the call is not a delegate call await expect( - mech1.connect(alice).exec(delegateCall.address, 0, callData, 0, 0) + mech1.connect(alice).execute(delegateCall.address, 0, callData, 0) ).to.be.revertedWith("Can only be called via delegatecall") // this should succeed because the call is a delegate call await expect( - mech1.connect(alice).exec(delegateCall.address, 0, callData, 1, 0) + mech1.connect(alice).execute(delegateCall.address, 0, callData, 1) ).to.not.be.reverted }) @@ -284,7 +286,7 @@ describe("Mech base contract", () => { // send just enough gas to meta tx -> gas estimation succeed const mechTxGas = await mech1 .connect(alice) - .estimateGas.exec( + .estimateGas.execute( testToken.address, 0, testToken.interface.encodeFunctionData("transferFrom", [ @@ -298,7 +300,7 @@ describe("Mech base contract", () => { // send too little gas to the meta tx -> tx fails await expect( - mech1.connect(alice).exec( + mech1.connect(alice).execute( testToken.address, 0, testToken.interface.encodeFunctionData("transferFrom", [ diff --git a/test/Receiver.ts b/test/Receiver.ts index b1b0be7..a723570 100644 --- a/test/Receiver.ts +++ b/test/Receiver.ts @@ -57,14 +57,13 @@ describe("Receiver base contract", () => { await mech1 .connect(alice) - .exec( + .execute( test20Token.address, 0, test20Token.interface.encodeFunctionData("transfer", [ alice.address, 500, ]), - 0, 0 ) diff --git a/test/ZodiacMech.ts b/test/ZodiacMech.ts index bccff20..6feaa64 100644 --- a/test/ZodiacMech.ts +++ b/test/ZodiacMech.ts @@ -333,7 +333,7 @@ describe("ZodiacMech contract", () => { // value: parseEther("1.0"), // }) - // const BURN_1_ETH = mech1.interface.encodeFunctionData("exec", [ + // const BURN_1_ETH = mech1.interface.encodeFunctionData("execute", [ // ZERO_ADDRESS, // parseEther("1.0"), // "0x", From 81dbd528c5369e81387ca683a08cdfad7f18900c Mon Sep 17 00:00:00 2001 From: Jan-Felix Date: Mon, 21 Aug 2023 14:54:53 +0200 Subject: [PATCH 20/41] upgrade tooling --- frontend/package.json | 2 +- package.json | 28 +-- sdk/package.json | 2 +- sdk/src/execute/makeExecTransaction.ts | 3 +- yarn.lock | 253 +++++++++++++++++-------- 5 files changed, 188 insertions(+), 100 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index dd635bd..5254356 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -17,7 +17,7 @@ "copy-to-clipboard": "^3.3.3", "cryptocurrency-icons": "^0.18.1", "ethereum-blockies-base64": "^1.0.2", - "ethers": "^5.7.2", + "ethers": "^6.7.1", "mech-sdk": "workspace:^", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/package.json b/package.json index a498531..c5eff03 100644 --- a/package.json +++ b/package.json @@ -42,20 +42,24 @@ }, "homepage": "https://github.com/gnosis/mech#readme", "devDependencies": { - "@account-abstraction/contracts": "^0.6.0", "@ambire/signature-validator": "^1.3.1", - "@erc6551/reference": "https://github.com/erc6551/reference.git#commit=df75cd1bab5fb8e320940783df5f14c6d8aaa0f2", "@ethersproject/abi": "^5.7.0", "@ethersproject/bytes": "^5.7.0", "@ethersproject/providers": "^5.7.2", - "@nomicfoundation/hardhat-chai-matchers": "^1.0.6", + "@gnosis.pm/zodiac": "^3.3.7", + "@nomicfoundation/hardhat-chai-matchers": "^2.0.2", + "@nomicfoundation/hardhat-ethers": "^3.0.4", "@nomicfoundation/hardhat-network-helpers": "^1.0.8", - "@nomicfoundation/hardhat-toolbox": "^2.0.2", + "@nomicfoundation/hardhat-toolbox": "^3.0.0", + "@nomicfoundation/hardhat-verify": "^1.0.0", "@nomiclabs/hardhat-ethers": "^2.2.3", "@nomiclabs/hardhat-etherscan": "^3.1.7", - "@typechain/ethers-v5": "^10.2.1", - "@typechain/hardhat": "^6.1.6", + "@safe-global/safe-core-sdk": "^3.3.5", + "@typechain/ethers-v6": "^0.5.0", + "@typechain/hardhat": "^9.0.0", + "@types/chai": "^4.3.5", "@types/mocha": "^10.0.1", + "@types/node": "^18.17.5", "@typescript-eslint/eslint-plugin": "^5.62.0", "@typescript-eslint/parser": "^5.62.0", "chai": "^4.3.7", @@ -65,6 +69,7 @@ "eslint-plugin-eslint-comments": "^3.2.0", "eslint-plugin-import": "^2.28.0", "eslint-plugin-prettier": "^4.2.1", + "ethers": "^6.4.0", "hardhat": "^2.17.1", "hardhat-deploy": "^0.11.36", "hardhat-gas-reporter": "^1.0.9", @@ -74,16 +79,13 @@ "solidity-coverage": "^0.8.4", "ts-node": "^10.9.1", "typechain": "^8.3.1", - "typescript": "^4.9.5" + "typescript": "^5.1.6" }, "dependencies": { + "@account-abstraction/contracts": "^0.6.0", + "@erc6551/reference": "https://github.com/erc6551/reference.git#commit=df75cd1bab5fb8e320940783df5f14c6d8aaa0f2", "@gnosis.pm/safe-contracts": "^1.3.0", - "@gnosis.pm/zodiac": "^3.3.7", - "@openzeppelin/contracts": "^4.9.3", - "@safe-global/safe-core-sdk": "^3.3.5", - "@types/chai": "^4.3.5", - "@types/node": "^18.17.5", - "ethers": "^5.7.2" + "@openzeppelin/contracts": "^4.9.3" }, "resolutions": { "@walletconnect/ethereum-provider": "2.7.0" diff --git a/sdk/package.json b/sdk/package.json index 2cadc89..4ec2f1d 100644 --- a/sdk/package.json +++ b/sdk/package.json @@ -41,7 +41,7 @@ "@safe-global/safe-core-sdk": "^3.3.5", "@types/chai": "^4.3.5", "@types/node": "^18.17.5", - "ethers": "^5.7.2", + "ethers": "^6.7.1", "viem": "^1.6.4" }, "packageManager": "yarn@3.6.1" diff --git a/sdk/src/execute/makeExecTransaction.ts b/sdk/src/execute/makeExecTransaction.ts index 20af5a4..5453d6d 100644 --- a/sdk/src/execute/makeExecTransaction.ts +++ b/sdk/src/execute/makeExecTransaction.ts @@ -36,12 +36,11 @@ export const makeExecuteTransaction = ( // gas for mech's onlyOperator modifier still needs to be calculated (can't be fixed, since it depends on external ERC721 ownerOf() function) gasLimit: undefined, - data: IMech.encodeFunctionData("execute()", [ + data: IMech.encodeFunctionData("execute(address,uint256,bytes,uint8)", [ to || "", value || 0, data || "0x", 0, - txGas, ]) as `0x${string}`, value: BigInt(0), diff --git a/yarn.lock b/yarn.lock index 6795044..1c5daf0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -33,6 +33,13 @@ __metadata: languageName: node linkType: hard +"@adraffy/ens-normalize@npm:1.9.2": + version: 1.9.2 + resolution: "@adraffy/ens-normalize@npm:1.9.2" + checksum: a9fdeb9e080774c19e4b7f9f60aa5b37cf23fe0e8fe80284bf8221f7396e9f78642bfd39a09a94a4dc3fb8e70f2ac81545204bdcaf222d93f4c4c2ae1f0dca0b + languageName: node + linkType: hard + "@alloc/quick-lru@npm:^5.2.0": version: 5.2.0 resolution: "@alloc/quick-lru@npm:5.2.0" @@ -3043,6 +3050,13 @@ __metadata: languageName: node linkType: hard +"@noble/hashes@npm:1.1.2": + version: 1.1.2 + resolution: "@noble/hashes@npm:1.1.2" + checksum: 3c2a8cb7c2e053811032f242155d870c5eb98844d924d69702244d48804cb03b42d4a666c49c2b71164420d8229cb9a6f242b972d50d5bb2f1d673b98b041de2 + languageName: node + linkType: hard + "@noble/hashes@npm:1.2.0, @noble/hashes@npm:~1.2.0": version: 1.2.0 resolution: "@noble/hashes@npm:1.2.0" @@ -3256,21 +3270,33 @@ __metadata: languageName: node linkType: hard -"@nomicfoundation/hardhat-chai-matchers@npm:^1.0.6": - version: 1.0.6 - resolution: "@nomicfoundation/hardhat-chai-matchers@npm:1.0.6" +"@nomicfoundation/hardhat-chai-matchers@npm:^2.0.2": + version: 2.0.2 + resolution: "@nomicfoundation/hardhat-chai-matchers@npm:2.0.2" dependencies: - "@ethersproject/abi": ^5.1.2 "@types/chai-as-promised": ^7.1.3 chai-as-promised: ^7.1.1 deep-eql: ^4.0.1 ordinal: ^1.0.3 peerDependencies: - "@nomiclabs/hardhat-ethers": ^2.0.0 + "@nomicfoundation/hardhat-ethers": ^3.0.0 chai: ^4.2.0 - ethers: ^5.0.0 + ethers: ^6.1.0 hardhat: ^2.9.4 - checksum: c388e5ed9068f2ba7c227737ab7312dd03405d5fab195247b061f2fa52e700fbd0fb65359c2d4f2086f2905bfca642c19a9122d034533edd936f89aea65ac7f2 + checksum: 62d7d69f6b34a06bc43fe0dab8adc9e3b6f907f1b68bb5cf47feb78a4c7ef057b9a4aa713611abeca38df9d8fe166bbd9bbf98e42c4edbdf7aece477b3f9485a + languageName: node + linkType: hard + +"@nomicfoundation/hardhat-ethers@npm:^3.0.4": + version: 3.0.4 + resolution: "@nomicfoundation/hardhat-ethers@npm:3.0.4" + dependencies: + debug: ^4.1.1 + lodash.isequal: ^4.5.0 + peerDependencies: + ethers: ^6.1.0 + hardhat: ^2.0.0 + checksum: 57cbb13682cf0e14cf5bb17b47a2004f69765358fffba7d660ab277a6aff38583216637aa3c5c68410a649a9cd41f774a8df2cb89098f6f616f6108c0f6e5d7a languageName: node linkType: hard @@ -3285,30 +3311,47 @@ __metadata: languageName: node linkType: hard -"@nomicfoundation/hardhat-toolbox@npm:^2.0.2": - version: 2.0.2 - resolution: "@nomicfoundation/hardhat-toolbox@npm:2.0.2" +"@nomicfoundation/hardhat-toolbox@npm:^3.0.0": + version: 3.0.0 + resolution: "@nomicfoundation/hardhat-toolbox@npm:3.0.0" peerDependencies: - "@ethersproject/abi": ^5.4.7 - "@ethersproject/providers": ^5.4.7 - "@nomicfoundation/hardhat-chai-matchers": ^1.0.0 + "@nomicfoundation/hardhat-chai-matchers": ^2.0.0 + "@nomicfoundation/hardhat-ethers": ^3.0.0 "@nomicfoundation/hardhat-network-helpers": ^1.0.0 - "@nomiclabs/hardhat-ethers": ^2.0.0 - "@nomiclabs/hardhat-etherscan": ^3.0.0 - "@typechain/ethers-v5": ^10.1.0 - "@typechain/hardhat": ^6.1.2 + "@nomicfoundation/hardhat-verify": ^1.0.0 + "@typechain/ethers-v6": ^0.4.0 + "@typechain/hardhat": ^8.0.0 "@types/chai": ^4.2.0 "@types/mocha": ">=9.1.0" "@types/node": ">=12.0.0" chai: ^4.2.0 - ethers: ^5.4.7 + ethers: ^6.4.0 hardhat: ^2.11.0 hardhat-gas-reporter: ^1.0.8 solidity-coverage: ^0.8.1 ts-node: ">=8.0.0" - typechain: ^8.1.0 + typechain: ^8.2.0 typescript: ">=4.5.0" - checksum: a2eafb709acbabe40de4871c4e8684a03098f045dba4fc6c6e9281358d072f386a668488c109e2a36b8eade01dc4c4f9e8a76fa45c92591857c590c6e19f1ae7 + checksum: d38d6d9224f10ec11edf5281b2204db7be0dd1bd5225e55bb6a3d8f89b4015f316f6407086914c6a22e1f19cf3968fc750014b81034e91fd51cf28696d2b7b68 + languageName: node + linkType: hard + +"@nomicfoundation/hardhat-verify@npm:^1.0.0": + version: 1.1.1 + resolution: "@nomicfoundation/hardhat-verify@npm:1.1.1" + dependencies: + "@ethersproject/abi": ^5.1.2 + "@ethersproject/address": ^5.0.2 + cbor: ^8.1.0 + chalk: ^2.4.2 + debug: ^4.1.1 + lodash.clonedeep: ^4.5.0 + semver: ^6.3.0 + table: ^6.8.0 + undici: ^5.14.0 + peerDependencies: + hardhat: ^2.0.4 + checksum: 2d83d32d6833f23fb62c30c68c9a2ab3956098030edcf459e69639960f059c72572d203bcf92f191c69c9cb0fbbf011a1113bacde1e3cbb28d5e812334f04f32 languageName: node linkType: hard @@ -4307,35 +4350,31 @@ __metadata: languageName: node linkType: hard -"@typechain/ethers-v5@npm:^10.2.1": - version: 10.2.1 - resolution: "@typechain/ethers-v5@npm:10.2.1" +"@typechain/ethers-v6@npm:^0.5.0": + version: 0.5.0 + resolution: "@typechain/ethers-v6@npm:0.5.0" dependencies: lodash: ^4.17.15 ts-essentials: ^7.0.1 peerDependencies: - "@ethersproject/abi": ^5.0.0 - "@ethersproject/providers": ^5.0.0 - ethers: ^5.1.3 - typechain: ^8.1.1 - typescript: ">=4.3.0" - checksum: 852da4b1ff368ef87251111a5d50077de3d0fc12c519529269a74223740f8bda89297e67a5eb6c1f5b04ee23119566d6cbccf58264d32a83132be0f328a58d22 + ethers: 6.x + typechain: ^8.3.1 + typescript: ">=4.7.0" + checksum: 98ad8785b26bf750e2eac31989b0ec8b5bb2f4d2f567358ce9e05180c63c72ddde89d7b8caf79f0c36003e95475e524c1a7b98c40fa3eabcee1a8e1174a4015a languageName: node linkType: hard -"@typechain/hardhat@npm:^6.1.6": - version: 6.1.6 - resolution: "@typechain/hardhat@npm:6.1.6" +"@typechain/hardhat@npm:^9.0.0": + version: 9.0.0 + resolution: "@typechain/hardhat@npm:9.0.0" dependencies: fs-extra: ^9.1.0 peerDependencies: - "@ethersproject/abi": ^5.4.7 - "@ethersproject/providers": ^5.4.7 - "@typechain/ethers-v5": ^10.2.1 - ethers: ^5.4.7 + "@typechain/ethers-v6": ^0.5.0 + ethers: ^6.1.0 hardhat: ^2.9.9 - typechain: ^8.1.1 - checksum: f214bebf7860956230478cb92696ba757829cfd9dc65ac99c3bc7e539378310318d92b009054186f446595c8ffc1a81e9c6d028da0eb04253253049ea1b6e8d3 + typechain: ^8.3.1 + checksum: cf2f3ad5ffa3496c8452766ceece5a8a97011ee8932ee8c9639013fc7dac26758a11e2080b205d8aa3b236ee016ce838a1faeb7f85cb09ff4d82b25fec83e435 languageName: node linkType: hard @@ -4667,6 +4706,13 @@ __metadata: languageName: node linkType: hard +"@types/node@npm:18.15.13": + version: 18.15.13 + resolution: "@types/node@npm:18.15.13" + checksum: 79cc5a2b5f98e8973061a4260a781425efd39161a0e117a69cd089603964816c1a14025e1387b4590c8e82d05133b7b4154fa53a7dffb3877890a66145e76515 + languageName: node + linkType: hard + "@types/node@npm:^10.0.3": version: 10.17.60 resolution: "@types/node@npm:10.17.60" @@ -5084,18 +5130,6 @@ __metadata: languageName: node linkType: hard -"@wagmi/chains@npm:1.6.0": - version: 1.6.0 - resolution: "@wagmi/chains@npm:1.6.0" - peerDependencies: - typescript: ">=5.0.4" - peerDependenciesMeta: - typescript: - optional: true - checksum: 6c3d477936622f763b9e44c4a66c080020f1119165c8f6b840c51f5822880fedd5031036461d4b28df5cf1ae19cb12e139e4a4b3c129b475f0363fd9c4c8bb0d - languageName: node - linkType: hard - "@wagmi/chains@npm:1.7.0": version: 1.7.0 resolution: "@wagmi/chains@npm:1.7.0" @@ -6276,6 +6310,13 @@ __metadata: languageName: node linkType: hard +"aes-js@npm:4.0.0-beta.5": + version: 4.0.0-beta.5 + resolution: "aes-js@npm:4.0.0-beta.5" + checksum: cc2ea969d77df939c32057f7e361b6530aa6cb93cb10617a17a45cd164e6d761002f031ff6330af3e67e58b1f0a3a8fd0b63a720afd591a653b02f649470e15b + languageName: node + linkType: hard + "aes-js@npm:^3.1.2": version: 3.1.2 resolution: "aes-js@npm:3.1.2" @@ -10233,7 +10274,7 @@ __metadata: languageName: node linkType: hard -"ethers@npm:^5.5.3, ethers@npm:^5.6.5, ethers@npm:^5.7.1, ethers@npm:^5.7.2": +"ethers@npm:^5.5.3, ethers@npm:^5.6.5, ethers@npm:^5.7.1": version: 5.7.2 resolution: "ethers@npm:5.7.2" dependencies: @@ -10271,6 +10312,21 @@ __metadata: languageName: node linkType: hard +"ethers@npm:^6.4.0, ethers@npm:^6.7.1": + version: 6.7.1 + resolution: "ethers@npm:6.7.1" + dependencies: + "@adraffy/ens-normalize": 1.9.2 + "@noble/hashes": 1.1.2 + "@noble/secp256k1": 1.7.1 + "@types/node": 18.15.13 + aes-js: 4.0.0-beta.5 + tslib: 2.4.0 + ws: 8.5.0 + checksum: 07833692e3f53b18e28c4cba9f53f3d5ebff8360de02ad57b2584c00c52b88f5b790373f9b9f6b4f6b52ffa2074530a6101192b30c3260f7cdeff929d34bb88b + languageName: node + linkType: hard + "ethjs-unit@npm:0.1.6": version: 0.1.6 resolution: "ethjs-unit@npm:0.1.6" @@ -10884,15 +10940,15 @@ __metadata: copy-to-clipboard: ^3.3.3 cryptocurrency-icons: ^0.18.1 ethereum-blockies-base64: ^1.0.2 - ethers: ^5.7.2 + ethers: ^6.7.1 mech-sdk: "workspace:^" react: ^18.2.0 react-dom: ^18.2.0 react-router-dom: ^6.15.0 react-scripts: 5.0.1 - typescript: ^4.9.5 - typescript-plugin-css-modules: ^4.2.3 - viem: ^1.6.0 + typescript: ^5.1.6 + typescript-plugin-css-modules: ^5.0.1 + viem: ^1.6.4 wagmi: ^1.3.10 languageName: unknown linkType: soft @@ -13901,6 +13957,13 @@ __metadata: languageName: node linkType: hard +"lodash.clonedeep@npm:^4.5.0": + version: 4.5.0 + resolution: "lodash.clonedeep@npm:4.5.0" + checksum: 92c46f094b064e876a23c97f57f81fbffd5d760bf2d8a1c61d85db6d1e488c66b0384c943abee4f6af7debf5ad4e4282e74ff83177c9e63d8ff081a4837c3489 + languageName: node + linkType: hard + "lodash.debounce@npm:^4.0.8": version: 4.0.8 resolution: "lodash.debounce@npm:4.0.8" @@ -13908,7 +13971,7 @@ __metadata: languageName: node linkType: hard -"lodash.isequal@npm:4.5.0": +"lodash.isequal@npm:4.5.0, lodash.isequal@npm:^4.5.0": version: 4.5.0 resolution: "lodash.isequal@npm:4.5.0" checksum: da27515dc5230eb1140ba65ff8de3613649620e8656b19a6270afe4866b7bd461d9ba2ac8a48dcc57f7adac4ee80e1de9f965d89d4d81a0ad52bb3eec2609644 @@ -14169,15 +14232,17 @@ __metadata: "@ethersproject/providers": ^5.7.2 "@gnosis.pm/safe-contracts": ^1.3.0 "@gnosis.pm/zodiac": ^3.3.7 - "@nomicfoundation/hardhat-chai-matchers": ^1.0.6 + "@nomicfoundation/hardhat-chai-matchers": ^2.0.2 + "@nomicfoundation/hardhat-ethers": ^3.0.4 "@nomicfoundation/hardhat-network-helpers": ^1.0.8 - "@nomicfoundation/hardhat-toolbox": ^2.0.2 + "@nomicfoundation/hardhat-toolbox": ^3.0.0 + "@nomicfoundation/hardhat-verify": ^1.0.0 "@nomiclabs/hardhat-ethers": ^2.2.3 "@nomiclabs/hardhat-etherscan": ^3.1.7 "@openzeppelin/contracts": ^4.9.3 "@safe-global/safe-core-sdk": ^3.3.5 - "@typechain/ethers-v5": ^10.2.1 - "@typechain/hardhat": ^6.1.6 + "@typechain/ethers-v6": ^0.5.0 + "@typechain/hardhat": ^9.0.0 "@types/chai": ^4.3.5 "@types/mocha": ^10.0.1 "@types/node": ^18.17.5 @@ -14190,7 +14255,7 @@ __metadata: eslint-plugin-eslint-comments: ^3.2.0 eslint-plugin-import: ^2.28.0 eslint-plugin-prettier: ^4.2.1 - ethers: ^5.7.2 + ethers: ^6.4.0 hardhat: ^2.17.1 hardhat-deploy: ^0.11.36 hardhat-gas-reporter: ^1.0.9 @@ -14200,7 +14265,7 @@ __metadata: solidity-coverage: ^0.8.4 ts-node: ^10.9.1 typechain: ^8.3.1 - typescript: ^4.9.5 + typescript: ^5.1.6 languageName: unknown linkType: soft @@ -14214,10 +14279,10 @@ __metadata: "@safe-global/safe-core-sdk": ^3.3.5 "@types/chai": ^4.3.5 "@types/node": ^18.17.5 - ethers: ^5.7.2 + ethers: ^6.7.1 rimraf: ^4.4.1 - typescript: ^4.9.5 - viem: ^1.6.0 + typescript: ^5.1.6 + viem: ^1.6.4 languageName: unknown linkType: soft @@ -19576,6 +19641,13 @@ __metadata: languageName: node linkType: hard +"tslib@npm:2.4.0": + version: 2.4.0 + resolution: "tslib@npm:2.4.0" + checksum: 8c4aa6a3c5a754bf76aefc38026134180c053b7bd2f81338cb5e5ebf96fefa0f417bff221592bf801077f5bf990562f6264fecbc42cd3309b33872cb6fc3b113 + languageName: node + linkType: hard + "tslib@npm:^2.0.0, tslib@npm:^2.0.3, tslib@npm:^2.3.0, tslib@npm:^2.3.1": version: 2.6.0 resolution: "tslib@npm:2.6.0" @@ -19770,9 +19842,9 @@ __metadata: languageName: node linkType: hard -"typescript-plugin-css-modules@npm:^4.2.3": - version: 4.2.3 - resolution: "typescript-plugin-css-modules@npm:4.2.3" +"typescript-plugin-css-modules@npm:^5.0.1": + version: 5.0.1 + resolution: "typescript-plugin-css-modules@npm:5.0.1" dependencies: "@types/postcss-modules-local-by-default": ^4.0.0 "@types/postcss-modules-scope": ^3.0.1 @@ -19791,28 +19863,28 @@ __metadata: stylus: ^0.59.0 tsconfig-paths: ^4.1.2 peerDependencies: - typescript: ">=3.9.0" - checksum: 55455068b92cee070c024fa059283bdad5a4b7fa16615e13634a62c6698869ce44ff92e959de5aa2002abe409770f18584e6b982c69809d2d6319897a3234729 + typescript: ">=4.0.0" + checksum: 5d6d6003c97ce821904981273f9d6e9c1bb27b1b712b187fd17255eb27634a9dfe0a5e961b5dad3d1274c90161439736b65b605fd55c22d88907275a8abda9c8 languageName: node linkType: hard -"typescript@npm:^4.9.5": - version: 4.9.5 - resolution: "typescript@npm:4.9.5" +"typescript@npm:^5.1.6": + version: 5.1.6 + resolution: "typescript@npm:5.1.6" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: ee000bc26848147ad423b581bd250075662a354d84f0e06eb76d3b892328d8d4440b7487b5a83e851b12b255f55d71835b008a66cbf8f255a11e4400159237db + checksum: b2f2c35096035fe1f5facd1e38922ccb8558996331405eb00a5111cc948b2e733163cc22fab5db46992aba7dd520fff637f2c1df4996ff0e134e77d3249a7350 languageName: node linkType: hard -"typescript@patch:typescript@^4.9.5#~builtin": - version: 4.9.5 - resolution: "typescript@patch:typescript@npm%3A4.9.5#~builtin::version=4.9.5&hash=289587" +"typescript@patch:typescript@^5.1.6#~builtin": + version: 5.1.6 + resolution: "typescript@patch:typescript@npm%3A5.1.6#~builtin::version=5.1.6&hash=5da071" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 1f8f3b6aaea19f0f67cba79057674ba580438a7db55057eb89cc06950483c5d632115c14077f6663ea76fd09fce3c190e6414bb98582ec80aa5a4eaf345d5b68 + checksum: f53bfe97f7c8b2b6d23cf572750d4e7d1e0c5fff1c36d859d0ec84556a827b8785077bc27676bf7e71fae538e517c3ecc0f37e7f593be913d884805d931bc8be languageName: node linkType: hard @@ -20194,9 +20266,9 @@ __metadata: languageName: node linkType: hard -"viem@npm:^1.6.0": - version: 1.6.0 - resolution: "viem@npm:1.6.0" +"viem@npm:^1.6.4": + version: 1.6.4 + resolution: "viem@npm:1.6.4" dependencies: "@adraffy/ens-normalize": 1.9.0 "@noble/curves": 1.1.0 @@ -20204,7 +20276,7 @@ __metadata: "@scure/bip32": 1.3.0 "@scure/bip39": 1.2.0 "@types/ws": ^8.5.4 - "@wagmi/chains": 1.6.0 + "@wagmi/chains": 1.7.0 abitype: 0.9.3 isomorphic-ws: 5.0.0 ws: 8.12.0 @@ -20213,7 +20285,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: b01301645bc00d438318bea86fca63321e1a7e29a857a451207caaced89afb1472a219b8e62d4c42ef10cf8ef5d8fa945b0c1a2a2fdef5af08aa2ff3ae9aa250 + checksum: 3b77db9e09fd7066f29db48fe37817a126bbafe97c36f2737c15684e1d5ed1a6458d37f336036702052b17bbb552b0687ec8ae4514b82ad3c9a07b6a07c051a1 languageName: node linkType: hard @@ -21095,6 +21167,21 @@ __metadata: languageName: node linkType: hard +"ws@npm:8.5.0": + version: 8.5.0 + resolution: "ws@npm:8.5.0" + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + checksum: 76f2f90e40344bf18fd544194e7067812fb1372b2a37865678d8f12afe4b478ff2ebc0c7c0aff82cd5e6b66fc43d889eec0f1865c2365d8f7a66d92da7744a77 + languageName: node + linkType: hard + "ws@npm:^7.4.0, ws@npm:^7.4.5, ws@npm:^7.4.6, ws@npm:^7.5.1": version: 7.5.9 resolution: "ws@npm:7.5.9" From 00304e469f81cdaec9e0ba67e57d9043e66fcdcd Mon Sep 17 00:00:00 2001 From: Jan-Felix Date: Mon, 21 Aug 2023 16:01:47 +0200 Subject: [PATCH 21/41] ethers v5 -> v6 migration --- ... 00_deploy_mastercopy_ERC721Tokenbound.ts} | 19 +- ...01_deploy_mastercopy_ERC1155Tokenbound.ts} | 19 +- deploy/02_deploy_mastercopy_Zodiac.ts | 5 +- integrationTest/SafeMigration.ts | 28 ++- integrationTest/accountAbstraction.ts | 56 ++--- sdk/src/deploy/deployERC1155ThresholdMech.ts | 3 - ...ansaction.ts => makeExecuteTransaction.ts} | 6 +- sdk/src/sign/signWithMech.ts | 8 +- test/Account.ts | 43 ++-- test/Mech.ts | 199 +++++++++++------- test/Receiver.ts | 87 ++++---- test/ZodiacMech.ts | 84 ++++---- test/signing.ts | 19 +- 13 files changed, 315 insertions(+), 261 deletions(-) rename deploy/{01_deploy_mastercopy_ERC1155.ts => 00_deploy_mastercopy_ERC721Tokenbound.ts} (61%) rename deploy/{00_deploy_mastercopy_ERC721.ts => 01_deploy_mastercopy_ERC1155Tokenbound.ts} (61%) rename sdk/src/execute/{makeExecTransaction.ts => makeExecuteTransaction.ts} (86%) diff --git a/deploy/01_deploy_mastercopy_ERC1155.ts b/deploy/00_deploy_mastercopy_ERC721Tokenbound.ts similarity index 61% rename from deploy/01_deploy_mastercopy_ERC1155.ts rename to deploy/00_deploy_mastercopy_ERC721Tokenbound.ts index 6c7dfdf..ef4e79b 100644 --- a/deploy/01_deploy_mastercopy_ERC1155.ts +++ b/deploy/00_deploy_mastercopy_ERC721Tokenbound.ts @@ -1,22 +1,21 @@ import { DeployFunction } from "hardhat-deploy/types" import { - calculateERC1155MechMastercopyAddress, - deployERC1155MechMastercopy, - ERC1155_MASTERCOPY_INIT_DATA, -} from "../sdk" + calculateERC721TokenboundMechMastercopyAddress, + deployERC721TokenboundMechMastercopy, +} from "../sdk/build/cjs/sdk/src" -const deployMastercopyERC1155: DeployFunction = async (hre) => { +const deployMastercopyERC721Tokenbound: DeployFunction = async (hre) => { const [signer] = await hre.ethers.getSigners() const deployer = hre.ethers.provider.getSigner(signer.address) - await deployERC1155MechMastercopy(deployer) - const address = calculateERC1155MechMastercopyAddress() + await deployERC721TokenboundMechMastercopy(deployer) + const address = calculateERC721TokenboundMechMastercopyAddress() try { await hre.run("verify:verify", { address, - constructorArguments: ERC1155_MASTERCOPY_INIT_DATA, + constructorArguments: [], }) } catch (e) { if ( @@ -35,6 +34,6 @@ const deployMastercopyERC1155: DeployFunction = async (hre) => { } } -deployMastercopyERC1155.tags = ["ERC1155Mech"] +deployMastercopyERC721Tokenbound.tags = ["ERC721TokenboundMech"] -export default deployMastercopyERC1155 +export default deployMastercopyERC721Tokenbound diff --git a/deploy/00_deploy_mastercopy_ERC721.ts b/deploy/01_deploy_mastercopy_ERC1155Tokenbound.ts similarity index 61% rename from deploy/00_deploy_mastercopy_ERC721.ts rename to deploy/01_deploy_mastercopy_ERC1155Tokenbound.ts index 047a138..c4a9747 100644 --- a/deploy/00_deploy_mastercopy_ERC721.ts +++ b/deploy/01_deploy_mastercopy_ERC1155Tokenbound.ts @@ -1,22 +1,21 @@ import { DeployFunction } from "hardhat-deploy/types" import { - calculateERC721MechMastercopyAddress, - deployERC721MechMastercopy, - ERC721_MASTERCOPY_INIT_DATA, -} from "../sdk" + calculateERC1155TokenboundMechMastercopyAddress, + deployERC1155TokenboundMechMastercopy, +} from "../sdk/build/cjs/sdk/src" -const deployMastercopyERC721: DeployFunction = async (hre) => { +const deployMastercopyERC1155Tokenbound: DeployFunction = async (hre) => { const [signer] = await hre.ethers.getSigners() const deployer = hre.ethers.provider.getSigner(signer.address) - await deployERC721MechMastercopy(deployer) - const address = calculateERC721MechMastercopyAddress() + await deployERC1155TokenboundMechMastercopy(deployer) + const address = calculateERC1155TokenboundMechMastercopyAddress() try { await hre.run("verify:verify", { address, - constructorArguments: ERC721_MASTERCOPY_INIT_DATA, + constructorArguments: [], }) } catch (e) { if ( @@ -35,6 +34,6 @@ const deployMastercopyERC721: DeployFunction = async (hre) => { } } -deployMastercopyERC721.tags = ["ERC721Mech"] +deployMastercopyERC1155Tokenbound.tags = ["ERC1155TokenboundMech"] -export default deployMastercopyERC721 +export default deployMastercopyERC1155Tokenbound diff --git a/deploy/02_deploy_mastercopy_Zodiac.ts b/deploy/02_deploy_mastercopy_Zodiac.ts index c98cba0..e366312 100644 --- a/deploy/02_deploy_mastercopy_Zodiac.ts +++ b/deploy/02_deploy_mastercopy_Zodiac.ts @@ -3,7 +3,6 @@ import { DeployFunction } from "hardhat-deploy/types" import { calculateZodiacMechMastercopyAddress, deployZodiacMechMastercopy, - ZODIAC_MASTERCOPY_INIT_DATA, } from "../sdk" const deployMastercopyZodiac: DeployFunction = async (hre) => { @@ -11,7 +10,7 @@ const deployMastercopyZodiac: DeployFunction = async (hre) => { return const [signer] = await hre.ethers.getSigners() - const deployer = hre.ethers.provider.getSigner(signer.address) + const deployer = await hre.ethers.provider.getSigner(signer.address) await deployZodiacMechMastercopy(deployer) const address = calculateZodiacMechMastercopyAddress() @@ -19,7 +18,7 @@ const deployMastercopyZodiac: DeployFunction = async (hre) => { try { await hre.run("verify:verify", { address, - constructorArguments: ZODIAC_MASTERCOPY_INIT_DATA, + constructorArguments: [], }) } catch (e) { if ( diff --git a/integrationTest/SafeMigration.ts b/integrationTest/SafeMigration.ts index d4be5db..57f3d62 100644 --- a/integrationTest/SafeMigration.ts +++ b/integrationTest/SafeMigration.ts @@ -1,5 +1,5 @@ import { expect } from "chai" -import { defaultAbiCoder, parseEther } from "ethers/lib/utils" +import { AbiCoder, parseEther } from "ethers" import { ethers, network } from "hardhat" import { @@ -13,7 +13,7 @@ import { IAvatar__factory } from "../typechain-types/factories/@gnosis.pm/zodiac describe("Safe migration", () => { it("supports migrating an existing Safe to a ZodiacMech", async () => { const [signer] = await ethers.getSigners() - const deployer = ethers.provider.getSigner(signer.address) + const deployer = await ethers.provider.getSigner(signer.address) // migrate the Gnosis DAO Safe const safeAddress = "0x849D52316331967b6fF1198e5E32A0eB168D039d" @@ -40,8 +40,14 @@ describe("Safe migration", () => { // sanity check making sure the Gnosis DAO Safe is configured as expected expect(await safe.isModuleEnabled(enabledModule)).to.be.true - await expect(zodiacMech.execute(ZERO_ADDRESS, parseEther("1.0"), "0x", 0)) - .to.be.reverted + await expect( + zodiacMech["execute(address,uint256,bytes,uint8)"]( + ZERO_ADDRESS, + parseEther("1.0"), + "0x", + 0 + ) + ).to.be.reverted // deploy ZodiacMech mastercopy const zodiacMechMastercopyAddress = calculateZodiacMechMastercopyAddress() @@ -57,7 +63,7 @@ describe("Safe migration", () => { // migrate the Safe await expect( safe.execTransactionFromModule( - migrationLib.address, + migrationLib.getAddress(), 0, migrationLib.interface.encodeFunctionData("migrate"), 1 // important: delegatecall @@ -71,12 +77,20 @@ describe("Safe migration", () => { params: [safeAddress, "0x0"], }) ).to.equal( - defaultAbiCoder.encode(["address"], [zodiacMechMastercopyAddress]) + AbiCoder.defaultAbiCoder().encode( + ["address"], + [zodiacMechMastercopyAddress] + ) ) // make sure the Safe is now a ZodiacMech await expect( - zodiacMech.execute(ZERO_ADDRESS, parseEther("1.0"), "0x", 0) + zodiacMech["execute(address,uint256,bytes,uint8)"]( + ZERO_ADDRESS, + parseEther("1.0"), + "0x", + 0 + ) ).to.changeEtherBalance(safeAddress, parseEther("-1.0")) // the enabled modules did not change diff --git a/integrationTest/accountAbstraction.ts b/integrationTest/accountAbstraction.ts index cae608e..d96b624 100644 --- a/integrationTest/accountAbstraction.ts +++ b/integrationTest/accountAbstraction.ts @@ -1,12 +1,7 @@ import { anyValue } from "@nomicfoundation/hardhat-chai-matchers/withArgs" -import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers" +import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers" import { expect } from "chai" -import { - arrayify, - defaultAbiCoder, - hexConcat, - keccak256, -} from "ethers/lib/utils" +import { AbiCoder, concat, getBytes, keccak256 } from "ethers" import { ethers, network } from "hardhat" import { @@ -27,13 +22,17 @@ const entryPointAddress = "0x0576a174D229E3cFA37253523E645A78A0C91B57" describe("account abstraction", () => { it("implements ERC-4337 account abstraction", async () => { const [signer, enabledModule, anotherModule] = await ethers.getSigners() - const deployer = ethers.provider.getSigner(signer.address) + const deployer = await ethers.provider.getSigner(await signer.getAddress()) // deploy a ZodiacMech await deployZodiacMechMastercopy(deployer) - await deployZodiacMech([enabledModule.address], deployer) + await deployZodiacMech(deployer, { + modules: [(await enabledModule.getAddress()) as `0x${string}`], + }) const zodiacMech = ZodiacMech__factory.connect( - calculateZodiacMechAddress([enabledModule.address]), + calculateZodiacMechAddress([ + (await enabledModule.getAddress()) as `0x${string}`, + ]), deployer ) @@ -46,14 +45,14 @@ describe("account abstraction", () => { await fillUserOp( { callData: zodiacMech.interface.encodeFunctionData("enableModule", [ - anotherModule.address, + anotherModule.getAddress(), ]), }, zodiacMech ), enabledModule ) - await expect(entryPoint.handleOps([userOp], signer.address)) + await expect(entryPoint.handleOps([userOp], signer.getAddress())) .to.emit(entryPoint, "UserOperationEvent") .withArgs( getUserOpHash(userOp), @@ -66,19 +65,20 @@ describe("account abstraction", () => { ) // make sure the module is enabled - expect(await zodiacMech.isModuleEnabled(anotherModule.address)).to.be.true + expect(await zodiacMech.isModuleEnabled(anotherModule.getAddress())).to.be + .true }) it("deploys the mech at the expected address if it does not exist yet", async () => { // skip 2 signers, so this test const [signer, , , enabledModule, anotherModule] = await ethers.getSigners() - const deployer = ethers.provider.getSigner(signer.address) + const deployer = ethers.provider.getSigner(signer.getAddress()) // deploy the ZodiacMech mastercopy await deployZodiacMechMastercopy(deployer) // make sure the mech does not exist yet - const mechAddress = calculateZodiacMechAddress([enabledModule.address]) + const mechAddress = calculateZodiacMechAddress([enabledModule.getAddress()]) expect(await ethers.provider.getCode(mechAddress)).to.equal("0x") // make sure the entry point contract is there @@ -87,10 +87,10 @@ describe("account abstraction", () => { // calculate the ZodiacMech init code const deployTx = await makeZodiacMechDeployTransaction( - [enabledModule.address], + [enabledModule.getAddress()], ethers.provider ) - const initCode = hexConcat([deployTx.to, deployTx.data]) + const initCode = concat([deployTx.to, deployTx.data]) const zodiacMech = ZodiacMech__factory.connect(mechAddress, deployer) @@ -100,7 +100,7 @@ describe("account abstraction", () => { { // sender: mechAddress, // optional callData: zodiacMech.interface.encodeFunctionData("enableModule", [ - anotherModule.address, + anotherModule.getAddress(), ]), initCode, nonce: 0, @@ -110,7 +110,7 @@ describe("account abstraction", () => { enabledModule ) - await expect(entryPoint.handleOps([userOp], signer.address)) + await expect(entryPoint.handleOps([userOp], signer.getAddress())) .to.emit(entryPoint, "UserOperationEvent") .withArgs( getUserOpHash(userOp), @@ -126,7 +126,8 @@ describe("account abstraction", () => { expect(await ethers.provider.getCode(mechAddress)).to.not.equal("0x") // make sure the module is enabled - expect(await zodiacMech.isModuleEnabled(anotherModule.address)).to.be.true + expect(await zodiacMech.isModuleEnabled(anotherModule.getAddress())).to.be + .true }) }) @@ -135,7 +136,7 @@ export const fillUserOp = async ( op: Partial, account: ZodiacMech ): Promise => ({ - sender: account.address, + sender: account.getAddress(), callData: "0x", initCode: "0x", callGasLimit: 100000, @@ -150,9 +151,9 @@ export const fillUserOp = async ( export const signUserOp = async ( op: UserOperation, - signer: SignerWithAddress + signer: HardhatEthersSigner ): Promise => { - const message = arrayify(getUserOpHash(op)) + const message = getBytes(getUserOpHash(op)) return { ...op, @@ -164,7 +165,7 @@ export function getUserOpHash(op: UserOperation): string { const { chainId } = network.config const userOpHash = keccak256(packUserOp(op)) - const enc = defaultAbiCoder.encode( + const enc = AbiCoder.defaultAbiCoder().encode( ["bytes32", "address", "uint256"], [userOpHash, entryPointAddress, chainId] ) @@ -173,10 +174,9 @@ export function getUserOpHash(op: UserOperation): string { function packUserOp(op: UserOperation): string { const userOpAbiType = - ZodiacMech__factory.createInterface().functions[ - "validateUserOp((address,uint256,bytes,bytes,uint256,uint256,uint256,uint256,uint256,bytes,bytes),bytes32,uint256)" - ].inputs[0] - const encoded = defaultAbiCoder.encode( + ZodiacMech__factory.createInterface().getFunction("validateUserOp") + .inputs[0] + const encoded = AbiCoder.defaultAbiCoder().encode( [userOpAbiType], [{ ...op, signature: "0x" }] ) diff --git a/sdk/src/deploy/deployERC1155ThresholdMech.ts b/sdk/src/deploy/deployERC1155ThresholdMech.ts index 4ed4232..cbcba60 100644 --- a/sdk/src/deploy/deployERC1155ThresholdMech.ts +++ b/sdk/src/deploy/deployERC1155ThresholdMech.ts @@ -13,7 +13,6 @@ import { DEFAULT_SALT, ERC2470_SINGLETON_FACTORY_ADDRESS, MECH_FACTORY_ADDRESS, - ZERO_ADDRESS, } from "../constants" import { deployMastercopy, mechProxyBytecode } from "./factory" @@ -55,8 +54,6 @@ export const calculateERC1155ThresholdMechAddress = ({ }) } -export const ERC1155_MASTERCOPY_INIT_DATA = [ZERO_ADDRESS, [0], [0], 0] - export const calculateERC1155ThresholdMechMastercopyAddress = () => { return getCreate2Address({ bytecode: ERC1155ThresholdMech__factory.bytecode, diff --git a/sdk/src/execute/makeExecTransaction.ts b/sdk/src/execute/makeExecuteTransaction.ts similarity index 86% rename from sdk/src/execute/makeExecTransaction.ts rename to sdk/src/execute/makeExecuteTransaction.ts index 5453d6d..ba3ecbb 100644 --- a/sdk/src/execute/makeExecTransaction.ts +++ b/sdk/src/execute/makeExecuteTransaction.ts @@ -1,4 +1,4 @@ -import { BigNumber, BigNumberish } from "ethers" +import { BigNumberish } from "ethers" import { IMech__factory } from "../../../typechain-types" @@ -20,7 +20,7 @@ export const makeExecuteTransaction = ( transaction: TransactionRequest ) => { const { nonce, to, from, gasPrice, gasLimit, data, value } = transaction - const txGas = gasLimit ? BigNumber.from(gasLimit).sub(BASE_TX_GAS) : BigInt(0) + const txGas = gasLimit ? BigInt(gasLimit) - BASE_TX_GAS : BigInt(0) if (from && from.toLowerCase() !== mechAddress.toLowerCase()) { throw new Error( @@ -32,7 +32,7 @@ export const makeExecuteTransaction = ( to: mechAddress, from: undefined, - gasPrice: BigNumber.from(gasPrice).toBigInt(), + gasPrice: gasPrice !== undefined ? BigInt(gasPrice) : undefined, // gas for mech's onlyOperator modifier still needs to be calculated (can't be fixed, since it depends on external ERC721 ownerOf() function) gasLimit: undefined, diff --git a/sdk/src/sign/signWithMech.ts b/sdk/src/sign/signWithMech.ts index ab4c9a5..7e60d07 100644 --- a/sdk/src/sign/signWithMech.ts +++ b/sdk/src/sign/signWithMech.ts @@ -1,10 +1,10 @@ import { defaultAbiCoder } from "@ethersproject/abi" -import { Bytes } from "ethers" -import { arrayify, hexlify } from "ethers/lib/utils" +import { BytesLike } from "ethers" +import { getBytes, hexlify } from "ethers" export const signWithMech = ( mechAddress: string, - signatureData: string | Bytes + signatureData: BytesLike ): `0x${string}` => { // Produce a signature as bytes of the form: // {bytes32 r = mech address}{bytes32 s = 65 (offset to signature data)}{unpadded uint8 v = 0}{bytes32 signature data length}{bytes signature data} @@ -16,7 +16,7 @@ export const signWithMech = ( const data = hexlify(signatureData).slice(2) const dataLength = defaultAbiCoder - .encode(["uint256"], [arrayify(signatureData).length]) + .encode(["uint256"], [getBytes(signatureData).length]) .slice(2) return `0x${r}${s}${v}${dataLength}${data}` diff --git a/test/Account.ts b/test/Account.ts index 67e48f1..363f770 100644 --- a/test/Account.ts +++ b/test/Account.ts @@ -1,12 +1,7 @@ +import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers" import { loadFixture } from "@nomicfoundation/hardhat-network-helpers" -import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers" import { expect } from "chai" -import { - arrayify, - defaultAbiCoder, - keccak256, - parseEther, -} from "ethers/lib/utils" +import { AbiCoder, getBytes, keccak256, parseEther } from "ethers" import { ethers, network } from "hardhat" import { ZERO_ADDRESS } from "../sdk/src/constants" @@ -24,16 +19,18 @@ describe("Account base contract", () => { // Network to that snapshot in every test. async function deployMech1() { const TestToken = await ethers.getContractFactory("ERC721Token") - const ERC721Mech = await ethers.getContractFactory("ERC721Mech") + const ERC721TokenboundMech = await ethers.getContractFactory( + "ERC721TokenboundMech" + ) const [deployer, alice, bob] = await ethers.getSigners() const testToken = await TestToken.deploy() - const mech1 = await ERC721Mech.deploy(testToken.address, 1) + const mech1 = await ERC721TokenboundMech.deploy(testToken.getAddress(), 1) // make alice the operator of mech1 await testToken.mintToken(alice.address, 1) - await mech1.deployed() + await mech1.waitForDeployment() await network.provider.request({ method: "hardhat_impersonateAccount", @@ -45,7 +42,7 @@ describe("Account base contract", () => { // Fixtures can return anything you consider useful for your tests return { - ERC721Mech, + ERC721TokenboundMech, testToken, mech1, alice, @@ -55,7 +52,7 @@ describe("Account base contract", () => { } const BURN_1_ETH = Mech__factory.createInterface().encodeFunctionData( - "execute", + "execute(address,uint256,bytes,uint8)", [ZERO_ADDRESS, parseEther("1.0"), "0x", 0] ) @@ -94,7 +91,7 @@ describe("Account base contract", () => { expect( await mech1 .connect(entryPointSigner) - .callStatic.validateUserOp(userOp, getUserOpHash(userOp), 0) + .validateUserOp.staticCallResult(userOp, getUserOpHash(userOp), 0) ).to.equal(0) }) @@ -114,7 +111,7 @@ describe("Account base contract", () => { expect( await mech1 .connect(entryPointSigner) - .callStatic.validateUserOp(userOp, getUserOpHash(userOp), 0) + .validateUserOp.staticCallResult(userOp, getUserOpHash(userOp), 0) ).to.equal(1) }) @@ -133,7 +130,7 @@ describe("Account base contract", () => { // fund mech1 with 1 ETH await alice.sendTransaction({ - to: mech1.address, + to: mech1.getAddress(), value: parseEther("1.0"), }) @@ -143,7 +140,7 @@ describe("Account base contract", () => { .connect(entryPointSigner) .validateUserOp(userOp, getUserOpHash(userOp), parseEther("0.123")) ).to.changeEtherBalances( - [mech1.address, entryPointSigner.address], + [mech1.getAddress(), entryPointSigner.address], [parseEther("-0.123"), parseEther("0.123")] ) }) @@ -155,7 +152,7 @@ export const fillUserOp = async ( op: Partial, account: Account ): Promise => ({ - sender: account.address, + sender: account.getAddress(), callData: "0x", initCode: "0x", callGasLimit: 0, @@ -170,9 +167,9 @@ export const fillUserOp = async ( export const signUserOp = async ( op: UserOperation, - signer: SignerWithAddress + signer: HardhatEthersSigner ): Promise => { - const message = arrayify(getUserOpHash(op)) + const message = getBytes(getUserOpHash(op)) return { ...op, @@ -184,7 +181,7 @@ export function getUserOpHash(op: UserOperation): string { const { chainId } = network.config const userOpHash = keccak256(packUserOp(op)) - const enc = defaultAbiCoder.encode( + const enc = AbiCoder.defaultAbiCoder().encode( ["bytes32", "address", "uint256"], [userOpHash, entryPoint, chainId] ) @@ -193,10 +190,8 @@ export function getUserOpHash(op: UserOperation): string { function packUserOp(op: UserOperation): string { const userOpAbiType = - Account__factory.createInterface().functions[ - "validateUserOp((address,uint256,bytes,bytes,uint256,uint256,uint256,uint256,uint256,bytes,bytes),bytes32,uint256)" - ].inputs[0] - const encoded = defaultAbiCoder.encode( + Account__factory.createInterface().getFunction("validateUserOp").inputs[0] + const encoded = AbiCoder.defaultAbiCoder().encode( [userOpAbiType], [{ ...op, signature: "0x" }] ) diff --git a/test/Mech.ts b/test/Mech.ts index 8840335..add71d3 100644 --- a/test/Mech.ts +++ b/test/Mech.ts @@ -1,5 +1,6 @@ import { loadFixture } from "@nomicfoundation/hardhat-network-helpers" import { expect } from "chai" +import { hashMessage } from "ethers" import { ethers } from "hardhat" // We use `loadFixture` to share common setups (or fixtures) between tests. @@ -15,16 +16,18 @@ describe("Mech base contract", () => { // Network to that snapshot in every test. async function deployMech1() { const TestToken = await ethers.getContractFactory("ERC721Token") - const ERC721Mech = await ethers.getContractFactory("ERC721Mech") + const ERC721TokenboundMech = await ethers.getContractFactory( + "ERC721TokenboundMech" + ) const [, alice, bob] = await ethers.getSigners() const testToken = await TestToken.deploy() - const mech1 = await ERC721Mech.deploy(testToken.address, 1) + const mech1 = await ERC721TokenboundMech.deploy(testToken.getAddress(), 1) - await mech1.deployed() + await mech1.waitForDeployment() // Fixtures can return anything you consider useful for your tests - return { ERC721Mech, testToken, mech1, alice, bob } + return { ERC721TokenboundMech, testToken, mech1, alice, bob } } describe("isValidSignature()", () => { @@ -33,11 +36,11 @@ describe("Mech base contract", () => { // mech1 is linked to testToken#1 // mint testToken#1 to alice - await testToken.mintToken(alice.address, 1) + await testToken.mintToken(alice.getAddress(), 1) const message = "Test message" const signature = await alice.signMessage(message) - const messageHash = ethers.utils.hashMessage(message) + const messageHash = hashMessage(message) expect(await mech1.isValidSignature(messageHash, signature)).to.equal( EIP1271_MAGIC_VALUE @@ -49,12 +52,12 @@ describe("Mech base contract", () => { // mech1 is linked to testToken#1 // mint testToken#1 to alice - await testToken.mintToken(alice.address, 1) + await testToken.mintToken(alice.getAddress(), 1) // let bob sign message const message = "Test message" const signature = await bob.signMessage(message) - const messageHash = ethers.utils.hashMessage(message) + const messageHash = hashMessage(message) expect(await mech1.isValidSignature(messageHash, signature)).to.equal( "0xffffffff" @@ -62,25 +65,27 @@ describe("Mech base contract", () => { }) it("returns magic value for a valid EIP-1271 signature of the mech operator contract", async () => { - const { ERC721Mech, mech1, testToken, alice } = await loadFixture( - deployMech1 - ) + const { ERC721TokenboundMech, mech1, testToken, alice } = + await loadFixture(deployMech1) // mech1 is linked to testToken#1 - const mech2 = await ERC721Mech.deploy(testToken.address, 2) - await mech2.deployed() + const mech2 = await ERC721TokenboundMech.deploy(testToken.getAddress(), 2) + await mech2.waitForDeployment() // mint testToken#1 to alice - await testToken.mintToken(alice.address, 1) + await testToken.mintToken(alice.getAddress(), 1) // mint testToken#2 to mech1, making mech1 the operator of mech2 - await testToken.mintToken(mech1.address, 2) + await testToken.mintToken(mech1.getAddress(), 2) const message = "Test message" const ecdsaSignature = await alice.signMessage(message) - const messageHash = ethers.utils.hashMessage(message) + const messageHash = hashMessage(message) - const contractSignature = signWithMech(mech1.address, ecdsaSignature) + const contractSignature = signWithMech( + await mech1.getAddress(), + ecdsaSignature + ) expect( await mech2.isValidSignature(messageHash, contractSignature) @@ -92,13 +97,16 @@ describe("Mech base contract", () => { // mech1 is linked to testToken#1 // mint testToken#1 to alice - await testToken.mintToken(alice.address, 1) + await testToken.mintToken(alice.getAddress(), 1) const message = "Test message" const ecdsaSignature = await alice.signMessage(message) - const messageHash = ethers.utils.hashMessage(message) + const messageHash = hashMessage(message) - const ownContractSignature = signWithMech(mech1.address, ecdsaSignature) + const ownContractSignature = signWithMech( + await mech1.getAddress(), + ecdsaSignature + ) expect( await mech1.isValidSignature(messageHash, ownContractSignature) @@ -106,25 +114,27 @@ describe("Mech base contract", () => { }) it("returns zero for an invalid EIP-1271 signature of the mech operator contract", async () => { - const { ERC721Mech, mech1, testToken, alice, bob } = await loadFixture( - deployMech1 - ) + const { ERC721TokenboundMech, mech1, testToken, alice, bob } = + await loadFixture(deployMech1) // mech1 is linked to testToken#1 - const mech2 = await ERC721Mech.deploy(testToken.address, 2) - await mech2.deployed() + const mech2 = await ERC721TokenboundMech.deploy(testToken.getAddress(), 2) + await mech2.waitForDeployment() // mint testToken#1 to alice - await testToken.mintToken(alice.address, 1) + await testToken.mintToken(alice.getAddress(), 1) // mint testToken#2 to mech1 - await testToken.mintToken(mech1.address, 2) + await testToken.mintToken(mech1.getAddress(), 2) const message = "Test message" const wrongEcdsaSignature = await bob.signMessage(message) - const messageHash = ethers.utils.hashMessage(message) + const messageHash = hashMessage(message) - const contractSignature = signWithMech(mech1.address, wrongEcdsaSignature) + const contractSignature = signWithMech( + await mech1.getAddress(), + wrongEcdsaSignature + ) expect( await mech2.isValidSignature(messageHash, contractSignature) @@ -132,25 +142,27 @@ describe("Mech base contract", () => { }) it("returns zero for an EIP-1271 signature from a contract that is not the mech operator", async () => { - const { ERC721Mech, mech1, testToken, alice } = await loadFixture( - deployMech1 - ) + const { ERC721TokenboundMech, mech1, testToken, alice } = + await loadFixture(deployMech1) // mech1 is linked to testToken#1 - const mech2 = await ERC721Mech.deploy(testToken.address, 2) - await mech2.deployed() + const mech2 = await ERC721TokenboundMech.deploy(testToken.getAddress(), 2) + await mech2.waitForDeployment() // mint testToken#1 to alice - await testToken.mintToken(alice.address, 1) + await testToken.mintToken(alice.getAddress(), 1) // mint testToken#2 to mech1 - await testToken.mintToken(mech1.address, 2) + await testToken.mintToken(mech1.getAddress(), 2) const message = "Test message" const ecdsaSignature = await alice.signMessage(message) - const messageHash = ethers.utils.hashMessage(message) + const messageHash = hashMessage(message) - const contractSignature = signWithMech(mech2.address, ecdsaSignature) + const contractSignature = signWithMech( + await mech2.getAddress(), + ecdsaSignature + ) expect( await mech1.isValidSignature(messageHash, contractSignature) @@ -165,15 +177,20 @@ describe("Mech base contract", () => { // don't mint testToken#1 // make testTx (token#2 transfer from mech1 to alice) - await testToken.mintToken(mech1.address, 2) - const testTx = await testToken.populateTransaction.transferFrom( - mech1.address, - alice.address, + await testToken.mintToken(mech1.getAddress(), 2) + const testTx = await testToken.transferFrom.populateTransaction( + mech1.getAddress(), + alice.getAddress(), 2 ) await expect( - mech1.execute(testToken.address, 0, testTx.data as string, 0) + mech1["execute(address,uint256,bytes,uint8)"]( + testToken.getAddress(), + 0, + testTx.data as string, + 0 + ) ).to.be.revertedWith("ERC721: invalid token ID") }) @@ -181,19 +198,24 @@ describe("Mech base contract", () => { const { mech1, testToken, alice } = await loadFixture(deployMech1) // mint testToken#1 to alice to make her the operator of mech1 - await testToken.mintToken(alice.address, 1) + await testToken.mintToken(alice.getAddress(), 1) // make testTx (token#2 transfer from mech1 to alice) - await testToken.mintToken(mech1.address, 2) - const testTx = await testToken.populateTransaction.transferFrom( - mech1.address, - alice.address, + await testToken.mintToken(mech1.getAddress(), 2) + const testTx = await testToken.transferFrom.populateTransaction( + mech1.getAddress(), + alice.getAddress(), 2 ) // call exec() from deployer who is not an operator await expect( - mech1.execute(testToken.address, 0, testTx.data as string, 0) + mech1["execute(address,uint256,bytes,uint8)"]( + testToken.getAddress(), + 0, + testTx.data as string, + 0 + ) ).to.be.revertedWith( "Only callable by the mech operator or the entry point contract" ) @@ -203,18 +225,23 @@ describe("Mech base contract", () => { const { mech1, testToken, alice } = await loadFixture(deployMech1) // mint testToken#1 to alice to make her the operator of mech1 - await testToken.mintToken(alice.address, 1) + await testToken.mintToken(alice.getAddress(), 1) // this tx will revert because mech1 does not own token#1 const revertingTxData = testToken.interface.encodeFunctionData( "transferFrom", - [mech1.address, alice.address, 1] + [mech1.getAddress(), alice.getAddress(), 1] ) await expect( mech1 .connect(alice) - .execute(testToken.address, 0, revertingTxData, 0, 0) + ["execute(address,uint256,bytes,uint8)"]( + testToken.getAddress(), + 0, + revertingTxData, + 0 + ) ).to.be.revertedWith("ERC721: caller is not token owner or approved") }) @@ -222,26 +249,32 @@ describe("Mech base contract", () => { const { mech1, testToken, alice } = await loadFixture(deployMech1) // mint testToken#1 to alice to make her the operator of mech1 - await testToken.mintToken(alice.address, 1) + await testToken.mintToken(alice.getAddress(), 1) // this tx will revert because mech1 does not own token#1 const callData = testToken.interface.encodeFunctionData("ownerOf", [1]) - const result = await mech1 + const [result] = await mech1 .connect(alice) - .callStatic.execute(testToken.address, 0, callData, 0) + ["execute(address,uint256,bytes,uint8)"].staticCallResult( + testToken.getAddress(), + 0, + callData, + 0 + ) + const decoded = testToken.interface.decodeFunctionResult( "ownerOf", result ) - expect(decoded[0]).to.equal(alice.address) + expect(decoded[0]).to.equal(alice.getAddress()) }) it("allows to execute delegate calls", async () => { const { mech1, testToken, alice } = await loadFixture(deployMech1) // mint testToken#1 to alice to make her the operator of mech1 - await testToken.mintToken(alice.address, 1) + await testToken.mintToken(alice.getAddress(), 1) // deploy a contract with a test() function that reverts if not called via delegatecall const DelegateCall = await ethers.getContractFactory("DelegateCall") @@ -251,12 +284,26 @@ describe("Mech base contract", () => { // this should revert because the call is not a delegate call await expect( - mech1.connect(alice).execute(delegateCall.address, 0, callData, 0) + mech1 + .connect(alice) + ["execute(address,uint256,bytes,uint8)"]( + delegateCall.getAddress(), + 0, + callData, + 0 + ) ).to.be.revertedWith("Can only be called via delegatecall") // this should succeed because the call is a delegate call await expect( - mech1.connect(alice).execute(delegateCall.address, 0, callData, 1) + mech1 + .connect(alice) + ["execute(address,uint256,bytes,uint8)"]( + delegateCall.getAddress(), + 0, + callData, + 1 + ) ).to.not.be.reverted }) @@ -264,34 +311,34 @@ describe("Mech base contract", () => { const { mech1, testToken, alice, bob } = await loadFixture(deployMech1) // mint testToken#1 to alice to make her the operator of mech1 - await testToken.mintToken(alice.address, 1) + await testToken.mintToken(alice.getAddress(), 1) // mint testToken#2 to alice - await testToken.mintToken(alice.address, 2) + await testToken.mintToken(alice.getAddress(), 2) // mint testToken#3 to mech1 - await testToken.mintToken(mech1.address, 3) + await testToken.mintToken(mech1.getAddress(), 3) // mint a token to bob, since receiving the first token will cost more gas - await testToken.mintToken(bob.address, 4) + await testToken.mintToken(bob.getAddress(), 4) // measure actual gas of a transfer and subtract the base tx gas to get a good estimate of the required gas for the meta tx const aliceTransferTx = await testToken .connect(alice) - .transferFrom(alice.address, bob.address, 2) - const aliceGasUsed = (await aliceTransferTx.wait()).gasUsed - const BASE_TX_GAS = 21000 - const metaTxGasCost = aliceGasUsed.sub(BASE_TX_GAS) // the actual transfer gas + .transferFrom(alice.getAddress(), bob.getAddress(), 2) + const aliceGasUsed = (await aliceTransferTx.wait())?.gasUsed || 0n + const BASE_TX_GAS = 21000n + const metaTxGasCost = aliceGasUsed - BASE_TX_GAS // the actual transfer gas // send just enough gas to meta tx -> gas estimation succeed const mechTxGas = await mech1 .connect(alice) - .estimateGas.execute( - testToken.address, + ["execute(address,uint256,bytes,uint8,uint256)"].estimateGas( + testToken.getAddress(), 0, testToken.interface.encodeFunctionData("transferFrom", [ - mech1.address, - bob.address, + mech1.getAddress(), + bob.getAddress(), 3, ]), 0, @@ -300,16 +347,16 @@ describe("Mech base contract", () => { // send too little gas to the meta tx -> tx fails await expect( - mech1.connect(alice).execute( - testToken.address, + mech1.connect(alice)["execute(address,uint256,bytes,uint8,uint256)"]( + testToken.getAddress(), 0, testToken.interface.encodeFunctionData("transferFrom", [ - mech1.address, - bob.address, + mech1.getAddress(), + bob.getAddress(), 3, ]), 0, - metaTxGasCost.sub(1000), // send too little gas + metaTxGasCost - 1000n, // send too little gas { gasLimit: mechTxGas } // send enough ) ).to.be.revertedWithoutReason diff --git a/test/Receiver.ts b/test/Receiver.ts index a723570..13428f8 100644 --- a/test/Receiver.ts +++ b/test/Receiver.ts @@ -1,5 +1,6 @@ import { loadFixture } from "@nomicfoundation/hardhat-network-helpers" import { expect } from "chai" +import { parseEther, randomBytes } from "ethers" import { ethers } from "hardhat" describe("Receiver base contract", () => { @@ -10,22 +11,27 @@ describe("Receiver base contract", () => { const test721 = await ethers.getContractFactory("ERC721Token") const test1155 = await ethers.getContractFactory("ERC1155Token") const test20 = await ethers.getContractFactory("ERC20Token") - const ERC721Mech = await ethers.getContractFactory("ERC721Mech") + const ERC721TokenboundMech = await ethers.getContractFactory( + "ERC721TokenboundMech" + ) const [deployer, alice, bob] = await ethers.getSigners() const test721Token = await test721.deploy() const test1155Token = await test1155.deploy() const test20Token = await test20.deploy() - const mech1 = await ERC721Mech.deploy(test721Token.address, 1) + const mech1 = await ERC721TokenboundMech.deploy( + test721Token.getAddress(), + 1 + ) - await mech1.deployed() + await mech1.waitForDeployment() // send alice a nft associated with the mech - await test721Token.mintToken(alice.address, 1) + await test721Token.mintToken(alice.getAddress(), 1) // Fixtures can return anything you consider useful for your tests return { - ERC721Mech, + ERC721TokenboundMech, test721Token, test1155Token, test20Token, @@ -41,107 +47,92 @@ describe("Receiver base contract", () => { const [deployer] = await ethers.getSigners() await deployer.sendTransaction({ - to: mech1.address, - value: ethers.utils.parseEther("1.0"), + to: mech1.getAddress(), + value: parseEther("1.0"), }) - expect(await ethers.provider.getBalance(mech1.address)).to.equal( - ethers.utils.parseEther("1.0") + expect(await ethers.provider.getBalance(mech1.getAddress())).to.equal( + parseEther("1.0") ) }) it("can receive and send erc20 tokens", async () => { const { mech1, test20Token, alice } = await loadFixture(deployMech1) - await test20Token.mintToken(mech1.address, 1000) - expect(await test20Token.balanceOf(mech1.address)).to.equal(1000) + await test20Token.mintToken(mech1.getAddress(), 1000) + expect(await test20Token.balanceOf(mech1.getAddress())).to.equal(1000) await mech1 .connect(alice) - .execute( - test20Token.address, + ["execute(address,uint256,bytes,uint8)"]( + test20Token.getAddress(), 0, test20Token.interface.encodeFunctionData("transfer", [ - alice.address, + alice.getAddress(), 500, ]), 0 ) - expect(await test20Token.balanceOf(alice.address)).to.equal(500) + expect(await test20Token.balanceOf(alice.getAddress())).to.equal(500) }) it("can receive erc721 tokens", async () => { const { mech1, test721Token, alice } = await loadFixture(deployMech1) // mint alice another nft to send to the mech - await test721Token.mintToken(alice.address, 2) + await test721Token.mintToken(alice.getAddress(), 2) await alice.sendTransaction({ - to: test721Token.address, + to: test721Token.getAddress(), value: 0, data: test721Token.interface.encodeFunctionData( "safeTransferFrom(address,address,uint256)", - [alice.address, mech1.address, 2] + [alice.getAddress(), mech1.getAddress(), 2] ), }) - expect(await test721Token.ownerOf(2)).to.equal(mech1.address) + expect(await test721Token.ownerOf(2)).to.equal(mech1.getAddress()) }) it("can receive erc1155 tokens", async () => { const { mech1, test1155Token, alice } = await loadFixture(deployMech1) // mint alice an 1155 nft to send to the mech - await test1155Token.mintToken( - alice.address, - 1, - 2, - ethers.utils.randomBytes(0) - ) + await test1155Token.mintToken(alice.getAddress(), 1, 2, randomBytes(0)) await alice.sendTransaction({ - to: test1155Token.address, + to: test1155Token.getAddress(), value: 0, data: test1155Token.interface.encodeFunctionData("safeTransferFrom", [ - alice.address, - mech1.address, + alice.getAddress(), + mech1.getAddress(), 1, 2, - ethers.utils.randomBytes(0), + randomBytes(0), ]), }) - expect(await test1155Token.balanceOf(mech1.address, 1)).to.equal(2) + expect(await test1155Token.balanceOf(mech1.getAddress(), 1)).to.equal(2) }) it("can receive erc1155 token batches", async () => { const { mech1, test1155Token, alice } = await loadFixture(deployMech1) // mint alice some tokens - await test1155Token.mintToken( - alice.address, - 1, - 10, - ethers.utils.randomBytes(0) - ) - await test1155Token.mintToken( - alice.address, - 2, - 20, - ethers.utils.randomBytes(0) - ) + await test1155Token.mintToken(alice.getAddress(), 1, 10, randomBytes(0)) + await test1155Token.mintToken(alice.getAddress(), 2, 20, randomBytes(0)) await alice.sendTransaction({ - to: test1155Token.address, + to: test1155Token.getAddress(), value: 0, data: test1155Token.interface.encodeFunctionData( "safeBatchTransferFrom", [ - alice.address, - mech1.address, + alice.getAddress(), + mech1.getAddress(), [1, 2], [10, 20], - ethers.utils.randomBytes(0), + randomBytes(0), ] ), }) - expect(await test1155Token.balanceOf(mech1.address, 1)).to.equal(10) - expect(await test1155Token.balanceOf(mech1.address, 2)).to.equal(20) + expect(await test1155Token.balanceOf(mech1.getAddress(), 1)).to.equal(10) + expect(await test1155Token.balanceOf(mech1.getAddress(), 2)).to.equal(20) }) }) }) diff --git a/test/ZodiacMech.ts b/test/ZodiacMech.ts index 6feaa64..6b6942c 100644 --- a/test/ZodiacMech.ts +++ b/test/ZodiacMech.ts @@ -1,7 +1,7 @@ import { defaultAbiCoder } from "@ethersproject/abi" import { loadFixture } from "@nomicfoundation/hardhat-network-helpers" import { expect } from "chai" -import { parseEther } from "ethers/lib/utils" +import { parseEther } from "ethers" import { ethers, network } from "hardhat" import { SENTINEL_MODULES, ZERO_ADDRESS } from "../sdk/src/constants" @@ -20,9 +20,12 @@ describe("ZodiacMech contract", () => { const ZodiacMech = await ethers.getContractFactory("ZodiacMech") const [, alice, bob, eve] = await ethers.getSigners() - const mech1 = await ZodiacMech.deploy([alice.address, bob.address]) + const mech1 = await ZodiacMech.deploy([ + alice.getAddress(), + bob.getAddress(), + ]) - await mech1.deployed() + await mech1.waitForDeployment() // Fixtures can return anything you consider useful for your tests return { ZodiacMech, mech1, alice, bob, eve } @@ -33,7 +36,9 @@ describe("ZodiacMech contract", () => { const { mech1, alice } = await loadFixture(deployMech1) await expect( - mech1.setUp(defaultAbiCoder.encode(["address[]"], [[alice.address]])) + mech1.setUp( + defaultAbiCoder.encode(["address[]"], [[alice.getAddress()]]) + ) ).to.be.revertedWith("Already initialized") }) }) @@ -47,7 +52,7 @@ describe("ZodiacMech contract", () => { 2 ) expect(enabledModules.toString()).to.equal( - [bob.address, alice.address, SENTINEL_MODULES].toString() + [bob.getAddress(), alice.getAddress(), SENTINEL_MODULES].toString() ) }) }) @@ -55,14 +60,14 @@ describe("ZodiacMech contract", () => { describe("isOperator() / isModuleEnabled()", () => { it("returns true for enabled modules", async () => { const { mech1, alice } = await loadFixture(deployMech1) - expect(await mech1.isModuleEnabled(alice.address)).to.equal(true) - expect(await mech1.isOperator(alice.address)).to.equal(true) + expect(await mech1.isModuleEnabled(alice.getAddress())).to.equal(true) + expect(await mech1.isOperator(alice.getAddress())).to.equal(true) }) it("returns false for any other address", async () => { const { mech1, eve } = await loadFixture(deployMech1) - expect(await mech1.isModuleEnabled(eve.address)).to.equal(false) - expect(await mech1.isOperator(eve.address)).to.equal(false) + expect(await mech1.isModuleEnabled(eve.getAddress())).to.equal(false) + expect(await mech1.isOperator(eve.getAddress())).to.equal(false) }) it("returns false if SENTINEL_MODULES is provided", async () => { @@ -84,7 +89,7 @@ describe("ZodiacMech contract", () => { it("reverts if caller is not an enabled module", async () => { const { mech1, eve } = await loadFixture(deployMech1) await expect( - mech1.connect(eve).enableModule(eve.address) + mech1.connect(eve).enableModule(eve.getAddress()) ).to.be.revertedWith( "Only callable by the mech operator or the entry point contract" ) @@ -106,16 +111,16 @@ describe("ZodiacMech contract", () => { it('emits "EnabledModule" event and enables the module', async () => { const { mech1, alice, eve } = await loadFixture(deployMech1) - await expect(mech1.connect(alice).enableModule(eve.address)) + await expect(mech1.connect(alice).enableModule(eve.getAddress())) .to.emit(mech1, "EnabledModule") - .withArgs(eve.address) - expect(await mech1.isModuleEnabled(eve.address)).to.equal(true) + .withArgs(eve.getAddress()) + expect(await mech1.isModuleEnabled(eve.getAddress())).to.equal(true) }) it("reverts if module is already enabled", async () => { const { mech1, alice } = await loadFixture(deployMech1) await expect( - mech1.connect(alice).enableModule(alice.address) + mech1.connect(alice).enableModule(alice.getAddress()) ).to.be.revertedWithCustomError(mech1, "AlreadyEnabledModule") }) }) @@ -124,7 +129,7 @@ describe("ZodiacMech contract", () => { it("reverts if caller is not the owner", async () => { const { mech1, alice, eve } = await loadFixture(deployMech1) await expect( - mech1.connect(eve).disableModule(SENTINEL_MODULES, alice.address) + mech1.connect(eve).disableModule(SENTINEL_MODULES, alice.getAddress()) ).to.be.revertedWith( "Only callable by the mech operator or the entry point contract" ) @@ -147,7 +152,7 @@ describe("ZodiacMech contract", () => { it("reverts if module is already disabled", async () => { const { mech1, alice, eve } = await loadFixture(deployMech1) await expect( - mech1.connect(alice).disableModule(SENTINEL_MODULES, eve.address) + mech1.connect(alice).disableModule(SENTINEL_MODULES, eve.getAddress()) ).to.be.revertedWithCustomError(mech1, "AlreadyDisabledModule") }) @@ -155,12 +160,12 @@ describe("ZodiacMech contract", () => { const { mech1, alice, bob } = await loadFixture(deployMech1) await expect( - mech1.connect(alice).disableModule(SENTINEL_MODULES, bob.address) + mech1.connect(alice).disableModule(SENTINEL_MODULES, bob.getAddress()) ) .to.emit(mech1, "DisabledModule") - .withArgs(bob.address) + .withArgs(bob.getAddress()) - expect(await mech1.isModuleEnabled(bob.address)).to.equal(false) + expect(await mech1.isModuleEnabled(bob.getAddress())).to.equal(false) }) }) @@ -172,7 +177,7 @@ describe("ZodiacMech contract", () => { SENTINEL_MODULES, 3 ) - await expect(array).to.deep.equal([bob.address, alice.address]) + await expect(array).to.deep.equal([bob.getAddress(), alice.getAddress()]) expect(next).to.equal(SENTINEL_MODULES) }) @@ -191,12 +196,11 @@ describe("ZodiacMech contract", () => { mech1.getModulesPaginated(ZERO_ADDRESS, 1) ).to.be.revertedWith("Invalid start address") - expect(await mech1.getModulesPaginated(bob.address, 1)).to.be.deep.equal([ - [alice.address], - SENTINEL_MODULES, - ]) + expect( + await mech1.getModulesPaginated(bob.getAddress(), 1) + ).to.be.deep.equal([[alice.getAddress()], SENTINEL_MODULES]) await expect( - mech1.getModulesPaginated(eve.address, 1) + mech1.getModulesPaginated(eve.getAddress(), 1) ).to.be.revertedWith("Invalid start address") }) @@ -205,17 +209,21 @@ describe("ZodiacMech contract", () => { await expect( await mech1.getModulesPaginated(SENTINEL_MODULES, 1) - ).to.be.deep.equal([[bob.address], bob.address]) + ).to.be.deep.equal([[bob.getAddress()], bob.getAddress()]) await expect( - await mech1.getModulesPaginated(bob.address, 1) - ).to.be.deep.equal([[alice.address], SENTINEL_MODULES]) + await mech1.getModulesPaginated(bob.getAddress(), 1) + ).to.be.deep.equal([[alice.getAddress()], SENTINEL_MODULES]) }) it("returns an empty array for a bricked mech", async () => { const { mech1, alice, bob } = await loadFixture(deployMech1) - await mech1.connect(alice).disableModule(SENTINEL_MODULES, bob.address) - await mech1.connect(alice).disableModule(SENTINEL_MODULES, alice.address) + await mech1 + .connect(alice) + .disableModule(SENTINEL_MODULES, bob.getAddress()) + await mech1 + .connect(alice) + .disableModule(SENTINEL_MODULES, alice.getAddress()) expect( await mech1.getModulesPaginated(SENTINEL_MODULES, 10) @@ -240,7 +248,7 @@ describe("ZodiacMech contract", () => { // fund mech1 with 1 ETH await alice.sendTransaction({ - to: mech1.address, + to: mech1.getAddress(), value: parseEther("1.0"), }) @@ -260,7 +268,7 @@ describe("ZodiacMech contract", () => { mech1 .connect(eve) .execTransactionFromModuleReturnData( - mech1.address, + mech1.getAddress(), 0, mech1.interface.encodeFunctionData("getModulesPaginated", [ SENTINEL_MODULES, @@ -278,14 +286,14 @@ describe("ZodiacMech contract", () => { // fund mech1 with 1 ETH await alice.sendTransaction({ - to: mech1.address, + to: mech1.getAddress(), value: parseEther("1.0"), }) - const { success, returnData } = await mech1 + const [{ success, returnData }] = await mech1 .connect(alice) - .callStatic.execTransactionFromModuleReturnData( - mech1.address, + .execTransactionFromModuleReturnData.staticCallResult( + mech1.getAddress(), 0, mech1.interface.encodeFunctionData("getModulesPaginated", [ SENTINEL_MODULES, @@ -310,7 +318,7 @@ describe("ZodiacMech contract", () => { // const nonceSlot = "0x5" // see SafeStorage.sol // await network.provider.request({ // method: "hardhat_setStorageAt", - // params: [mech1.address, nonceSlot, nonceEncoded], + // params: [mech1.getAddress(), nonceSlot, nonceEncoded], // }) // // validate that the nonce is read from that slot @@ -329,7 +337,7 @@ describe("ZodiacMech contract", () => { // // fund mech1 with 1 ETH // await alice.sendTransaction({ - // to: mech1.address, + // to: mech1.getAddress(), // value: parseEther("1.0"), // }) diff --git a/test/signing.ts b/test/signing.ts index 5c09983..1ecfe67 100644 --- a/test/signing.ts +++ b/test/signing.ts @@ -11,17 +11,19 @@ describe("signing", () => { // Network to that snapshot in every test. async function deployMech1() { const TestToken = await ethers.getContractFactory("ERC721Token") - const ERC721Mech = await ethers.getContractFactory("ERC721Mech") + const ERC721TokenboundMech = await ethers.getContractFactory( + "ERC721TokenboundMech" + ) const [deployer, alice, bob, eve] = await ethers.getSigners() const testToken = await TestToken.deploy() - const mech1 = await ERC721Mech.deploy(testToken.address, 1) + const mech1 = await ERC721TokenboundMech.deploy(testToken.getAddress(), 1) - await mech1.deployed() - await testToken.mintToken(alice.address, 1) + await mech1.waitForDeployment() + await testToken.mintToken(alice.getAddress(), 1) // Fixtures can return anything you consider useful for your tests - return { ERC721Mech, testToken, mech1, alice, bob, eve } + return { ERC721TokenboundMech, testToken, mech1, alice, bob, eve } } describe("signWithMech()", () => { @@ -31,10 +33,13 @@ describe("signing", () => { const message = "Congratulations!" const operatorSignature = await alice.signMessage(message) - const mechSignature = signWithMech(mech1.address, operatorSignature) + const mechSignature = signWithMech( + await mech1.getAddress(), + operatorSignature + ) const isValidSig = await verifyMessage({ - signer: mech1.address, + signer: mech1.getAddress(), message, signature: mechSignature, provider: ethers.provider, From 8d249e66ccf68782a6c1f5c36a0ec1cadad29edc Mon Sep 17 00:00:00 2001 From: Jan-Felix Date: Mon, 21 Aug 2023 16:31:19 +0200 Subject: [PATCH 22/41] erc165 --- contracts/base/Mech.sol | 19 +++++++++++++++++++ contracts/base/TokenboundMech.sol | 8 ++++++++ package.json | 4 ++-- sdk/src/execute/index.ts | 2 +- 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/contracts/base/Mech.sol b/contracts/base/Mech.sol index 64b8a12..7d70864 100644 --- a/contracts/base/Mech.sol +++ b/contracts/base/Mech.sol @@ -3,6 +3,12 @@ pragma solidity ^0.8.12; import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import "@gnosis.pm/safe-contracts/contracts/common/Enum.sol"; +import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; +import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; +import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; +import "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol"; +import "@openzeppelin/contracts/interfaces/IERC1271.sol"; +import "@account-abstraction/contracts/interfaces/IAccount.sol"; import "./Receiver.sol"; import "./Account.sol"; @@ -175,4 +181,17 @@ abstract contract Mech is IMech, Account, Receiver { v := byte(0, mload(add(signature, 0x60))) } } + + /// @dev Returns true if a given interfaceId is supported by this account. This method can be + /// extended by an override + function supportsInterface( + bytes4 interfaceId + ) public pure virtual returns (bool) { + return + interfaceId == type(IERC165).interfaceId || + interfaceId == type(IAccount).interfaceId || + interfaceId == type(IERC1271).interfaceId || + interfaceId == type(IERC1155Receiver).interfaceId || + interfaceId == type(IERC6551Executable).interfaceId; + } } diff --git a/contracts/base/TokenboundMech.sol b/contracts/base/TokenboundMech.sol index ba4ab36..9f8d298 100644 --- a/contracts/base/TokenboundMech.sol +++ b/contracts/base/TokenboundMech.sol @@ -46,4 +46,12 @@ abstract contract TokenboundMech is Mech, IERC6551Account { ? IERC6551Account.isValidSigner.selector : bytes4(0); } + + function supportsInterface( + bytes4 interfaceId + ) public pure override returns (bool) { + return + super.supportsInterface(interfaceId) || + interfaceId == type(IERC6551Account).interfaceId; + } } diff --git a/package.json b/package.json index c5eff03..c1d174a 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "frontend" ], "scripts": { - "clean": "yarn rimraf artifacts cache typechain-types", + "clean": "yarn hardhat clean", "build:contracts": "yarn hardhat compile", "build:sdk": "yarn workspace mech-sdk build", "build:frontend": "yarn workspace frontend build", @@ -91,4 +91,4 @@ "@walletconnect/ethereum-provider": "2.7.0" }, "packageManager": "yarn@3.6.1" -} +} \ No newline at end of file diff --git a/sdk/src/execute/index.ts b/sdk/src/execute/index.ts index b58b727..b091b38 100644 --- a/sdk/src/execute/index.ts +++ b/sdk/src/execute/index.ts @@ -1 +1 @@ -export * from "./makeExecTransaction" +export * from "./makeExecuteTransaction" From a5a32feb96c84706b2c6137402e74b8dff435454 Mon Sep 17 00:00:00 2001 From: Jan-Felix Date: Fri, 25 Aug 2023 10:29:13 +0200 Subject: [PATCH 23/41] tokenbound deterministic deployment test green --- contracts/base/Mech.sol | 1 + contracts/base/TokenboundMech.sol | 8 +- contracts/test/ERC6551Registry.sol | 4 + sdk/src/constants.ts | 63 +++- sdk/src/deploy/deployERC1155ThresholdMech.ts | 6 +- sdk/src/deploy/deployERC1155TokenboundMech.ts | 35 +- sdk/src/deploy/deployERC721TokenboundMech.ts | 35 +- sdk/src/deploy/deployZodiacMech.ts | 2 +- sdk/src/deploy/factory.ts | 51 ++- test/ERC1155ThresholdMech.ts | 2 +- test/ZodiacMech.ts | 2 +- test/deterministicDeployment.ts | 336 +++++++++++------- 12 files changed, 356 insertions(+), 189 deletions(-) create mode 100644 contracts/test/ERC6551Registry.sol diff --git a/contracts/base/Mech.sol b/contracts/base/Mech.sol index 7d70864..afd2706 100644 --- a/contracts/base/Mech.sol +++ b/contracts/base/Mech.sol @@ -188,6 +188,7 @@ abstract contract Mech is IMech, Account, Receiver { bytes4 interfaceId ) public pure virtual returns (bool) { return + interfaceId == type(IMech).interfaceId || interfaceId == type(IERC165).interfaceId || interfaceId == type(IAccount).interfaceId || interfaceId == type(IERC1271).interfaceId || diff --git a/contracts/base/TokenboundMech.sol b/contracts/base/TokenboundMech.sol index 9f8d298..d57a1a4 100644 --- a/contracts/base/TokenboundMech.sol +++ b/contracts/base/TokenboundMech.sol @@ -2,9 +2,9 @@ pragma solidity ^0.8.12; import "@erc6551/reference/src/interfaces/IERC6551Account.sol"; +import "@erc6551/reference/src/lib/ERC6551AccountLib.sol"; import "./Mech.sol"; -import "../libraries/MinimalProxyStore.sol"; /** * @dev A Mech that is operated by the holder of a designated token, implements the ERC6551 standard and is deployed through the ERC6551 registry @@ -22,11 +22,7 @@ abstract contract TokenboundMech is Mech, IERC6551Account { view returns (uint256 chainId, address tokenContract, uint256 tokenId) { - return - abi.decode( - MinimalProxyStore.getContext(address(this)), - (uint256, address, uint256) - ); + return ERC6551AccountLib.token(); } receive() external payable override(Receiver, IERC6551Account) {} diff --git a/contracts/test/ERC6551Registry.sol b/contracts/test/ERC6551Registry.sol new file mode 100644 index 0000000..d62021f --- /dev/null +++ b/contracts/test/ERC6551Registry.sol @@ -0,0 +1,4 @@ +//SPDX-License-Identifier: LGPL-3.0 +pragma solidity ^0.8.12; + +import "@erc6551/reference/src/ERC6551Registry.sol"; diff --git a/sdk/src/constants.ts b/sdk/src/constants.ts index 18ef2e5..048bc8c 100644 --- a/sdk/src/constants.ts +++ b/sdk/src/constants.ts @@ -16,6 +16,67 @@ export const DEFAULT_SALT = export const SENTINEL_MODULES = "0x0000000000000000000000000000000000000001" as const +export const ERC2470_SINGLETON_FACTORY_ABI = [ + { + type: "function", + name: "deploy", + constant: false, + payable: false, + inputs: [ + { + type: "bytes", + name: "_initCode", + }, + { + type: "bytes32", + name: "_salt", + }, + ], + outputs: [ + { + type: "address", + name: "createdContract", + }, + ], + }, +] + export const ERC6551_REGISTRY_ABI = [ - "createAccount(address implementation, uint256 chainId, address tokenContract, uint256 tokenId, uint256 salt, bytes initData) returns (address)", + { + type: "function", + name: "createAccount", + constant: false, + payable: false, + inputs: [ + { + type: "address", + name: "implementation", + }, + { + type: "uint256", + name: "chainId", + }, + { + type: "address", + name: "tokenContract", + }, + { + type: "uint256", + name: "tokenId", + }, + { + type: "uint256", + name: "salt", + }, + { + type: "bytes", + name: "initData", + }, + ], + outputs: [ + { + type: "address", + }, + ], + }, ] diff --git a/sdk/src/deploy/deployERC1155ThresholdMech.ts b/sdk/src/deploy/deployERC1155ThresholdMech.ts index cbcba60..a6c60fa 100644 --- a/sdk/src/deploy/deployERC1155ThresholdMech.ts +++ b/sdk/src/deploy/deployERC1155ThresholdMech.ts @@ -32,7 +32,7 @@ export const calculateERC1155ThresholdMechAddress = ({ minBalances: bigint[] /** minimum total balance over all tokens */ minTotalBalance: bigint - salt: `0x${string}` + salt?: `0x${string}` }) => { const context = encodeAbiParameters( [ @@ -77,7 +77,7 @@ export const makeERC1155ThresholdMechDeployTransaction = ({ minBalances: bigint[] /** minimum total balance over all tokens */ minTotalBalance: bigint - salt: `0x${string}` + salt?: `0x${string}` }) => { const context = encodeAbiParameters( [ @@ -121,7 +121,7 @@ export const deployERC1155ThresholdMech = async ( minBalances: bigint[] /** minimum total balance over all tokens */ minTotalBalance: bigint - salt: `0x${string}` + salt?: `0x${string}` } ) => { const { chain, account } = walletClient diff --git a/sdk/src/deploy/deployERC1155TokenboundMech.ts b/sdk/src/deploy/deployERC1155TokenboundMech.ts index 1d1451f..a007038 100644 --- a/sdk/src/deploy/deployERC1155TokenboundMech.ts +++ b/sdk/src/deploy/deployERC1155TokenboundMech.ts @@ -13,34 +13,25 @@ import { ERC6551_REGISTRY_ADDRESS, } from "../constants" -import { deployMastercopy, mechProxyBytecode } from "./factory" +import { deployMastercopy, erc6551ProxyBytecode } from "./factory" -export const calculateERC1155TokenboundMechAddress = ({ - chainId, - token, - tokenId, - salt = DEFAULT_SALT, -}: { +export const calculateERC1155TokenboundMechAddress = (context: { /** Address of the ERC1155 token contract */ chainId: number /** Address of the ERC1155 token contract */ token: `0x${string}` /** ID of the ERC1155 token */ tokenId: bigint - salt: `0x${string}` + salt?: `0x${string}` + from?: `0x${string}` }) => { - const context = encodeAbiParameters( - [{ type: "uint256" }, { type: "address" }, { type: "uint256" }], - [BigInt(chainId), token, tokenId] - ) - return getCreate2Address({ - bytecode: mechProxyBytecode( + bytecode: erc6551ProxyBytecode( calculateERC1155TokenboundMechMastercopyAddress(), context ), - from: ERC6551_REGISTRY_ADDRESS, - salt, + from: context.from || ERC6551_REGISTRY_ADDRESS, + salt: context.salt || DEFAULT_SALT, }) } @@ -57,6 +48,7 @@ export const makeERC1155TokenboundMechDeployTransaction = ({ token, tokenId, salt = DEFAULT_SALT, + from = ERC6551_REGISTRY_ADDRESS, }: { /** ID of the chain the token lives on */ chainId: number @@ -64,10 +56,11 @@ export const makeERC1155TokenboundMechDeployTransaction = ({ token: `0x${string}` /** ID of the ERC1155 token */ tokenId: bigint - salt: string + salt?: string + from?: `0x${string}` }) => { return { - to: ERC6551_REGISTRY_ADDRESS, + to: from, data: encodeFunctionData({ abi: ERC6551_REGISTRY_ABI, functionName: "createAccount", @@ -77,6 +70,7 @@ export const makeERC1155TokenboundMechDeployTransaction = ({ token, tokenId, salt, + "0x", ], }), } @@ -89,6 +83,7 @@ export const deployERC1155TokenboundMech = async ( token, tokenId, salt = DEFAULT_SALT, + from = ERC6551_REGISTRY_ADDRESS, }: { /** ID of the chain the token lives on, default to the current chain of walletClient */ chainId?: number @@ -96,7 +91,8 @@ export const deployERC1155TokenboundMech = async ( token: `0x${string}` /** ID of the ERC1155 token */ tokenId: bigint - salt: `0x${string}` + salt?: `0x${string}` + from?: `0x${string}` } ) => { const { chain, account } = walletClient @@ -110,6 +106,7 @@ export const deployERC1155TokenboundMech = async ( token, tokenId, salt, + from, }) return walletClient.sendTransaction({ diff --git a/sdk/src/deploy/deployERC721TokenboundMech.ts b/sdk/src/deploy/deployERC721TokenboundMech.ts index 75d0a41..1a615be 100644 --- a/sdk/src/deploy/deployERC721TokenboundMech.ts +++ b/sdk/src/deploy/deployERC721TokenboundMech.ts @@ -13,34 +13,25 @@ import { ERC6551_REGISTRY_ADDRESS, } from "../constants" -import { deployMastercopy, mechProxyBytecode } from "./factory" +import { deployMastercopy, erc6551ProxyBytecode } from "./factory" -export const calculateERC721TokenboundMechAddress = ({ - chainId, - token, - tokenId, - salt = DEFAULT_SALT, -}: { +export const calculateERC721TokenboundMechAddress = (context: { /** Address of the ERC721 token contract */ chainId: number /** Address of the ERC721 token contract */ token: `0x${string}` /** ID of the ERC721 token */ tokenId: bigint - salt: `0x${string}` + salt?: `0x${string}` + from?: `0x${string}` }) => { - const context = encodeAbiParameters( - [{ type: "uint256" }, { type: "address" }, { type: "uint256" }], - [BigInt(chainId), token, tokenId] - ) - return getCreate2Address({ - bytecode: mechProxyBytecode( + bytecode: erc6551ProxyBytecode( calculateERC721TokenboundMechMastercopyAddress(), context ), - from: ERC6551_REGISTRY_ADDRESS, - salt, + from: context.from || ERC6551_REGISTRY_ADDRESS, + salt: context.salt || DEFAULT_SALT, }) } @@ -57,6 +48,7 @@ export const makeERC721TokenboundMechDeployTransaction = ({ token, tokenId, salt = DEFAULT_SALT, + from = ERC6551_REGISTRY_ADDRESS, }: { /** ID of the chain the token lives on */ chainId: number @@ -64,10 +56,11 @@ export const makeERC721TokenboundMechDeployTransaction = ({ token: `0x${string}` /** ID of the ERC721 token */ tokenId: bigint - salt: string + salt?: string + from?: `0x${string}` }) => { return { - to: ERC6551_REGISTRY_ADDRESS, + to: from, data: encodeFunctionData({ abi: ERC6551_REGISTRY_ABI, functionName: "createAccount", @@ -77,6 +70,7 @@ export const makeERC721TokenboundMechDeployTransaction = ({ token, tokenId, salt, + "0x", ], }), } @@ -89,6 +83,7 @@ export const deployERC721TokenboundMech = async ( token, tokenId, salt = DEFAULT_SALT, + from = ERC6551_REGISTRY_ADDRESS, }: { /** ID of the chain the token lives on, default to the current chain of walletClient */ chainId?: number @@ -96,7 +91,8 @@ export const deployERC721TokenboundMech = async ( token: `0x${string}` /** ID of the ERC721 token */ tokenId: bigint - salt: `0x${string}` + salt?: `0x${string}` + from?: `0x${string}` } ) => { const { chain, account } = walletClient @@ -110,6 +106,7 @@ export const deployERC721TokenboundMech = async ( token, tokenId, salt, + from, }) return walletClient.sendTransaction({ diff --git a/sdk/src/deploy/deployZodiacMech.ts b/sdk/src/deploy/deployZodiacMech.ts index 1a6c044..88b1226 100644 --- a/sdk/src/deploy/deployZodiacMech.ts +++ b/sdk/src/deploy/deployZodiacMech.ts @@ -60,7 +60,7 @@ export const makeZodiacMechDeployTransaction = ({ }: { /** Addresses of the Zodiac modules */ modules: `0x${string}`[] - salt: `0x${string}` + salt?: `0x${string}` }) => { const initCall = encodeFunctionData({ abi: ZodiacMech__factory.abi, diff --git a/sdk/src/deploy/factory.ts b/sdk/src/deploy/factory.ts index 3c3e498..585c120 100644 --- a/sdk/src/deploy/factory.ts +++ b/sdk/src/deploy/factory.ts @@ -8,7 +8,11 @@ import { } from "viem" import { MechFactory__factory } from "../../../typechain-types" -import { ERC2470_SINGLETON_FACTORY_ADDRESS } from "../constants" +import { + DEFAULT_SALT, + ERC2470_SINGLETON_FACTORY_ABI, + ERC2470_SINGLETON_FACTORY_ADDRESS, +} from "../constants" export const mechProxyBytecode = ( implementation: `0x${string}`, @@ -31,6 +35,43 @@ export const mechProxyBytecode = ( ]) } +export const erc6551ProxyBytecode = ( + implementation: `0x${string}`, + { + chainId, + token, + tokenId, + salt = DEFAULT_SALT, + }: { + /** ID of the chain the token lives on, default to the current chain of walletClient */ + chainId: number + /** Address of the ERC721 token contract */ + token: `0x${string}` + /** ID of the ERC721 token */ + tokenId: bigint + salt?: `0x${string}` + } +) => { + if (implementation.length !== 42) { + throw new Error(`Invalid implementation address: ${implementation}`) + } + + return concat([ + "0x3d60ad80600a3d3981f3363d3d373d3d3d363d73", + implementation, + "0x5af43d82803e903d91602b57fd5bf3", + encodeAbiParameters( + [ + { type: "uint256" }, + { type: "uint256" }, + { type: "address" }, + { type: "uint256" }, + ], + [BigInt(salt), BigInt(chainId), token, tokenId] + ), + ]) +} + /** * Deploy a mastercopy via the ERC-2470 singleton factory. */ @@ -40,20 +81,18 @@ export const deployMastercopy = async ( ) => { const singletonFactory = getContract({ address: ERC2470_SINGLETON_FACTORY_ADDRESS, - abi: [ - "function deploy(bytes memory _initCode, bytes32 _salt) public returns (address payable createdContract)", - ], + abi: ERC2470_SINGLETON_FACTORY_ABI, walletClient, }) - await singletonFactory.write.deploy([bytecode]) + return await singletonFactory.write.deploy([bytecode, DEFAULT_SALT]) } /** * Deploy MechFactory via the ERC-2470 singleton factory. */ export const deployMechFactory = async (walletClient: WalletClient) => { - await deployMastercopy(walletClient, MechFactory__factory.bytecode) + return await deployMastercopy(walletClient, MechFactory__factory.bytecode) } /** diff --git a/test/ERC1155ThresholdMech.ts b/test/ERC1155ThresholdMech.ts index 8d4e873..936411f 100644 --- a/test/ERC1155ThresholdMech.ts +++ b/test/ERC1155ThresholdMech.ts @@ -7,7 +7,7 @@ import { ethers } from "hardhat" // Using this simplifies your tests and makes them run faster, by taking // advantage or Hardhat Network's snapshot functionality. -describe("ERC115ThresholdMech contract", () => { +describe.skip("ERC115ThresholdMech contract", () => { // We define a fixture to reuse the same setup in every test. We use // loadFixture to run this setup once, snapshot that state, and reset Hardhat // Network to that snapshot in every test. diff --git a/test/ZodiacMech.ts b/test/ZodiacMech.ts index 6b6942c..eab829e 100644 --- a/test/ZodiacMech.ts +++ b/test/ZodiacMech.ts @@ -12,7 +12,7 @@ import { entryPoint, fillUserOp, getUserOpHash, signUserOp } from "./Account" // Using this simplifies your tests and makes them run faster, by taking // advantage or Hardhat Network's snapshot functionality. -describe("ZodiacMech contract", () => { +describe.skip("ZodiacMech contract", () => { // We define a fixture to reuse the same setup in every test. We use // loadFixture to run this setup once, snapshot that state, and reset Hardhat // Network to that snapshot in every test. diff --git a/test/deterministicDeployment.ts b/test/deterministicDeployment.ts index 849581f..3031d05 100644 --- a/test/deterministicDeployment.ts +++ b/test/deterministicDeployment.ts @@ -1,8 +1,9 @@ import { defaultAbiCoder } from "@ethersproject/abi" +import { JsonRpcProvider } from "@ethersproject/providers" import { loadFixture } from "@nomicfoundation/hardhat-network-helpers" import { expect } from "chai" import hre, { ethers } from "hardhat" -import { createWalletClient, http } from "viem" +import { createWalletClient, custom as customTransport } from "viem" import { hardhat } from "viem/chains" // We use `loadFixture` to share common setups (or fixtures) between tests. @@ -12,22 +13,33 @@ import { hardhat } from "viem/chains" import { calculateERC1155ThresholdMechAddress, calculateERC1155ThresholdMechMastercopyAddress, + calculateERC1155TokenboundMechAddress, + calculateERC1155TokenboundMechMastercopyAddress, calculateERC721TokenboundMechAddress, calculateERC721TokenboundMechMastercopyAddress, calculateZodiacMechAddress, calculateZodiacMechMastercopyAddress, deployERC1155ThresholdMech, deployERC1155ThresholdMechMastercopy, + deployERC1155TokenboundMech, + deployERC1155TokenboundMechMastercopy, + deployERC2470SingletonFactory, deployERC721TokenboundMech, deployERC721TokenboundMechMastercopy, deployMechFactory, deployZodiacMech, deployZodiacMechMastercopy, } from "../sdk" -import { SENTINEL_MODULES, ZERO_ADDRESS } from "../sdk/src/constants" +import { + DEFAULT_SALT, + SENTINEL_MODULES, + ZERO_ADDRESS, +} from "../sdk/src/constants" import { ERC1155Mech__factory, + ERC1155TokenboundMech__factory, ERC721Mech__factory, + ERC721TokenboundMech__factory, ZodiacMech__factory, } from "../typechain-types" @@ -35,145 +47,239 @@ describe("deterministic deployment", () => { /** deploy ERC2470 singleton factory, MechFactory, and ERC6551 registry */ async function deployFactories() { const [signer, alice] = await hre.ethers.getSigners() - const deployer = hre.ethers.provider.getSigner(signer.address) + const deployer = await hre.ethers.provider.getSigner( + await signer.getAddress() + ) + + const ERC6551Registry = await ethers.getContractFactory("ERC6551Registry") + const erc6551Registry = await ERC6551Registry.deploy() - const walletClient = createWalletClient({ + const deployerClient = createWalletClient({ chain: hardhat, - account: signer.address as `0x${string}`, - transport: http(), + account: (await signer.getAddress()) as `0x${string}`, + transport: customTransport({ + request({ method, params }) { + return hre.ethers.provider.send(method, params) + }, + }), }) - await deployERC2470SingletonFactory(walletClient) - await deployMechFactory(walletClient) - - const mastercopyAddresses = { - erc721: await deployERC721TokenboundMechMastercopy(deployer), - erc1155: await deployERC1155ThresholdMechMastercopy(deployer), - zodiac: await deployZodiacMechMastercopy(deployer), - } + await deployERC2470SingletonFactory(deployerClient) + await deployMechFactory(deployerClient) return { - mastercopyAddresses, + erc6551Registry, deployer, + deployerClient, alice, } } - describe.only("deployERC721TokenboundMech()", () => { - it("correctly initializes the mech proxy instance", async () => { - const { alice, deployer } = await loadFixture( - deployModuleFactoryAndMastercopy + describe("calculateERC721TokenboundMechAddress()", () => { + it("returns the correct address", async () => { + const { deployerClient, erc6551Registry } = await loadFixture( + deployFactories ) + const chainId = deployerClient.chain.id const TestToken = await ethers.getContractFactory("ERC721Token") const testToken = await TestToken.deploy() + const testTokenAddress = (await testToken.getAddress()) as `0x${string}` - await deployERC721TokenboundMech(testToken.address, 1, deployer) - const mechAddress = calculateERC721TokenboundMechAddress( - testToken.address, - 1 + expect( + calculateERC721TokenboundMechAddress({ + chainId, + token: testTokenAddress, + tokenId: 1n, + from: (await erc6551Registry.getAddress()) as `0x${string}`, + }) + ).to.equal( + await erc6551Registry.account( + calculateERC721TokenboundMechMastercopyAddress(), + deployerClient.chain.id, + testTokenAddress, + 1n, + DEFAULT_SALT + ) ) + }) + }) + + describe("deployERC721TokenboundMech()", () => { + it("correctly initializes the 6551 proxy instance at the expected address", async () => { + const { alice, deployerClient, erc6551Registry } = await loadFixture( + deployFactories + ) + + const chainId = deployerClient.chain.id + const registryAddress = + (await erc6551Registry.getAddress()) as `0x${string}` + + const TestToken = await ethers.getContractFactory("ERC721Token") + const testToken = await TestToken.deploy() + const testTokenAddress = (await testToken.getAddress()) as `0x${string}` + + await deployERC721TokenboundMechMastercopy(deployerClient) + await deployERC721TokenboundMech(deployerClient, { + token: testTokenAddress, + tokenId: 1n, + from: registryAddress, + }) + + const mechAddress = calculateERC721TokenboundMechAddress({ + chainId, + token: testTokenAddress, + tokenId: 1n, + from: registryAddress, + }) + const mech = ERC721TokenboundMech__factory.connect(mechAddress, alice) - expect(await mech.token()).to.equal(testToken.address) - expect(await mech.tokenId()).to.equal(1) + expect(await mech.token()).to.deep.equal([ + BigInt(deployerClient.chain.id), + testTokenAddress, + 1n, + ]) }) }) describe("calculateERC721TokenboundMechMastercopyAddress", () => { it("returns the address of the ERC721TokenboundMech mastercopy", async () => { - const { mastercopyAddresses } = await loadFixture( - deployModuleFactoryAndMastercopy - ) + const { deployerClient } = await loadFixture(deployFactories) - expect(calculateERC721TokenboundMechMastercopyAddress()).to.equal( - mastercopyAddresses.erc721 - ) + expect( + await hre.ethers.provider.getCode( + calculateERC721TokenboundMechMastercopyAddress() + ) + ).to.equal("0x") + + await deployERC721TokenboundMechMastercopy(deployerClient) + + expect( + await hre.ethers.provider.getCode( + calculateERC721TokenboundMechMastercopyAddress() + ) + ).to.not.equal("0x") }) }) - describe("calculateERC721TokenboundMechAddress()", () => { - it("returns the address of the mech for a given NFT", async () => { - await loadFixture(deployModuleFactoryAndMastercopy) - const TestToken = await ethers.getContractFactory("ERC721Token") - const testToken = await TestToken.deploy() + ///// ERC1155TokenboundMech - const calculatedAddress = calculateERC721TokenboundMechAddress( - testToken.address, - 1 + describe("calculateERC1155TokenboundMechAddress()", () => { + it("returns the correct address", async () => { + const { deployerClient, erc6551Registry } = await loadFixture( + deployFactories ) + const chainId = deployerClient.chain.id + const registryAddress = + (await erc6551Registry.getAddress()) as `0x${string}` - expect(await ethers.provider.getCode(calculatedAddress)).to.equal("0x") + const TestToken = await ethers.getContractFactory("ERC1155Token") + const testToken = await TestToken.deploy() + const testTokenAddress = (await testToken.getAddress()) as `0x${string}` - await deployERC721TokenboundMech( - testToken.address, - 1, - hre.ethers.provider.getSigner() + expect( + calculateERC1155TokenboundMechAddress({ + chainId, + token: testTokenAddress, + tokenId: 1n, + from: registryAddress, + }) + ).to.equal( + await erc6551Registry.account( + calculateERC1155TokenboundMechMastercopyAddress(), + deployerClient.chain.id, + testTokenAddress, + 1n, + DEFAULT_SALT + ) ) + }) + }) - expect(await ethers.provider.getCode(calculatedAddress)).to.not.equal( - "0x" + describe("deployERC1155TokenboundMech()", () => { + it("correctly initializes the 6551 proxy instance at the expected address", async () => { + const { alice, deployerClient, erc6551Registry } = await loadFixture( + deployFactories ) + + const chainId = deployerClient.chain.id + const registryAddress = + (await erc6551Registry.getAddress()) as `0x${string}` + + const TestToken = await ethers.getContractFactory("ERC1155Token") + const testToken = await TestToken.deploy() + const testTokenAddress = (await testToken.getAddress()) as `0x${string}` + + await deployERC1155TokenboundMechMastercopy(deployerClient) + await deployERC1155TokenboundMech(deployerClient, { + token: testTokenAddress, + tokenId: 1n, + from: registryAddress, + }) + + const mechAddress = calculateERC1155TokenboundMechAddress({ + chainId, + token: testTokenAddress, + tokenId: 1n, + from: registryAddress, + }) + + const mech = ERC1155TokenboundMech__factory.connect(mechAddress, alice) + + expect(await mech.token()).to.deep.equal([ + BigInt(deployerClient.chain.id), + testTokenAddress, + 1n, + ]) }) }) - describe("deployERC721TokenboundMechMastercopy()", () => { - it("initializes the mastercopy", async () => { - const { mastercopyAddresses, deployer } = await loadFixture( - deployModuleFactoryAndMastercopy - ) + describe("calculateERC1155TokenboundMechMastercopyAddress", () => { + it("returns the address of the ERC721TokenboundMech mastercopy", async () => { + const { deployerClient } = await loadFixture(deployFactories) - const mech = ERC721TokenboundMech__factory.connect( - mastercopyAddresses.erc721, - deployer - ) - const SOME_ADDRESS = "0x1111111111111111111111111111111111111111" expect( - mech.setUp( - defaultAbiCoder.encode(["address", "uint256"], [SOME_ADDRESS, 1]) + await hre.ethers.provider.getCode( + calculateERC1155TokenboundMechMastercopyAddress() ) - ).to.be.revertedWith("Already initialized") - }) + ).to.equal("0x") - it("makes sure no one can operate the mastercopy", async () => { - const { mastercopyAddresses, deployer } = await loadFixture( - deployModuleFactoryAndMastercopy - ) - const mech = ERC721TokenboundMech__factory.connect( - mastercopyAddresses.erc721, - deployer - ) - await expect(mech.isOperator(deployer._address)).to.be.reverted + await deployERC1155TokenboundMechMastercopy(deployerClient) + + expect( + await hre.ethers.provider.getCode( + calculateERC1155TokenboundMechMastercopyAddress() + ) + ).to.not.equal("0x") }) }) ///// ERC1155ThresholdMech - describe("deployERC1155ThresholdMech()", () => { + describe.skip("deployERC1155ThresholdMech()", () => { it("correctly initializes the mech proxy instance", async () => { - const { alice, deployer } = await loadFixture( - deployModuleFactoryAndMastercopy - ) + const { alice, deployer } = await loadFixture(deployFactories) const TestToken = await ethers.getContractFactory("ERC1155Token") const testToken = await TestToken.deploy() await deployERC1155ThresholdMech( - testToken.address, + testToken.getAddress(), [1, 2], [10, 20], 0, deployer ) const mechAddress = calculateERC1155ThresholdMechAddress( - testToken.address, + testToken.getAddress(), [1, 2], [10, 20], 0 ) const mech = ERC1155ThresholdMech__factory.connect(mechAddress, alice) - expect(await mech.token()).to.equal(testToken.address) + expect(await mech.token()).to.equal(testToken.getAddress()) expect(await mech.tokenIds(0)).to.equal(1) expect(await mech.tokenIds(1)).to.equal(2) expect(await mech.minBalances(0)).to.equal(10) @@ -181,11 +287,9 @@ describe("deterministic deployment", () => { }) }) - describe("calculateERC1155ThresholdMechMastercopyAddress", () => { + describe.skip("calculateERC1155ThresholdMechMastercopyAddress", () => { it("returns the address of the ERC1155ThresholdMech mastercopy", async () => { - const { mastercopyAddresses } = await loadFixture( - deployModuleFactoryAndMastercopy - ) + const { mastercopyAddresses } = await loadFixture(deployFactories) expect(calculateERC1155ThresholdMechMastercopyAddress()).to.equal( mastercopyAddresses.erc1155 @@ -193,15 +297,15 @@ describe("deterministic deployment", () => { }) }) - describe("calculateERC1155ThresholdMechAddress()", () => { + describe.skip("calculateERC1155ThresholdMechAddress()", () => { it("returns the address of the mech for a given NFT", async () => { - await loadFixture(deployModuleFactoryAndMastercopy) + await loadFixture(deployFactories) const TestToken = await ethers.getContractFactory("ERC1155Token") const testToken = await TestToken.deploy() const calculatedAddress = calculateERC1155ThresholdMechAddress( - testToken.address, + testToken.getAddress(), [1], [1], 0 @@ -210,7 +314,7 @@ describe("deterministic deployment", () => { expect(await ethers.provider.getCode(calculatedAddress)).to.equal("0x") await deployERC1155ThresholdMech( - testToken.address, + testToken.getAddress(), [1], [1], 0, @@ -223,57 +327,25 @@ describe("deterministic deployment", () => { }) }) - describe("deployERC1155ThresholdMechMastercopy()", () => { - it("initializes the mastercopy with zero address and threshold [0, 0]", async () => { - const { mastercopyAddresses, deployer } = await loadFixture( - deployModuleFactoryAndMastercopy - ) - - const mech = ERC1155ThresholdMech__factory.connect( - mastercopyAddresses.erc1155, - deployer - ) - expect(await mech.token()).to.equal(ZERO_ADDRESS) - expect(await mech.tokenIds(0)).to.equal(0) - expect(await mech.minBalances(0)).to.equal(0) - expect(await mech.minTotalBalance()).to.equal(0) - }) - - it("makes sure no one can operate the mastercopy", async () => { - const { mastercopyAddresses, deployer } = await loadFixture( - deployModuleFactoryAndMastercopy - ) - const mech = ERC1155ThresholdMech__factory.connect( - mastercopyAddresses.erc1155, - deployer - ) - await expect(mech.isOperator(deployer._address)).to.be.reverted - }) - }) - ///// ZodiacMech - describe("deployZodiacMech()", () => { + describe.skip("deployZodiacMech()", () => { it("correctly initializes the mech proxy instance", async () => { - const { deployer, alice } = await loadFixture( - deployModuleFactoryAndMastercopy - ) + const { deployer, alice } = await loadFixture(deployFactories) - await deployZodiacMech([alice.address], deployer) - const mechAddress = calculateZodiacMechAddress([alice.address]) + await deployZodiacMech([alice.getAddress()], deployer) + const mechAddress = calculateZodiacMechAddress([alice.getAddress()]) const mech = ZodiacMech__factory.connect(mechAddress, alice) expect(await mech.getModulesPaginated(SENTINEL_MODULES, 2)).to.deep.equal( - [[alice.address], SENTINEL_MODULES] + [[alice.getAddress()], SENTINEL_MODULES] ) }) }) - describe("calculateZodiacMechMastercopyAddress", () => { + describe.skip("calculateZodiacMechMastercopyAddress", () => { it("returns the address of the ZodiacMech mastercopy", async () => { - const { mastercopyAddresses } = await loadFixture( - deployModuleFactoryAndMastercopy - ) + const { mastercopyAddresses } = await loadFixture(deployFactories) expect(calculateZodiacMechMastercopyAddress()).to.equal( mastercopyAddresses.zodiac @@ -281,21 +353,21 @@ describe("deterministic deployment", () => { }) }) - describe("calculateZodiacMechAddress()", () => { + describe.skip("calculateZodiacMechAddress()", () => { it("returns the address of the mech for a given NFT", async () => { - await loadFixture(deployModuleFactoryAndMastercopy) + await loadFixture(deployFactories) const [, mod1, mod2] = await hre.ethers.getSigners() const calculatedAddress = calculateZodiacMechAddress([ - mod1.address, - mod2.address, + mod1.getAddress(), + mod2.getAddress(), ]) expect(await ethers.provider.getCode(calculatedAddress)).to.equal("0x") await deployZodiacMech( - [mod1.address, mod2.address], + [mod1.getAddress(), mod2.getAddress()], hre.ethers.provider.getSigner() ) @@ -305,10 +377,10 @@ describe("deterministic deployment", () => { }) }) - describe("deployZodiacMechMastercopy()", () => { + describe.skip("deployZodiacMechMastercopy()", () => { it("initializes the mastercopy with an empty modules array", async () => { const { mastercopyAddresses, deployer } = await loadFixture( - deployModuleFactoryAndMastercopy + deployFactories ) const mech = ZodiacMech__factory.connect( @@ -323,7 +395,7 @@ describe("deterministic deployment", () => { it("initializes the mastercopy", async () => { const { mastercopyAddresses, deployer } = await loadFixture( - deployModuleFactoryAndMastercopy + deployFactories ) const mech = ZodiacMech__factory.connect( @@ -338,7 +410,7 @@ describe("deterministic deployment", () => { it("makes sure no one can operate the mastercopy", async () => { const { mastercopyAddresses, deployer } = await loadFixture( - deployModuleFactoryAndMastercopy + deployFactories ) const mech = ZodiacMech__factory.connect( From cd7e95d56751646dd8a282e65be690d52cd5df1e Mon Sep 17 00:00:00 2001 From: Jan-Felix Date: Fri, 25 Aug 2023 11:27:26 +0200 Subject: [PATCH 24/41] update 4337 entrypoint address --- contracts/base/Account.sol | 2 +- integrationTest/accountAbstraction.ts | 2 +- test/Account.ts | 52 +++++++++++++++++++-------- test/deterministicDeployment.ts | 46 +++--------------------- test/utils.ts | 37 +++++++++++++++++++ 5 files changed, 81 insertions(+), 58 deletions(-) create mode 100644 test/utils.ts diff --git a/contracts/base/Account.sol b/contracts/base/Account.sol index 55ae73f..31f84a2 100644 --- a/contracts/base/Account.sol +++ b/contracts/base/Account.sol @@ -18,7 +18,7 @@ abstract contract Account is BaseAccount { * @dev Hard-code the ERC4337 entry point contract address so it cannot be changed by anyone */ IEntryPoint private constant _entryPoint = - IEntryPoint(0x0576a174D229E3cFA37253523E645A78A0C91B57); + IEntryPoint(0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789); /// @inheritdoc BaseAccount function entryPoint() public view virtual override returns (IEntryPoint) { diff --git a/integrationTest/accountAbstraction.ts b/integrationTest/accountAbstraction.ts index d96b624..4d5e6a4 100644 --- a/integrationTest/accountAbstraction.ts +++ b/integrationTest/accountAbstraction.ts @@ -17,7 +17,7 @@ import { } from "../typechain-types" import { UserOperationStruct } from "../typechain-types/@account-abstraction/contracts/core/BaseAccount" -const entryPointAddress = "0x0576a174D229E3cFA37253523E645A78A0C91B57" +const entryPointAddress = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" describe("account abstraction", () => { it("implements ERC-4337 account abstraction", async () => { diff --git a/test/Account.ts b/test/Account.ts index 363f770..9a07711 100644 --- a/test/Account.ts +++ b/test/Account.ts @@ -4,6 +4,11 @@ import { expect } from "chai" import { AbiCoder, getBytes, keccak256, parseEther } from "ethers" import { ethers, network } from "hardhat" +import { ERC721TokenboundMech__factory } from "../sdk/build/cjs/typechain-types" +import { + calculateERC721TokenboundMechAddress, + deployERC721TokenboundMech, +} from "../sdk/src" import { ZERO_ADDRESS } from "../sdk/src/constants" import { Account__factory, Mech__factory } from "../typechain-types" import { @@ -11,38 +16,55 @@ import { UserOperationStruct, } from "../typechain-types/contracts/base/Account" -export const entryPoint = "0x0576a174D229E3cFA37253523E645A78A0C91B57" +import { deployFactories } from "./utils" + +export const entryPoint = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" -describe("Account base contract", () => { +describe.only("Account base contract", () => { // We define a fixture to reuse the same setup in every test. We use // loadFixture to run this setup once, snapshot that state, and reset Hardhat // Network to that snapshot in every test. async function deployMech1() { - const TestToken = await ethers.getContractFactory("ERC721Token") - const ERC721TokenboundMech = await ethers.getContractFactory( - "ERC721TokenboundMech" - ) - const [deployer, alice, bob] = await ethers.getSigners() + const { deployer, deployerClient, erc6551Registry, alice, bob } = + await deployFactories() + const TestToken = await ethers.getContractFactory("ERC721Token") const testToken = await TestToken.deploy() - const mech1 = await ERC721TokenboundMech.deploy(testToken.getAddress(), 1) + const testTokenAddress = (await testToken.getAddress()) as `0x${string}` + + const chainId = deployerClient.chain.id + const registryAddress = + (await erc6551Registry.getAddress()) as `0x${string}` + + await deployERC721TokenboundMech(deployerClient, { + token: testTokenAddress, + tokenId: 1n, + from: registryAddress, + }) // make alice the operator of mech1 await testToken.mintToken(alice.address, 1) - await mech1.waitForDeployment() - await network.provider.request({ method: "hardhat_impersonateAccount", params: [entryPoint], }) const entryPointSigner = await ethers.getSigner(entryPoint) + // fund the entry point await deployer.sendTransaction({ to: entryPoint, value: parseEther("1.0") }) + const mech1 = ERC721TokenboundMech__factory.connect( + calculateERC721TokenboundMechAddress({ + chainId, + token: testTokenAddress, + tokenId: 1n, + from: registryAddress, + }) + ) + // Fixtures can return anything you consider useful for your tests return { - ERC721TokenboundMech, testToken, mech1, alice, @@ -58,7 +80,7 @@ describe("Account base contract", () => { describe("validateUserOp()", () => { it("reverts if called by another address than the entry point", async () => { - const { mech1, alice } = await loadFixture(deployMech1) + const { mech1, alice, entryPointSigner } = await loadFixture(deployMech1) const userOp = await signUserOp( await fillUserOp( @@ -71,7 +93,7 @@ describe("Account base contract", () => { ) await expect( - mech1.validateUserOp(userOp, getUserOpHash(userOp), 0) + mech1.connect(alice).validateUserOp(userOp, getUserOpHash(userOp), 0) ).to.be.revertedWith("account: not from EntryPoint") }) @@ -140,7 +162,7 @@ describe("Account base contract", () => { .connect(entryPointSigner) .validateUserOp(userOp, getUserOpHash(userOp), parseEther("0.123")) ).to.changeEtherBalances( - [mech1.getAddress(), entryPointSigner.address], + [await mech1.getAddress(), entryPointSigner.address], [parseEther("-0.123"), parseEther("0.123")] ) }) @@ -152,7 +174,7 @@ export const fillUserOp = async ( op: Partial, account: Account ): Promise => ({ - sender: account.getAddress(), + sender: await account.getAddress(), callData: "0x", initCode: "0x", callGasLimit: 0, diff --git a/test/deterministicDeployment.ts b/test/deterministicDeployment.ts index 3031d05..2ceb2b1 100644 --- a/test/deterministicDeployment.ts +++ b/test/deterministicDeployment.ts @@ -1,14 +1,7 @@ import { defaultAbiCoder } from "@ethersproject/abi" -import { JsonRpcProvider } from "@ethersproject/providers" import { loadFixture } from "@nomicfoundation/hardhat-network-helpers" import { expect } from "chai" import hre, { ethers } from "hardhat" -import { createWalletClient, custom as customTransport } from "viem" -import { hardhat } from "viem/chains" - -// We use `loadFixture` to share common setups (or fixtures) between tests. -// Using this simplifies your tests and makes them run faster, by taking -// advantage or Hardhat Network's snapshot functionality. import { calculateERC1155ThresholdMechAddress, @@ -23,10 +16,8 @@ import { deployERC1155ThresholdMechMastercopy, deployERC1155TokenboundMech, deployERC1155TokenboundMechMastercopy, - deployERC2470SingletonFactory, deployERC721TokenboundMech, deployERC721TokenboundMechMastercopy, - deployMechFactory, deployZodiacMech, deployZodiacMechMastercopy, } from "../sdk" @@ -36,45 +27,18 @@ import { ZERO_ADDRESS, } from "../sdk/src/constants" import { - ERC1155Mech__factory, ERC1155TokenboundMech__factory, - ERC721Mech__factory, ERC721TokenboundMech__factory, ZodiacMech__factory, } from "../typechain-types" -describe("deterministic deployment", () => { - /** deploy ERC2470 singleton factory, MechFactory, and ERC6551 registry */ - async function deployFactories() { - const [signer, alice] = await hre.ethers.getSigners() - const deployer = await hre.ethers.provider.getSigner( - await signer.getAddress() - ) - - const ERC6551Registry = await ethers.getContractFactory("ERC6551Registry") - const erc6551Registry = await ERC6551Registry.deploy() - - const deployerClient = createWalletClient({ - chain: hardhat, - account: (await signer.getAddress()) as `0x${string}`, - transport: customTransport({ - request({ method, params }) { - return hre.ethers.provider.send(method, params) - }, - }), - }) +import { deployFactories } from "./utils" - await deployERC2470SingletonFactory(deployerClient) - await deployMechFactory(deployerClient) - - return { - erc6551Registry, - deployer, - deployerClient, - alice, - } - } +// We use `loadFixture` to share common setups (or fixtures) between tests. +// Using this simplifies your tests and makes them run faster, by taking +// advantage or Hardhat Network's snapshot functionality. +describe("deterministic deployment", () => { describe("calculateERC721TokenboundMechAddress()", () => { it("returns the correct address", async () => { const { deployerClient, erc6551Registry } = await loadFixture( diff --git a/test/utils.ts b/test/utils.ts new file mode 100644 index 0000000..169e550 --- /dev/null +++ b/test/utils.ts @@ -0,0 +1,37 @@ +import hre, { ethers } from "hardhat" +import { createWalletClient, custom as customTransport } from "viem" +import { hardhat } from "viem/chains" + +import { deployERC2470SingletonFactory, deployMechFactory } from "../sdk" + +/** deploy ERC2470 singleton factory, MechFactory, and ERC6551 registry */ +export async function deployFactories() { + const [signer, alice, bob] = await hre.ethers.getSigners() + const deployer = await hre.ethers.provider.getSigner( + await signer.getAddress() + ) + + const ERC6551Registry = await ethers.getContractFactory("ERC6551Registry") + const erc6551Registry = await ERC6551Registry.deploy() + + const deployerClient = createWalletClient({ + chain: hardhat, + account: (await signer.getAddress()) as `0x${string}`, + transport: customTransport({ + request({ method, params }) { + return hre.ethers.provider.send(method, params) + }, + }), + }) + + await deployERC2470SingletonFactory(deployerClient) + await deployMechFactory(deployerClient) + + return { + erc6551Registry, + deployer, + deployerClient, + alice, + bob, + } +} From 4167db568bddb269feaf5e32d856680b6cccb8ff Mon Sep 17 00:00:00 2001 From: Jan-Felix Date: Fri, 25 Aug 2023 13:20:03 +0200 Subject: [PATCH 25/41] fix 4337 tests --- frontend/package.json | 6 +- package.json | 16 +++--- sdk/package.json | 6 +- test/Account.ts | 42 +++++++------- test/utils.ts | 9 ++- yarn.lock | 125 +++++++++++++++++------------------------- 6 files changed, 92 insertions(+), 112 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index 5254356..c6158ac 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -3,7 +3,7 @@ "version": "1.0.0", "private": true, "devDependencies": { - "@types/react": "^18.2.20", + "@types/react": "^18.2.21", "@types/react-dom": "^18.2.7", "@walletconnect/client": "^1.8.0", "@walletconnect/core": "^2.10.0", @@ -23,9 +23,9 @@ "react-dom": "^18.2.0", "react-router-dom": "^6.15.0", "react-scripts": "5.0.1", - "typescript": "^5.1.6", + "typescript": "^5.2.2", "typescript-plugin-css-modules": "^5.0.1", - "viem": "^1.6.4", + "viem": "^1.7.0", "wagmi": "^1.3.10" }, "scripts": { diff --git a/package.json b/package.json index c1d174a..5afc86a 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "@nomicfoundation/hardhat-ethers": "^3.0.4", "@nomicfoundation/hardhat-network-helpers": "^1.0.8", "@nomicfoundation/hardhat-toolbox": "^3.0.0", - "@nomicfoundation/hardhat-verify": "^1.0.0", + "@nomicfoundation/hardhat-verify": "^1.1.1", "@nomiclabs/hardhat-ethers": "^2.2.3", "@nomiclabs/hardhat-etherscan": "^3.1.7", "@safe-global/safe-core-sdk": "^3.3.5", @@ -59,19 +59,19 @@ "@typechain/hardhat": "^9.0.0", "@types/chai": "^4.3.5", "@types/mocha": "^10.0.1", - "@types/node": "^18.17.5", + "@types/node": "^18.17.11", "@typescript-eslint/eslint-plugin": "^5.62.0", "@typescript-eslint/parser": "^5.62.0", - "chai": "^4.3.7", + "chai": "^4.3.8", "dotenv": "^16.3.1", "eslint": "^8.47.0", "eslint-config-prettier": "^8.10.0", "eslint-plugin-eslint-comments": "^3.2.0", - "eslint-plugin-import": "^2.28.0", + "eslint-plugin-import": "^2.28.1", "eslint-plugin-prettier": "^4.2.1", - "ethers": "^6.4.0", + "ethers": "^6.7.1", "hardhat": "^2.17.1", - "hardhat-deploy": "^0.11.36", + "hardhat-deploy": "^0.11.37", "hardhat-gas-reporter": "^1.0.9", "prettier": "^2.8.8", "prettier-plugin-solidity": "^1.1.3", @@ -79,7 +79,7 @@ "solidity-coverage": "^0.8.4", "ts-node": "^10.9.1", "typechain": "^8.3.1", - "typescript": "^5.1.6" + "typescript": "^5.2.2" }, "dependencies": { "@account-abstraction/contracts": "^0.6.0", @@ -91,4 +91,4 @@ "@walletconnect/ethereum-provider": "2.7.0" }, "packageManager": "yarn@3.6.1" -} \ No newline at end of file +} diff --git a/sdk/package.json b/sdk/package.json index 4ec2f1d..a5a3f37 100644 --- a/sdk/package.json +++ b/sdk/package.json @@ -32,7 +32,7 @@ "homepage": "https://github.com/gnosis/mech#readme", "devDependencies": { "rimraf": "^4.4.1", - "typescript": "^5.1.6" + "typescript": "^5.2.2" }, "dependencies": { "@gnosis.pm/safe-contracts": "^1.3.0", @@ -40,9 +40,9 @@ "@openzeppelin/contracts": "^4.9.3", "@safe-global/safe-core-sdk": "^3.3.5", "@types/chai": "^4.3.5", - "@types/node": "^18.17.5", + "@types/node": "^18.17.11", "ethers": "^6.7.1", - "viem": "^1.6.4" + "viem": "^1.7.0" }, "packageManager": "yarn@3.6.1" } diff --git a/test/Account.ts b/test/Account.ts index 9a07711..ccd40f8 100644 --- a/test/Account.ts +++ b/test/Account.ts @@ -8,6 +8,7 @@ import { ERC721TokenboundMech__factory } from "../sdk/build/cjs/typechain-types" import { calculateERC721TokenboundMechAddress, deployERC721TokenboundMech, + deployERC721TokenboundMechMastercopy, } from "../sdk/src" import { ZERO_ADDRESS } from "../sdk/src/constants" import { Account__factory, Mech__factory } from "../typechain-types" @@ -20,7 +21,7 @@ import { deployFactories } from "./utils" export const entryPoint = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789" -describe.only("Account base contract", () => { +describe("Account base contract", () => { // We define a fixture to reuse the same setup in every test. We use // loadFixture to run this setup once, snapshot that state, and reset Hardhat // Network to that snapshot in every test. @@ -28,6 +29,8 @@ describe.only("Account base contract", () => { const { deployer, deployerClient, erc6551Registry, alice, bob } = await deployFactories() + await deployERC721TokenboundMechMastercopy(deployerClient) + const TestToken = await ethers.getContractFactory("ERC721Token") const testToken = await TestToken.deploy() const testTokenAddress = (await testToken.getAddress()) as `0x${string}` @@ -41,6 +44,14 @@ describe.only("Account base contract", () => { tokenId: 1n, from: registryAddress, }) + const mech1 = ERC721TokenboundMech__factory.connect( + calculateERC721TokenboundMechAddress({ + chainId, + token: testTokenAddress, + tokenId: 1n, + from: registryAddress, + }) + ) // make alice the operator of mech1 await testToken.mintToken(alice.address, 1) @@ -54,15 +65,6 @@ describe.only("Account base contract", () => { // fund the entry point await deployer.sendTransaction({ to: entryPoint, value: parseEther("1.0") }) - const mech1 = ERC721TokenboundMech__factory.connect( - calculateERC721TokenboundMechAddress({ - chainId, - token: testTokenAddress, - tokenId: 1n, - from: registryAddress, - }) - ) - // Fixtures can return anything you consider useful for your tests return { testToken, @@ -80,7 +82,7 @@ describe.only("Account base contract", () => { describe("validateUserOp()", () => { it("reverts if called by another address than the entry point", async () => { - const { mech1, alice, entryPointSigner } = await loadFixture(deployMech1) + const { mech1, alice } = await loadFixture(deployMech1) const userOp = await signUserOp( await fillUserOp( @@ -110,11 +112,10 @@ describe.only("Account base contract", () => { alice ) - expect( - await mech1 - .connect(entryPointSigner) - .validateUserOp.staticCallResult(userOp, getUserOpHash(userOp), 0) - ).to.equal(0) + const [result] = await mech1 + .connect(entryPointSigner) + .validateUserOp.staticCallResult(userOp, getUserOpHash(userOp), 0) + expect(result).to.equal(0n) }) it("returns 1 for any other ECDSA signature", async () => { @@ -130,11 +131,10 @@ describe.only("Account base contract", () => { bob ) - expect( - await mech1 - .connect(entryPointSigner) - .validateUserOp.staticCallResult(userOp, getUserOpHash(userOp), 0) - ).to.equal(1) + const [result] = await mech1 + .connect(entryPointSigner) + .validateUserOp.staticCallResult(userOp, getUserOpHash(userOp), 0) + expect(result).to.equal(1n) }) it("sends the pre-fund to sender if the user op has valid signature", async () => { diff --git a/test/utils.ts b/test/utils.ts index 169e550..addd6cd 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -2,7 +2,14 @@ import hre, { ethers } from "hardhat" import { createWalletClient, custom as customTransport } from "viem" import { hardhat } from "viem/chains" -import { deployERC2470SingletonFactory, deployMechFactory } from "../sdk" +import { + deployERC1155ThresholdMechMastercopy, + deployERC1155TokenboundMechMastercopy, + deployERC2470SingletonFactory, + deployERC721TokenboundMechMastercopy, + deployMechFactory, + deployZodiacMechMastercopy, +} from "../sdk" /** deploy ERC2470 singleton factory, MechFactory, and ERC6551 registry */ export async function deployFactories() { diff --git a/yarn.lock b/yarn.lock index 1c5daf0..a60e8d3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3336,7 +3336,7 @@ __metadata: languageName: node linkType: hard -"@nomicfoundation/hardhat-verify@npm:^1.0.0": +"@nomicfoundation/hardhat-verify@npm:^1.1.1": version: 1.1.1 resolution: "@nomicfoundation/hardhat-verify@npm:1.1.1" dependencies: @@ -4727,10 +4727,10 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:^18.17.5": - version: 18.17.5 - resolution: "@types/node@npm:18.17.5" - checksum: b8c658a99234b99425243c324b641ed7b9ceb6bee6b06421fdc9bb7c58f9a5552e353225cc549e6982462ac384abe1985022ed76e2e4728797f59b21f659ca2b +"@types/node@npm:^18.17.11": + version: 18.17.11 + resolution: "@types/node@npm:18.17.11" + checksum: c31d9f4a6f7c5c413b6548ded0fab046571832718361c5cda325960f32d6b386dd0a7fa9228911111fee54c180d09df82a622efdabdbef89fa9e1923891892bc languageName: node linkType: hard @@ -4830,14 +4830,14 @@ __metadata: languageName: node linkType: hard -"@types/react@npm:^18.2.20": - version: 18.2.20 - resolution: "@types/react@npm:18.2.20" +"@types/react@npm:^18.2.21": + version: 18.2.21 + resolution: "@types/react@npm:18.2.21" dependencies: "@types/prop-types": "*" "@types/scheduler": "*" csstype: ^3.0.2 - checksum: 30f699c60e5e4bfef273ce64d320651cdd60f5c6a08361c6c7eca8cebcccda1ac953d2ee57c9f321b5ae87f8a62c72b6d35ca42df0e261d337849952daab2141 + checksum: ffed203bfe7aad772b8286f7953305c9181ac3a8f27d3f5400fbbc2a8e27ca8e5bbff818ee014f39ca0d19d2b3bb154e5bdbec7e232c6f80b59069375aa78349 languageName: node linkType: hard @@ -7613,9 +7613,9 @@ __metadata: languageName: node linkType: hard -"chai@npm:^4.3.7": - version: 4.3.7 - resolution: "chai@npm:4.3.7" +"chai@npm:^4.3.8": + version: 4.3.8 + resolution: "chai@npm:4.3.8" dependencies: assertion-error: ^1.1.0 check-error: ^1.0.2 @@ -7624,7 +7624,7 @@ __metadata: loupe: ^2.3.1 pathval: ^1.1.1 type-detect: ^4.0.5 - checksum: 0bba7d267848015246a66995f044ce3f0ebc35e530da3cbdf171db744e14cbe301ab913a8d07caf7952b430257ccbb1a4a983c570a7c5748dc537897e5131f7c + checksum: 29e0984ed13308319cadc35437c8ef0a3e271544d226c991bf7e3b6d771bf89707321669e11d05e362bc0ad0bd26585079b989d1032f3c106e3bb95d7f079cce languageName: node linkType: hard @@ -9689,9 +9689,9 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-import@npm:^2.28.0": - version: 2.28.0 - resolution: "eslint-plugin-import@npm:2.28.0" +"eslint-plugin-import@npm:^2.28.1": + version: 2.28.1 + resolution: "eslint-plugin-import@npm:2.28.1" dependencies: array-includes: ^3.1.6 array.prototype.findlastindex: ^1.2.2 @@ -9702,18 +9702,17 @@ __metadata: eslint-import-resolver-node: ^0.3.7 eslint-module-utils: ^2.8.0 has: ^1.0.3 - is-core-module: ^2.12.1 + is-core-module: ^2.13.0 is-glob: ^4.0.3 minimatch: ^3.1.2 object.fromentries: ^2.0.6 object.groupby: ^1.0.0 object.values: ^1.1.6 - resolve: ^1.22.3 semver: ^6.3.1 tsconfig-paths: ^3.14.2 peerDependencies: eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 - checksum: f9eba311b93ca1bb89311856b1f7285bd79e0181d7eb70fe115053ff77e2235fea749b30f538b78927dc65769340b5be61f4c9581d1c82bcdcccb2061f440ad1 + checksum: e8ae6dd8f06d8adf685f9c1cfd46ac9e053e344a05c4090767e83b63a85c8421ada389807a39e73c643b9bff156715c122e89778169110ed68d6428e12607edf languageName: node linkType: hard @@ -10312,7 +10311,7 @@ __metadata: languageName: node linkType: hard -"ethers@npm:^6.4.0, ethers@npm:^6.7.1": +"ethers@npm:^6.7.1": version: 6.7.1 resolution: "ethers@npm:6.7.1" dependencies: @@ -10926,7 +10925,7 @@ __metadata: version: 0.0.0-use.local resolution: "frontend@workspace:frontend" dependencies: - "@types/react": ^18.2.20 + "@types/react": ^18.2.21 "@types/react-dom": ^18.2.7 "@walletconnect/client": ^1.8.0 "@walletconnect/core": ^2.10.0 @@ -10946,9 +10945,9 @@ __metadata: react-dom: ^18.2.0 react-router-dom: ^6.15.0 react-scripts: 5.0.1 - typescript: ^5.1.6 + typescript: ^5.2.2 typescript-plugin-css-modules: ^5.0.1 - viem: ^1.6.4 + viem: ^1.7.0 wagmi: ^1.3.10 languageName: unknown linkType: soft @@ -11520,9 +11519,9 @@ __metadata: languageName: node linkType: hard -"hardhat-deploy@npm:^0.11.36": - version: 0.11.36 - resolution: "hardhat-deploy@npm:0.11.36" +"hardhat-deploy@npm:^0.11.37": + version: 0.11.37 + resolution: "hardhat-deploy@npm:0.11.37" dependencies: "@ethersproject/abi": ^5.7.0 "@ethersproject/abstract-signer": ^5.7.0 @@ -11548,7 +11547,7 @@ __metadata: murmur-128: ^0.2.1 qs: ^6.9.4 zksync-web3: ^0.14.3 - checksum: 138fa0c22aec9367bd9cf2ff1ca03c2ee8c4c90c7d30ab20da86537533fd2ec53480af4cf6ce985528f3291a260baeb4ef584dbcaba5c0d64ccf27f0dea9a084 + checksum: c338289849f26530296be648c7bfc2d4673d0786855ed256ee9cc864f40b94125cfa36808bedfbae4f2bad7adc38def7547bbeb3b84cbfb0aeabae04de5238fd languageName: node linkType: hard @@ -12327,7 +12326,7 @@ __metadata: languageName: node linkType: hard -"is-core-module@npm:^2.12.1, is-core-module@npm:^2.13.0": +"is-core-module@npm:^2.13.0": version: 2.13.0 resolution: "is-core-module@npm:2.13.0" dependencies: @@ -14236,7 +14235,7 @@ __metadata: "@nomicfoundation/hardhat-ethers": ^3.0.4 "@nomicfoundation/hardhat-network-helpers": ^1.0.8 "@nomicfoundation/hardhat-toolbox": ^3.0.0 - "@nomicfoundation/hardhat-verify": ^1.0.0 + "@nomicfoundation/hardhat-verify": ^1.1.1 "@nomiclabs/hardhat-ethers": ^2.2.3 "@nomiclabs/hardhat-etherscan": ^3.1.7 "@openzeppelin/contracts": ^4.9.3 @@ -14245,19 +14244,19 @@ __metadata: "@typechain/hardhat": ^9.0.0 "@types/chai": ^4.3.5 "@types/mocha": ^10.0.1 - "@types/node": ^18.17.5 + "@types/node": ^18.17.11 "@typescript-eslint/eslint-plugin": ^5.62.0 "@typescript-eslint/parser": ^5.62.0 - chai: ^4.3.7 + chai: ^4.3.8 dotenv: ^16.3.1 eslint: ^8.47.0 eslint-config-prettier: ^8.10.0 eslint-plugin-eslint-comments: ^3.2.0 - eslint-plugin-import: ^2.28.0 + eslint-plugin-import: ^2.28.1 eslint-plugin-prettier: ^4.2.1 - ethers: ^6.4.0 + ethers: ^6.7.1 hardhat: ^2.17.1 - hardhat-deploy: ^0.11.36 + hardhat-deploy: ^0.11.37 hardhat-gas-reporter: ^1.0.9 prettier: ^2.8.8 prettier-plugin-solidity: ^1.1.3 @@ -14265,7 +14264,7 @@ __metadata: solidity-coverage: ^0.8.4 ts-node: ^10.9.1 typechain: ^8.3.1 - typescript: ^5.1.6 + typescript: ^5.2.2 languageName: unknown linkType: soft @@ -14278,11 +14277,11 @@ __metadata: "@openzeppelin/contracts": ^4.9.3 "@safe-global/safe-core-sdk": ^3.3.5 "@types/chai": ^4.3.5 - "@types/node": ^18.17.5 + "@types/node": ^18.17.11 ethers: ^6.7.1 rimraf: ^4.4.1 - typescript: ^5.1.6 - viem: ^1.6.4 + typescript: ^5.2.2 + viem: ^1.7.0 languageName: unknown linkType: soft @@ -17546,19 +17545,6 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.22.3": - version: 1.22.4 - resolution: "resolve@npm:1.22.4" - dependencies: - is-core-module: ^2.13.0 - path-parse: ^1.0.7 - supports-preserve-symlinks-flag: ^1.0.0 - bin: - resolve: bin/resolve - checksum: 23f25174c2736ce24c6d918910e0d1f89b6b38fefa07a995dff864acd7863d59a7f049e691f93b4b2ee29696303390d921552b6d1b841ed4a8101f517e1d0124 - languageName: node - linkType: hard - "resolve@npm:^2.0.0-next.4": version: 2.0.0-next.4 resolution: "resolve@npm:2.0.0-next.4" @@ -17601,19 +17587,6 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@^1.22.3#~builtin": - version: 1.22.4 - resolution: "resolve@patch:resolve@npm%3A1.22.4#~builtin::version=1.22.4&hash=c3c19d" - dependencies: - is-core-module: ^2.13.0 - path-parse: ^1.0.7 - supports-preserve-symlinks-flag: ^1.0.0 - bin: - resolve: bin/resolve - checksum: c45f2545fdc4d21883861b032789e20aa67a2f2692f68da320cc84d5724cd02f2923766c5354b3210897e88f1a7b3d6d2c7c22faeead8eed7078e4c783a444bc - languageName: node - linkType: hard - "resolve@patch:resolve@^2.0.0-next.4#~builtin": version: 2.0.0-next.4 resolution: "resolve@patch:resolve@npm%3A2.0.0-next.4#~builtin::version=2.0.0-next.4&hash=c3c19d" @@ -19868,23 +19841,23 @@ __metadata: languageName: node linkType: hard -"typescript@npm:^5.1.6": - version: 5.1.6 - resolution: "typescript@npm:5.1.6" +"typescript@npm:^5.2.2": + version: 5.2.2 + resolution: "typescript@npm:5.2.2" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: b2f2c35096035fe1f5facd1e38922ccb8558996331405eb00a5111cc948b2e733163cc22fab5db46992aba7dd520fff637f2c1df4996ff0e134e77d3249a7350 + checksum: 7912821dac4d962d315c36800fe387cdc0a6298dba7ec171b350b4a6e988b51d7b8f051317786db1094bd7431d526b648aba7da8236607febb26cf5b871d2d3c languageName: node linkType: hard -"typescript@patch:typescript@^5.1.6#~builtin": - version: 5.1.6 - resolution: "typescript@patch:typescript@npm%3A5.1.6#~builtin::version=5.1.6&hash=5da071" +"typescript@patch:typescript@^5.2.2#~builtin": + version: 5.2.2 + resolution: "typescript@patch:typescript@npm%3A5.2.2#~builtin::version=5.2.2&hash=14eedb" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: f53bfe97f7c8b2b6d23cf572750d4e7d1e0c5fff1c36d859d0ec84556a827b8785077bc27676bf7e71fae538e517c3ecc0f37e7f593be913d884805d931bc8be + checksum: 07106822b4305de3f22835cbba949a2b35451cad50888759b6818421290ff95d522b38ef7919e70fb381c5fe9c1c643d7dea22c8b31652a717ddbd57b7f4d554 languageName: node linkType: hard @@ -20266,9 +20239,9 @@ __metadata: languageName: node linkType: hard -"viem@npm:^1.6.4": - version: 1.6.4 - resolution: "viem@npm:1.6.4" +"viem@npm:^1.7.0": + version: 1.7.0 + resolution: "viem@npm:1.7.0" dependencies: "@adraffy/ens-normalize": 1.9.0 "@noble/curves": 1.1.0 @@ -20285,7 +20258,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 3b77db9e09fd7066f29db48fe37817a126bbafe97c36f2737c15684e1d5ed1a6458d37f336036702052b17bbb552b0687ec8ae4514b82ad3c9a07b6a07c051a1 + checksum: d56d6317be7e07204c601eca3e90661122767ef883dc1f4aa615bc725c2bd65eb99ebbfb2180459147f327a38293f9c70bd8bdf7be64c4b9222b9d40fcb7fc69 languageName: node linkType: hard From f399e1d58a36b3b6fd2bfe79dd725a3127d288ef Mon Sep 17 00:00:00 2001 From: Jan-Felix Date: Fri, 25 Aug 2023 13:54:56 +0200 Subject: [PATCH 26/41] fix missing onlyOperator annotation --- contracts/base/Mech.sol | 2 +- test/ERC1155TokenboundMech.ts | 107 +++++++++++++++++++ test/ERC721TokenboundMech.ts | 81 +++++++++------ test/Mech.ts | 179 +++++++++++++++++++++----------- test/deterministicDeployment.ts | 4 - 5 files changed, 275 insertions(+), 98 deletions(-) create mode 100644 test/ERC1155TokenboundMech.ts diff --git a/contracts/base/Mech.sol b/contracts/base/Mech.sol index afd2706..b6ce392 100644 --- a/contracts/base/Mech.sol +++ b/contracts/base/Mech.sol @@ -152,7 +152,7 @@ abstract contract Mech is IMech, Account, Receiver { uint256 value, bytes calldata data, Enum.Operation operation - ) external payable returns (bytes memory returnData) { + ) external payable onlyOperator returns (bytes memory returnData) { bool success; (success, returnData) = _exec(to, value, data, operation, gasleft()); diff --git a/test/ERC1155TokenboundMech.ts b/test/ERC1155TokenboundMech.ts new file mode 100644 index 0000000..99f5799 --- /dev/null +++ b/test/ERC1155TokenboundMech.ts @@ -0,0 +1,107 @@ +import { loadFixture } from "@nomicfoundation/hardhat-network-helpers" +import { expect } from "chai" +import { ethers } from "hardhat" + +import { + calculateERC1155TokenboundMechAddress, + deployERC1155TokenboundMech, + deployERC1155TokenboundMechMastercopy, +} from "../sdk/src" +import { ERC1155TokenboundMech__factory } from "../typechain-types" + +import { deployFactories } from "./utils" + +describe("ERC1155TokenboundMech contract", () => { + // We define a fixture to reuse the same setup in every test. We use + // loadFixture to run this setup once, snapshot that state, and reset Hardhat + // Network to that snapshot in every test. + async function deployMech1() { + const { deployerClient, erc6551Registry, alice, bob } = + await deployFactories() + + await deployERC1155TokenboundMechMastercopy(deployerClient) + + const TestToken = await ethers.getContractFactory("ERC1155Token") + const testToken = await TestToken.deploy() + const testTokenAddress = (await testToken.getAddress()) as `0x${string}` + + const chainId = deployerClient.chain.id + const registryAddress = + (await erc6551Registry.getAddress()) as `0x${string}` + + await deployERC1155TokenboundMech(deployerClient, { + token: testTokenAddress, + tokenId: 1n, + from: registryAddress, + }) + + const mech1 = ERC1155TokenboundMech__factory.connect( + calculateERC1155TokenboundMechAddress({ + chainId, + token: testTokenAddress, + tokenId: 1n, + from: registryAddress, + }), + ethers.provider + ) + + // Fixtures can return anything you consider useful for your tests + return { + testToken, + mech1, + alice, + bob, + chainId, + } + } + + describe("token()", () => { + it("should return chain ID. token address and token ID", async () => { + const { mech1, chainId, testToken } = await loadFixture(deployMech1) + + expect(await mech1.token()).to.deep.equal([ + chainId, + await testToken.getAddress(), + 1n, + ]) + }) + }) + + describe("isOperator()", () => { + it("returns true for any holder of the linked tokenId", async () => { + const { mech1, testToken, alice, bob } = await loadFixture(deployMech1) + // mech1 is linked to testToken#1 + + // mint testToken#1 to alice + await testToken.mintToken(alice.address, 1n, 1n, "0x") + // mint testToken#1 to bob + await testToken.mintToken(bob.address, 1n, 1n, "0x") + + expect(await mech1.isOperator(alice.address)).to.equal(true) + expect(await mech1.isOperator(bob.address)).to.equal(true) + }) + + it("returns false for any other address", async () => { + const { mech1, testToken, alice, bob } = await loadFixture(deployMech1) + // mech1 is linked to testToken#1 + + // mint testToken#1 to alice + await testToken.mintToken(alice.address, 1n, 1n, "0x") + // mint testToken#2 to bob + await testToken.mintToken(bob.address, 2n, 1n, "0x") + + // bob does not hold mech1 since he doesn't own testToken#1 + expect(await mech1.isOperator(bob.address)).to.equal(false) + }) + + it("reverts if the linked token does not exist", async () => { + const { mech1, alice } = await loadFixture(deployMech1) + // mech1 is linked to testToken#1 + + // testToken#1 has not been minted + expect(mech1.isOperator(alice.address)).to.be.revertedWith( + "ERC1155: invalid token ID" + ) + }) + }) +}) diff --git a/test/ERC721TokenboundMech.ts b/test/ERC721TokenboundMech.ts index 0283acd..a054634 100644 --- a/test/ERC721TokenboundMech.ts +++ b/test/ERC721TokenboundMech.ts @@ -1,48 +1,69 @@ -import { defaultAbiCoder } from "@ethersproject/abi" import { loadFixture } from "@nomicfoundation/hardhat-network-helpers" import { expect } from "chai" import { ethers } from "hardhat" -// We use `loadFixture` to share common setups (or fixtures) between tests. -// Using this simplifies your tests and makes them run faster, by taking -// advantage or Hardhat Network's snapshot functionality. +import { + calculateERC721TokenboundMechAddress, + deployERC721TokenboundMech, + deployERC721TokenboundMechMastercopy, +} from "../sdk/src" +import { ERC721TokenboundMech__factory } from "../typechain-types" + +import { deployFactories } from "./utils" describe("ERC721TokenboundMech contract", () => { // We define a fixture to reuse the same setup in every test. We use // loadFixture to run this setup once, snapshot that state, and reset Hardhat // Network to that snapshot in every test. async function deployMech1() { - const TestToken = await ethers.getContractFactory("ERC721Token") - const ERC721TokenboundMech = await ethers.getContractFactory( - "ERC721TokenboundMech" - ) - const [, alice, bob] = await ethers.getSigners() + const { deployerClient, erc6551Registry, alice, bob } = + await deployFactories() + await deployERC721TokenboundMechMastercopy(deployerClient) + + const TestToken = await ethers.getContractFactory("ERC721Token") const testToken = await TestToken.deploy() - const mech1 = await ERC721TokenboundMech.deploy(testToken.address, 1) + const testTokenAddress = (await testToken.getAddress()) as `0x${string}` - await mech1.deployed() + const chainId = deployerClient.chain.id + const registryAddress = + (await erc6551Registry.getAddress()) as `0x${string}` - // Fixtures can return anything you consider useful for your tests - return { ERC721TokenboundMech, testToken, mech1, alice, bob } - } + await deployERC721TokenboundMech(deployerClient, { + token: testTokenAddress, + tokenId: 1n, + from: registryAddress, + }) - describe("deployment", () => { - it("should set token address and ID", async () => { - const { mech1, testToken } = await loadFixture(deployMech1) + const mech1 = ERC721TokenboundMech__factory.connect( + calculateERC721TokenboundMechAddress({ + chainId, + token: testTokenAddress, + tokenId: 1n, + from: registryAddress, + }), + ethers.provider + ) - expect(await mech1.token()).to.equal(testToken.address) - expect(await mech1.tokenId()).to.equal(1) - }) + // Fixtures can return anything you consider useful for your tests + return { + testToken, + mech1, + alice, + bob, + chainId, + } + } - it("should not allow any calls to setUp() afterwards", async () => { - const { mech1, testToken } = await loadFixture(deployMech1) + describe("token()", () => { + it("should return chain ID. token address and token ID", async () => { + const { mech1, chainId, testToken } = await loadFixture(deployMech1) - expect( - mech1.setUp( - defaultAbiCoder.encode(["address", "uint256"], [testToken.address, 2]) - ) - ).to.be.revertedWith("Already initialized") + expect(await mech1.token()).to.deep.equal([ + chainId, + await testToken.getAddress(), + 1n, + ]) }) }) @@ -52,7 +73,7 @@ describe("ERC721TokenboundMech contract", () => { // mech1 is linked to testToken#1 // mint testToken#1 to alice - await testToken.mintToken(alice.address, 1) + await testToken.mintToken(alice.address, 1n) expect(await mech1.isOperator(alice.address)).to.equal(true) }) @@ -61,9 +82,9 @@ describe("ERC721TokenboundMech contract", () => { // mech1 is linked to testToken#1 // mint testToken#1 to alice - await testToken.mintToken(alice.address, 1) + await testToken.mintToken(alice.address, 1n) // mint testToken#2 to bob - await testToken.mintToken(bob.address, 2) + await testToken.mintToken(bob.address, 2n) // bob does not hold mech1 since he doesn't own testToken#1 expect(await mech1.isOperator(bob.address)).to.equal(false) diff --git a/test/Mech.ts b/test/Mech.ts index add71d3..6cce3c4 100644 --- a/test/Mech.ts +++ b/test/Mech.ts @@ -6,28 +6,79 @@ import { ethers } from "hardhat" // We use `loadFixture` to share common setups (or fixtures) between tests. // Using this simplifies your tests and makes them run faster, by taking // advantage or Hardhat Network's snapshot functionality. +import { + calculateERC721TokenboundMechAddress, + deployERC721TokenboundMech, + deployERC721TokenboundMechMastercopy, +} from "../sdk/src" import { signWithMech } from "../sdk/src/sign/signWithMech" +import { ERC721TokenboundMech__factory } from "../typechain-types" + +import { deployFactories } from "./utils" const EIP1271_MAGIC_VALUE = "0x1626ba7e" -describe("Mech base contract", () => { +describe.only("Mech base contract", () => { // We define a fixture to reuse the same setup in every test. We use // loadFixture to run this setup once, snapshot that state, and reset Hardhat // Network to that snapshot in every test. async function deployMech1() { - const TestToken = await ethers.getContractFactory("ERC721Token") - const ERC721TokenboundMech = await ethers.getContractFactory( - "ERC721TokenboundMech" - ) - const [, alice, bob] = await ethers.getSigners() + const { deployerClient, deployer, erc6551Registry, alice, bob } = + await deployFactories() + await deployERC721TokenboundMechMastercopy(deployerClient) + + const TestToken = await ethers.getContractFactory("ERC721Token") const testToken = await TestToken.deploy() - const mech1 = await ERC721TokenboundMech.deploy(testToken.getAddress(), 1) + const testTokenAddress = (await testToken.getAddress()) as `0x${string}` + + const chainId = deployerClient.chain.id + const registryAddress = + (await erc6551Registry.getAddress()) as `0x${string}` - await mech1.waitForDeployment() + // deploy mech1 bound to testToken#1 + await deployERC721TokenboundMech(deployerClient, { + token: testTokenAddress, + tokenId: 1n, + from: registryAddress, + }) + const mech1 = ERC721TokenboundMech__factory.connect( + calculateERC721TokenboundMechAddress({ + chainId, + token: testTokenAddress, + tokenId: 1n, + from: registryAddress, + }), + deployer + ) + + // deploy mech2 bound to testToken#2 + deployERC721TokenboundMech(deployerClient, { + token: testTokenAddress, + tokenId: 2n, + from: registryAddress, + }) + const mech2 = ERC721TokenboundMech__factory.connect( + calculateERC721TokenboundMechAddress({ + chainId, + token: testTokenAddress, + tokenId: 2n, + from: registryAddress, + }), + deployer + ) // Fixtures can return anything you consider useful for your tests - return { ERC721TokenboundMech, testToken, mech1, alice, bob } + return { + deployerClient, + erc6551Registry, + testToken, + mech1, + mech2, + alice, + bob, + chainId, + } } describe("isValidSignature()", () => { @@ -36,7 +87,7 @@ describe("Mech base contract", () => { // mech1 is linked to testToken#1 // mint testToken#1 to alice - await testToken.mintToken(alice.getAddress(), 1) + await testToken.mintToken(await alice.getAddress(), 1n) const message = "Test message" const signature = await alice.signMessage(message) @@ -52,7 +103,7 @@ describe("Mech base contract", () => { // mech1 is linked to testToken#1 // mint testToken#1 to alice - await testToken.mintToken(alice.getAddress(), 1) + await testToken.mintToken(await alice.getAddress(), 1n) // let bob sign message const message = "Test message" @@ -65,18 +116,15 @@ describe("Mech base contract", () => { }) it("returns magic value for a valid EIP-1271 signature of the mech operator contract", async () => { - const { ERC721TokenboundMech, mech1, testToken, alice } = - await loadFixture(deployMech1) + const { mech1, mech2, testToken, alice } = await loadFixture(deployMech1) // mech1 is linked to testToken#1 - - const mech2 = await ERC721TokenboundMech.deploy(testToken.getAddress(), 2) - await mech2.waitForDeployment() + // mech2 is linked to testToken#2 // mint testToken#1 to alice - await testToken.mintToken(alice.getAddress(), 1) + await testToken.mintToken(alice.getAddress(), 1n) // mint testToken#2 to mech1, making mech1 the operator of mech2 - await testToken.mintToken(mech1.getAddress(), 2) + await testToken.mintToken(mech1.getAddress(), 2n) const message = "Test message" const ecdsaSignature = await alice.signMessage(message) @@ -97,7 +145,7 @@ describe("Mech base contract", () => { // mech1 is linked to testToken#1 // mint testToken#1 to alice - await testToken.mintToken(alice.getAddress(), 1) + await testToken.mintToken(alice.getAddress(), 1n) const message = "Test message" const ecdsaSignature = await alice.signMessage(message) @@ -114,18 +162,17 @@ describe("Mech base contract", () => { }) it("returns zero for an invalid EIP-1271 signature of the mech operator contract", async () => { - const { ERC721TokenboundMech, mech1, testToken, alice, bob } = - await loadFixture(deployMech1) + const { mech1, mech2, testToken, alice, bob } = await loadFixture( + deployMech1 + ) // mech1 is linked to testToken#1 - - const mech2 = await ERC721TokenboundMech.deploy(testToken.getAddress(), 2) - await mech2.waitForDeployment() + // mech2 is linked to testToken#2 // mint testToken#1 to alice - await testToken.mintToken(alice.getAddress(), 1) + await testToken.mintToken(alice.getAddress(), 1n) // mint testToken#2 to mech1 - await testToken.mintToken(mech1.getAddress(), 2) + await testToken.mintToken(mech1.getAddress(), 2n) const message = "Test message" const wrongEcdsaSignature = await bob.signMessage(message) @@ -142,12 +189,9 @@ describe("Mech base contract", () => { }) it("returns zero for an EIP-1271 signature from a contract that is not the mech operator", async () => { - const { ERC721TokenboundMech, mech1, testToken, alice } = - await loadFixture(deployMech1) + const { mech1, mech2, testToken, alice } = await loadFixture(deployMech1) // mech1 is linked to testToken#1 - - const mech2 = await ERC721TokenboundMech.deploy(testToken.getAddress(), 2) - await mech2.waitForDeployment() + // mech2 is linked to testToken#2 // mint testToken#1 to alice await testToken.mintToken(alice.getAddress(), 1) @@ -177,11 +221,11 @@ describe("Mech base contract", () => { // don't mint testToken#1 // make testTx (token#2 transfer from mech1 to alice) - await testToken.mintToken(mech1.getAddress(), 2) + await testToken.mintToken(mech1.getAddress(), 2n) const testTx = await testToken.transferFrom.populateTransaction( mech1.getAddress(), alice.getAddress(), - 2 + 2n ) await expect( @@ -195,27 +239,29 @@ describe("Mech base contract", () => { }) it("reverts if called from an account that is not the mech operator or entry point", async () => { - const { mech1, testToken, alice } = await loadFixture(deployMech1) + const { mech1, testToken, alice, bob } = await loadFixture(deployMech1) // mint testToken#1 to alice to make her the operator of mech1 - await testToken.mintToken(alice.getAddress(), 1) + await testToken.mintToken(alice.getAddress(), 1n) // make testTx (token#2 transfer from mech1 to alice) - await testToken.mintToken(mech1.getAddress(), 2) + await testToken.mintToken(mech1.getAddress(), 2n) const testTx = await testToken.transferFrom.populateTransaction( mech1.getAddress(), alice.getAddress(), - 2 + 2n ) - // call exec() from deployer who is not an operator + // call execute() from bob who is not an operator await expect( - mech1["execute(address,uint256,bytes,uint8)"]( - testToken.getAddress(), - 0, - testTx.data as string, - 0 - ) + mech1 + .connect(bob) + ["execute(address,uint256,bytes,uint8)"]( + testToken.getAddress(), + 0n, + testTx.data as string, + 0n + ) ).to.be.revertedWith( "Only callable by the mech operator or the entry point contract" ) @@ -224,23 +270,26 @@ describe("Mech base contract", () => { it("reverts with original data if the meta transaction reverts", async () => { const { mech1, testToken, alice } = await loadFixture(deployMech1) + const aliceAddress = await alice.getAddress() + const mech1Address = await mech1.getAddress() + // mint testToken#1 to alice to make her the operator of mech1 - await testToken.mintToken(alice.getAddress(), 1) + await testToken.mintToken(aliceAddress, 1n) // this tx will revert because mech1 does not own token#1 const revertingTxData = testToken.interface.encodeFunctionData( "transferFrom", - [mech1.getAddress(), alice.getAddress(), 1] + [mech1Address, aliceAddress, 1n] ) await expect( mech1 .connect(alice) ["execute(address,uint256,bytes,uint8)"]( - testToken.getAddress(), - 0, + await testToken.getAddress(), + 0n, revertingTxData, - 0 + 0n ) ).to.be.revertedWith("ERC721: caller is not token owner or approved") }) @@ -258,16 +307,16 @@ describe("Mech base contract", () => { .connect(alice) ["execute(address,uint256,bytes,uint8)"].staticCallResult( testToken.getAddress(), - 0, + 0n, callData, - 0 + 0n ) const decoded = testToken.interface.decodeFunctionResult( "ownerOf", result ) - expect(decoded[0]).to.equal(alice.getAddress()) + expect(decoded[0]).to.equal(await alice.getAddress()) }) it("allows to execute delegate calls", async () => { @@ -310,22 +359,26 @@ describe("Mech base contract", () => { it('respects the "txGas" argument', async () => { const { mech1, testToken, alice, bob } = await loadFixture(deployMech1) + const aliceAddress = await alice.getAddress() + const bobAddress = await bob.getAddress() + const mech1Address = await mech1.getAddress() + // mint testToken#1 to alice to make her the operator of mech1 - await testToken.mintToken(alice.getAddress(), 1) + await testToken.mintToken(aliceAddress, 1) // mint testToken#2 to alice - await testToken.mintToken(alice.getAddress(), 2) + await testToken.mintToken(aliceAddress, 2) // mint testToken#3 to mech1 - await testToken.mintToken(mech1.getAddress(), 3) + await testToken.mintToken(mech1Address, 3) // mint a token to bob, since receiving the first token will cost more gas - await testToken.mintToken(bob.getAddress(), 4) + await testToken.mintToken(bobAddress, 4) // measure actual gas of a transfer and subtract the base tx gas to get a good estimate of the required gas for the meta tx const aliceTransferTx = await testToken .connect(alice) - .transferFrom(alice.getAddress(), bob.getAddress(), 2) + .transferFrom(aliceAddress, bob.getAddress(), 2) const aliceGasUsed = (await aliceTransferTx.wait())?.gasUsed || 0n const BASE_TX_GAS = 21000n const metaTxGasCost = aliceGasUsed - BASE_TX_GAS // the actual transfer gas @@ -334,11 +387,11 @@ describe("Mech base contract", () => { const mechTxGas = await mech1 .connect(alice) ["execute(address,uint256,bytes,uint8,uint256)"].estimateGas( - testToken.getAddress(), + await testToken.getAddress(), 0, testToken.interface.encodeFunctionData("transferFrom", [ - mech1.getAddress(), - bob.getAddress(), + mech1Address, + bobAddress, 3, ]), 0, @@ -348,11 +401,11 @@ describe("Mech base contract", () => { // send too little gas to the meta tx -> tx fails await expect( mech1.connect(alice)["execute(address,uint256,bytes,uint8,uint256)"]( - testToken.getAddress(), + await testToken.getAddress(), 0, testToken.interface.encodeFunctionData("transferFrom", [ - mech1.getAddress(), - bob.getAddress(), + mech1Address, + bobAddress, 3, ]), 0, diff --git a/test/deterministicDeployment.ts b/test/deterministicDeployment.ts index 2ceb2b1..8d5332b 100644 --- a/test/deterministicDeployment.ts +++ b/test/deterministicDeployment.ts @@ -34,10 +34,6 @@ import { import { deployFactories } from "./utils" -// We use `loadFixture` to share common setups (or fixtures) between tests. -// Using this simplifies your tests and makes them run faster, by taking -// advantage or Hardhat Network's snapshot functionality. - describe("deterministic deployment", () => { describe("calculateERC721TokenboundMechAddress()", () => { it("returns the correct address", async () => { From ee82d3fed0f3f89deeaf4c5101c8597c22a2c455 Mon Sep 17 00:00:00 2001 From: Jan-Felix Date: Fri, 25 Aug 2023 13:58:30 +0200 Subject: [PATCH 27/41] improve test coverage --- test/Mech.ts | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/test/Mech.ts b/test/Mech.ts index 6cce3c4..8169f60 100644 --- a/test/Mech.ts +++ b/test/Mech.ts @@ -3,9 +3,6 @@ import { expect } from "chai" import { hashMessage } from "ethers" import { ethers } from "hardhat" -// We use `loadFixture` to share common setups (or fixtures) between tests. -// Using this simplifies your tests and makes them run faster, by taking -// advantage or Hardhat Network's snapshot functionality. import { calculateERC721TokenboundMechAddress, deployERC721TokenboundMech, @@ -18,7 +15,7 @@ import { deployFactories } from "./utils" const EIP1271_MAGIC_VALUE = "0x1626ba7e" -describe.only("Mech base contract", () => { +describe("Mech base contract", () => { // We define a fixture to reuse the same setup in every test. We use // loadFixture to run this setup once, snapshot that state, and reset Hardhat // Network to that snapshot in every test. @@ -265,6 +262,20 @@ describe.only("Mech base contract", () => { ).to.be.revertedWith( "Only callable by the mech operator or the entry point contract" ) + // same with the other overload + await expect( + mech1 + .connect(bob) + ["execute(address,uint256,bytes,uint8,uint256)"]( + testToken.getAddress(), + 0n, + testTx.data as string, + 0n, + 0n + ) + ).to.be.revertedWith( + "Only callable by the mech operator or the entry point contract" + ) }) it("reverts with original data if the meta transaction reverts", async () => { @@ -292,6 +303,18 @@ describe.only("Mech base contract", () => { 0n ) ).to.be.revertedWith("ERC721: caller is not token owner or approved") + // same with the other overload + await expect( + mech1 + .connect(alice) + ["execute(address,uint256,bytes,uint8,uint256)"]( + await testToken.getAddress(), + 0n, + revertingTxData, + 0n, + 0n + ) + ).to.be.revertedWith("ERC721: caller is not token owner or approved") }) it("returns the return data of the meta transaction", async () => { From c2f8e3c6390d019eca95081edbef4e731d1db048 Mon Sep 17 00:00:00 2001 From: Jan-Felix Date: Mon, 28 Aug 2023 11:21:32 +0200 Subject: [PATCH 28/41] test fixes --- test/signing.ts | 56 +++++++++++++++++++++++++++++++++++++++---------- test/utils.ts | 28 ++++++++++++------------- 2 files changed, 58 insertions(+), 26 deletions(-) diff --git a/test/signing.ts b/test/signing.ts index 1ecfe67..6da4d5b 100644 --- a/test/signing.ts +++ b/test/signing.ts @@ -3,27 +3,61 @@ import { loadFixture } from "@nomicfoundation/hardhat-network-helpers" import { expect } from "chai" import { ethers } from "hardhat" -import { signWithMech } from "../sdk" +import { + calculateERC721TokenboundMechAddress, + deployERC721TokenboundMech, + deployERC721TokenboundMechMastercopy, + signWithMech, +} from "../sdk/src" +import { ERC721TokenboundMech__factory } from "../typechain-types" + +import { deployFactories } from "./utils" describe("signing", () => { // We define a fixture to reuse the same setup in every test. We use // loadFixture to run this setup once, snapshot that state, and reset Hardhat // Network to that snapshot in every test. async function deployMech1() { - const TestToken = await ethers.getContractFactory("ERC721Token") - const ERC721TokenboundMech = await ethers.getContractFactory( - "ERC721TokenboundMech" - ) - const [deployer, alice, bob, eve] = await ethers.getSigners() + const { deployerClient, erc6551Registry, alice, bob } = + await deployFactories() + await deployERC721TokenboundMechMastercopy(deployerClient) + + const TestToken = await ethers.getContractFactory("ERC721Token") const testToken = await TestToken.deploy() - const mech1 = await ERC721TokenboundMech.deploy(testToken.getAddress(), 1) + const testTokenAddress = (await testToken.getAddress()) as `0x${string}` + + const chainId = deployerClient.chain.id + const registryAddress = + (await erc6551Registry.getAddress()) as `0x${string}` + + await deployERC721TokenboundMech(deployerClient, { + token: testTokenAddress, + tokenId: 1n, + from: registryAddress, + }) + + const mech1 = ERC721TokenboundMech__factory.connect( + calculateERC721TokenboundMechAddress({ + chainId, + token: testTokenAddress, + tokenId: 1n, + from: registryAddress, + }), + ethers.provider + ) - await mech1.waitForDeployment() - await testToken.mintToken(alice.getAddress(), 1) + // make alice the operator of mech1 + await testToken.mintToken(await alice.getAddress(), 1n) // Fixtures can return anything you consider useful for your tests - return { ERC721TokenboundMech, testToken, mech1, alice, bob, eve } + return { + testToken, + mech1, + alice, + bob, + chainId, + } } describe("signWithMech()", () => { @@ -39,7 +73,7 @@ describe("signing", () => { ) const isValidSig = await verifyMessage({ - signer: mech1.getAddress(), + signer: await mech1.getAddress(), message, signature: mechSignature, provider: ethers.provider, diff --git a/test/utils.ts b/test/utils.ts index addd6cd..fddf8a6 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -1,15 +1,12 @@ import hre, { ethers } from "hardhat" -import { createWalletClient, custom as customTransport } from "viem" +import { + createTestClient, + custom as customTransport, + walletActions, +} from "viem" import { hardhat } from "viem/chains" -import { - deployERC1155ThresholdMechMastercopy, - deployERC1155TokenboundMechMastercopy, - deployERC2470SingletonFactory, - deployERC721TokenboundMechMastercopy, - deployMechFactory, - deployZodiacMechMastercopy, -} from "../sdk" +import { deployERC2470SingletonFactory, deployMechFactory } from "../sdk/src" /** deploy ERC2470 singleton factory, MechFactory, and ERC6551 registry */ export async function deployFactories() { @@ -20,16 +17,17 @@ export async function deployFactories() { const ERC6551Registry = await ethers.getContractFactory("ERC6551Registry") const erc6551Registry = await ERC6551Registry.deploy() - - const deployerClient = createWalletClient({ + deployer.populateTransaction + const deployerClient = createTestClient({ + account: deployer.address as `0x${string}`, chain: hardhat, - account: (await signer.getAddress()) as `0x${string}`, + mode: "hardhat", transport: customTransport({ - request({ method, params }) { - return hre.ethers.provider.send(method, params) + async request({ method, params }) { + return deployer.provider.send(method, params) }, }), - }) + }).extend(walletActions) await deployERC2470SingletonFactory(deployerClient) await deployMechFactory(deployerClient) From a39dc16882a1290612da3ab660b194ee31da7691 Mon Sep 17 00:00:00 2001 From: Jan-Felix Date: Mon, 28 Aug 2023 11:48:04 +0200 Subject: [PATCH 29/41] front-end updates --- frontend/package.json | 2 +- frontend/src/hooks/useHandleRequest.ts | 18 +- frontend/src/utils/addressValidation.ts | 2 +- frontend/src/utils/calculateMechAddress.ts | 21 +- frontend/src/utils/deployMech.ts | 23 +- package.json | 4 +- sdk/package.json | 4 +- yarn.lock | 1886 ++++++++++---------- 8 files changed, 984 insertions(+), 976 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index c6158ac..54e0924 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -25,7 +25,7 @@ "react-scripts": "5.0.1", "typescript": "^5.2.2", "typescript-plugin-css-modules": "^5.0.1", - "viem": "^1.7.0", + "viem": "^1.8.1", "wagmi": "^1.3.10" }, "scripts": { diff --git a/frontend/src/hooks/useHandleRequest.ts b/frontend/src/hooks/useHandleRequest.ts index d07d604..7995134 100644 --- a/frontend/src/hooks/useHandleRequest.ts +++ b/frontend/src/hooks/useHandleRequest.ts @@ -1,4 +1,4 @@ -import { makeExecTransaction, signWithMech } from "mech-sdk" +import { makeExecuteTransaction, signWithMech } from "mech-sdk" import { useCallback } from "react" import { useWalletClient } from "wagmi" import { ProvideWalletConnect } from "./useWalletConnect" @@ -23,12 +23,12 @@ export const useHandleRequest = (mechAddress: `0x${string}` | null) => { const txFields = request.params[0] as TransactionFields // use ethers signer to auto-populate gas and nonce rather than using provider.send return await client.sendTransaction( - makeExecTransaction(mechAddress, txFields) + makeExecuteTransaction(mechAddress, txFields) ) } case "eth_signTransaction": { const txFields = request.params[0] as TransactionFields - const tx = makeExecTransaction(mechAddress, txFields) + const tx = makeExecuteTransaction(mechAddress, txFields) return await client.request({ method: "eth_signTransaction", params: [tx], @@ -38,19 +38,19 @@ export const useHandleRequest = (mechAddress: `0x${string}` | null) => { case "eth_sign": { // replace mech address with signer address in the params const [, message] = request.params - const ecdsaSignature = await client.request({ + const ecdsaSignature = (await client.request({ method: request.method, params: [client.account, message], - } as any) // TODO the viem types are giving us a hard time here + } as any)) as `0x${string}` // TODO the viem types are giving us a hard time here return signWithMech(mechAddress, ecdsaSignature) } case "personal_sign": { // replace mech address with signer address in the params const [message, , password] = request.params - const ecdsaSignature = await client.request({ + const ecdsaSignature = (await client.request({ method: request.method, params: [message, client.account, password], - } as any) // TODO the viem types are giving us a hard time here + } as any)) as `0x${string}` // TODO the viem types are giving us a hard time here return signWithMech(mechAddress, ecdsaSignature) } @@ -59,10 +59,10 @@ export const useHandleRequest = (mechAddress: `0x${string}` | null) => { case "eth_signTypedData_v3": case "eth_signTypedData_v4": { const typedData = request.params[1] as any - const ecdsaSignature = await client.request({ + const ecdsaSignature = (await client.request({ method: request.method, params: [client.account, typedData], - } as any) // TODO the viem types are giving us a hard time here + } as any)) as `0x${string}` // TODO the viem types are giving us a hard time here return signWithMech(mechAddress, ecdsaSignature) } diff --git a/frontend/src/utils/addressValidation.ts b/frontend/src/utils/addressValidation.ts index bc7bb1d..8ff58b2 100644 --- a/frontend/src/utils/addressValidation.ts +++ b/frontend/src/utils/addressValidation.ts @@ -1,4 +1,4 @@ -import { getAddress } from "ethers/lib/utils" +import { getAddress } from "viem" export const validateAddress = (address: string) => { try { diff --git a/frontend/src/utils/calculateMechAddress.ts b/frontend/src/utils/calculateMechAddress.ts index 0cc4959..b7430b1 100644 --- a/frontend/src/utils/calculateMechAddress.ts +++ b/frontend/src/utils/calculateMechAddress.ts @@ -1,19 +1,16 @@ import { - calculateERC1155MechAddress, - calculateERC721MechAddress, + calculateERC1155TokenboundMechAddress, + calculateERC721TokenboundMechAddress, } from "mech-sdk" import { MechNFT } from "../hooks/useNFTsByOwner" export const calculateMechAddress = (token: MechNFT) => { + const context = { + chainId: parseInt(token.blockchain.shortChainID), + token: token.contractAddress as `0x${string}`, + tokenId: BigInt(token.nft.tokenID), + } return token.tokenStandard === "ERC-1155" - ? calculateERC1155MechAddress( - token.contractAddress, - [token.nft.tokenID], - [1], - 1 - ) - : calculateERC721MechAddress( - token.contractAddress, - BigInt(token.nft.tokenID) - ) + ? calculateERC1155TokenboundMechAddress(context) + : calculateERC721TokenboundMechAddress(context) } diff --git a/frontend/src/utils/deployMech.ts b/frontend/src/utils/deployMech.ts index 57f7146..8d8b03e 100644 --- a/frontend/src/utils/deployMech.ts +++ b/frontend/src/utils/deployMech.ts @@ -1,22 +1,17 @@ import { - makeERC1155MechDeployTransaction, - makeERC721MechDeployTransaction, + makeERC1155TokenboundMechDeployTransaction, + makeERC721TokenboundMechDeployTransaction, } from "mech-sdk" import { MechNFT } from "../hooks/useNFTsByOwner" export const makeMechDeployTransaction = (token: MechNFT) => { const chainId = parseInt(token.blockchain.shortChainID) + const context = { + chainId: parseInt(token.blockchain.shortChainID), + token: token.contractAddress as `0x${string}`, + tokenId: BigInt(token.nft.tokenID), + } return token.tokenStandard === "ERC-1155" - ? makeERC1155MechDeployTransaction( - token.contractAddress, - [token.nft.tokenID], - [1], - 0, - chainId - ) - : makeERC721MechDeployTransaction( - token.contractAddress, - BigInt(token.nft.tokenID), - chainId - ) + ? makeERC1155TokenboundMechDeployTransaction(context) + : makeERC721TokenboundMechDeployTransaction(context) } diff --git a/package.json b/package.json index 5afc86a..8a157b0 100644 --- a/package.json +++ b/package.json @@ -59,12 +59,12 @@ "@typechain/hardhat": "^9.0.0", "@types/chai": "^4.3.5", "@types/mocha": "^10.0.1", - "@types/node": "^18.17.11", + "@types/node": "^18.17.12", "@typescript-eslint/eslint-plugin": "^5.62.0", "@typescript-eslint/parser": "^5.62.0", "chai": "^4.3.8", "dotenv": "^16.3.1", - "eslint": "^8.47.0", + "eslint": "^8.48.0", "eslint-config-prettier": "^8.10.0", "eslint-plugin-eslint-comments": "^3.2.0", "eslint-plugin-import": "^2.28.1", diff --git a/sdk/package.json b/sdk/package.json index a5a3f37..bde6913 100644 --- a/sdk/package.json +++ b/sdk/package.json @@ -40,9 +40,9 @@ "@openzeppelin/contracts": "^4.9.3", "@safe-global/safe-core-sdk": "^3.3.5", "@types/chai": "^4.3.5", - "@types/node": "^18.17.11", + "@types/node": "^18.17.12", "ethers": "^6.7.1", - "viem": "^1.7.0" + "viem": "^1.8.1" }, "packageManager": "yarn@3.6.1" } diff --git a/yarn.lock b/yarn.lock index a60e8d3..d12aeed 100644 --- a/yarn.lock +++ b/yarn.lock @@ -20,9 +20,9 @@ __metadata: linkType: hard "@adobe/css-tools@npm:^4.0.1": - version: 4.2.0 - resolution: "@adobe/css-tools@npm:4.2.0" - checksum: dc5cc92ba3d562e7ffddb79d6d222c7e00b65f255fd2725b3d71490ff268844be322f917415d8c4ab39eca646343b632058db8bd5b1d646193fcc94d1d3e420b + version: 4.3.1 + resolution: "@adobe/css-tools@npm:4.3.1" + checksum: ad43456379ff391132aff687ece190cb23ea69395e23c9b96690eeabe2468da89a4aaf266e4f8b6eaab53db3d1064107ce0f63c3a974e864f4a04affc768da3f languageName: node linkType: hard @@ -81,16 +81,17 @@ __metadata: languageName: node linkType: hard -"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.16.0, @babel/code-frame@npm:^7.22.5, @babel/code-frame@npm:^7.8.3": - version: 7.22.5 - resolution: "@babel/code-frame@npm:7.22.5" +"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.16.0, @babel/code-frame@npm:^7.22.10, @babel/code-frame@npm:^7.22.5, @babel/code-frame@npm:^7.8.3": + version: 7.22.10 + resolution: "@babel/code-frame@npm:7.22.10" dependencies: - "@babel/highlight": ^7.22.5 - checksum: cfe804f518f53faaf9a1d3e0f9f74127ab9a004912c3a16fda07fb6a633393ecb9918a053cb71804204c1b7ec3d49e1699604715e2cfb0c9f7bc4933d324ebb6 + "@babel/highlight": ^7.22.10 + chalk: ^2.4.2 + checksum: 89a06534ad19759da6203a71bad120b1d7b2ddc016c8e07d4c56b35dea25e7396c6da60a754e8532a86733092b131ae7f661dbe6ba5d165ea777555daa2ed3c9 languageName: node linkType: hard -"@babel/compat-data@npm:^7.22.5, @babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.22.9": +"@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.22.9": version: 7.22.9 resolution: "@babel/compat-data@npm:7.22.9" checksum: bed77d9044ce948b4327b30dd0de0779fa9f3a7ed1f2d31638714ed00229fa71fc4d1617ae0eb1fad419338d3658d0e9a5a083297451e09e73e078d0347ff808 @@ -98,51 +99,51 @@ __metadata: linkType: hard "@babel/core@npm:^7.1.0, @babel/core@npm:^7.11.1, @babel/core@npm:^7.12.3, @babel/core@npm:^7.16.0, @babel/core@npm:^7.7.2, @babel/core@npm:^7.8.0": - version: 7.22.9 - resolution: "@babel/core@npm:7.22.9" + version: 7.22.11 + resolution: "@babel/core@npm:7.22.11" dependencies: "@ampproject/remapping": ^2.2.0 - "@babel/code-frame": ^7.22.5 - "@babel/generator": ^7.22.9 - "@babel/helper-compilation-targets": ^7.22.9 + "@babel/code-frame": ^7.22.10 + "@babel/generator": ^7.22.10 + "@babel/helper-compilation-targets": ^7.22.10 "@babel/helper-module-transforms": ^7.22.9 - "@babel/helpers": ^7.22.6 - "@babel/parser": ^7.22.7 + "@babel/helpers": ^7.22.11 + "@babel/parser": ^7.22.11 "@babel/template": ^7.22.5 - "@babel/traverse": ^7.22.8 - "@babel/types": ^7.22.5 + "@babel/traverse": ^7.22.11 + "@babel/types": ^7.22.11 convert-source-map: ^1.7.0 debug: ^4.1.0 gensync: ^1.0.0-beta.2 - json5: ^2.2.2 + json5: ^2.2.3 semver: ^6.3.1 - checksum: 7bf069aeceb417902c4efdaefab1f7b94adb7dea694a9aed1bda2edf4135348a080820529b1a300c6f8605740a00ca00c19b2d5e74b5dd489d99d8c11d5e56d1 + checksum: f258b2539ea2e5bfe55a708c2f3e1093a1b4744f12becc35abeb896037b66210de9a8ad6296a706046d5dc3a24e564362b73a9b814e5bfe500c8baab60c22d2e languageName: node linkType: hard "@babel/eslint-parser@npm:^7.16.3": - version: 7.22.9 - resolution: "@babel/eslint-parser@npm:7.22.9" + version: 7.22.11 + resolution: "@babel/eslint-parser@npm:7.22.11" dependencies: "@nicolo-ribaudo/eslint-scope-5-internals": 5.1.1-v1 eslint-visitor-keys: ^2.1.0 semver: ^6.3.1 peerDependencies: - "@babel/core": ">=7.11.0" + "@babel/core": ^7.11.0 eslint: ^7.5.0 || ^8.0.0 - checksum: 4f417796c803056aad2c8fa69b8a7a78a1fdacc307d95702f22894cab42b83554e47de7d0b3cfbee667f25014bca0179f859aa86ceb684b09803192e1200b48d + checksum: a7d4406ac021a192c8e2d2dd5a9ebe6352dc4c0c842c0971080e5ac1bcb81eb6dceb72899ec611b82ab4356c658649a0a4f85815f6245ab1674cd329dde06369 languageName: node linkType: hard -"@babel/generator@npm:^7.22.7, @babel/generator@npm:^7.22.9, @babel/generator@npm:^7.7.2": - version: 7.22.9 - resolution: "@babel/generator@npm:7.22.9" +"@babel/generator@npm:^7.22.10, @babel/generator@npm:^7.7.2": + version: 7.22.10 + resolution: "@babel/generator@npm:7.22.10" dependencies: - "@babel/types": ^7.22.5 + "@babel/types": ^7.22.10 "@jridgewell/gen-mapping": ^0.3.2 "@jridgewell/trace-mapping": ^0.3.17 jsesc: ^2.5.1 - checksum: 7c9d2c58b8d5ac5e047421a6ab03ec2ff5d9a5ff2c2212130a0055e063ac349e0b19d435537d6886c999771aef394832e4f54cd9fc810100a7f23d982f6af06b + checksum: 59a79730abdff9070692834bd3af179e7a9413fa2ff7f83dff3eb888765aeaeb2bfc7b0238a49613ed56e1af05956eff303cc139f2407eda8df974813e486074 languageName: node linkType: hard @@ -156,32 +157,30 @@ __metadata: linkType: hard "@babel/helper-builder-binary-assignment-operator-visitor@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-builder-binary-assignment-operator-visitor@npm:7.22.5" + version: 7.22.10 + resolution: "@babel/helper-builder-binary-assignment-operator-visitor@npm:7.22.10" dependencies: - "@babel/types": ^7.22.5 - checksum: d753acac62399fc6dd354cf1b9441bde0c331c2fe792a4c14904c5e5eafc3cac79478f6aa038e8a51c1148b0af6710a2e619855e4b5d54497ac972eaffed5884 + "@babel/types": ^7.22.10 + checksum: 6de4a1f30e6244f9a1efdfcbe89df39923df3d165be606da5ad11319f8a11c12c72c60d9dc5fb696363281e2d6f741444c1af51f525fc7cf1d2a90fe23370bd9 languageName: node linkType: hard -"@babel/helper-compilation-targets@npm:^7.22.5, @babel/helper-compilation-targets@npm:^7.22.6, @babel/helper-compilation-targets@npm:^7.22.9": - version: 7.22.9 - resolution: "@babel/helper-compilation-targets@npm:7.22.9" +"@babel/helper-compilation-targets@npm:^7.22.10, @babel/helper-compilation-targets@npm:^7.22.5, @babel/helper-compilation-targets@npm:^7.22.6": + version: 7.22.10 + resolution: "@babel/helper-compilation-targets@npm:7.22.10" dependencies: "@babel/compat-data": ^7.22.9 "@babel/helper-validator-option": ^7.22.5 browserslist: ^4.21.9 lru-cache: ^5.1.1 semver: ^6.3.1 - peerDependencies: - "@babel/core": ^7.0.0 - checksum: ea0006c6a93759025f4a35a25228ae260538c9f15023e8aac2a6d45ca68aef4cf86cfc429b19af9a402cbdd54d5de74ad3fbcf6baa7e48184dc079f1a791e178 + checksum: f6f1896816392bcff671bbe6e277307729aee53befb4a66ea126e2a91eda78d819a70d06fa384c74ef46c1595544b94dca50bef6c78438d9ffd31776dafbd435 languageName: node linkType: hard -"@babel/helper-create-class-features-plugin@npm:^7.18.6, @babel/helper-create-class-features-plugin@npm:^7.21.0, @babel/helper-create-class-features-plugin@npm:^7.22.5, @babel/helper-create-class-features-plugin@npm:^7.22.6, @babel/helper-create-class-features-plugin@npm:^7.22.9": - version: 7.22.9 - resolution: "@babel/helper-create-class-features-plugin@npm:7.22.9" +"@babel/helper-create-class-features-plugin@npm:^7.18.6, @babel/helper-create-class-features-plugin@npm:^7.21.0, @babel/helper-create-class-features-plugin@npm:^7.22.10, @babel/helper-create-class-features-plugin@npm:^7.22.11, @babel/helper-create-class-features-plugin@npm:^7.22.5": + version: 7.22.11 + resolution: "@babel/helper-create-class-features-plugin@npm:7.22.11" dependencies: "@babel/helper-annotate-as-pure": ^7.22.5 "@babel/helper-environment-visitor": ^7.22.5 @@ -194,7 +193,7 @@ __metadata: semver: ^6.3.1 peerDependencies: "@babel/core": ^7.0.0 - checksum: 6c2436d1a5a3f1ff24628d78fa8c6d3120c40285aa3eda7815b1adbf8c5951e0dd73d368cf845825888fa3dc2f207dadce53309825598d7c67953e5ed9dd51d2 + checksum: b7aeb22e29aba5327616328576363522b3b186918faeda605e300822af4a5f29416eb34b5bd825d07ab496550e271d02d7634f0022a62b5b8cbf0eb6389bc3fa languageName: node linkType: hard @@ -211,9 +210,9 @@ __metadata: languageName: node linkType: hard -"@babel/helper-define-polyfill-provider@npm:^0.4.1": - version: 0.4.1 - resolution: "@babel/helper-define-polyfill-provider@npm:0.4.1" +"@babel/helper-define-polyfill-provider@npm:^0.4.2": + version: 0.4.2 + resolution: "@babel/helper-define-polyfill-provider@npm:0.4.2" dependencies: "@babel/helper-compilation-targets": ^7.22.6 "@babel/helper-plugin-utils": ^7.22.5 @@ -221,8 +220,8 @@ __metadata: lodash.debounce: ^4.0.8 resolve: ^1.14.2 peerDependencies: - "@babel/core": ^7.4.0-0 - checksum: 712b440cdd343ac7c4617225f91b0a9db5a7b1c96356b720e011af64ad6c4da9c66889f8d2962a0a2ae2e4ccb6a9b4a210c4a3c8c8ff103846b3d93b61bc6634 + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: 1f6dec0c5d0876d278fe15b71238eccc5f74c4e2efa2c78aaafa8bc2cc96336b8e68d94cd1a78497356c96e8b91b8c1f4452179820624d1702aee2f9832e6569 languageName: node linkType: hard @@ -301,7 +300,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-remap-async-to-generator@npm:^7.22.5": +"@babel/helper-remap-async-to-generator@npm:^7.22.5, @babel/helper-remap-async-to-generator@npm:^7.22.9": version: 7.22.9 resolution: "@babel/helper-remap-async-to-generator@npm:7.22.9" dependencies: @@ -376,44 +375,44 @@ __metadata: linkType: hard "@babel/helper-wrap-function@npm:^7.22.9": - version: 7.22.9 - resolution: "@babel/helper-wrap-function@npm:7.22.9" + version: 7.22.10 + resolution: "@babel/helper-wrap-function@npm:7.22.10" dependencies: "@babel/helper-function-name": ^7.22.5 "@babel/template": ^7.22.5 - "@babel/types": ^7.22.5 - checksum: 037317dc06dac6593e388738ae1d3e43193bc1d31698f067c0ef3d4dc6f074dbed860ed42aa137b48a67aa7cb87336826c4bdc13189260481bcf67eb7256c789 + "@babel/types": ^7.22.10 + checksum: 854bd85fc1de1d4c633f04aa1f5b6b022fbc013b47d012b6a11a7a9125a1f4a2a4f13a3e0d7a7056fe7eda8a9ecd1ea3daf8af685685a2d1b16578768cfdd28f languageName: node linkType: hard -"@babel/helpers@npm:^7.22.6": - version: 7.22.6 - resolution: "@babel/helpers@npm:7.22.6" +"@babel/helpers@npm:^7.22.11": + version: 7.22.11 + resolution: "@babel/helpers@npm:7.22.11" dependencies: "@babel/template": ^7.22.5 - "@babel/traverse": ^7.22.6 - "@babel/types": ^7.22.5 - checksum: 5c1f33241fe7bf7709868c2105134a0a86dca26a0fbd508af10a89312b1f77ca38ebae43e50be3b208613c5eacca1559618af4ca236f0abc55d294800faeff30 + "@babel/traverse": ^7.22.11 + "@babel/types": ^7.22.11 + checksum: 93186544228b5e371486466ec3b86a77cce91beeff24a5670ca8ec46d50328f7700dab82d532351286e9d68624dc51d6d71589b051dd9535e44be077a43ec013 languageName: node linkType: hard -"@babel/highlight@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/highlight@npm:7.22.5" +"@babel/highlight@npm:^7.22.10": + version: 7.22.10 + resolution: "@babel/highlight@npm:7.22.10" dependencies: "@babel/helper-validator-identifier": ^7.22.5 - chalk: ^2.0.0 + chalk: ^2.4.2 js-tokens: ^4.0.0 - checksum: f61ae6de6ee0ea8d9b5bcf2a532faec5ab0a1dc0f7c640e5047fc61630a0edb88b18d8c92eb06566d30da7a27db841aca11820ecd3ebe9ce514c9350fbed39c4 + checksum: f714a1e1a72dd9d72f6383f4f30fd342e21a8df32d984a4ea8f5eab691bb6ba6db2f8823d4b4cf135d98869e7a98925b81306aa32ee3c429f8cfa52c75889e1b languageName: node linkType: hard -"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.22.5, @babel/parser@npm:^7.22.7": - version: 7.22.7 - resolution: "@babel/parser@npm:7.22.7" +"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.22.11, @babel/parser@npm:^7.22.5": + version: 7.22.11 + resolution: "@babel/parser@npm:7.22.11" bin: parser: ./bin/babel-parser.js - checksum: 02209ddbd445831ee8bf966fdf7c29d189ed4b14343a68eb2479d940e7e3846340d7cc6bd654a5f3d87d19dc84f49f50a58cf9363bee249dc5409ff3ba3dab54 + checksum: 332079ed09794d3685343e9fc39c6a12dcb6ea589119f2135952cdef2424296786bb609a33f6dfa9be271797bbf8339f1865118418ea50b32a0c701734c96664 languageName: node linkType: hard @@ -454,17 +453,17 @@ __metadata: linkType: hard "@babel/plugin-proposal-decorators@npm:^7.16.4": - version: 7.22.7 - resolution: "@babel/plugin-proposal-decorators@npm:7.22.7" + version: 7.22.10 + resolution: "@babel/plugin-proposal-decorators@npm:7.22.10" dependencies: - "@babel/helper-create-class-features-plugin": ^7.22.6 + "@babel/helper-create-class-features-plugin": ^7.22.10 "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-replace-supers": ^7.22.5 + "@babel/helper-replace-supers": ^7.22.9 "@babel/helper-split-export-declaration": ^7.22.6 - "@babel/plugin-syntax-decorators": ^7.22.5 + "@babel/plugin-syntax-decorators": ^7.22.10 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: d9d6f7cc8b3f1450963d3f26909af025836189b81e43c48ad455db5db2319beaf4ad2fda5aa12a1afcf856de11ecd5ee6894a9e906e8de8ee445c79102b50d26 + checksum: dc5d220f94d3d02a4a68d2e29abc038fe1731634569279956438ba4476e930dab76eac71524be89c9f199731f730e7d2537f947acbefaf29a51130a0e714ecbd languageName: node linkType: hard @@ -540,18 +539,6 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-proposal-unicode-property-regex@npm:^7.4.4": - version: 7.18.6 - resolution: "@babel/plugin-proposal-unicode-property-regex@npm:7.18.6" - dependencies: - "@babel/helper-create-regexp-features-plugin": ^7.18.6 - "@babel/helper-plugin-utils": ^7.18.6 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: a8575ecb7ff24bf6c6e94808d5c84bb5a0c6dd7892b54f09f4646711ba0ee1e1668032b3c43e3e1dfec2c5716c302e851ac756c1645e15882d73df6ad21ae951 - languageName: node - linkType: hard - "@babel/plugin-syntax-async-generators@npm:^7.8.4": version: 7.8.4 resolution: "@babel/plugin-syntax-async-generators@npm:7.8.4" @@ -596,14 +583,14 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-decorators@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-syntax-decorators@npm:7.22.5" +"@babel/plugin-syntax-decorators@npm:^7.22.10": + version: 7.22.10 + resolution: "@babel/plugin-syntax-decorators@npm:7.22.10" dependencies: "@babel/helper-plugin-utils": ^7.22.5 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 643c75a3b603320c499a0542ca97b5cced81e99de02ae9cbfca1a1ec6d938467546a65023b13df742e1b2f94ffe352ddfe908d14b9303fae7514ed9325886a97 + checksum: baaa10fa52d76ee8b9447f7aedb1c8df7cf2ef83ae29c085c07444e691685aa8b1a326dfb7a3a0e3ae4d5f9fd083175e46ea5e2316d8200f0278f3fd54a58696 languageName: node linkType: hard @@ -817,17 +804,17 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-async-generator-functions@npm:^7.22.7": - version: 7.22.7 - resolution: "@babel/plugin-transform-async-generator-functions@npm:7.22.7" +"@babel/plugin-transform-async-generator-functions@npm:^7.22.10": + version: 7.22.11 + resolution: "@babel/plugin-transform-async-generator-functions@npm:7.22.11" dependencies: "@babel/helper-environment-visitor": ^7.22.5 "@babel/helper-plugin-utils": ^7.22.5 - "@babel/helper-remap-async-to-generator": ^7.22.5 + "@babel/helper-remap-async-to-generator": ^7.22.9 "@babel/plugin-syntax-async-generators": ^7.8.4 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 57cd2cce3fb696dadf00e88f168683df69e900b92dadeae07429243c43bc21d5ccdc0c2db61cf5c37bd0fbd893fc455466bef6babe4aa5b79d9cb8ba89f40ae7 + checksum: f11227a1d2831972a7fe28ed54a618ee251547632dc384b2f291f9d8d6aae1177a68c6bbd7709ab78275fa84e757ae795ec08061d94f6f01826f02a35ee875d4 languageName: node linkType: hard @@ -855,14 +842,14 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-block-scoping@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-block-scoping@npm:7.22.5" +"@babel/plugin-transform-block-scoping@npm:^7.22.10": + version: 7.22.10 + resolution: "@babel/plugin-transform-block-scoping@npm:7.22.10" dependencies: "@babel/helper-plugin-utils": ^7.22.5 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 26987002cfe6e24544e60fa35f07052b6557f590c1a1cc5cf35d6dc341d7fea163c1222a2d70d5d2692f0b9860d942fd3ba979848b2995d4debffa387b9b19ae + checksum: b1d06f358dedcb748a57e5feea4b9285c60593fb2912b921f22898c57c552c78fe18128678c8f84dd4ea1d4e5aebede8783830b24cd63f22c30261156d78bc77 languageName: node linkType: hard @@ -879,15 +866,15 @@ __metadata: linkType: hard "@babel/plugin-transform-class-static-block@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-class-static-block@npm:7.22.5" + version: 7.22.11 + resolution: "@babel/plugin-transform-class-static-block@npm:7.22.11" dependencies: - "@babel/helper-create-class-features-plugin": ^7.22.5 + "@babel/helper-create-class-features-plugin": ^7.22.11 "@babel/helper-plugin-utils": ^7.22.5 "@babel/plugin-syntax-class-static-block": ^7.14.5 peerDependencies: "@babel/core": ^7.12.0 - checksum: bc48b92dbaf625a14f2bf62382384eef01e0515802426841636ae9146e27395d068c7a8a45e9e15699491b0a01d990f38f179cbc9dc89274a393f85648772f12 + checksum: 69f040506fad66f1c6918d288d0e0edbc5c8a07c8b4462c1184ad2f9f08995d68b057126c213871c0853ae0c72afc60ec87492049dfacb20902e32346a448bcb languageName: node linkType: hard @@ -922,18 +909,18 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-destructuring@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-destructuring@npm:7.22.5" +"@babel/plugin-transform-destructuring@npm:^7.22.10": + version: 7.22.10 + resolution: "@babel/plugin-transform-destructuring@npm:7.22.10" dependencies: "@babel/helper-plugin-utils": ^7.22.5 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 76f6ea2aee1fcfa1c3791eb7a5b89703c6472650b993e8666fff0f1d6e9d737a84134edf89f63c92297f3e75064c1263219463b02dd9bc7434b6e5b9935e3f20 + checksum: 011707801bd0029fd4f0523d24d06fdc0cbe8c9da280d75728f76713d639c4dc976e1b56a1ba7bff25468f86867efb71c9b4cac81140adbdd0abf2324b19a8bb languageName: node linkType: hard -"@babel/plugin-transform-dotall-regex@npm:^7.22.5, @babel/plugin-transform-dotall-regex@npm:^7.4.4": +"@babel/plugin-transform-dotall-regex@npm:^7.22.5": version: 7.22.5 resolution: "@babel/plugin-transform-dotall-regex@npm:7.22.5" dependencies: @@ -957,14 +944,14 @@ __metadata: linkType: hard "@babel/plugin-transform-dynamic-import@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-dynamic-import@npm:7.22.5" + version: 7.22.11 + resolution: "@babel/plugin-transform-dynamic-import@npm:7.22.11" dependencies: "@babel/helper-plugin-utils": ^7.22.5 "@babel/plugin-syntax-dynamic-import": ^7.8.3 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 186a6d59f36eb3c5824739fc9c22ed0f4ca68e001662aa3a302634346a8b785cb9579b23b0c158f4570604d697d19598ca09b58c60a7fa2894da1163c4eb1907 + checksum: 78fc9c532210bf9e8f231747f542318568ac360ee6c27e80853962c984283c73da3f8f8aebe83c2096090a435b356b092ed85de617a156cbe0729d847632be45 languageName: node linkType: hard @@ -981,14 +968,14 @@ __metadata: linkType: hard "@babel/plugin-transform-export-namespace-from@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-export-namespace-from@npm:7.22.5" + version: 7.22.11 + resolution: "@babel/plugin-transform-export-namespace-from@npm:7.22.11" dependencies: "@babel/helper-plugin-utils": ^7.22.5 "@babel/plugin-syntax-export-namespace-from": ^7.8.3 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 3d197b788758044983c96b9c49bed4b456055f35a388521a405968db0f6e2ffb6fd59110e3931f4dcc5e126ae9e5e00e154a0afb47a7ea359d8d0dea79f480d7 + checksum: 73af5883a321ed56a4bfd43c8a7de0164faebe619287706896fc6ee2f7a4e69042adaa1338c0b8b4bdb9f7e5fdceb016fb1d40694cb43ca3b8827429e8aac4bf languageName: node linkType: hard @@ -1029,14 +1016,14 @@ __metadata: linkType: hard "@babel/plugin-transform-json-strings@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-json-strings@npm:7.22.5" + version: 7.22.11 + resolution: "@babel/plugin-transform-json-strings@npm:7.22.11" dependencies: "@babel/helper-plugin-utils": ^7.22.5 "@babel/plugin-syntax-json-strings": ^7.8.3 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 4e00b902487a670b6c8948f33f9108133fd745cf9d1478aca515fb460b9b2f12e137988ebc1663630fb82070a870aed8b0c1aa4d007a841c18004619798f255c + checksum: 50665e5979e66358c50e90a26db53c55917f78175127ac2fa05c7888d156d418ffb930ec0a109353db0a7c5f57c756ce01bfc9825d24cbfd2b3ec453f2ed8cba languageName: node linkType: hard @@ -1052,14 +1039,14 @@ __metadata: linkType: hard "@babel/plugin-transform-logical-assignment-operators@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-logical-assignment-operators@npm:7.22.5" + version: 7.22.11 + resolution: "@babel/plugin-transform-logical-assignment-operators@npm:7.22.11" dependencies: "@babel/helper-plugin-utils": ^7.22.5 "@babel/plugin-syntax-logical-assignment-operators": ^7.10.4 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 18748e953c08f64885f18c224eac58df10a13eac4d845d16b5d9b6276907da7ca2530dfebe6ed41cdc5f8a75d9db3e36d8eb54ddce7cd0364af1cab09b435302 + checksum: c664e9798e85afa7f92f07b867682dee7392046181d82f5d21bae6f2ca26dfe9c8375cdc52b7483c3fc09a983c1989f60eff9fbc4f373b0c0a74090553d05739 languageName: node linkType: hard @@ -1086,30 +1073,30 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-modules-commonjs@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-modules-commonjs@npm:7.22.5" +"@babel/plugin-transform-modules-commonjs@npm:^7.22.11, @babel/plugin-transform-modules-commonjs@npm:^7.22.5": + version: 7.22.11 + resolution: "@babel/plugin-transform-modules-commonjs@npm:7.22.11" dependencies: - "@babel/helper-module-transforms": ^7.22.5 + "@babel/helper-module-transforms": ^7.22.9 "@babel/helper-plugin-utils": ^7.22.5 "@babel/helper-simple-access": ^7.22.5 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 2067aca8f6454d54ffcce69b02c457cfa61428e11372f6a1d99ff4fcfbb55c396ed2ca6ca886bf06c852e38c1a205b8095921b2364fd0243f3e66bc1dda61caa + checksum: c15ad7f1234a930cab214224bb85f6b3a3f301fa1d4d15bef193e5c11c614ce369551e5cbb708fde8d3f7e1cb84b05e9798a3647a11b56c3d67580e362a712d4 languageName: node linkType: hard "@babel/plugin-transform-modules-systemjs@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-modules-systemjs@npm:7.22.5" + version: 7.22.11 + resolution: "@babel/plugin-transform-modules-systemjs@npm:7.22.11" dependencies: "@babel/helper-hoist-variables": ^7.22.5 - "@babel/helper-module-transforms": ^7.22.5 + "@babel/helper-module-transforms": ^7.22.9 "@babel/helper-plugin-utils": ^7.22.5 "@babel/helper-validator-identifier": ^7.22.5 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 04f4178589543396b3c24330a67a59c5e69af5e96119c9adda730c0f20122deaff54671ebbc72ad2df6495a5db8a758bd96942de95fba7ad427de9c80b1b38c8 + checksum: d0991e4bdc3352b6a9f4d12b6662e3645d892cd5c3c005ba5f14e65f1e218c6a8f7f4497e64a51d82a046e507aaa7db3143b800b0270dca1824cbd214ff3363d languageName: node linkType: hard @@ -1149,41 +1136,41 @@ __metadata: linkType: hard "@babel/plugin-transform-nullish-coalescing-operator@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-nullish-coalescing-operator@npm:7.22.5" + version: 7.22.11 + resolution: "@babel/plugin-transform-nullish-coalescing-operator@npm:7.22.11" dependencies: "@babel/helper-plugin-utils": ^7.22.5 "@babel/plugin-syntax-nullish-coalescing-operator": ^7.8.3 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: e6a059169d257fc61322d0708edae423072449b7c33de396261e68dee582aec5396789a1c22bce84e5bd88a169623c2e750b513fc222930979e6accd52a44bf2 + checksum: 167babecc8b8fe70796a7b7d34af667ebbf43da166c21689502e5e8cc93180b7a85979c77c9f64b7cce431b36718bd0a6df9e5e0ffea4ae22afb22cfef886372 languageName: node linkType: hard "@babel/plugin-transform-numeric-separator@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-numeric-separator@npm:7.22.5" + version: 7.22.11 + resolution: "@babel/plugin-transform-numeric-separator@npm:7.22.11" dependencies: "@babel/helper-plugin-utils": ^7.22.5 "@babel/plugin-syntax-numeric-separator": ^7.10.4 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 9e7837d4eae04f211ebaa034fe5003d2927b6bf6d5b9dc09f2b1183c01482cdde5a75b8bd5c7ff195c2abc7b923339eb0b2a9d27cb78359d38248a3b2c2367c4 + checksum: af064d06a4a041767ec396a5f258103f64785df290e038bba9f0ef454e6c914f2ac45d862bbdad8fac2c7ad47fa4e95356f29053c60c100a0160b02a995fe2a3 languageName: node linkType: hard "@babel/plugin-transform-object-rest-spread@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-object-rest-spread@npm:7.22.5" + version: 7.22.11 + resolution: "@babel/plugin-transform-object-rest-spread@npm:7.22.11" dependencies: - "@babel/compat-data": ^7.22.5 - "@babel/helper-compilation-targets": ^7.22.5 + "@babel/compat-data": ^7.22.9 + "@babel/helper-compilation-targets": ^7.22.10 "@babel/helper-plugin-utils": ^7.22.5 "@babel/plugin-syntax-object-rest-spread": ^7.8.3 "@babel/plugin-transform-parameters": ^7.22.5 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 3b5e091f0dc67108f2e41ed5a97e15bbe4381a19d9a7eea80b71c7de1d8169fd28784e1e41a3d2ad12709ab212e58fc481282a5bb65d591fae7b443048de3330 + checksum: b9c9ed8df8d6d7563eb42844d8e3e6748ba8f7568998230f7317bc49304db65828df48fc4b93bf4421772a6c9f7b389f3dd1c4e84379c17dd9ee223fb3fc5245 languageName: node linkType: hard @@ -1200,27 +1187,27 @@ __metadata: linkType: hard "@babel/plugin-transform-optional-catch-binding@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-optional-catch-binding@npm:7.22.5" + version: 7.22.11 + resolution: "@babel/plugin-transform-optional-catch-binding@npm:7.22.11" dependencies: "@babel/helper-plugin-utils": ^7.22.5 "@babel/plugin-syntax-optional-catch-binding": ^7.8.3 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: b0e8b4233ff06b5c9d285257f49c5bd441f883189b24282e6200f9ebdf5db29aeeebbffae57fbbcd5df9f4387b3e66e5d322aaae5652a78e89685ddbae46bbd1 + checksum: f17abd90e1de67c84d63afea29c8021c74abb2794d3a6eeafb0bbe7372d3db32aefca386e392116ec63884537a4a2815d090d26264d259bacc08f6e3ed05294c languageName: node linkType: hard -"@babel/plugin-transform-optional-chaining@npm:^7.22.5, @babel/plugin-transform-optional-chaining@npm:^7.22.6": - version: 7.22.6 - resolution: "@babel/plugin-transform-optional-chaining@npm:7.22.6" +"@babel/plugin-transform-optional-chaining@npm:^7.22.10, @babel/plugin-transform-optional-chaining@npm:^7.22.5": + version: 7.22.12 + resolution: "@babel/plugin-transform-optional-chaining@npm:7.22.12" dependencies: "@babel/helper-plugin-utils": ^7.22.5 "@babel/helper-skip-transparent-expression-wrappers": ^7.22.5 "@babel/plugin-syntax-optional-chaining": ^7.8.3 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 9713f7920ed04090c149fc5ec024dd1638e8b97aa4ae3753b93072d84103b8de380afb96d6cf03e53b285420db4f705f3ac13149c6fd54f322b61dc19e33c54f + checksum: 47065439bb721a0967cdcc83895700bb7b18b146b2ef27e43449d7b5a7130a2497afadddc42c616253858cac6732546646b9f0c581f4bb8a3d362baeb4c30bbb languageName: node linkType: hard @@ -1248,16 +1235,16 @@ __metadata: linkType: hard "@babel/plugin-transform-private-property-in-object@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-private-property-in-object@npm:7.22.5" + version: 7.22.11 + resolution: "@babel/plugin-transform-private-property-in-object@npm:7.22.11" dependencies: "@babel/helper-annotate-as-pure": ^7.22.5 - "@babel/helper-create-class-features-plugin": ^7.22.5 + "@babel/helper-create-class-features-plugin": ^7.22.11 "@babel/helper-plugin-utils": ^7.22.5 "@babel/plugin-syntax-private-property-in-object": ^7.14.5 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 9ac019fb2772f3af6278a7f4b8b14b0663accb3fd123d87142ceb2fbc57fd1afa07c945d1329029b026b9ee122096ef71a3f34f257a9e04cf4245b87298c38b4 + checksum: 4d029d84901e53c46dead7a46e2990a7bc62470f4e4ca58a0d063394f86652fd58fe4eea1eb941da3669cd536b559b9d058b342b59300026346b7a2a51badac8 languageName: node linkType: hard @@ -1332,15 +1319,15 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-regenerator@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-regenerator@npm:7.22.5" +"@babel/plugin-transform-regenerator@npm:^7.22.10": + version: 7.22.10 + resolution: "@babel/plugin-transform-regenerator@npm:7.22.10" dependencies: "@babel/helper-plugin-utils": ^7.22.5 - regenerator-transform: ^0.15.1 + regenerator-transform: ^0.15.2 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: f7c5ca5151321963df777cc02725d10d1ccc3b3b8323da0423aecd9ac6144cbdd2274af5281a5580db2fc2f8b234e318517b5d76b85669118906533a559f2b6a + checksum: e13678d62d6fa96f11cb8b863f00e8693491e7adc88bfca3f2820f80cbac8336e7dec3a596eee6a1c4663b7ececc3564f2cd7fb44ed6d4ce84ac2bb7f39ecc6e languageName: node linkType: hard @@ -1356,18 +1343,18 @@ __metadata: linkType: hard "@babel/plugin-transform-runtime@npm:^7.16.4": - version: 7.22.9 - resolution: "@babel/plugin-transform-runtime@npm:7.22.9" + version: 7.22.10 + resolution: "@babel/plugin-transform-runtime@npm:7.22.10" dependencies: "@babel/helper-module-imports": ^7.22.5 "@babel/helper-plugin-utils": ^7.22.5 - babel-plugin-polyfill-corejs2: ^0.4.4 - babel-plugin-polyfill-corejs3: ^0.8.2 - babel-plugin-polyfill-regenerator: ^0.5.1 + babel-plugin-polyfill-corejs2: ^0.4.5 + babel-plugin-polyfill-corejs3: ^0.8.3 + babel-plugin-polyfill-regenerator: ^0.5.2 semver: ^6.3.1 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 2fe5e41f83015ca174feda841d77aa9012fc855c907f9b360a11927f41b100537c8c83487771769147668e797eec26d5294e972b997f4759133cc43a22a43eec + checksum: 45a54a8d0ea5aa50129137d22e44bb643b685739b52d02d912b08ce6615ab9c1356ef141b26161f9454768132fb7417c5e1c73e9fd5719afe0c6d84c839918be languageName: node linkType: hard @@ -1427,28 +1414,28 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-typescript@npm:^7.22.5": - version: 7.22.9 - resolution: "@babel/plugin-transform-typescript@npm:7.22.9" +"@babel/plugin-transform-typescript@npm:^7.22.11": + version: 7.22.11 + resolution: "@babel/plugin-transform-typescript@npm:7.22.11" dependencies: "@babel/helper-annotate-as-pure": ^7.22.5 - "@babel/helper-create-class-features-plugin": ^7.22.9 + "@babel/helper-create-class-features-plugin": ^7.22.11 "@babel/helper-plugin-utils": ^7.22.5 "@babel/plugin-syntax-typescript": ^7.22.5 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 6d1317a54d093b302599a4bee8ba9865d0de8b7b6ac1a0746c4316231d632f75b7f086e6e78acb9ac95ba12ba3b9da462dc9ca69370abb4603c4cc987f62e67e + checksum: a0dc3c2427b55602944705c9a91b4c074524badd5ea87edb603ddeabe7fae531bcbe68475106d7a00079b67bb422dbf2e9f50e15c25ac24d7e9fe77f37ebcfb4 languageName: node linkType: hard -"@babel/plugin-transform-unicode-escapes@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/plugin-transform-unicode-escapes@npm:7.22.5" +"@babel/plugin-transform-unicode-escapes@npm:^7.22.10": + version: 7.22.10 + resolution: "@babel/plugin-transform-unicode-escapes@npm:7.22.10" dependencies: "@babel/helper-plugin-utils": ^7.22.5 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: da5e85ab3bb33a75cbf6181bfd236b208dc934702fd304db127232f17b4e0f42c6d3f238de8589470b4190906967eea8ca27adf3ae9d8ee4de2a2eae906ed186 + checksum: 807f40ed1324c8cb107c45358f1903384ca3f0ef1d01c5a3c5c9b271c8d8eec66936a3dcc8d75ddfceea9421420368c2e77ae3adef0a50557e778dfe296bf382 languageName: node linkType: hard @@ -1489,11 +1476,11 @@ __metadata: linkType: hard "@babel/preset-env@npm:^7.11.0, @babel/preset-env@npm:^7.12.1, @babel/preset-env@npm:^7.16.4": - version: 7.22.9 - resolution: "@babel/preset-env@npm:7.22.9" + version: 7.22.10 + resolution: "@babel/preset-env@npm:7.22.10" dependencies: "@babel/compat-data": ^7.22.9 - "@babel/helper-compilation-targets": ^7.22.9 + "@babel/helper-compilation-targets": ^7.22.10 "@babel/helper-plugin-utils": ^7.22.5 "@babel/helper-validator-option": ^7.22.5 "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": ^7.22.5 @@ -1518,15 +1505,15 @@ __metadata: "@babel/plugin-syntax-top-level-await": ^7.14.5 "@babel/plugin-syntax-unicode-sets-regex": ^7.18.6 "@babel/plugin-transform-arrow-functions": ^7.22.5 - "@babel/plugin-transform-async-generator-functions": ^7.22.7 + "@babel/plugin-transform-async-generator-functions": ^7.22.10 "@babel/plugin-transform-async-to-generator": ^7.22.5 "@babel/plugin-transform-block-scoped-functions": ^7.22.5 - "@babel/plugin-transform-block-scoping": ^7.22.5 + "@babel/plugin-transform-block-scoping": ^7.22.10 "@babel/plugin-transform-class-properties": ^7.22.5 "@babel/plugin-transform-class-static-block": ^7.22.5 "@babel/plugin-transform-classes": ^7.22.6 "@babel/plugin-transform-computed-properties": ^7.22.5 - "@babel/plugin-transform-destructuring": ^7.22.5 + "@babel/plugin-transform-destructuring": ^7.22.10 "@babel/plugin-transform-dotall-regex": ^7.22.5 "@babel/plugin-transform-duplicate-keys": ^7.22.5 "@babel/plugin-transform-dynamic-import": ^7.22.5 @@ -1549,47 +1536,45 @@ __metadata: "@babel/plugin-transform-object-rest-spread": ^7.22.5 "@babel/plugin-transform-object-super": ^7.22.5 "@babel/plugin-transform-optional-catch-binding": ^7.22.5 - "@babel/plugin-transform-optional-chaining": ^7.22.6 + "@babel/plugin-transform-optional-chaining": ^7.22.10 "@babel/plugin-transform-parameters": ^7.22.5 "@babel/plugin-transform-private-methods": ^7.22.5 "@babel/plugin-transform-private-property-in-object": ^7.22.5 "@babel/plugin-transform-property-literals": ^7.22.5 - "@babel/plugin-transform-regenerator": ^7.22.5 + "@babel/plugin-transform-regenerator": ^7.22.10 "@babel/plugin-transform-reserved-words": ^7.22.5 "@babel/plugin-transform-shorthand-properties": ^7.22.5 "@babel/plugin-transform-spread": ^7.22.5 "@babel/plugin-transform-sticky-regex": ^7.22.5 "@babel/plugin-transform-template-literals": ^7.22.5 "@babel/plugin-transform-typeof-symbol": ^7.22.5 - "@babel/plugin-transform-unicode-escapes": ^7.22.5 + "@babel/plugin-transform-unicode-escapes": ^7.22.10 "@babel/plugin-transform-unicode-property-regex": ^7.22.5 "@babel/plugin-transform-unicode-regex": ^7.22.5 "@babel/plugin-transform-unicode-sets-regex": ^7.22.5 - "@babel/preset-modules": ^0.1.5 - "@babel/types": ^7.22.5 - babel-plugin-polyfill-corejs2: ^0.4.4 - babel-plugin-polyfill-corejs3: ^0.8.2 - babel-plugin-polyfill-regenerator: ^0.5.1 + "@babel/preset-modules": 0.1.6-no-external-plugins + "@babel/types": ^7.22.10 + babel-plugin-polyfill-corejs2: ^0.4.5 + babel-plugin-polyfill-corejs3: ^0.8.3 + babel-plugin-polyfill-regenerator: ^0.5.2 core-js-compat: ^3.31.0 semver: ^6.3.1 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 6caa2897bbda30c6932aed0a03827deb1337c57108050c9f97dc9a857e1533c7125b168b6d70b9d191965bf05f9f233f0ad20303080505dff7ce39740aaa759d + checksum: 4145a660a7b05e21e6d8b6cdf348c6931238abb15282a258bdb5e04cd3cca9356dc120ecfe0d1b977819ade4aac50163127c86db2300227ff60392d24daa0b7c languageName: node linkType: hard -"@babel/preset-modules@npm:^0.1.5": - version: 0.1.5 - resolution: "@babel/preset-modules@npm:0.1.5" +"@babel/preset-modules@npm:0.1.6-no-external-plugins": + version: 0.1.6-no-external-plugins + resolution: "@babel/preset-modules@npm:0.1.6-no-external-plugins" dependencies: "@babel/helper-plugin-utils": ^7.0.0 - "@babel/plugin-proposal-unicode-property-regex": ^7.4.4 - "@babel/plugin-transform-dotall-regex": ^7.4.4 "@babel/types": ^7.4.4 esutils: ^2.0.2 peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 8430e0e9e9d520b53e22e8c4c6a5a080a12b63af6eabe559c2310b187bd62ae113f3da82ba33e9d1d0f3230930ca702843aae9dd226dec51f7d7114dc1f51c10 + "@babel/core": ^7.0.0-0 || ^8.0.0-0 <8.0.0 + checksum: 4855e799bc50f2449fb5210f78ea9e8fd46cf4f242243f1e2ed838e2bd702e25e73e822e7f8447722a5f4baa5e67a8f7a0e403f3e7ce04540ff743a9c411c375 languageName: node linkType: hard @@ -1610,17 +1595,17 @@ __metadata: linkType: hard "@babel/preset-typescript@npm:^7.16.0": - version: 7.22.5 - resolution: "@babel/preset-typescript@npm:7.22.5" + version: 7.22.11 + resolution: "@babel/preset-typescript@npm:7.22.11" dependencies: "@babel/helper-plugin-utils": ^7.22.5 "@babel/helper-validator-option": ^7.22.5 "@babel/plugin-syntax-jsx": ^7.22.5 - "@babel/plugin-transform-modules-commonjs": ^7.22.5 - "@babel/plugin-transform-typescript": ^7.22.5 + "@babel/plugin-transform-modules-commonjs": ^7.22.11 + "@babel/plugin-transform-typescript": ^7.22.11 peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 7be1670cb4404797d3a473bd72d66eb2b3e0f2f8a672a5e40bdb0812cc66085ec84bcd7b896709764cabf042fdc6b7f2d4755ac7cce10515eb596ff61dab5154 + checksum: 8ae7162c31db896f5eeecd6f67ab2e58555fdc06fe84e95fe4a3f60b64cd6f782d2d7dfbde0c0eac04b55dac18222752d91dd8786245cccedd7e42f080e07233 languageName: node linkType: hard @@ -1631,12 +1616,12 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.16.3, @babel/runtime@npm:^7.17.2, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.22.3, @babel/runtime@npm:^7.8.4": - version: 7.22.6 - resolution: "@babel/runtime@npm:7.22.6" +"@babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.16.3, @babel/runtime@npm:^7.17.2, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.22.6, @babel/runtime@npm:^7.8.4": + version: 7.22.11 + resolution: "@babel/runtime@npm:7.22.11" dependencies: - regenerator-runtime: ^0.13.11 - checksum: e585338287c4514a713babf4fdb8fc2a67adcebab3e7723a739fc62c79cfda875b314c90fd25f827afb150d781af97bc16c85bfdbfa2889f06053879a1ddb597 + regenerator-runtime: ^0.14.0 + checksum: a5cd6683a8fcdb8065cb1677f221e22f6c67ec8f15ad1d273b180b93ab3bd86c66da2c48f500d4e72d8d2cfa85ff4872a3f350e5aa3855630036af5da765c001 languageName: node linkType: hard @@ -1651,32 +1636,32 @@ __metadata: languageName: node linkType: hard -"@babel/traverse@npm:^7.22.6, @babel/traverse@npm:^7.22.8, @babel/traverse@npm:^7.7.2": - version: 7.22.8 - resolution: "@babel/traverse@npm:7.22.8" +"@babel/traverse@npm:^7.22.11, @babel/traverse@npm:^7.7.2": + version: 7.22.11 + resolution: "@babel/traverse@npm:7.22.11" dependencies: - "@babel/code-frame": ^7.22.5 - "@babel/generator": ^7.22.7 + "@babel/code-frame": ^7.22.10 + "@babel/generator": ^7.22.10 "@babel/helper-environment-visitor": ^7.22.5 "@babel/helper-function-name": ^7.22.5 "@babel/helper-hoist-variables": ^7.22.5 "@babel/helper-split-export-declaration": ^7.22.6 - "@babel/parser": ^7.22.7 - "@babel/types": ^7.22.5 + "@babel/parser": ^7.22.11 + "@babel/types": ^7.22.11 debug: ^4.1.0 globals: ^11.1.0 - checksum: a381369bc3eedfd13ed5fef7b884657f1c29024ea7388198149f0edc34bd69ce3966e9f40188d15f56490a5e12ba250ccc485f2882b53d41b054fccefb233e33 + checksum: 4ad62d548ca8b95dbf45bae16cc167428f174f3c837d55a5878b1f17bdbc8b384d6df741dc7c461b62c04d881cf25644d3ab885909ba46e3ac43224e2b15b504 languageName: node linkType: hard -"@babel/types@npm:^7.0.0, @babel/types@npm:^7.12.6, @babel/types@npm:^7.20.7, @babel/types@npm:^7.22.5, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3": - version: 7.22.5 - resolution: "@babel/types@npm:7.22.5" +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.12.6, @babel/types@npm:^7.20.7, @babel/types@npm:^7.22.10, @babel/types@npm:^7.22.11, @babel/types@npm:^7.22.5, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3": + version: 7.22.11 + resolution: "@babel/types@npm:7.22.11" dependencies: "@babel/helper-string-parser": ^7.22.5 "@babel/helper-validator-identifier": ^7.22.5 to-fast-properties: ^2.0.0 - checksum: c13a9c1dc7d2d1a241a2f8363540cb9af1d66e978e8984b400a20c4f38ba38ca29f06e26a0f2d49a70bad9e57615dac09c35accfddf1bb90d23cd3e0a0bab892 + checksum: 431a6446896adb62c876d0fe75263835735d3c974aae05356a87eb55f087c20a777028cf08eadcace7993e058bbafe3b21ce2119363222c6cef9eedd7a204810 languageName: node linkType: hard @@ -1958,34 +1943,10 @@ __metadata: languageName: node linkType: hard -"@eslint-community/regexpp@npm:^4.4.0": - version: 4.5.1 - resolution: "@eslint-community/regexpp@npm:4.5.1" - checksum: 6d901166d64998d591fab4db1c2f872981ccd5f6fe066a1ad0a93d4e11855ecae6bfb76660869a469563e8882d4307228cebd41142adb409d182f2966771e57e - languageName: node - linkType: hard - -"@eslint-community/regexpp@npm:^4.6.1": - version: 4.6.2 - resolution: "@eslint-community/regexpp@npm:4.6.2" - checksum: a3c341377b46b54fa228f455771b901d1a2717f95d47dcdf40199df30abc000ba020f747f114f08560d119e979d882a94cf46cfc51744544d54b00319c0f2724 - languageName: node - linkType: hard - -"@eslint/eslintrc@npm:^2.1.0": - version: 2.1.0 - resolution: "@eslint/eslintrc@npm:2.1.0" - dependencies: - ajv: ^6.12.4 - debug: ^4.3.2 - espree: ^9.6.0 - globals: ^13.19.0 - ignore: ^5.2.0 - import-fresh: ^3.2.1 - js-yaml: ^4.1.0 - minimatch: ^3.1.2 - strip-json-comments: ^3.1.1 - checksum: d5ed0adbe23f6571d8c9bb0ca6edf7618dc6aed4046aa56df7139f65ae7b578874e0d9c796df784c25bda648ceb754b6320277d828c8b004876d7443b8dc018c +"@eslint-community/regexpp@npm:^4.4.0, @eslint-community/regexpp@npm:^4.6.1": + version: 4.8.0 + resolution: "@eslint-community/regexpp@npm:4.8.0" + checksum: 601e6d033d556e98e8c929905bef335f20d7389762812df4d0f709d9b4d2631610dda975fb272e23b5b68e24a163b3851b114c8080a0a19fb4c141a1eff6305b languageName: node linkType: hard @@ -2006,17 +1967,30 @@ __metadata: languageName: node linkType: hard -"@eslint/js@npm:8.44.0": - version: 8.44.0 - resolution: "@eslint/js@npm:8.44.0" - checksum: fc539583226a28f5677356e9f00d2789c34253f076643d2e32888250e509a4e13aafe0880cb2425139051de0f3a48d25bfc5afa96b7304f203b706c17340e3cf +"@eslint/js@npm:8.48.0": + version: 8.48.0 + resolution: "@eslint/js@npm:8.48.0" + checksum: b2755f9c0ee810c886eba3c50dcacb184ba5a5cd1cbc01988ee506ad7340653cae0bd55f1d95c64b56dfc6d25c2caa7825335ffd2c50165bae9996fe0f396851 + languageName: node + linkType: hard + +"@ethereumjs/rlp@npm:^4.0.1": + version: 4.0.1 + resolution: "@ethereumjs/rlp@npm:4.0.1" + bin: + rlp: bin/rlp + checksum: 30db19c78faa2b6ff27275ab767646929207bb207f903f09eb3e4c273ce2738b45f3c82169ddacd67468b4f063d8d96035f2bf36f02b6b7e4d928eefe2e3ecbc languageName: node linkType: hard -"@eslint/js@npm:^8.47.0": - version: 8.47.0 - resolution: "@eslint/js@npm:8.47.0" - checksum: 0ef57fe27b6d4c305b33f3b2d2fee1ab397a619006f1d6f4ce5ee4746b8f03d11a4e098805a7d78601ca534cf72917d37f0ac19896c992a32e26299ecb9f9de1 +"@ethereumjs/util@npm:^8.1.0": + version: 8.1.0 + resolution: "@ethereumjs/util@npm:8.1.0" + dependencies: + "@ethereumjs/rlp": ^4.0.1 + ethereum-cryptography: ^2.0.0 + micro-ftch: ^0.3.1 + checksum: 9ae5dee8f12b0faf81cd83f06a41560e79b0ba96a48262771d897a510ecae605eb6d84f687da001ab8ccffd50f612ae50f988ef76e6312c752897f462f3ac08d languageName: node linkType: hard @@ -2771,14 +2745,7 @@ __metadata: languageName: node linkType: hard -"@jridgewell/resolve-uri@npm:3.1.0": - version: 3.1.0 - resolution: "@jridgewell/resolve-uri@npm:3.1.0" - checksum: b5ceaaf9a110fcb2780d1d8f8d4a0bfd216702f31c988d8042e5f8fbe353c55d9b0f55a1733afdc64806f8e79c485d2464680ac48a0d9fcadb9548ee6b81d267 - languageName: node - linkType: hard - -"@jridgewell/resolve-uri@npm:^3.0.3": +"@jridgewell/resolve-uri@npm:^3.0.3, @jridgewell/resolve-uri@npm:^3.1.0": version: 3.1.1 resolution: "@jridgewell/resolve-uri@npm:3.1.1" checksum: f5b441fe7900eab4f9155b3b93f9800a916257f4e8563afbcd3b5a5337b55e52bd8ae6735453b1b745457d9f6cdb16d74cd6220bbdd98cf153239e13f6cbb653 @@ -2802,14 +2769,7 @@ __metadata: languageName: node linkType: hard -"@jridgewell/sourcemap-codec@npm:1.4.14": - version: 1.4.14 - resolution: "@jridgewell/sourcemap-codec@npm:1.4.14" - checksum: 61100637b6d173d3ba786a5dff019e1a74b1f394f323c1fee337ff390239f053b87266c7a948777f4b1ee68c01a8ad0ab61e5ff4abb5a012a0b091bec391ab97 - languageName: node - linkType: hard - -"@jridgewell/sourcemap-codec@npm:^1.4.10": +"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.14": version: 1.4.15 resolution: "@jridgewell/sourcemap-codec@npm:1.4.15" checksum: b881c7e503db3fc7f3c1f35a1dd2655a188cc51a3612d76efc8a6eb74728bef5606e6758ee77423e564092b4a518aba569bbb21c9bac5ab7a35b0c6ae7e344c8 @@ -2827,12 +2787,12 @@ __metadata: linkType: hard "@jridgewell/trace-mapping@npm:^0.3.17, @jridgewell/trace-mapping@npm:^0.3.9": - version: 0.3.18 - resolution: "@jridgewell/trace-mapping@npm:0.3.18" + version: 0.3.19 + resolution: "@jridgewell/trace-mapping@npm:0.3.19" dependencies: - "@jridgewell/resolve-uri": 3.1.0 - "@jridgewell/sourcemap-codec": 1.4.14 - checksum: 0572669f855260808c16fe8f78f5f1b4356463b11d3f2c7c0b5580c8ba1cbf4ae53efe9f627595830856e57dbac2325ac17eb0c3dd0ec42102e6f227cc289c02 + "@jridgewell/resolve-uri": ^3.1.0 + "@jridgewell/sourcemap-codec": ^1.4.14 + checksum: 956a6f0f6fec060fb48c6bf1f5ec2064e13cd38c8be3873877d4b92b4a27ba58289a34071752671262a3e3c202abcc3fa2aac64d8447b4b0fa1ba3c9047f1c20 languageName: node linkType: hard @@ -2868,9 +2828,9 @@ __metadata: linkType: hard "@ledgerhq/connect-kit-loader@npm:^1.1.0": - version: 1.1.0 - resolution: "@ledgerhq/connect-kit-loader@npm:1.1.0" - checksum: 47fedfc64d2e4d287f3f469dc67066c6ce21bfb3e26ca565132181ad8a4d5aacbd57e8cc30d32ab6fb92cba6ed64553675a2509f02fecfb017e112a6e5dea924 + version: 1.1.2 + resolution: "@ledgerhq/connect-kit-loader@npm:1.1.2" + checksum: 614fdd9ac2363da60af667adcfe4721f863d8ea06ee45a08192a162c28e806dc07491bee4833d14def74de673eac1f1450eaf67e783c8c28da4e0cd095b4474a languageName: node linkType: hard @@ -2889,11 +2849,27 @@ __metadata: linkType: hard "@lit/reactive-element@npm:^1.3.0, @lit/reactive-element@npm:^1.6.0": - version: 1.6.2 - resolution: "@lit/reactive-element@npm:1.6.2" + version: 1.6.3 + resolution: "@lit/reactive-element@npm:1.6.3" dependencies: "@lit-labs/ssr-dom-shim": ^1.0.0 - checksum: 011a3ef0933fda86ec726d29ebc14e829e2f1ba23eca8ed8ed4d5c6f2a102c55cc6986000c5f4c8c3d0c549bc671f5d84d00ce91adc5bbd95970eec3662c0a92 + checksum: 79b58631c38effeabad090070324431da8a22cf0ff665f5e4de35e4d791f984742b3d340c9c7fce996d1124a8da95febc582471b4c237236c770b1300b56ef6e + languageName: node + linkType: hard + +"@ljharb/resumer@npm:^0.0.1": + version: 0.0.1 + resolution: "@ljharb/resumer@npm:0.0.1" + dependencies: + "@ljharb/through": ^2.3.9 + checksum: 1cff0a485cb857933d2921cb05a349f8fe894fa2bb6b31a347010ecccc4a2b369e43ebe5383a32a60ee6c9572d2c83fcab383eb01727e1507bf29c59f312dae6 + languageName: node + linkType: hard + +"@ljharb/through@npm:^2.3.9": + version: 2.3.9 + resolution: "@ljharb/through@npm:2.3.9" + checksum: a47ffed12ef4b08d07458db8bff5f7a13a7030fddf7dbfa947a765581a634d42ee90f7b8c249315aad122c21ad061e97a74f65aef3c03d2c09291d11312f0bfb languageName: node linkType: hard @@ -3023,30 +2999,30 @@ __metadata: languageName: node linkType: hard -"@nicolo-ribaudo/semver-v6@npm:^6.3.3": - version: 6.3.3 - resolution: "@nicolo-ribaudo/semver-v6@npm:6.3.3" - bin: - semver: bin/semver.js - checksum: 8290855b1591477d2298364541fda64fafd4acc110b387067a71c9b05f4105c0a4ac079857ae9cd107c42ee884e8724a406b5116f069575e02d7ab87a35a5272 +"@noble/curves@npm:1.1.0, @noble/curves@npm:~1.1.0": + version: 1.1.0 + resolution: "@noble/curves@npm:1.1.0" + dependencies: + "@noble/hashes": 1.3.1 + checksum: 2658cdd3f84f71079b4e3516c47559d22cf4b55c23ac8ee9d2b1f8e5b72916d9689e59820e0f9d9cb4a46a8423af5b56dc6bb7782405c88be06a015180508db5 languageName: node linkType: hard -"@noble/curves@npm:1.0.0, @noble/curves@npm:~1.0.0": - version: 1.0.0 - resolution: "@noble/curves@npm:1.0.0" +"@noble/curves@npm:^1.0.0": + version: 1.2.0 + resolution: "@noble/curves@npm:1.2.0" dependencies: - "@noble/hashes": 1.3.0 - checksum: 6bcef44d626c640dc8961819d68dd67dffb907e3b973b7c27efe0ecdd9a5c6ce62c7b9e3dfc930c66605dced7f1ec0514d191c09a2ce98d6d52b66e3315ffa79 + "@noble/hashes": 1.3.2 + checksum: bb798d7a66d8e43789e93bc3c2ddff91a1e19fdb79a99b86cd98f1e5eff0ee2024a2672902c2576ef3577b6f282f3b5c778bebd55761ddbb30e36bf275e83dd0 languageName: node linkType: hard -"@noble/curves@npm:1.1.0, @noble/curves@npm:^1.0.0": - version: 1.1.0 - resolution: "@noble/curves@npm:1.1.0" +"@noble/curves@npm:~1.0.0": + version: 1.0.0 + resolution: "@noble/curves@npm:1.0.0" dependencies: - "@noble/hashes": 1.3.1 - checksum: 2658cdd3f84f71079b4e3516c47559d22cf4b55c23ac8ee9d2b1f8e5b72916d9689e59820e0f9d9cb4a46a8423af5b56dc6bb7782405c88be06a015180508db5 + "@noble/hashes": 1.3.0 + checksum: 6bcef44d626c640dc8961819d68dd67dffb907e3b973b7c27efe0ecdd9a5c6ce62c7b9e3dfc930c66605dced7f1ec0514d191c09a2ce98d6d52b66e3315ffa79 languageName: node linkType: hard @@ -3071,13 +3047,20 @@ __metadata: languageName: node linkType: hard -"@noble/hashes@npm:1.3.1, @noble/hashes@npm:^1.3.0, @noble/hashes@npm:~1.3.0": +"@noble/hashes@npm:1.3.1": version: 1.3.1 resolution: "@noble/hashes@npm:1.3.1" checksum: 7fdefc0f7a0c1ec27acc6ff88841793e3f93ec4ce6b8a6a12bfc0dd70ae6b7c4c82fe305fdfeda1735d5ad4a9eebe761e6693b3d355689c559e91242f4bc95b1 languageName: node linkType: hard +"@noble/hashes@npm:1.3.2, @noble/hashes@npm:^1.3.1, @noble/hashes@npm:~1.3.0, @noble/hashes@npm:~1.3.1": + version: 1.3.2 + resolution: "@noble/hashes@npm:1.3.2" + checksum: fe23536b436539d13f90e4b9be843cc63b1b17666a07634a2b1259dded6f490be3d050249e6af98076ea8f2ea0d56f578773c2197f2aa0eeaa5fba5bc18ba474 + languageName: node + linkType: hard + "@noble/secp256k1@npm:1.7.1, @noble/secp256k1@npm:~1.7.0": version: 1.7.1 resolution: "@noble/secp256k1@npm:1.7.1" @@ -3504,20 +3487,13 @@ __metadata: linkType: hard "@openzeppelin/contracts-upgradeable@npm:^4.8.1": - version: 4.9.2 - resolution: "@openzeppelin/contracts-upgradeable@npm:4.9.2" - checksum: 88df083e886006b9fac61848edf224a725b99e1b8a302173165a857e3bbc1d00d61cb9c71590b37d955b179fe23652fc157347a086dbaad8f66ce8470603f151 - languageName: node - linkType: hard - -"@openzeppelin/contracts@npm:^4.8.1": - version: 4.9.2 - resolution: "@openzeppelin/contracts@npm:4.9.2" - checksum: 0538b18fe222e5414a5a539c240b155e0bef2a23c5182fb8e137d71a0c390fe899160f2d55701f75b127f54cc61aee4375370acc832475f19829368ac65c1fc6 + version: 4.9.3 + resolution: "@openzeppelin/contracts-upgradeable@npm:4.9.3" + checksum: bda0240b1d44c913ec5a4e109c622f216c2bbd7b468d210822f75782a5f7fe0609d08bf03b78b253333625e99e507cf2f75212f1de3b274bd9fc64ae967aeec3 languageName: node linkType: hard -"@openzeppelin/contracts@npm:^4.9.3": +"@openzeppelin/contracts@npm:^4.8.1, @openzeppelin/contracts@npm:^4.9.3": version: 4.9.3 resolution: "@openzeppelin/contracts@npm:4.9.3" checksum: 4932063e733b35fa7669b9fe2053f69b062366c5c208b0c6cfa1ac451712100c78acff98120c3a4b88d94154c802be05d160d71f37e7d74cadbe150964458838 @@ -3539,8 +3515,8 @@ __metadata: linkType: hard "@pmmmwh/react-refresh-webpack-plugin@npm:^0.5.3": - version: 0.5.10 - resolution: "@pmmmwh/react-refresh-webpack-plugin@npm:0.5.10" + version: 0.5.11 + resolution: "@pmmmwh/react-refresh-webpack-plugin@npm:0.5.11" dependencies: ansi-html-community: ^0.0.8 common-path-prefix: ^3.0.0 @@ -3555,7 +3531,7 @@ __metadata: "@types/webpack": 4.x || 5.x react-refresh: ">=0.10.0 <1.0.0" sockjs-client: ^1.4.0 - type-fest: ">=0.17.0 <4.0.0" + type-fest: ">=0.17.0 <5.0.0" webpack: ">=4.43.0 <6.0.0" webpack-dev-server: 3.x || 4.x webpack-hot-middleware: 2.x @@ -3573,7 +3549,7 @@ __metadata: optional: true webpack-plugin-serve: optional: true - checksum: c45beded9c56fbbdc7213a2c36131ace5db360ed704d462cc39d6678f980173a91c9a3f691e6bd3a026f25486644cd0027e8a12a0a4eced8e8b886a0472e7d34 + checksum: a82eced9519f4dcac424acae719f819ab4150bfcf2874ac7daaf25a4f1c409e3d8b9d693fea0c686c24d520a5473756df32da90d8b89739670f8f8084c600bb4 languageName: node linkType: hard @@ -3643,9 +3619,9 @@ __metadata: linkType: hard "@rushstack/eslint-patch@npm:^1.1.0": - version: 1.3.2 - resolution: "@rushstack/eslint-patch@npm:1.3.2" - checksum: 010c87ef2d901faaaf70ea1bf86fd3e7b74f24e23205f836e9a32790bca2076afe5de58ded03c35cb482f83691c8d22b1a0c34291b075bfe81afd26cfa5d14cc + version: 1.3.3 + resolution: "@rushstack/eslint-patch@npm:1.3.3" + checksum: fd8a19ec5842634da8e4c2c479a4d13ecbefa4f212e42c7f9c39e8706f9eeef7a50db8d6ea939884ac0ff36bb21930c9642068cf68e8309ad491c54f2fc30c01 languageName: node linkType: hard @@ -3659,7 +3635,7 @@ __metadata: languageName: node linkType: hard -"@safe-global/safe-apps-sdk@npm:8.0.0, @safe-global/safe-apps-sdk@npm:^8.0.0": +"@safe-global/safe-apps-sdk@npm:8.0.0": version: 8.0.0 resolution: "@safe-global/safe-apps-sdk@npm:8.0.0" dependencies: @@ -3669,6 +3645,16 @@ __metadata: languageName: node linkType: hard +"@safe-global/safe-apps-sdk@npm:^8.0.0": + version: 8.1.0 + resolution: "@safe-global/safe-apps-sdk@npm:8.1.0" + dependencies: + "@safe-global/safe-gateway-typescript-sdk": ^3.5.3 + viem: ^1.0.0 + checksum: e9d31ed6d9cd2cd9ed71ef5a0e1f6ecfca9f0c62acb9b86a0ddb1b65a609090f2297c4304591ac0518b266a1bcc88d1dad31b0d05e50c7732accccb65adab754 + languageName: node + linkType: hard + "@safe-global/safe-core-sdk-types@npm:^1.9.2": version: 1.10.1 resolution: "@safe-global/safe-core-sdk-types@npm:1.10.1" @@ -3719,18 +3705,18 @@ __metadata: linkType: hard "@safe-global/safe-gateway-typescript-sdk@npm:^3.5.3": - version: 3.7.3 - resolution: "@safe-global/safe-gateway-typescript-sdk@npm:3.7.3" + version: 3.10.0 + resolution: "@safe-global/safe-gateway-typescript-sdk@npm:3.10.0" dependencies: cross-fetch: ^3.1.5 - checksum: 5ee57fe228ff107cc7f08db231e52e8ac217894d1a34189374a01ac3ef18a69ef0ae802a5b21d2d2de11654b96e0117deea007d814eef4dfb9b8c7b82e36ae63 + checksum: 27d51db7e081bd616c34ba859a736e17932540aa16f1d5909639026e8d48380f37a33047172fa2dbd2912c92270cda1f550f52ec6bc9cd0a5522dd1172843e59 languageName: node linkType: hard "@scure/base@npm:~1.1.0": - version: 1.1.1 - resolution: "@scure/base@npm:1.1.1" - checksum: b4fc810b492693e7e8d0107313ac74c3646970c198bbe26d7332820886fa4f09441991023ec9aa3a2a51246b74409ab5ebae2e8ef148bbc253da79ac49130309 + version: 1.1.2 + resolution: "@scure/base@npm:1.1.2" + checksum: f666b09dbd62ecb5fe6d0e7a629c8a86a972a47dc4f4555ebbbd7b09782b10a5f894fed9c3b8c74fd683b1588c064df079a44e9f695c075ccd98c30a8d3e91f7 languageName: node linkType: hard @@ -3756,6 +3742,17 @@ __metadata: languageName: node linkType: hard +"@scure/bip32@npm:1.3.1": + version: 1.3.1 + resolution: "@scure/bip32@npm:1.3.1" + dependencies: + "@noble/curves": ~1.1.0 + "@noble/hashes": ~1.3.1 + "@scure/base": ~1.1.0 + checksum: 394d65f77a40651eba21a5096da0f4233c3b50d422864751d373fcf142eeedb94a1149f9ab1dbb078086dab2d0bc27e2b1afec8321bf22d4403c7df2fea5bfe2 + languageName: node + linkType: hard + "@scure/bip39@npm:1.1.1": version: 1.1.1 resolution: "@scure/bip39@npm:1.1.1" @@ -3776,6 +3773,16 @@ __metadata: languageName: node linkType: hard +"@scure/bip39@npm:1.2.1": + version: 1.2.1 + resolution: "@scure/bip39@npm:1.2.1" + dependencies: + "@noble/hashes": ~1.3.0 + "@scure/base": ~1.1.0 + checksum: c5bd6f1328fdbeae2dcdd891825b1610225310e5e62a4942714db51066866e4f7bef242c7b06a1b9dcc8043a4a13412cf5c5df76d3b10aa9e36b82e9b6e3eeaa + languageName: node + linkType: hard + "@sentry/core@npm:5.30.0": version: 5.30.0 resolution: "@sentry/core@npm:5.30.0" @@ -3893,25 +3900,25 @@ __metadata: linkType: hard "@solana/web3.js@npm:^1.70.1": - version: 1.78.0 - resolution: "@solana/web3.js@npm:1.78.0" + version: 1.78.4 + resolution: "@solana/web3.js@npm:1.78.4" dependencies: - "@babel/runtime": ^7.22.3 + "@babel/runtime": ^7.22.6 "@noble/curves": ^1.0.0 - "@noble/hashes": ^1.3.0 + "@noble/hashes": ^1.3.1 "@solana/buffer-layout": ^4.0.0 - agentkeepalive: ^4.2.1 + agentkeepalive: ^4.3.0 bigint-buffer: ^1.1.5 - bn.js: ^5.0.0 + bn.js: ^5.2.1 borsh: ^0.7.0 bs58: ^4.0.1 buffer: 6.0.3 fast-stable-stringify: ^1.0.0 jayson: ^4.1.0 - node-fetch: ^2.6.11 + node-fetch: ^2.6.12 rpc-websockets: ^7.5.1 superstruct: ^0.14.2 - checksum: 9f0aae54fa8f2d9285ae525b4f962a17160fd98ac588fbf528742630fb2cf0208ec7b6c0c307d6bba82a92a0e8cbb5411b965d553cc4c62488e24b57c2211d84 + checksum: e1c44c6cbec87cdfd4d6d23b4241b746e14ed3a9ca73d596693758d91ac825cecf579345da3b0b7bb5e54b6794791bc0eac02cadf11f1ec79e859b6536f26f11 languageName: node linkType: hard @@ -4246,47 +4253,47 @@ __metadata: languageName: node linkType: hard -"@tanstack/query-core@npm:4.29.19": - version: 4.29.19 - resolution: "@tanstack/query-core@npm:4.29.19" - checksum: 91a79dbebebc139d118542a5fe83fb54a6f6448bbe1563db1a0bed0c6d44e1d023613efde3c4ac747c72d067110013ac56f90611bf8affc390eda1ac3f99066e +"@tanstack/query-core@npm:4.33.0": + version: 4.33.0 + resolution: "@tanstack/query-core@npm:4.33.0" + checksum: fae325f1d79b936435787797c32367331d5b8e9c5ced84852bf2085115e3aafef57a7ae530a6b0af46da4abafb4b0afaef885926b71715a0e6f166d74da61c7f languageName: node linkType: hard -"@tanstack/query-persist-client-core@npm:4.29.19": - version: 4.29.19 - resolution: "@tanstack/query-persist-client-core@npm:4.29.19" +"@tanstack/query-persist-client-core@npm:4.33.0": + version: 4.33.0 + resolution: "@tanstack/query-persist-client-core@npm:4.33.0" dependencies: - "@tanstack/query-core": 4.29.19 - checksum: dc7f9ed313624ec667a507414287df52affe0df7a1922b7e54218fca9780e3bd3f8b0f214d431b20400efe0b51b8691d44a0ed6211df3e4ab26d9929b0492c93 + "@tanstack/query-core": 4.33.0 + checksum: c80e2805061da3c497504a6132d273fc351ef94b4685c0da5658fe25f759f692fad2c752f9f8af17c47edcf9ce9064f3f44d2b99d03f011345d8450b1bb940d5 languageName: node linkType: hard "@tanstack/query-sync-storage-persister@npm:^4.27.1": - version: 4.29.19 - resolution: "@tanstack/query-sync-storage-persister@npm:4.29.19" + version: 4.33.0 + resolution: "@tanstack/query-sync-storage-persister@npm:4.33.0" dependencies: - "@tanstack/query-persist-client-core": 4.29.19 - checksum: 9c7cad5bccf43c9bb1bb6f78f86c9eee65c714d9413d7931b853379eff0855552b1f91e4dd9b94d241221d4dee4e90340a0dc2979fe77f14bc50bafe060c29eb + "@tanstack/query-persist-client-core": 4.33.0 + checksum: ad949f94e18b5188de363e780cf99e738d8468dafff72345f464e784b493f774dffbaa554122306a8fd81f9965de58588a2cf4f940d52e77b2ca4346a650aed9 languageName: node linkType: hard "@tanstack/react-query-persist-client@npm:^4.28.0": - version: 4.29.19 - resolution: "@tanstack/react-query-persist-client@npm:4.29.19" + version: 4.33.0 + resolution: "@tanstack/react-query-persist-client@npm:4.33.0" dependencies: - "@tanstack/query-persist-client-core": 4.29.19 + "@tanstack/query-persist-client-core": 4.33.0 peerDependencies: - "@tanstack/react-query": 4.29.19 - checksum: 30dda9270b8fec314d01f9602f8f49ee681d63a3293614dfb397f3b80f13bdccff575957c42577659dc25b68da4f06eb5047efbd950c5ac40d5103476b095fa1 + "@tanstack/react-query": ^4.33.0 + checksum: 403de6e6659d87f21ee4412e7e8e15b32cbcf5adcb7d340b93c890321fa8a88f7681690774c6e5253d28227869f01b170a32d23bd0ed8870fbd109890ee5fa9f languageName: node linkType: hard "@tanstack/react-query@npm:^4.28.0": - version: 4.29.19 - resolution: "@tanstack/react-query@npm:4.29.19" + version: 4.33.0 + resolution: "@tanstack/react-query@npm:4.33.0" dependencies: - "@tanstack/query-core": 4.29.19 + "@tanstack/query-core": 4.33.0 use-sync-external-store: ^1.2.0 peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -4297,7 +4304,7 @@ __metadata: optional: true react-native: optional: true - checksum: 2780ac35b4d1dabcd3e708b95891376e7e609109270d40442b33f4747c508c23e46bcadc692f997f81d38f62b5ab31f8e42bc9a785dfa4afe0c390adb6f37e52 + checksum: b3cf4afa427435e464e077b3f23c891e38e5f78873518f15c1d061ad55f1464d6241ecd92d796a5dbc9412b4fd7eb30b01f2a9cfc285ee9f30dfdd2ca0ecaf4b languageName: node linkType: hard @@ -4520,12 +4527,12 @@ __metadata: linkType: hard "@types/eslint@npm:*, @types/eslint@npm:^7.29.0 || ^8.4.1": - version: 8.44.0 - resolution: "@types/eslint@npm:8.44.0" + version: 8.44.2 + resolution: "@types/eslint@npm:8.44.2" dependencies: "@types/estree": "*" "@types/json-schema": "*" - checksum: 2655f409a4ecdd64bb9dd9eb6715e7a2ac30c0e7f902b414e10dbe9d6d497baa5a0f13105e1f7bd5ad7a913338e2ab4bed1faf192a7a0d27d1acd45ba79d3f69 + checksum: 25b3ef61bae96350026593c9914c8a61ee02fde48ab8d568a73ee45032f13c0028c62e47a5ff78715af488dfe8e8bba913f7d30f859f60c7f9e639d328e80482 languageName: node linkType: hard @@ -4544,14 +4551,14 @@ __metadata: linkType: hard "@types/express-serve-static-core@npm:*, @types/express-serve-static-core@npm:^4.17.33": - version: 4.17.35 - resolution: "@types/express-serve-static-core@npm:4.17.35" + version: 4.17.36 + resolution: "@types/express-serve-static-core@npm:4.17.36" dependencies: "@types/node": "*" "@types/qs": "*" "@types/range-parser": "*" "@types/send": "*" - checksum: cc8995d10c6feda475ec1b3a0e69eb0f35f21ab6b49129ad5c6f279e0bc5de8175bc04ec51304cb79a43eec3ed2f5a1e01472eb6d5f827b8c35c6ca8ad24eb6e + checksum: 410b13cbd663f18c0f8729e7f2ff54d960d96de76ebbae7cadb612972f85cc66c54051e00d32f11aa230c0a683d81a6d6fc7f7e4e383a95c0801494c517f36e1 languageName: node linkType: hard @@ -4700,9 +4707,9 @@ __metadata: linkType: hard "@types/node@npm:*": - version: 20.4.2 - resolution: "@types/node@npm:20.4.2" - checksum: 99e544ea7560d51f01f95627fc40394c24a13da8f041121a0da13e4ef0a2aa332932eaf9a5e8d0e30d1c07106e96a183be392cbba62e8cf0bf6a085d5c0f4149 + version: 20.5.7 + resolution: "@types/node@npm:20.5.7" + checksum: fc284c8e16ddc04569730d58e87eae349eb1c3dd9020cb79a1862d9d9add6f04e7367a236f3252db8db2572f90278e250f4cd43d27d264972b54394eaba1ed76 languageName: node linkType: hard @@ -4727,10 +4734,10 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:^18.17.11": - version: 18.17.11 - resolution: "@types/node@npm:18.17.11" - checksum: c31d9f4a6f7c5c413b6548ded0fab046571832718361c5cda325960f32d6b386dd0a7fa9228911111fee54c180d09df82a622efdabdbef89fa9e1923891892bc +"@types/node@npm:^18.17.12": + version: 18.17.12 + resolution: "@types/node@npm:18.17.12" + checksum: 79f8bcca3067a3c529f30e172df8d14f25ab9e4cd6a05ed897a924ab1dec774e8ea172ef5c4a67ffec433d423a0c81778f17db22606d574bc83871b60aab298e languageName: node linkType: hard @@ -4819,18 +4826,7 @@ __metadata: languageName: node linkType: hard -"@types/react@npm:*": - version: 18.2.14 - resolution: "@types/react@npm:18.2.14" - dependencies: - "@types/prop-types": "*" - "@types/scheduler": "*" - csstype: ^3.0.2 - checksum: a6a5e8cc78f486b9020d1ad009aa6c56943c68c7c6376e0f8399e9cbcd950b7b8f5d73f00200f5379f5e58d31d57d8aed24357f301d8e86108cd438ce6c8b3dd - languageName: node - linkType: hard - -"@types/react@npm:^18.2.21": +"@types/react@npm:*, @types/react@npm:^18.2.21": version: 18.2.21 resolution: "@types/react@npm:18.2.21" dependencies: @@ -5118,18 +5114,6 @@ __metadata: languageName: node linkType: hard -"@wagmi/chains@npm:1.2.0": - version: 1.2.0 - resolution: "@wagmi/chains@npm:1.2.0" - peerDependencies: - typescript: ">=5.0.4" - peerDependenciesMeta: - typescript: - optional: true - checksum: adac1caf245820bb50292bf2509be195e8efb3b349dc2ac0e0ed7370993b5fed93db57deaf4d27192b20e8418e9f10cdc7a59bd0a6ce1ac0447e61af76efe423 - languageName: node - linkType: hard - "@wagmi/chains@npm:1.7.0": version: 1.7.0 resolution: "@wagmi/chains@npm:1.7.0" @@ -6146,19 +6130,6 @@ __metadata: languageName: node linkType: hard -"abitype@npm:0.8.11": - version: 0.8.11 - resolution: "abitype@npm:0.8.11" - peerDependencies: - typescript: ">=5.0.4" - zod: ^3 >=3.19.1 - peerDependenciesMeta: - zod: - optional: true - checksum: 94e6ad5d3d3851f68ea54d090312d35e38aa15d19b65d25f02d8c54400b184a87b121adb23e930f2e92d597e9290e8ca4f2ff70751e6dada4e8f1440948e0c44 - languageName: node - linkType: hard - "abitype@npm:0.8.7": version: 0.8.7 resolution: "abitype@npm:0.8.7" @@ -6333,14 +6304,12 @@ __metadata: languageName: node linkType: hard -"agentkeepalive@npm:^4.2.1": - version: 4.3.0 - resolution: "agentkeepalive@npm:4.3.0" +"agentkeepalive@npm:^4.2.1, agentkeepalive@npm:^4.3.0": + version: 4.5.0 + resolution: "agentkeepalive@npm:4.5.0" dependencies: - debug: ^4.1.0 - depd: ^2.0.0 humanize-ms: ^1.2.1 - checksum: 982453aa44c11a06826c836025e5162c846e1200adb56f2d075400da7d32d87021b3b0a58768d949d824811f5654223d5a8a3dad120921a2439625eb847c6260 + checksum: 13278cd5b125e51eddd5079f04d6fe0914ac1b8b91c1f3db2c1822f99ac1a7457869068997784342fe455d59daaff22e14fb7b8c3da4e741896e7e31faf92481 languageName: node linkType: hard @@ -6388,7 +6357,7 @@ __metadata: languageName: node linkType: hard -"ajv@npm:^6.10.0, ajv@npm:^6.12.2, ajv@npm:^6.12.3, ajv@npm:^6.12.4, ajv@npm:^6.12.5": +"ajv@npm:^6.12.2, ajv@npm:^6.12.3, ajv@npm:^6.12.4, ajv@npm:^6.12.5": version: 6.12.6 resolution: "ajv@npm:6.12.6" dependencies: @@ -6680,14 +6649,14 @@ __metadata: linkType: hard "array.prototype.every@npm:^1.1.4": - version: 1.1.4 - resolution: "array.prototype.every@npm:1.1.4" + version: 1.1.5 + resolution: "array.prototype.every@npm:1.1.5" dependencies: call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 + define-properties: ^1.2.0 + es-abstract: ^1.22.1 is-string: ^1.0.7 - checksum: 6a11683fd0148a1f70108ad20eeb5e174813dc22799264584a543d463810ed42261aad0c1c5de1097ea515ec159d20deb9babb465f4ae3ceeb11e28094c3b5b3 + checksum: 9974435604e135fc8c359a76c89bfe0672c1a80974a76dc61c673e5ea5068f78a31b7a168634ed7691501130ed61d3c788dd1d48ec1265c6cdf3910897b1eba4 languageName: node linkType: hard @@ -6754,6 +6723,20 @@ __metadata: languageName: node linkType: hard +"arraybuffer.prototype.slice@npm:^1.0.1": + version: 1.0.1 + resolution: "arraybuffer.prototype.slice@npm:1.0.1" + dependencies: + array-buffer-byte-length: ^1.0.0 + call-bind: ^1.0.2 + define-properties: ^1.2.0 + get-intrinsic: ^1.2.1 + is-array-buffer: ^3.0.2 + is-shared-array-buffer: ^1.0.2 + checksum: e3e9b2a3e988ebfeddce4c7e8f69df730c9e48cb04b0d40ff0874ce3d86b3d1339dd520ffde5e39c02610bc172ecfbd4bc93324b1cabd9554c44a56b131ce0ce + languageName: node + linkType: hard + "asap@npm:~2.0.6": version: 2.0.6 resolution: "asap@npm:2.0.6" @@ -6821,6 +6804,15 @@ __metadata: languageName: node linkType: hard +"asynciterator.prototype@npm:^1.0.0": + version: 1.0.0 + resolution: "asynciterator.prototype@npm:1.0.0" + dependencies: + has-symbols: ^1.0.3 + checksum: e8ebfd9493ac651cf9b4165e9d64030b3da1d17181bb1963627b59e240cdaf021d9b59d44b827dc1dde4e22387ec04c2d0f8720cf58a1c282e34e40cc12721b3 + languageName: node + linkType: hard + "asynckit@npm:^0.4.0": version: 0.4.0 resolution: "asynckit@npm:0.4.0" @@ -6843,11 +6835,11 @@ __metadata: linkType: hard "autoprefixer@npm:^10.4.13": - version: 10.4.14 - resolution: "autoprefixer@npm:10.4.14" + version: 10.4.15 + resolution: "autoprefixer@npm:10.4.15" dependencies: - browserslist: ^4.21.5 - caniuse-lite: ^1.0.30001464 + browserslist: ^4.21.10 + caniuse-lite: ^1.0.30001520 fraction.js: ^4.2.0 normalize-range: ^0.1.2 picocolors: ^1.0.0 @@ -6856,7 +6848,7 @@ __metadata: postcss: ^8.1.0 bin: autoprefixer: bin/autoprefixer - checksum: e9f18e664a4e4a54a8f4ec5f6b49ed228ec45afaa76efcae361c93721795dc5ab644f36d2fdfc0dea446b02a8067b9372f91542ea431994399e972781ed46d95 + checksum: d490b14fb098c043e109fc13cd23628f146af99a493d35b9df3a26f8ec0b4dd8937c5601cdbaeb465b98ea31d3ea05aa7184711d4d93dfb52358d073dcb67032 languageName: node linkType: hard @@ -6984,39 +6976,39 @@ __metadata: languageName: node linkType: hard -"babel-plugin-polyfill-corejs2@npm:^0.4.4": - version: 0.4.4 - resolution: "babel-plugin-polyfill-corejs2@npm:0.4.4" +"babel-plugin-polyfill-corejs2@npm:^0.4.5": + version: 0.4.5 + resolution: "babel-plugin-polyfill-corejs2@npm:0.4.5" dependencies: "@babel/compat-data": ^7.22.6 - "@babel/helper-define-polyfill-provider": ^0.4.1 - "@nicolo-ribaudo/semver-v6": ^6.3.3 + "@babel/helper-define-polyfill-provider": ^0.4.2 + semver: ^6.3.1 peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 0273f3d74ccbf78086a3b14bb11b1fb94933830f51c576a24229d75b3b91c8b357c3a381d4ab3146abf9b052fa4c33ec9368dd010ada9ee355e1d03ff64e1ff0 + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: 33a8e06aa54e2858d211c743d179f0487b03222f9ca1bfd7c4865bca243fca942a3358cb75f6bb894ed476cbddede834811fbd6903ff589f055821146f053e1a languageName: node linkType: hard -"babel-plugin-polyfill-corejs3@npm:^0.8.2": - version: 0.8.2 - resolution: "babel-plugin-polyfill-corejs3@npm:0.8.2" +"babel-plugin-polyfill-corejs3@npm:^0.8.3": + version: 0.8.3 + resolution: "babel-plugin-polyfill-corejs3@npm:0.8.3" dependencies: - "@babel/helper-define-polyfill-provider": ^0.4.1 + "@babel/helper-define-polyfill-provider": ^0.4.2 core-js-compat: ^3.31.0 peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 0bc3e9e0114eba18f4fea8a9ff5a6016cae73b74cb091290c3f75fd7b9e34e712ee26f95b52d796f283970d7c6256fb01196e3608e8db03f620e3389d56d37c6 + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: dcbb30e551702a82cfd4d2c375da2c317658e55f95e9edcda93b9bbfdcc8fb6e5344efcb144e04d3406859e7682afce7974c60ededd9f12072a48a83dd22a0da languageName: node linkType: hard -"babel-plugin-polyfill-regenerator@npm:^0.5.1": - version: 0.5.1 - resolution: "babel-plugin-polyfill-regenerator@npm:0.5.1" +"babel-plugin-polyfill-regenerator@npm:^0.5.2": + version: 0.5.2 + resolution: "babel-plugin-polyfill-regenerator@npm:0.5.2" dependencies: - "@babel/helper-define-polyfill-provider": ^0.4.1 + "@babel/helper-define-polyfill-provider": ^0.4.2 peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 85a56d28b34586fbe482225fb6a9592fc793a459c5eea987a3427fb723c7aa2f76916348a9fc5e9ca48754ebf6086cfbb9226f4cd0cf9c6257f94553622562ed + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: d962200f604016a9a09bc9b4aaf60a3db7af876bb65bcefaeac04d44ac9d9ec4037cf24ce117760cc141d7046b6394c7eb0320ba9665cb4a2ee64df2be187c93 languageName: node linkType: hard @@ -7232,7 +7224,7 @@ __metadata: languageName: node linkType: hard -"bn.js@npm:^5.0.0, bn.js@npm:^5.1.1, bn.js@npm:^5.1.2, bn.js@npm:^5.2.0, bn.js@npm:^5.2.1": +"bn.js@npm:^5.1.1, bn.js@npm:^5.1.2, bn.js@npm:^5.2.0, bn.js@npm:^5.2.1": version: 5.2.1 resolution: "bn.js@npm:5.2.1" checksum: 3dd8c8d38055fedfa95c1d5fc3c99f8dd547b36287b37768db0abab3c239711f88ff58d18d155dd8ad902b0b0cee973747b7ae20ea12a09473272b0201c9edd3 @@ -7364,17 +7356,17 @@ __metadata: languageName: node linkType: hard -"browserslist@npm:^4.0.0, browserslist@npm:^4.14.5, browserslist@npm:^4.18.1, browserslist@npm:^4.21.4, browserslist@npm:^4.21.5, browserslist@npm:^4.21.9": - version: 4.21.9 - resolution: "browserslist@npm:4.21.9" +"browserslist@npm:^4.0.0, browserslist@npm:^4.14.5, browserslist@npm:^4.18.1, browserslist@npm:^4.21.10, browserslist@npm:^4.21.4, browserslist@npm:^4.21.9": + version: 4.21.10 + resolution: "browserslist@npm:4.21.10" dependencies: - caniuse-lite: ^1.0.30001503 - electron-to-chromium: ^1.4.431 - node-releases: ^2.0.12 + caniuse-lite: ^1.0.30001517 + electron-to-chromium: ^1.4.477 + node-releases: ^2.0.13 update-browserslist-db: ^1.0.11 bin: browserslist: cli.js - checksum: 80d3820584e211484ad1b1a5cfdeca1dd00442f47be87e117e1dda34b628c87e18b81ae7986fa5977b3e6a03154f6d13cd763baa6b8bf5dd9dd19f4926603698 + checksum: 1e27c0f111a35d1dd0e8fc2c61781b0daefabc2c9471b0b10537ce54843014bceb2a1ce4571af1a82b2bf1e6e6e05d38865916689a158f03bc2c7a4ec2577db8 languageName: node linkType: hard @@ -7479,14 +7471,14 @@ __metadata: linkType: hard "cacache@npm:^17.0.0": - version: 17.1.3 - resolution: "cacache@npm:17.1.3" + version: 17.1.4 + resolution: "cacache@npm:17.1.4" dependencies: "@npmcli/fs": ^3.1.0 fs-minipass: ^3.0.0 glob: ^10.2.2 lru-cache: ^7.7.1 - minipass: ^5.0.0 + minipass: ^7.0.3 minipass-collect: ^1.0.2 minipass-flush: ^1.0.5 minipass-pipeline: ^1.2.4 @@ -7494,7 +7486,7 @@ __metadata: ssri: ^10.0.0 tar: ^6.1.11 unique-filename: ^3.0.0 - checksum: 385756781e1e21af089160d89d7462b7ed9883c978e848c7075b90b73cb823680e66092d61513050164588387d2ca87dd6d910e28d64bc13a9ac82cd8580c796 + checksum: b7751df756656954a51201335addced8f63fc53266fa56392c9f5ae83c8d27debffb4458ac2d168a744a4517ec3f2163af05c20097f93d17bdc2dc8a385e14a6 languageName: node linkType: hard @@ -7558,10 +7550,10 @@ __metadata: languageName: node linkType: hard -"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001464, caniuse-lite@npm:^1.0.30001503": - version: 1.0.30001515 - resolution: "caniuse-lite@npm:1.0.30001515" - checksum: ec5d51785aea6af5cf62ca9d35821d36ab7fa0f85e3e7f752d532025ad59e07131fa3cb3a0a6c486b5ac8620c8c3440e761dc5b38c990d49c17655906f216123 +"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001517, caniuse-lite@npm:^1.0.30001520": + version: 1.0.30001524 + resolution: "caniuse-lite@npm:1.0.30001524" + checksum: 35d662a62f5e6be3c2d2141f1f30b3428ec72c5756cbd9fc723e33606846f28a515fd30f1e8b56e506c63fe0755f6eb7e3548dc6eefd53c5591b1a3bd28fee98 languageName: node linkType: hard @@ -7641,7 +7633,7 @@ __metadata: languageName: node linkType: hard -"chalk@npm:^2.0.0, chalk@npm:^2.4.1, chalk@npm:^2.4.2": +"chalk@npm:^2.4.1, chalk@npm:^2.4.2": version: 2.4.2 resolution: "chalk@npm:2.4.2" dependencies: @@ -8174,25 +8166,25 @@ __metadata: linkType: hard "core-js-compat@npm:^3.31.0": - version: 3.31.1 - resolution: "core-js-compat@npm:3.31.1" + version: 3.32.1 + resolution: "core-js-compat@npm:3.32.1" dependencies: - browserslist: ^4.21.9 - checksum: 9a16d6992621f4e099169297381a28d5712cdef7df1fa85352a7c285a5885d5d7a117ec2eae9ad715ed88c7cc774787a22cdb8aceababf6775fbc8b0cbeccdb7 + browserslist: ^4.21.10 + checksum: 2ce0002d6d2acabfc6f4c1ea32915683406a10051a186db354b761303cb6f5728f83887d070fb8d0072b5601bb16cb0d24555ee72bfa6df244f7b3ef74d61f76 languageName: node linkType: hard "core-js-pure@npm:^3.23.3": - version: 3.31.1 - resolution: "core-js-pure@npm:3.31.1" - checksum: 93c3dd28471755cb81ec4828f5617bd32a7c682295d88671534a6733a0d41dae9e28f8f8000ddd1f1e597a3bec4602db5f906a03c9ba1a360534f7ae2519db7c + version: 3.32.1 + resolution: "core-js-pure@npm:3.32.1" + checksum: 06d3b1585b1f161e84adaf6a0f1db2434309b8d6c748ee82f1806c5d9755272a30074dfa888d60a164c639c6820588ab8462f1073c6971e76659f13788c2f10d languageName: node linkType: hard "core-js@npm:^3.19.2": - version: 3.31.1 - resolution: "core-js@npm:3.31.1" - checksum: 14519213a63c55cf188bdd2f4dece54583feaf6b90e75d6c65e07f509cd487055bf64898aeda7c97c36029ac1ea2f2ed8e4b02281553f6a257e7143a32a14015 + version: 3.32.1 + resolution: "core-js@npm:3.32.1" + checksum: e4af91d9c6be7b59235feb3f273d16705126ce09a0b4a787144d131d874f0cd10be3c24fc52e5eea7d7cb03ceabe4be7b255abcd9474b5eb1ff365d2c5611f9a languageName: node linkType: hard @@ -8476,9 +8468,9 @@ __metadata: linkType: hard "cssdb@npm:^7.1.0": - version: 7.6.0 - resolution: "cssdb@npm:7.6.0" - checksum: 3b63c87f5e1ac49a131437165d62a7b850a003e6eca00d4dd66cda41269386464ead7e67ec5da21f7d612134a7a264a85795f496529baaa6a9b098eb6f3d8ec4 + version: 7.7.1 + resolution: "cssdb@npm:7.7.1" + checksum: 61e3094a3c5cc94c6965ddd1b91af3383f6fb24fe96945e44954c548612a24a06713fe384e4da5efcd37e6383e534e6193aedcac9f2441b207d3c04dcc1aabf7 languageName: node linkType: hard @@ -8819,7 +8811,7 @@ __metadata: languageName: node linkType: hard -"depd@npm:2.0.0, depd@npm:^2.0.0": +"depd@npm:2.0.0": version: 2.0.0 resolution: "depd@npm:2.0.0" checksum: abbe19c768c97ee2eed6282d8ce3031126662252c58d711f646921c9623f9052e3e1906443066beec1095832f534e57c523b7333f8e7e0d93051ab6baef5ab3a @@ -8976,11 +8968,11 @@ __metadata: linkType: hard "dns-packet@npm:^5.2.2": - version: 5.6.0 - resolution: "dns-packet@npm:5.6.0" + version: 5.6.1 + resolution: "dns-packet@npm:5.6.1" dependencies: "@leichtgewicht/ip-codec": ^2.0.1 - checksum: 1b643814e5947a87620f8a906287079347492282964ce1c236d52c414e3e3941126b96581376b180ba6e66899e70b86b587bc1aa23e3acd9957765be952d83fc + checksum: 64c06457f0c6e143f7a0946e0aeb8de1c5f752217cfa143ef527467c00a6d78db1835cfdb6bb68333d9f9a4963cf23f410439b5262a8935cce1236f45e344b81 languageName: node linkType: hard @@ -9190,10 +9182,10 @@ __metadata: languageName: node linkType: hard -"electron-to-chromium@npm:^1.4.431": - version: 1.4.459 - resolution: "electron-to-chromium@npm:1.4.459" - checksum: 2052797a639c131e459c7d8261506b52b277c3e9c0622a1171dcc9b9dc2293c3b2b43260687d320e89a2a82264521135a525c4ed97beba43f5507583d8c0d532 +"electron-to-chromium@npm:^1.4.477": + version: 1.4.503 + resolution: "electron-to-chromium@npm:1.4.503" + checksum: 77198f5d4365931fb6f18670f1cc2bc6833516dfe935e69209da45ba06fd9e3bb02678216ab8c1cf7b047655559b7d591d922d9a781a1f91c7f5a32d5f51f778 languageName: node linkType: hard @@ -9297,11 +9289,12 @@ __metadata: linkType: hard "enquirer@npm:^2.3.0, enquirer@npm:^2.3.6": - version: 2.3.6 - resolution: "enquirer@npm:2.3.6" + version: 2.4.1 + resolution: "enquirer@npm:2.4.1" dependencies: ansi-colors: ^4.1.1 - checksum: 1c0911e14a6f8d26721c91e01db06092a5f7675159f0261d69c403396a385afd13dd76825e7678f66daffa930cfaa8d45f506fb35f818a2788463d022af1b884 + strip-ansi: ^6.0.1 + checksum: f080f11a74209647dbf347a7c6a83c8a47ae1ebf1e75073a808bc1088eb780aa54075bfecd1bcdb3e3c724520edb8e6ee05da031529436b421b71066fcc48cb5 languageName: node linkType: hard @@ -9355,11 +9348,12 @@ __metadata: languageName: node linkType: hard -"es-abstract@npm:^1.17.2, es-abstract@npm:^1.19.0, es-abstract@npm:^1.20.4, es-abstract@npm:^1.21.2": - version: 1.21.3 - resolution: "es-abstract@npm:1.21.3" +"es-abstract@npm:^1.17.2, es-abstract@npm:^1.19.0, es-abstract@npm:^1.20.4, es-abstract@npm:^1.21.2, es-abstract@npm:^1.22.1": + version: 1.22.1 + resolution: "es-abstract@npm:1.22.1" dependencies: array-buffer-byte-length: ^1.0.0 + arraybuffer.prototype.slice: ^1.0.1 available-typed-arrays: ^1.0.5 call-bind: ^1.0.2 es-set-tostringtag: ^2.0.1 @@ -9386,15 +9380,18 @@ __metadata: object-keys: ^1.1.1 object.assign: ^4.1.4 regexp.prototype.flags: ^1.5.0 + safe-array-concat: ^1.0.0 safe-regex-test: ^1.0.0 string.prototype.trim: ^1.2.7 string.prototype.trimend: ^1.0.6 string.prototype.trimstart: ^1.0.6 + typed-array-buffer: ^1.0.0 + typed-array-byte-length: ^1.0.0 typed-array-byte-offset: ^1.0.0 typed-array-length: ^1.0.4 unbox-primitive: ^1.0.2 which-typed-array: ^1.1.10 - checksum: 4c5ee900699030a629fc224a3595dcd05f9ff31d607e72bc9042d15e3b1bfde99f408c940b622e96439e755a7b23a3b9e47f3be234015750d32dad38b8f772f4 + checksum: 614e2c1c3717cb8d30b6128ef12ea110e06fd7d75ad77091ca1c5dbfb00da130e62e4bbbbbdda190eada098a22b27fe0f99ae5a1171dac2c8663b1e8be8a3a9b languageName: node linkType: hard @@ -9422,6 +9419,28 @@ __metadata: languageName: node linkType: hard +"es-iterator-helpers@npm:^1.0.12": + version: 1.0.14 + resolution: "es-iterator-helpers@npm:1.0.14" + dependencies: + asynciterator.prototype: ^1.0.0 + call-bind: ^1.0.2 + define-properties: ^1.2.0 + es-abstract: ^1.22.1 + es-set-tostringtag: ^2.0.1 + function-bind: ^1.1.1 + get-intrinsic: ^1.2.1 + globalthis: ^1.0.3 + has-property-descriptors: ^1.0.0 + has-proto: ^1.0.1 + has-symbols: ^1.0.3 + internal-slot: ^1.0.5 + iterator.prototype: ^1.1.0 + safe-array-concat: ^1.0.0 + checksum: 484ca398389d5e259855e2d848573233985a7e7a4126c5de62c8a554174495aea47320ae1d2b55b757ece62ac1cb8455532aa61fd123fe4e01d0567eb2d7adfa + languageName: node + linkType: hard + "es-module-lexer@npm:^1.2.1": version: 1.3.0 resolution: "es-module-lexer@npm:1.3.0" @@ -9616,17 +9635,17 @@ __metadata: linkType: hard "eslint-import-resolver-node@npm:^0.3.7": - version: 0.3.7 - resolution: "eslint-import-resolver-node@npm:0.3.7" + version: 0.3.9 + resolution: "eslint-import-resolver-node@npm:0.3.9" dependencies: debug: ^3.2.7 - is-core-module: ^2.11.0 - resolve: ^1.22.1 - checksum: 3379aacf1d2c6952c1b9666c6fa5982c3023df695430b0d391c0029f6403a7775414873d90f397e98ba6245372b6c8960e16e74d9e4a3b0c0a4582f3bdbe3d6e + is-core-module: ^2.13.0 + resolve: ^1.22.4 + checksum: 439b91271236b452d478d0522a44482e8c8540bf9df9bd744062ebb89ab45727a3acd03366a6ba2bdbcde8f9f718bab7fe8db64688aca75acf37e04eafd25e22 languageName: node linkType: hard -"eslint-module-utils@npm:^2.7.4, eslint-module-utils@npm:^2.8.0": +"eslint-module-utils@npm:^2.8.0": version: 2.8.0 resolution: "eslint-module-utils@npm:2.8.0" dependencies: @@ -9664,32 +9683,7 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-import@npm:^2.25.3": - version: 2.27.5 - resolution: "eslint-plugin-import@npm:2.27.5" - dependencies: - array-includes: ^3.1.6 - array.prototype.flat: ^1.3.1 - array.prototype.flatmap: ^1.3.1 - debug: ^3.2.7 - doctrine: ^2.1.0 - eslint-import-resolver-node: ^0.3.7 - eslint-module-utils: ^2.7.4 - has: ^1.0.3 - is-core-module: ^2.11.0 - is-glob: ^4.0.3 - minimatch: ^3.1.2 - object.values: ^1.1.6 - resolve: ^1.22.1 - semver: ^6.3.0 - tsconfig-paths: ^3.14.1 - peerDependencies: - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 - checksum: f500571a380167e25d72a4d925ef9a7aae8899eada57653e5f3051ec3d3c16d08271fcefe41a30a9a2f4fefc232f066253673ee4ea77b30dba65ae173dade85d - languageName: node - linkType: hard - -"eslint-plugin-import@npm:^2.28.1": +"eslint-plugin-import@npm:^2.25.3, eslint-plugin-import@npm:^2.28.1": version: 2.28.1 resolution: "eslint-plugin-import@npm:2.28.1" dependencies: @@ -9784,13 +9778,14 @@ __metadata: linkType: hard "eslint-plugin-react@npm:^7.27.1": - version: 7.32.2 - resolution: "eslint-plugin-react@npm:7.32.2" + version: 7.33.2 + resolution: "eslint-plugin-react@npm:7.33.2" dependencies: array-includes: ^3.1.6 array.prototype.flatmap: ^1.3.1 array.prototype.tosorted: ^1.1.1 doctrine: ^2.1.0 + es-iterator-helpers: ^1.0.12 estraverse: ^5.3.0 jsx-ast-utils: ^2.4.1 || ^3.0.0 minimatch: ^3.1.2 @@ -9800,22 +9795,22 @@ __metadata: object.values: ^1.1.6 prop-types: ^15.8.1 resolve: ^2.0.0-next.4 - semver: ^6.3.0 + semver: ^6.3.1 string.prototype.matchall: ^4.0.8 peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 - checksum: 2232b3b8945aa50b7773919c15cd96892acf35d2f82503667a79e2f55def90f728ed4f0e496f0f157acbe1bd4397c5615b676ae7428fe84488a544ca53feb944 + checksum: b4c3d76390b0ae6b6f9fed78170604cc2c04b48e6778a637db339e8e3911ec9ef22510b0ae77c429698151d0f1b245f282177f384105b6830e7b29b9c9b26610 languageName: node linkType: hard "eslint-plugin-testing-library@npm:^5.0.1": - version: 5.11.0 - resolution: "eslint-plugin-testing-library@npm:5.11.0" + version: 5.11.1 + resolution: "eslint-plugin-testing-library@npm:5.11.1" dependencies: "@typescript-eslint/utils": ^5.58.0 peerDependencies: eslint: ^7.5.0 || ^8.0.0 - checksum: 7f19d3dedd7788b411ca3d9045de682feb26025b9c26d97d4e2f0bf62f5eaa276147d946bd5d0cd967b822e546a954330fdb7ef80485301264f646143f011a02 + checksum: 9f3fc68ef9f13016a4381b33ab5dbffcc189e5de3eaeba184bcf7d2771faa7f54e59c04b652162fb1c0f83fb52428dd909db5450a25508b94be59eba69fcc990 languageName: node linkType: hard @@ -9829,120 +9824,54 @@ __metadata: languageName: node linkType: hard -"eslint-scope@npm:^7.2.0": - version: 7.2.0 - resolution: "eslint-scope@npm:7.2.0" - dependencies: - esrecurse: ^4.3.0 - estraverse: ^5.2.0 - checksum: 64591a2d8b244ade9c690b59ef238a11d5c721a98bcee9e9f445454f442d03d3e04eda88e95a4daec558220a99fa384309d9faae3d459bd40e7a81b4063980ae - languageName: node - linkType: hard - -"eslint-scope@npm:^7.2.2": - version: 7.2.2 - resolution: "eslint-scope@npm:7.2.2" - dependencies: - esrecurse: ^4.3.0 - estraverse: ^5.2.0 - checksum: ec97dbf5fb04b94e8f4c5a91a7f0a6dd3c55e46bfc7bbcd0e3138c3a76977570e02ed89a1810c778dcd72072ff0e9621ba1379b4babe53921d71e2e4486fda3e - languageName: node - linkType: hard - -"eslint-visitor-keys@npm:^2.1.0": - version: 2.1.0 - resolution: "eslint-visitor-keys@npm:2.1.0" - checksum: e3081d7dd2611a35f0388bbdc2f5da60b3a3c5b8b6e928daffff7391146b434d691577aa95064c8b7faad0b8a680266bcda0a42439c18c717b80e6718d7e267d - languageName: node - linkType: hard - -"eslint-visitor-keys@npm:^3.3.0, eslint-visitor-keys@npm:^3.4.1": - version: 3.4.1 - resolution: "eslint-visitor-keys@npm:3.4.1" - checksum: f05121d868202736b97de7d750847a328fcfa8593b031c95ea89425333db59676ac087fa905eba438d0a3c5769632f828187e0c1a0d271832a2153c1d3661c2c - languageName: node - linkType: hard - -"eslint-visitor-keys@npm:^3.4.3": - version: 3.4.3 - resolution: "eslint-visitor-keys@npm:3.4.3" - checksum: 36e9ef87fca698b6fd7ca5ca35d7b2b6eeaaf106572e2f7fd31c12d3bfdaccdb587bba6d3621067e5aece31c8c3a348b93922ab8f7b2cbc6aaab5e1d89040c60 - languageName: node - linkType: hard - -"eslint-webpack-plugin@npm:^3.1.1": - version: 3.2.0 - resolution: "eslint-webpack-plugin@npm:3.2.0" - dependencies: - "@types/eslint": ^7.29.0 || ^8.4.1 - jest-worker: ^28.0.2 - micromatch: ^4.0.5 - normalize-path: ^3.0.0 - schema-utils: ^4.0.0 - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 - webpack: ^5.0.0 - checksum: 095034c35e773fdb21ec7e597ae1f8a6899679c290db29d8568ca94619e8c7f4971f0f9edccc8a965322ab8af9286c87205985a38f4fdcf17654aee7cd8bb7b5 - languageName: node - linkType: hard - -"eslint@npm:^8.3.0": - version: 8.44.0 - resolution: "eslint@npm:8.44.0" - dependencies: - "@eslint-community/eslint-utils": ^4.2.0 - "@eslint-community/regexpp": ^4.4.0 - "@eslint/eslintrc": ^2.1.0 - "@eslint/js": 8.44.0 - "@humanwhocodes/config-array": ^0.11.10 - "@humanwhocodes/module-importer": ^1.0.1 - "@nodelib/fs.walk": ^1.2.8 - ajv: ^6.10.0 - chalk: ^4.0.0 - cross-spawn: ^7.0.2 - debug: ^4.3.2 - doctrine: ^3.0.0 - escape-string-regexp: ^4.0.0 - eslint-scope: ^7.2.0 - eslint-visitor-keys: ^3.4.1 - espree: ^9.6.0 - esquery: ^1.4.2 - esutils: ^2.0.2 - fast-deep-equal: ^3.1.3 - file-entry-cache: ^6.0.1 - find-up: ^5.0.0 - glob-parent: ^6.0.2 - globals: ^13.19.0 - graphemer: ^1.4.0 - ignore: ^5.2.0 - import-fresh: ^3.0.0 - imurmurhash: ^0.1.4 - is-glob: ^4.0.0 - is-path-inside: ^3.0.3 - js-yaml: ^4.1.0 - json-stable-stringify-without-jsonify: ^1.0.1 - levn: ^0.4.1 - lodash.merge: ^4.6.2 - minimatch: ^3.1.2 - natural-compare: ^1.4.0 - optionator: ^0.9.3 - strip-ansi: ^6.0.1 - strip-json-comments: ^3.1.0 - text-table: ^0.2.0 - bin: - eslint: bin/eslint.js - checksum: d06309ce4aafb9d27d558c8e5e5aa5cba3bbec3ce8ceccbc7d4b7a35f2b67fd40189159155553270e2e6febeb69bd8a3b60d6241c8f5ddc2ef1702ccbd328501 +"eslint-scope@npm:^7.2.2": + version: 7.2.2 + resolution: "eslint-scope@npm:7.2.2" + dependencies: + esrecurse: ^4.3.0 + estraverse: ^5.2.0 + checksum: ec97dbf5fb04b94e8f4c5a91a7f0a6dd3c55e46bfc7bbcd0e3138c3a76977570e02ed89a1810c778dcd72072ff0e9621ba1379b4babe53921d71e2e4486fda3e + languageName: node + linkType: hard + +"eslint-visitor-keys@npm:^2.1.0": + version: 2.1.0 + resolution: "eslint-visitor-keys@npm:2.1.0" + checksum: e3081d7dd2611a35f0388bbdc2f5da60b3a3c5b8b6e928daffff7391146b434d691577aa95064c8b7faad0b8a680266bcda0a42439c18c717b80e6718d7e267d + languageName: node + linkType: hard + +"eslint-visitor-keys@npm:^3.3.0, eslint-visitor-keys@npm:^3.4.1, eslint-visitor-keys@npm:^3.4.3": + version: 3.4.3 + resolution: "eslint-visitor-keys@npm:3.4.3" + checksum: 36e9ef87fca698b6fd7ca5ca35d7b2b6eeaaf106572e2f7fd31c12d3bfdaccdb587bba6d3621067e5aece31c8c3a348b93922ab8f7b2cbc6aaab5e1d89040c60 + languageName: node + linkType: hard + +"eslint-webpack-plugin@npm:^3.1.1": + version: 3.2.0 + resolution: "eslint-webpack-plugin@npm:3.2.0" + dependencies: + "@types/eslint": ^7.29.0 || ^8.4.1 + jest-worker: ^28.0.2 + micromatch: ^4.0.5 + normalize-path: ^3.0.0 + schema-utils: ^4.0.0 + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + webpack: ^5.0.0 + checksum: 095034c35e773fdb21ec7e597ae1f8a6899679c290db29d8568ca94619e8c7f4971f0f9edccc8a965322ab8af9286c87205985a38f4fdcf17654aee7cd8bb7b5 languageName: node linkType: hard -"eslint@npm:^8.47.0": - version: 8.47.0 - resolution: "eslint@npm:8.47.0" +"eslint@npm:^8.3.0, eslint@npm:^8.48.0": + version: 8.48.0 + resolution: "eslint@npm:8.48.0" dependencies: "@eslint-community/eslint-utils": ^4.2.0 "@eslint-community/regexpp": ^4.6.1 "@eslint/eslintrc": ^2.1.2 - "@eslint/js": ^8.47.0 + "@eslint/js": 8.48.0 "@humanwhocodes/config-array": ^0.11.10 "@humanwhocodes/module-importer": ^1.0.1 "@nodelib/fs.walk": ^1.2.8 @@ -9978,22 +9907,11 @@ __metadata: text-table: ^0.2.0 bin: eslint: bin/eslint.js - checksum: 1988617f703eadc5c7540468d54dc8e5171cf2bb9483f6172799cd1ff54a9a5e4470f003784e8cef92687eaa14de37172732787040e67817581a20bcb9c15970 - languageName: node - linkType: hard - -"espree@npm:^9.6.0": - version: 9.6.0 - resolution: "espree@npm:9.6.0" - dependencies: - acorn: ^8.9.0 - acorn-jsx: ^5.3.2 - eslint-visitor-keys: ^3.4.1 - checksum: 1287979510efb052a6a97c73067ea5d0a40701b29adde87bbe2d3eb1667e39ca55e8129e20e2517fed3da570150e7ef470585228459a8f3e3755f45007a1c662 + checksum: f20b359a4f8123fec5c033577368cc020d42978b1b45303974acd8da7a27063168ee3fe297ab5b35327162f6a93154063e3ce6577102f70f9809aff793db9bd0 languageName: node linkType: hard -"espree@npm:^9.6.1": +"espree@npm:^9.6.0, espree@npm:^9.6.1": version: 9.6.1 resolution: "espree@npm:9.6.1" dependencies: @@ -10218,6 +10136,18 @@ __metadata: languageName: node linkType: hard +"ethereum-cryptography@npm:^2.0.0, ethereum-cryptography@npm:^2.1.2": + version: 2.1.2 + resolution: "ethereum-cryptography@npm:2.1.2" + dependencies: + "@noble/curves": 1.1.0 + "@noble/hashes": 1.3.1 + "@scure/bip32": 1.3.1 + "@scure/bip39": 1.2.1 + checksum: 2e8f7b8cc90232ae838ab6a8167708e8362621404d26e79b5d9e762c7b53d699f7520aff358d9254de658fcd54d2d0af168ff909943259ed27dc4cef2736410c + languageName: node + linkType: hard + "ethereumjs-abi@npm:^0.6.8": version: 0.6.8 resolution: "ethereumjs-abi@npm:0.6.8" @@ -10243,7 +10173,7 @@ __metadata: languageName: node linkType: hard -"ethereumjs-util@npm:^7.1.0, ethereumjs-util@npm:^7.1.4, ethereumjs-util@npm:^7.1.5": +"ethereumjs-util@npm:^7.1.4, ethereumjs-util@npm:^7.1.5": version: 7.1.5 resolution: "ethereumjs-util@npm:7.1.5" dependencies: @@ -10512,15 +10442,15 @@ __metadata: linkType: hard "fast-glob@npm:^3.0.3, fast-glob@npm:^3.2.12, fast-glob@npm:^3.2.9": - version: 3.3.0 - resolution: "fast-glob@npm:3.3.0" + version: 3.3.1 + resolution: "fast-glob@npm:3.3.1" dependencies: "@nodelib/fs.stat": ^2.0.2 "@nodelib/fs.walk": ^1.2.3 glob-parent: ^5.1.2 merge2: ^1.3.0 micromatch: ^4.0.4 - checksum: 20df62be28eb5426fe8e40e0d05601a63b1daceb7c3d87534afcad91bdcf1e4b1743cf2d5247d6e225b120b46df0b9053a032b2691ba34ee121e033acd81f547 + checksum: b6f3add6403e02cf3a798bfbb1183d0f6da2afd368f27456010c0bc1f9640aea308243d4cb2c0ab142f618276e65ecb8be1661d7c62a7b4e5ba774b9ce5432e5 languageName: node linkType: hard @@ -10539,9 +10469,9 @@ __metadata: linkType: hard "fast-redact@npm:^3.0.0": - version: 3.2.0 - resolution: "fast-redact@npm:3.2.0" - checksum: 7305740bbc708b0c5662f46fc30ec910da519275574fea84f6df0bea0cfe6066ddf90c6c4b879642c509e692edf862edd22eaccb2a647db122eebe8259942888 + version: 3.3.0 + resolution: "fast-redact@npm:3.3.0" + checksum: 3f7becc70a5a2662a9cbfdc52a4291594f62ae998806ee00315af307f32d9559dbf512146259a22739ee34401950ef47598c1f4777d33b0ed5027203d67f549c languageName: node linkType: hard @@ -10730,12 +10660,13 @@ __metadata: linkType: hard "flat-cache@npm:^3.0.4": - version: 3.0.4 - resolution: "flat-cache@npm:3.0.4" + version: 3.1.0 + resolution: "flat-cache@npm:3.1.0" dependencies: - flatted: ^3.1.0 + flatted: ^3.2.7 + keyv: ^4.5.3 rimraf: ^3.0.2 - checksum: 4fdd10ecbcbf7d520f9040dd1340eb5dfe951e6f0ecf2252edeec03ee68d989ec8b9a20f4434270e71bcfd57800dc09b3344fca3966b2eb8f613072c7d9a2365 + checksum: 99312601d5b90f44aef403f17f056dc09be7e437703740b166cdc9386d99e681f74e6b6e8bd7d010bda66904ea643c9527276b1b80308a2119741d94108a4d8f languageName: node linkType: hard @@ -10759,7 +10690,7 @@ __metadata: languageName: node linkType: hard -"flatted@npm:^3.1.0": +"flatted@npm:^3.2.7": version: 3.2.7 resolution: "flatted@npm:3.2.7" checksum: 427633049d55bdb80201c68f7eb1cbd533e03eac541f97d3aecab8c5526f12a20ccecaeede08b57503e772c769e7f8680b37e8d482d1e5f8d7e2194687f9ea35 @@ -10908,9 +10839,9 @@ __metadata: linkType: hard "fraction.js@npm:^4.2.0": - version: 4.2.0 - resolution: "fraction.js@npm:4.2.0" - checksum: 8c76a6e21dedea87109d6171a0ac77afa14205794a565d71cb10d2925f629a3922da61bf45ea52dbc30bce4d8636dc0a27213a88cbd600eab047d82f9a3a94c5 + version: 4.2.1 + resolution: "fraction.js@npm:4.2.1" + checksum: 94cc9844bf1e3071734fa70c7410cf26c09636a0e95f956f2f90d839bf516d60f07bac6f33fbe018dbdbba7bda360794c0232810900475295415a164c3c9cf78 languageName: node linkType: hard @@ -10947,7 +10878,7 @@ __metadata: react-scripts: 5.0.1 typescript: ^5.2.2 typescript-plugin-css-modules: ^5.0.1 - viem: ^1.7.0 + viem: ^1.8.1 wagmi: ^1.3.10 languageName: unknown linkType: soft @@ -11020,11 +10951,11 @@ __metadata: linkType: hard "fs-minipass@npm:^3.0.0": - version: 3.0.2 - resolution: "fs-minipass@npm:3.0.2" + version: 3.0.3 + resolution: "fs-minipass@npm:3.0.3" dependencies: - minipass: ^5.0.0 - checksum: e9cc0e1f2d01c6f6f62f567aee59530aba65c6c7b2ae88c5027bc34c711ebcfcfaefd0caf254afa6adfe7d1fba16bc2537508a6235196bac7276747d078aef0a + minipass: ^7.0.3 + checksum: 8722a41109130851d979222d3ec88aabaceeaaf8f57b2a8f744ef8bd2d1ce95453b04a61daa0078822bc5cd21e008814f06fe6586f56fef511e71b8d2394d802 languageName: node linkType: hard @@ -11050,11 +10981,11 @@ __metadata: linkType: hard "fsevents@npm:^2.3.2, fsevents@npm:~2.3.2": - version: 2.3.2 - resolution: "fsevents@npm:2.3.2" + version: 2.3.3 + resolution: "fsevents@npm:2.3.3" dependencies: node-gyp: latest - checksum: 97ade64e75091afee5265e6956cb72ba34db7819b4c3e94c431d4be2b19b8bb7a2d4116da417950c3425f17c8fe693d25e20212cac583ac1521ad066b77ae31f + checksum: 11e6ea6fea15e42461fc55b4b0e4a0a3c654faa567f1877dbd353f39156f69def97a69936d1746619d656c4b93de2238bf731f6085a03a50cabf287c9d024317 conditions: os=darwin languageName: node linkType: hard @@ -11070,8 +11001,8 @@ __metadata: linkType: hard "fsevents@patch:fsevents@^2.3.2#~builtin, fsevents@patch:fsevents@~2.3.2#~builtin": - version: 2.3.2 - resolution: "fsevents@patch:fsevents@npm%3A2.3.2#~builtin::version=2.3.2&hash=df0bf1" + version: 2.3.3 + resolution: "fsevents@patch:fsevents@npm%3A2.3.3#~builtin::version=2.3.3&hash=df0bf1" dependencies: node-gyp: latest conditions: os=darwin @@ -11391,11 +11322,11 @@ __metadata: linkType: hard "globals@npm:^13.19.0": - version: 13.20.0 - resolution: "globals@npm:13.20.0" + version: 13.21.0 + resolution: "globals@npm:13.21.0" dependencies: type-fest: ^0.20.2 - checksum: ad1ecf914bd051325faad281d02ea2c0b1df5d01bd94d368dcc5513340eac41d14b3c61af325768e3c7f8d44576e72780ec0b6f2d366121f8eec6e03c3a3b97a + checksum: 86c92ca8a04efd864c10852cd9abb1ebe6d447dcc72936783e66eaba1087d7dba5c9c3421a48d6ca722c319378754dbcc3f3f732dbe47592d7de908edf58a773 languageName: node linkType: hard @@ -11485,11 +11416,11 @@ __metadata: linkType: hard "handlebars@npm:^4.0.1": - version: 4.7.7 - resolution: "handlebars@npm:4.7.7" + version: 4.7.8 + resolution: "handlebars@npm:4.7.8" dependencies: minimist: ^1.2.5 - neo-async: ^2.6.0 + neo-async: ^2.6.2 source-map: ^0.6.1 uglify-js: ^3.1.4 wordwrap: ^1.0.0 @@ -11498,7 +11429,7 @@ __metadata: optional: true bin: handlebars: bin/handlebars - checksum: 1e79a43f5e18d15742977cb987923eab3e2a8f44f2d9d340982bcb69e1735ed049226e534d7c1074eaddaf37e4fb4f471a8adb71cddd5bc8cf3f894241df5cee + checksum: 00e68bb5c183fd7b8b63322e6234b5ac8fbb960d712cb3f25587d559c2951d9642df83c04a1172c918c41bcfc81bfbd7a7718bbce93b893e0135fc99edea93ff languageName: node linkType: hard @@ -12119,13 +12050,13 @@ __metadata: linkType: hard "immutable@npm:^4.0.0, immutable@npm:^4.0.0-rc.12": - version: 4.3.1 - resolution: "immutable@npm:4.3.1" - checksum: a3a5ba29bd43f3f9a2e4d599763d7455d11a0ea57e50bf43f2836672fc80003e90d69f2a4f5b589f1f3d6986faf97f08ce1e253583740dd33c00adebab88b217 + version: 4.3.4 + resolution: "immutable@npm:4.3.4" + checksum: de3edd964c394bab83432429d3fb0b4816b42f56050f2ca913ba520bd3068ec3e504230d0800332d3abc478616e8f55d3787424a90d0952e6aba864524f1afc3 languageName: node linkType: hard -"import-fresh@npm:^3.0.0, import-fresh@npm:^3.1.0, import-fresh@npm:^3.2.1": +"import-fresh@npm:^3.1.0, import-fresh@npm:^3.2.1": version: 3.3.0 resolution: "import-fresh@npm:3.3.0" dependencies: @@ -12275,6 +12206,15 @@ __metadata: languageName: node linkType: hard +"is-async-function@npm:^2.0.0": + version: 2.0.0 + resolution: "is-async-function@npm:2.0.0" + dependencies: + has-tostringtag: ^1.0.0 + checksum: e3471d95e6c014bf37cad8a93f2f4b6aac962178e0a5041e8903147166964fdc1c5c1d2ef87e86d77322c370ca18f2ea004fa7420581fa747bcaf7c223069dbd + languageName: node + linkType: hard + "is-bigint@npm:^1.0.1": version: 1.0.4 resolution: "is-bigint@npm:1.0.4" @@ -12317,16 +12257,7 @@ __metadata: languageName: node linkType: hard -"is-core-module@npm:^2.11.0, is-core-module@npm:^2.12.0, is-core-module@npm:^2.9.0": - version: 2.12.1 - resolution: "is-core-module@npm:2.12.1" - dependencies: - has: ^1.0.3 - checksum: f04ea30533b5e62764e7b2e049d3157dc0abd95ef44275b32489ea2081176ac9746ffb1cdb107445cf1ff0e0dfcad522726ca27c27ece64dadf3795428b8e468 - languageName: node - linkType: hard - -"is-core-module@npm:^2.13.0": +"is-core-module@npm:^2.13.0, is-core-module@npm:^2.9.0": version: 2.13.0 resolution: "is-core-module@npm:2.13.0" dependencies: @@ -12360,6 +12291,15 @@ __metadata: languageName: node linkType: hard +"is-finalizationregistry@npm:^1.0.2": + version: 1.0.2 + resolution: "is-finalizationregistry@npm:1.0.2" + dependencies: + call-bind: ^1.0.2 + checksum: 4f243a8e06228cd45bdab8608d2cb7abfc20f6f0189c8ac21ea8d603f1f196eabd531ce0bb8e08cbab047e9845ef2c191a3761c9a17ad5cabf8b35499c4ad35d + languageName: node + linkType: hard + "is-finite@npm:^1.0.1": version: 1.1.0 resolution: "is-finite@npm:1.1.0" @@ -12388,7 +12328,7 @@ __metadata: languageName: node linkType: hard -"is-generator-function@npm:^1.0.7": +"is-generator-function@npm:^1.0.10, is-generator-function@npm:^1.0.7": version: 1.0.10 resolution: "is-generator-function@npm:1.0.10" dependencies: @@ -12558,15 +12498,11 @@ __metadata: linkType: hard "is-typed-array@npm:^1.1.10, is-typed-array@npm:^1.1.3, is-typed-array@npm:^1.1.9": - version: 1.1.10 - resolution: "is-typed-array@npm:1.1.10" + version: 1.1.12 + resolution: "is-typed-array@npm:1.1.12" dependencies: - available-typed-arrays: ^1.0.5 - call-bind: ^1.0.2 - for-each: ^0.3.3 - gopd: ^1.0.1 - has-tostringtag: ^1.0.0 - checksum: aac6ecb59d4c56a1cdeb69b1f129154ef462bbffe434cb8a8235ca89b42f258b7ae94073c41b3cb7bce37f6a1733ad4499f07882d5d5093a7ba84dfc4ebb8017 + which-typed-array: ^1.1.11 + checksum: 4c89c4a3be07186caddadf92197b17fda663a9d259ea0d44a85f171558270d36059d1c386d34a12cba22dfade5aba497ce22778e866adc9406098c8fc4771796 languageName: node linkType: hard @@ -12703,13 +12639,13 @@ __metadata: linkType: hard "istanbul-lib-report@npm:^3.0.0": - version: 3.0.0 - resolution: "istanbul-lib-report@npm:3.0.0" + version: 3.0.1 + resolution: "istanbul-lib-report@npm:3.0.1" dependencies: istanbul-lib-coverage: ^3.0.0 - make-dir: ^3.0.0 + make-dir: ^4.0.0 supports-color: ^7.1.0 - checksum: 3f29eb3f53c59b987386e07fe772d24c7f58c6897f34c9d7a296f4000de7ae3de9eb95c3de3df91dc65b134c84dee35c54eee572a56243e8907c48064e34ff1b + checksum: fd17a1b879e7faf9bb1dc8f80b2a16e9f5b7b8498fe6ed580a618c34df0bfe53d2abd35bf8a0a00e628fb7405462576427c7df20bbe4148d19c14b431c974b21 languageName: node linkType: hard @@ -12725,25 +12661,38 @@ __metadata: linkType: hard "istanbul-reports@npm:^3.1.3": - version: 3.1.5 - resolution: "istanbul-reports@npm:3.1.5" + version: 3.1.6 + resolution: "istanbul-reports@npm:3.1.6" dependencies: html-escaper: ^2.0.0 istanbul-lib-report: ^3.0.0 - checksum: 7867228f83ed39477b188ea07e7ccb9b4f5320b6f73d1db93a0981b7414fa4ef72d3f80c4692c442f90fc250d9406e71d8d7ab65bb615cb334e6292b73192b89 + checksum: 44c4c0582f287f02341e9720997f9e82c071627e1e862895745d5f52ec72c9b9f38e1d12370015d2a71dcead794f34c7732aaef3fab80a24bc617a21c3d911d6 + languageName: node + linkType: hard + +"iterator.prototype@npm:^1.1.0": + version: 1.1.0 + resolution: "iterator.prototype@npm:1.1.0" + dependencies: + define-properties: ^1.1.4 + get-intrinsic: ^1.1.3 + has-symbols: ^1.0.3 + has-tostringtag: ^1.0.0 + reflect.getprototypeof: ^1.0.3 + checksum: 462fe16c770affeb9c08620b13fc98d38307335821f4fabd489f491d38c79855c6a93d4b56f6146eaa56711f61690aa5c7eb0ce8586c95145d2f665a3834d916 languageName: node linkType: hard "jackspeak@npm:^2.0.3": - version: 2.2.1 - resolution: "jackspeak@npm:2.2.1" + version: 2.3.0 + resolution: "jackspeak@npm:2.3.0" dependencies: "@isaacs/cliui": ^8.0.2 "@pkgjs/parseargs": ^0.11.0 dependenciesMeta: "@pkgjs/parseargs": optional: true - checksum: e29291c0d0f280a063fa18fbd1e891ab8c2d7519fd34052c0ebde38538a15c603140d60c2c7f432375ff7ee4c5f1c10daa8b2ae19a97c3d4affe308c8360c1df + checksum: 71bf716f4b5793226d4aeb9761ebf2605ee093b59f91a61451d57d998dd64bbf2b54323fb749b8b2ae8b6d8a463de4f6e3fedab50108671f247bbc80195a6306 languageName: node linkType: hard @@ -13366,18 +13315,18 @@ __metadata: linkType: hard "jiti@npm:^1.18.2": - version: 1.19.1 - resolution: "jiti@npm:1.19.1" + version: 1.19.3 + resolution: "jiti@npm:1.19.3" bin: jiti: bin/jiti.js - checksum: fdf55e315f9e81c04ae902416642062851d92c6cdcc17a59d5d1d35e1a0842e4e79be38da86613c5776fa18c579954542a441b93d1c347a50137dee2e558cbd0 + checksum: de3dacdfe30948d96b69712b04cc28127c17f43d5233a5aa069933e04ac4c9aaf265bef4cdf2b0c2a6f5af236a58aea9bfea83e8e289e2490802bdff7f99bff7 languageName: node linkType: hard "js-sdsl@npm:^4.1.4": - version: 4.4.1 - resolution: "js-sdsl@npm:4.4.1" - checksum: ba445b53531f2f353f8f66ed8c7edc7942c9bac68707161aa70528fa8ee9a89805d170cff171aa40bdac1aed5dfe97dce6f929e6f759a487ed619387a5ea1365 + version: 4.4.2 + resolution: "js-sdsl@npm:4.4.2" + checksum: ba705adc1788bf3c6f6c8e5077824f2bb4f0acab5a984420ce5cc492c7fff3daddc26335ad2c9a67d4f5e3241ec790f9e5b72a625adcf20cf321d2fd85e62b8b languageName: node linkType: hard @@ -13502,6 +13451,13 @@ __metadata: languageName: node linkType: hard +"json-buffer@npm:3.0.1": + version: 3.0.1 + resolution: "json-buffer@npm:3.0.1" + checksum: 9026b03edc2847eefa2e37646c579300a1f3a4586cfb62bf857832b60c852042d0d6ae55d1afb8926163fa54c2b01d83ae24705f34990348bdac6273a29d4581 + languageName: node + linkType: hard + "json-parse-even-better-errors@npm:^2.3.0, json-parse-even-better-errors@npm:^2.3.1": version: 2.3.1 resolution: "json-parse-even-better-errors@npm:2.3.1" @@ -13572,7 +13528,7 @@ __metadata: languageName: node linkType: hard -"json5@npm:^2.1.2, json5@npm:^2.2.0, json5@npm:^2.2.2": +"json5@npm:^2.1.2, json5@npm:^2.2.0, json5@npm:^2.2.2, json5@npm:^2.2.3": version: 2.2.3 resolution: "json5@npm:2.2.3" bin: @@ -13652,14 +13608,14 @@ __metadata: linkType: hard "jsx-ast-utils@npm:^2.4.1 || ^3.0.0, jsx-ast-utils@npm:^3.3.3": - version: 3.3.4 - resolution: "jsx-ast-utils@npm:3.3.4" + version: 3.3.5 + resolution: "jsx-ast-utils@npm:3.3.5" dependencies: array-includes: ^3.1.6 array.prototype.flat: ^1.3.1 object.assign: ^4.1.4 object.values: ^1.1.6 - checksum: a6a00d324e38f0d47e04f973d79670248a663422a4dccdc02efd6f1caf1c00042fb0aafcff1023707c85dea6f013d435b90db67c1c6841bf345628f0a720d8b3 + checksum: f4b05fa4d7b5234230c905cfa88d36dc8a58a6666975a3891429b1a8cdc8a140bca76c297225cb7a499fad25a2c052ac93934449a2c31a44fc9edd06c773780a languageName: node linkType: hard @@ -13675,6 +13631,15 @@ __metadata: languageName: node linkType: hard +"keyv@npm:^4.5.3": + version: 4.5.3 + resolution: "keyv@npm:4.5.3" + dependencies: + json-buffer: 3.0.1 + checksum: 3ffb4d5b72b6b4b4af443bbb75ca2526b23c750fccb5ac4c267c6116888b4b65681015c2833cb20d26cf3e6e32dac6b988c77f7f022e1a571b7d90f1442257da + languageName: node + linkType: hard + "keyvaluestorage-interface@npm:^1.0.0": version: 1.0.0 resolution: "keyvaluestorage-interface@npm:1.0.0" @@ -13742,8 +13707,8 @@ __metadata: linkType: hard "less@npm:^4.1.3": - version: 4.1.3 - resolution: "less@npm:4.1.3" + version: 4.2.0 + resolution: "less@npm:4.2.0" dependencies: copy-anything: ^2.0.1 errno: ^0.1.1 @@ -13772,7 +13737,7 @@ __metadata: optional: true bin: lessc: bin/lessc - checksum: 1470fbec993a375eb28d729cd906805fd62b7a7f1b4f5b4d62d04e81eaba987a9373e74aa0b9fa9191149ebc0bfb42e2ea98a038555555b7b241c10a854067cc + checksum: 2ec4fa41e35e5c0331c1ee64419aa5c2cbb9a17b9e9d1deb524ec45843f59d9c4612dffc164ca16126911fbe9913e4ff811a13f33805f71e546f6d022ece93b6 languageName: node linkType: hard @@ -13845,22 +13810,22 @@ __metadata: linkType: hard "lit-element@npm:^3.3.0": - version: 3.3.2 - resolution: "lit-element@npm:3.3.2" + version: 3.3.3 + resolution: "lit-element@npm:3.3.3" dependencies: "@lit-labs/ssr-dom-shim": ^1.1.0 "@lit/reactive-element": ^1.3.0 - lit-html: ^2.7.0 - checksum: afe50825be05a8c83be418432dfed2f9a84ca1c6c1d1807e2090def9f94cc403dcbf832b338cdfe39cd168518664c02a6c7392868ca323e356e5744e3b4f45e6 + lit-html: ^2.8.0 + checksum: 29a596fa556e231cce7246ca3e5687ad238f299b0cb374a0934d5e6fe9adf1436e031d4fbd21b280aabfc0e21a66e6c4b52da558a908df2566d09d960f3ca93d languageName: node linkType: hard -"lit-html@npm:^2.7.0": - version: 2.7.5 - resolution: "lit-html@npm:2.7.5" +"lit-html@npm:^2.7.0, lit-html@npm:^2.8.0": + version: 2.8.0 + resolution: "lit-html@npm:2.8.0" dependencies: "@types/trusted-types": ^2.0.2 - checksum: 7a54399f78c02f21ee5584fd9ff21b3edad8416df0aca22964bc5b221f0b57ba74d7bd98ad076acea2403b53b2ea87cc3eb47ba8395f371a645e3d584f2c1e49 + checksum: 2d70df07248bcb2f502a3afb1e91d260735024fa669669ffb1417575aa39c3092779725ac1b90f5f39e4ce78c63f431f51176bc67f532389f0285a6991573255 languageName: node linkType: hard @@ -14093,9 +14058,9 @@ __metadata: linkType: hard "lru-cache@npm:^9.1.1 || ^10.0.0": - version: 10.0.0 - resolution: "lru-cache@npm:10.0.0" - checksum: 18f101675fe283bc09cda0ef1e3cc83781aeb8373b439f086f758d1d91b28730950db785999cd060d3c825a8571c03073e8c14512b6655af2188d623031baf50 + version: 10.0.1 + resolution: "lru-cache@npm:10.0.1" + checksum: 06f8d0e1ceabd76bb6f644a26dbb0b4c471b79c7b514c13c6856113879b3bf369eb7b497dad4ff2b7e2636db202412394865b33c332100876d838ad1372f0181 languageName: node linkType: hard @@ -14125,7 +14090,7 @@ __metadata: languageName: node linkType: hard -"make-dir@npm:^3.0.0, make-dir@npm:^3.0.2, make-dir@npm:^3.1.0": +"make-dir@npm:^3.0.2, make-dir@npm:^3.1.0": version: 3.1.0 resolution: "make-dir@npm:3.1.0" dependencies: @@ -14134,6 +14099,15 @@ __metadata: languageName: node linkType: hard +"make-dir@npm:^4.0.0": + version: 4.0.0 + resolution: "make-dir@npm:4.0.0" + dependencies: + semver: ^7.5.3 + checksum: bf0731a2dd3aab4db6f3de1585cea0b746bb73eb5a02e3d8d72757e376e64e6ada190b1eddcde5b2f24a81b688a9897efd5018737d05e02e2a671dda9cff8a8a + languageName: node + linkType: hard + "make-error@npm:^1.1.1": version: 1.3.6 resolution: "make-error@npm:1.3.6" @@ -14244,12 +14218,12 @@ __metadata: "@typechain/hardhat": ^9.0.0 "@types/chai": ^4.3.5 "@types/mocha": ^10.0.1 - "@types/node": ^18.17.11 + "@types/node": ^18.17.12 "@typescript-eslint/eslint-plugin": ^5.62.0 "@typescript-eslint/parser": ^5.62.0 chai: ^4.3.8 dotenv: ^16.3.1 - eslint: ^8.47.0 + eslint: ^8.48.0 eslint-config-prettier: ^8.10.0 eslint-plugin-eslint-comments: ^3.2.0 eslint-plugin-import: ^2.28.1 @@ -14277,11 +14251,11 @@ __metadata: "@openzeppelin/contracts": ^4.9.3 "@safe-global/safe-core-sdk": ^3.3.5 "@types/chai": ^4.3.5 - "@types/node": ^18.17.11 + "@types/node": ^18.17.12 ethers: ^6.7.1 rimraf: ^4.4.1 typescript: ^5.2.2 - viem: ^1.7.0 + viem: ^1.8.1 languageName: unknown linkType: soft @@ -14347,6 +14321,13 @@ __metadata: languageName: node linkType: hard +"micro-ftch@npm:^0.3.1": + version: 0.3.1 + resolution: "micro-ftch@npm:0.3.1" + checksum: 0e496547253a36e98a83fb00c628c53c3fb540fa5aaeaf718438873785afd193244988c09d219bb1802984ff227d04938d9571ef90fe82b48bd282262586aaff + languageName: node + linkType: hard + "micromatch@npm:^4.0.2, micromatch@npm:^4.0.4, micromatch@npm:^4.0.5": version: 4.0.5 resolution: "micromatch@npm:4.0.5" @@ -14485,17 +14466,17 @@ __metadata: linkType: hard "minipass-fetch@npm:^3.0.0": - version: 3.0.3 - resolution: "minipass-fetch@npm:3.0.3" + version: 3.0.4 + resolution: "minipass-fetch@npm:3.0.4" dependencies: encoding: ^0.1.13 - minipass: ^5.0.0 + minipass: ^7.0.3 minipass-sized: ^1.0.3 minizlib: ^2.1.2 dependenciesMeta: encoding: optional: true - checksum: af5ab2552a16fcf505d35fd7ffb84b57f4a0eeb269e6e1d9a2a75824dda48b36e527083250b7cca4a4def21d9544e2ade441e4730e233c0bc2133f6abda31e18 + checksum: af7aad15d5c128ab1ebe52e043bdf7d62c3c6f0cecb9285b40d7b395e1375b45dcdfd40e63e93d26a0e8249c9efd5c325c65575aceee192883970ff8cb11364a languageName: node linkType: hard @@ -14549,10 +14530,10 @@ __metadata: languageName: node linkType: hard -"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0": - version: 7.0.2 - resolution: "minipass@npm:7.0.2" - checksum: 46776de732eb7cef2c7404a15fb28c41f5c54a22be50d47b03c605bf21f5c18d61a173c0a20b49a97e7a65f78d887245066410642551e45fffe04e9ac9e325bc +"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.3": + version: 7.0.3 + resolution: "minipass@npm:7.0.3" + checksum: 6f1614f5b5b55568a46bca5fec0e7c46dac027691db27d0e1923a8192866903144cd962ac772c0e9f89b608ea818b702709c042bce98e190d258847d85461531 languageName: node linkType: hard @@ -14857,7 +14838,7 @@ __metadata: languageName: node linkType: hard -"neo-async@npm:^2.6.0, neo-async@npm:^2.6.2": +"neo-async@npm:^2.6.2": version: 2.6.2 resolution: "neo-async@npm:2.6.2" checksum: deac9f8d00eda7b2e5cd1b2549e26e10a0faa70adaa6fdadca701cc55f49ee9018e427f424bac0c790b7c7e2d3068db97f3093f1093975f2acb8f8818b936ed9 @@ -14909,9 +14890,9 @@ __metadata: languageName: node linkType: hard -"node-fetch@npm:^2.6.1, node-fetch@npm:^2.6.11, node-fetch@npm:^2.6.12": - version: 2.6.12 - resolution: "node-fetch@npm:2.6.12" +"node-fetch@npm:^2.6.1, node-fetch@npm:^2.6.12": + version: 2.7.0 + resolution: "node-fetch@npm:2.7.0" dependencies: whatwg-url: ^5.0.0 peerDependencies: @@ -14919,7 +14900,7 @@ __metadata: peerDependenciesMeta: encoding: optional: true - checksum: 3bc1655203d47ee8e313c0d96664b9673a3d4dd8002740318e9d27d14ef306693a4b2ef8d6525775056fd912a19e23f3ac0d7111ad8925877b7567b29a625592 + checksum: d76d2f5edb451a3f05b15115ec89fc6be39de37c6089f1b6368df03b91e1633fd379a7e01b7ab05089a25034b2023d959b47e59759cb38d88341b2459e89d6e5 languageName: node linkType: hard @@ -14931,13 +14912,13 @@ __metadata: linkType: hard "node-gyp-build@npm:^4.2.0, node-gyp-build@npm:^4.3.0": - version: 4.6.0 - resolution: "node-gyp-build@npm:4.6.0" + version: 4.6.1 + resolution: "node-gyp-build@npm:4.6.1" bin: node-gyp-build: bin.js node-gyp-build-optional: optional.js node-gyp-build-test: build-test.js - checksum: 25d78c5ef1f8c24291f4a370c47ba52fcea14f39272041a90a7894cd50d766f7c8cb8fb06c0f42bf6f69b204b49d9be3c8fc344aac09714d5bdb95965499eb15 + checksum: c3676d337b36803bc7792e35bf7fdcda7cdcb7e289b8f9855a5535702a82498eb976842fefcf487258c58005ca32ce3d537fbed91280b04409161dcd7232a882 languageName: node linkType: hard @@ -14969,7 +14950,7 @@ __metadata: languageName: node linkType: hard -"node-releases@npm:^2.0.12": +"node-releases@npm:^2.0.13": version: 2.0.13 resolution: "node-releases@npm:2.0.13" checksum: 17ec8f315dba62710cae71a8dad3cd0288ba943d2ece43504b3b1aa8625bf138637798ab470b1d9035b0545996f63000a8a926e0f6d35d0996424f8b6d36dda3 @@ -15152,13 +15133,13 @@ __metadata: linkType: hard "object.entries@npm:^1.1.6": - version: 1.1.6 - resolution: "object.entries@npm:1.1.6" + version: 1.1.7 + resolution: "object.entries@npm:1.1.7" dependencies: call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 - checksum: 0f8c47517e6a9a980241eafe3b73de11e59511883173c2b93d67424a008e47e11b77c80e431ad1d8a806f6108b225a1cab9223e53e555776c612a24297117d28 + define-properties: ^1.2.0 + es-abstract: ^1.22.1 + checksum: da287d434e7e32989586cd734382364ba826a2527f2bc82e6acbf9f9bfafa35d51018b66ec02543ffdfa2a5ba4af2b6f1ca6e588c65030cb4fd9c67d6ced594c languageName: node linkType: hard @@ -15209,13 +15190,13 @@ __metadata: linkType: hard "object.values@npm:^1.1.0, object.values@npm:^1.1.6": - version: 1.1.6 - resolution: "object.values@npm:1.1.6" + version: 1.1.7 + resolution: "object.values@npm:1.1.7" dependencies: call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 - checksum: f6fff9fd817c24cfd8107f50fb33061d81cd11bacc4e3dbb3852e9ff7692fde4dbce823d4333ea27cd9637ef1b6690df5fbb61f1ed314fa2959598dc3ae23d8e + define-properties: ^1.2.0 + es-abstract: ^1.22.1 + checksum: f3e4ae4f21eb1cc7cebb6ce036d4c67b36e1c750428d7b7623c56a0db90edced63d08af8a316d81dfb7c41a3a5fa81b05b7cc9426e98d7da986b1682460f0777 languageName: node linkType: hard @@ -16576,20 +16557,20 @@ __metadata: linkType: hard "postcss@npm:^8.0.0, postcss@npm:^8.3.5, postcss@npm:^8.4.21, postcss@npm:^8.4.23, postcss@npm:^8.4.4": - version: 8.4.25 - resolution: "postcss@npm:8.4.25" + version: 8.4.28 + resolution: "postcss@npm:8.4.28" dependencies: nanoid: ^3.3.6 picocolors: ^1.0.0 source-map-js: ^1.0.2 - checksum: 9ed3ab8af43ad5210c28f56f916fd9b8c9f94fbeaebbf645dcf579bc28bdd8056c2a7ecc934668d399b81fedb6128f0c4b299f931e50454964bc911c25a3a0a2 + checksum: f605c24a36f7e400bad379735fbfc893ccb8d293ad6d419bb824db77cdcb69f43d614ef35f9f7091f32ca588d130ec60dbcf53b366e6bf88a8a64bbeb3c05f6d languageName: node linkType: hard "preact@npm:^10.12.0, preact@npm:^10.5.9": - version: 10.16.0 - resolution: "preact@npm:10.16.0" - checksum: 47a91f47d583b68a4afe971a7f992c06547df6d637cadf56eb3b69fee1fb202659b199af37d0e1a90637385144cadd75aa40acdb4e125cc4b3155e2883c24c07 + version: 10.17.1 + resolution: "preact@npm:10.17.1" + checksum: d25193272d2d2e58beb5dea7c0a715090a942d437638e39977b92f5729eb8d8a3410393f6f73799c850953e679ca79cf7a285dca31f34c492ff62df2f27643bf languageName: node linkType: hard @@ -17251,6 +17232,20 @@ __metadata: languageName: node linkType: hard +"reflect.getprototypeof@npm:^1.0.3": + version: 1.0.3 + resolution: "reflect.getprototypeof@npm:1.0.3" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.1.4 + es-abstract: ^1.20.4 + get-intrinsic: ^1.1.1 + globalthis: ^1.0.3 + which-builtin-type: ^1.1.3 + checksum: 843e2506c013da66f83635f943c5bd41243bc6c7703298531cfb16eb6baaefd92f83031fa37140ad31c4edc86938b6eb385e6fc85bf1628e79348ed49e044f3d + languageName: node + linkType: hard + "regenerate-unicode-properties@npm:^10.1.0": version: 10.1.0 resolution: "regenerate-unicode-properties@npm:10.1.0" @@ -17267,19 +17262,26 @@ __metadata: languageName: node linkType: hard -"regenerator-runtime@npm:^0.13.11, regenerator-runtime@npm:^0.13.9": +"regenerator-runtime@npm:^0.13.9": version: 0.13.11 resolution: "regenerator-runtime@npm:0.13.11" checksum: 27481628d22a1c4e3ff551096a683b424242a216fee44685467307f14d58020af1e19660bf2e26064de946bad7eff28950eae9f8209d55723e2d9351e632bbb4 languageName: node linkType: hard -"regenerator-transform@npm:^0.15.1": - version: 0.15.1 - resolution: "regenerator-transform@npm:0.15.1" +"regenerator-runtime@npm:^0.14.0": + version: 0.14.0 + resolution: "regenerator-runtime@npm:0.14.0" + checksum: 1c977ad82a82a4412e4f639d65d22be376d3ebdd30da2c003eeafdaaacd03fc00c2320f18120007ee700900979284fc78a9f00da7fb593f6e6eeebc673fba9a3 + languageName: node + linkType: hard + +"regenerator-transform@npm:^0.15.2": + version: 0.15.2 + resolution: "regenerator-transform@npm:0.15.2" dependencies: "@babel/runtime": ^7.8.4 - checksum: 2d15bdeadbbfb1d12c93f5775493d85874dbe1d405bec323da5c61ec6e701bc9eea36167483e1a5e752de9b2df59ab9a2dfff6bf3784f2b28af2279a673d29a4 + checksum: 20b6f9377d65954980fe044cfdd160de98df415b4bff38fbade67b3337efaf078308c4fed943067cd759827cc8cfeca9cb28ccda1f08333b85d6a2acbd022c27 languageName: node linkType: hard @@ -17532,16 +17534,16 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.1.6, resolve@npm:^1.1.7, resolve@npm:^1.14.2, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.1, resolve@npm:^1.22.2": - version: 1.22.3 - resolution: "resolve@npm:1.22.3" +"resolve@npm:^1.1.6, resolve@npm:^1.1.7, resolve@npm:^1.14.2, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.22.2, resolve@npm:^1.22.4": + version: 1.22.4 + resolution: "resolve@npm:1.22.4" dependencies: - is-core-module: ^2.12.0 + is-core-module: ^2.13.0 path-parse: ^1.0.7 supports-preserve-symlinks-flag: ^1.0.0 bin: resolve: bin/resolve - checksum: fb834b81348428cb545ff1b828a72ea28feb5a97c026a1cf40aa1008352c72811ff4d4e71f2035273dc536dcfcae20c13604ba6283c612d70fa0b6e44519c374 + checksum: 23f25174c2736ce24c6d918910e0d1f89b6b38fefa07a995dff864acd7863d59a7f049e691f93b4b2ee29696303390d921552b6d1b841ed4a8101f517e1d0124 languageName: node linkType: hard @@ -17574,16 +17576,16 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@^1.1.6#~builtin, resolve@patch:resolve@^1.1.7#~builtin, resolve@patch:resolve@^1.14.2#~builtin, resolve@patch:resolve@^1.19.0#~builtin, resolve@patch:resolve@^1.20.0#~builtin, resolve@patch:resolve@^1.22.1#~builtin, resolve@patch:resolve@^1.22.2#~builtin": - version: 1.22.3 - resolution: "resolve@patch:resolve@npm%3A1.22.3#~builtin::version=1.22.3&hash=c3c19d" +"resolve@patch:resolve@^1.1.6#~builtin, resolve@patch:resolve@^1.1.7#~builtin, resolve@patch:resolve@^1.14.2#~builtin, resolve@patch:resolve@^1.19.0#~builtin, resolve@patch:resolve@^1.20.0#~builtin, resolve@patch:resolve@^1.22.2#~builtin, resolve@patch:resolve@^1.22.4#~builtin": + version: 1.22.4 + resolution: "resolve@patch:resolve@npm%3A1.22.4#~builtin::version=1.22.4&hash=c3c19d" dependencies: - is-core-module: ^2.12.0 + is-core-module: ^2.13.0 path-parse: ^1.0.7 supports-preserve-symlinks-flag: ^1.0.0 bin: resolve: bin/resolve - checksum: ad59734723b596d0891321c951592ed9015a77ce84907f89c9d9307dd0c06e11a67906a3e628c4cae143d3e44898603478af0ddeb2bba3f229a9373efe342665 + checksum: c45f2545fdc4d21883861b032789e20aa67a2f2692f68da320cc84d5724cd02f2923766c5354b3210897e88f1a7b3d6d2c7c22faeead8eed7078e4c783a444bc languageName: node linkType: hard @@ -17600,15 +17602,6 @@ __metadata: languageName: node linkType: hard -"resumer@npm:^0.0.0": - version: 0.0.0 - resolution: "resumer@npm:0.0.0" - dependencies: - through: ~2.3.4 - checksum: 21b1c257aac24840643fae9bc99ca6447a71a0039e7c6dcf64d0ead447ce511eff158d529f1b6258ad12668e66ee3e49ff14932d2b88a3bd578f483e79708104 - languageName: node - linkType: hard - "retry@npm:^0.12.0": version: 0.12.0 resolution: "retry@npm:0.12.0" @@ -17713,8 +17706,8 @@ __metadata: linkType: hard "rpc-websockets@npm:^7.5.1": - version: 7.5.1 - resolution: "rpc-websockets@npm:7.5.1" + version: 7.6.0 + resolution: "rpc-websockets@npm:7.6.0" dependencies: "@babel/runtime": ^7.17.2 bufferutil: ^4.0.1 @@ -17727,7 +17720,7 @@ __metadata: optional: true utf-8-validate: optional: true - checksum: 9dda8c63a1d3e85e11597e1c364835ec6aa9a8de1b5cfb1629d0eafc3ae04509011d485025ed4f717c0b1dd048e2aafdd75080e866540b93e55fd8a2cd91bcfe + checksum: af2b254f65985610bd354e8e13de07b5a36010b94672b0b5a9d226b9bb1b8b17d01c63221cad97263845888f3610e55867a32e4c0017dfb92fddf89417c4cb6c languageName: node linkType: hard @@ -17856,15 +17849,15 @@ __metadata: linkType: hard "sass@npm:^1.58.3": - version: 1.63.6 - resolution: "sass@npm:1.63.6" + version: 1.66.1 + resolution: "sass@npm:1.66.1" dependencies: chokidar: ">=3.0.0 <4.0.0" immutable: ^4.0.0 source-map-js: ">=0.6.2 <2.0.0" bin: sass: sass.js - checksum: 3372319904658eeafaf78a09a6fcb3368a68e6d76fe3c43c2d009f4f72e475ab22b82ef483ef5c00fcda3ab00066846c0bd88c36b42771b855f6ab80c7eda541 + checksum: 74fc11d0fcd5e16c5331b57dd59865705a299c64e89f2b99646869caeb011dc8d0b6144a6c74a90c264e9ef70654207dbf44fc9b7e3393f8bd14809b904c8a52 languageName: node linkType: hard @@ -18022,7 +18015,7 @@ __metadata: languageName: node linkType: hard -"semver@npm:^7.3.2, semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.3.8": +"semver@npm:^7.3.2, semver@npm:^7.3.4, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.3.8, semver@npm:^7.5.3": version: 7.5.4 resolution: "semver@npm:7.5.4" dependencies: @@ -18220,9 +18213,9 @@ __metadata: linkType: hard "signal-exit@npm:^4.0.1": - version: 4.0.2 - resolution: "signal-exit@npm:4.0.2" - checksum: 41f5928431cc6e91087bf0343db786a6313dd7c6fd7e551dbc141c95bb5fb26663444fd9df8ea47c5d7fc202f60aa7468c3162a9365cbb0615fc5e1b1328fe31 + version: 4.1.0 + resolution: "signal-exit@npm:4.1.0" + checksum: 64c757b498cb8629ffa5f75485340594d2f8189e9b08700e69199069c8e3070fb3e255f7ab873c05dc0b3cec412aea7402e10a5990cb6a050bd33ba062a6c549 languageName: node linkType: hard @@ -18519,11 +18512,11 @@ __metadata: linkType: hard "ssri@npm:^10.0.0": - version: 10.0.4 - resolution: "ssri@npm:10.0.4" + version: 10.0.5 + resolution: "ssri@npm:10.0.5" dependencies: - minipass: ^5.0.0 - checksum: fb14da9f8a72b04eab163eb13a9dda11d5962cd2317f85457c4e0b575e9a6e0e3a6a87b5bf122c75cb36565830cd5f263fb457571bf6f1587eb5f95d095d6165 + minipass: ^7.0.3 + checksum: 0a31b65f21872dea1ed3f7c200d7bc1c1b91c15e419deca14f282508ba917cbb342c08a6814c7f68ca4ca4116dd1a85da2bbf39227480e50125a1ceffeecb750 languageName: node linkType: hard @@ -18873,7 +18866,7 @@ __metadata: languageName: node linkType: hard -"strip-json-comments@npm:3.1.1, strip-json-comments@npm:^3.1.0, strip-json-comments@npm:^3.1.1": +"strip-json-comments@npm:3.1.1, strip-json-comments@npm:^3.1.1": version: 3.1.1 resolution: "strip-json-comments@npm:3.1.1" checksum: 492f73e27268f9b1c122733f28ecb0e7e8d8a531a6662efbd08e22cccb3f9475e90a1b82cab06a392f6afae6d2de636f977e231296400d0ec5304ba70f166443 @@ -18917,8 +18910,8 @@ __metadata: linkType: hard "sucrase@npm:^3.32.0": - version: 3.32.0 - resolution: "sucrase@npm:3.32.0" + version: 3.34.0 + resolution: "sucrase@npm:3.34.0" dependencies: "@jridgewell/gen-mapping": ^0.3.2 commander: ^4.0.0 @@ -18930,7 +18923,7 @@ __metadata: bin: sucrase: bin/sucrase sucrase-node: bin/sucrase-node - checksum: 79f760aef513adcf22b882d43100296a8afa7f307acef3e8803304b763484cf138a3e2cebc498a6791110ab20c7b8deba097f6ce82f812ca8f1723e3440e5c95 + checksum: 61860063bdf6103413698e13247a3074d25843e91170825a9752e4af7668ffadd331b6e99e92fc32ee5b3c484ee134936f926fa9039d5711fafff29d017a2110 languageName: node linkType: hard @@ -19117,8 +19110,8 @@ __metadata: linkType: hard "tailwindcss@npm:^3.0.2": - version: 3.3.2 - resolution: "tailwindcss@npm:3.3.2" + version: 3.3.3 + resolution: "tailwindcss@npm:3.3.3" dependencies: "@alloc/quick-lru": ^5.2.0 arg: ^5.0.2 @@ -19140,13 +19133,12 @@ __metadata: postcss-load-config: ^4.0.1 postcss-nested: ^6.0.1 postcss-selector-parser: ^6.0.11 - postcss-value-parser: ^4.2.0 resolve: ^1.22.2 sucrase: ^3.32.0 bin: tailwind: lib/cli.js tailwindcss: lib/cli.js - checksum: 4897c70e671c885e151f57434d87ccb806f468a11900f028245b351ffbca5245ff0c10ca5dbb6eb4c7c4df3de8a15a05fe08c2aea4b152cb07bee9bb1d8a14a8 + checksum: 0195c7a3ebb0de5e391d2a883d777c78a4749f0c532d204ee8aea9129f2ed8e701d8c0c276aa5f7338d07176a3c2a7682c1d0ab9c8a6c2abe6d9325c2954eb50 languageName: node linkType: hard @@ -19198,9 +19190,11 @@ __metadata: linkType: hard "tape@npm:^5.5.3": - version: 5.6.5 - resolution: "tape@npm:5.6.5" + version: 5.6.6 + resolution: "tape@npm:5.6.6" dependencies: + "@ljharb/resumer": ^0.0.1 + "@ljharb/through": ^2.3.9 array.prototype.every: ^1.1.4 call-bind: ^1.0.2 deep-equal: ^2.2.2 @@ -19219,12 +19213,10 @@ __metadata: object-keys: ^1.1.1 object.assign: ^4.1.4 resolve: ^2.0.0-next.4 - resumer: ^0.0.0 string.prototype.trim: ^1.2.7 - through: ^2.3.8 bin: tape: bin/tape - checksum: 36663b4c91b548b26104a7b6c5344394416cd3daa74eff068a6fb34ad37b94163f93d36a82b804c2c9544b12b5591c72738d589098e06bcb1bc2cb7cbd09e00b + checksum: aac4722c7104f8478c8079aa1f441636b720f432074355c2edb1b0c0e2f2822004af2097669186d65ce7c70c57164d85d7da3662338e53515bdb778f5412af30 languageName: node linkType: hard @@ -19294,8 +19286,8 @@ __metadata: linkType: hard "terser@npm:^5.0.0, terser@npm:^5.10.0, terser@npm:^5.16.8": - version: 5.19.0 - resolution: "terser@npm:5.19.0" + version: 5.19.2 + resolution: "terser@npm:5.19.2" dependencies: "@jridgewell/source-map": ^0.3.3 acorn: ^8.8.2 @@ -19303,7 +19295,7 @@ __metadata: source-map-support: ~0.5.20 bin: terser: bin/terser - checksum: 31c937f1a30c03b68825df7803a3584b13616647438be6cbc0914b688f064a3f4f938d8182e476342ddd1675e84798393b076caeb549393f4df768aec9abd6bd + checksum: e059177775b4d4f4cff219ad89293175aefbd1b081252270444dc83e42a2c5f07824eb2a85eae6e22ef6eb7ef04b21af36dd7d1dd7cfb93912310e57d416a205 languageName: node linkType: hard @@ -19395,7 +19387,7 @@ __metadata: languageName: node linkType: hard -"through@npm:2, through@npm:>=2.2.7 <3, through@npm:^2.3.8, through@npm:~2.3.4": +"through@npm:2, through@npm:>=2.2.7 <3": version: 2.3.8 resolution: "through@npm:2.3.8" checksum: a38c3e059853c494af95d50c072b83f8b676a9ba2818dcc5b108ef252230735c54e0185437618596c790bbba8fcdaef5b290405981ffa09dce67b1f1bf190cbd @@ -19584,7 +19576,7 @@ __metadata: languageName: node linkType: hard -"tsconfig-paths@npm:^3.14.1, tsconfig-paths@npm:^3.14.2": +"tsconfig-paths@npm:^3.14.2": version: 3.14.2 resolution: "tsconfig-paths@npm:3.14.2" dependencies: @@ -19622,9 +19614,9 @@ __metadata: linkType: hard "tslib@npm:^2.0.0, tslib@npm:^2.0.3, tslib@npm:^2.3.0, tslib@npm:^2.3.1": - version: 2.6.0 - resolution: "tslib@npm:2.6.0" - checksum: c01066038f950016a18106ddeca4649b4d76caa76ec5a31e2a26e10586a59fceb4ee45e96719bf6c715648e7c14085a81fee5c62f7e9ebee68e77a5396e5538f + version: 2.6.2 + resolution: "tslib@npm:2.6.2" + checksum: 329ea56123005922f39642318e3d1f0f8265d1e7fcb92c633e0809521da75eeaca28d2cf96d7248229deb40e5c19adf408259f4b9640afd20d13aecc1430f3ad languageName: node linkType: hard @@ -19775,6 +19767,29 @@ __metadata: languageName: node linkType: hard +"typed-array-buffer@npm:^1.0.0": + version: 1.0.0 + resolution: "typed-array-buffer@npm:1.0.0" + dependencies: + call-bind: ^1.0.2 + get-intrinsic: ^1.2.1 + is-typed-array: ^1.1.10 + checksum: 3e0281c79b2a40cd97fe715db803884301993f4e8c18e8d79d75fd18f796e8cd203310fec8c7fdb5e6c09bedf0af4f6ab8b75eb3d3a85da69328f28a80456bd3 + languageName: node + linkType: hard + +"typed-array-byte-length@npm:^1.0.0": + version: 1.0.0 + resolution: "typed-array-byte-length@npm:1.0.0" + dependencies: + call-bind: ^1.0.2 + for-each: ^0.3.3 + has-proto: ^1.0.1 + is-typed-array: ^1.1.10 + checksum: b03db16458322b263d87a702ff25388293f1356326c8a678d7515767ef563ef80e1e67ce648b821ec13178dd628eb2afdc19f97001ceae7a31acf674c849af94 + languageName: node + linkType: hard + "typed-array-byte-offset@npm:^1.0.0": version: 1.0.0 resolution: "typed-array-byte-offset@npm:1.0.0" @@ -19906,11 +19921,11 @@ __metadata: linkType: hard "undici@npm:^5.14.0": - version: 5.22.1 - resolution: "undici@npm:5.22.1" + version: 5.23.0 + resolution: "undici@npm:5.23.0" dependencies: busboy: ^1.6.0 - checksum: 048a3365f622be44fb319316cedfaa241c59cf7f3368ae7667a12323447e1822e8cc3d00f6956c852d1478a6fde1cbbe753f49e05f2fdaed229693e716ebaf35 + checksum: 906ca4fb1d47163d2cee2ecbbc664a1d92508a2cdf1558146621109f525c983a83597910b36e6ba468240e95259be5939cea6babc99fc0c36360b16630f66784 languageName: node linkType: hard @@ -20217,31 +20232,9 @@ __metadata: languageName: node linkType: hard -"viem@npm:^1.0.0": - version: 1.2.14 - resolution: "viem@npm:1.2.14" - dependencies: - "@adraffy/ens-normalize": 1.9.0 - "@noble/curves": 1.0.0 - "@noble/hashes": 1.3.0 - "@scure/bip32": 1.3.0 - "@scure/bip39": 1.2.0 - "@wagmi/chains": 1.2.0 - abitype: 0.8.11 - isomorphic-ws: 5.0.0 - ws: 8.12.0 - peerDependencies: - typescript: ">=5.0.4" - peerDependenciesMeta: - typescript: - optional: true - checksum: ed41bf3328dc8c952dd583454b40ed3f62f657c9392f23a30a0e90610e2f5a6644a319dd94581c2b20e9546b9576d373c1a1e6f830e717b1ca755bcd6ae1f6a3 - languageName: node - linkType: hard - -"viem@npm:^1.7.0": - version: 1.7.0 - resolution: "viem@npm:1.7.0" +"viem@npm:^1.0.0, viem@npm:^1.8.1": + version: 1.8.1 + resolution: "viem@npm:1.8.1" dependencies: "@adraffy/ens-normalize": 1.9.0 "@noble/curves": 1.1.0 @@ -20258,7 +20251,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: d56d6317be7e07204c601eca3e90661122767ef883dc1f4aa615bc725c2bd65eb99ebbfb2180459147f327a38293f9c70bd8bdf7be64c4b9222b9d40fcb7fc69 + checksum: ab8515cc54f07ad1ba2dc0906f0614e3c4be4c7fda3e13f22475eaf50c9a68cfce424d65738507e210fdfa1db52ec587242544504360fdf5b4b146d2e1534c16 languageName: node linkType: hard @@ -20329,131 +20322,132 @@ __metadata: languageName: node linkType: hard -"web3-core-helpers@npm:1.10.0": - version: 1.10.0 - resolution: "web3-core-helpers@npm:1.10.0" +"web3-core-helpers@npm:1.10.1": + version: 1.10.1 + resolution: "web3-core-helpers@npm:1.10.1" dependencies: - web3-eth-iban: 1.10.0 - web3-utils: 1.10.0 - checksum: 3f8b8ed5e3f56c5760452e5d8850d77607cd7046392c7df78a0903611dcbf875acc9bff04bbc397cd967ce27d45b61de19dcf47fada0c958f54a5d69181a40a6 + web3-eth-iban: 1.10.1 + web3-utils: 1.10.1 + checksum: d68fa1c51c51fe1859fed609091bd8de31ffcb75fa23ed068a7b05ca80de15af63cc280da4f63535d475faa8266942e1b22a8ac1de43e210e319730d7775fbd7 languageName: node linkType: hard -"web3-core-method@npm:1.10.0": - version: 1.10.0 - resolution: "web3-core-method@npm:1.10.0" +"web3-core-method@npm:1.10.1": + version: 1.10.1 + resolution: "web3-core-method@npm:1.10.1" dependencies: "@ethersproject/transactions": ^5.6.2 - web3-core-helpers: 1.10.0 - web3-core-promievent: 1.10.0 - web3-core-subscriptions: 1.10.0 - web3-utils: 1.10.0 - checksum: 29c42c92f0f6d895245c6d3dba4adffd822787b09bee0d9953a5d50365ae1ab0559085e9d6104e2dfb00b372fbf02ff1d6292c9a9e565ada1a5c531754d654cd + web3-core-helpers: 1.10.1 + web3-core-promievent: 1.10.1 + web3-core-subscriptions: 1.10.1 + web3-utils: 1.10.1 + checksum: 3ae837619712b5c6ec1430fa3ea280df7b5a410d47c7277671a280cc4cb574ca17ab126731878bb0cd1153f6e0cfb93bb813730cadd56d96c231cb0d1055b5ae languageName: node linkType: hard -"web3-core-promievent@npm:1.10.0": - version: 1.10.0 - resolution: "web3-core-promievent@npm:1.10.0" +"web3-core-promievent@npm:1.10.1": + version: 1.10.1 + resolution: "web3-core-promievent@npm:1.10.1" dependencies: eventemitter3: 4.0.4 - checksum: 68e9f40f78d92ce1ee9808d04a28a89d20ab4dc36af5ba8405f132044cbb01825f76f35249a9599f9568a95d5e7c9e4a09ada6d4dc2e27e0c1b32c9232c8c973 + checksum: cd9bc5c067782f374ad4aa69536f382c0c0528a545f9ea8763e605de297cb78bdbc0ea708601d099f8d6ceaae11529062357309a6e037db3673601d7f9a63e88 languageName: node linkType: hard -"web3-core-requestmanager@npm:1.10.0": - version: 1.10.0 - resolution: "web3-core-requestmanager@npm:1.10.0" +"web3-core-requestmanager@npm:1.10.1": + version: 1.10.1 + resolution: "web3-core-requestmanager@npm:1.10.1" dependencies: util: ^0.12.5 - web3-core-helpers: 1.10.0 - web3-providers-http: 1.10.0 - web3-providers-ipc: 1.10.0 - web3-providers-ws: 1.10.0 - checksum: ce63b521b70b4e159510abf9d70e09d0c704b924a83951b350bb1d8f56b03dae21d3ea709a118019d272f754940ad6f6772002e7a8692bf733126fee80c84226 + web3-core-helpers: 1.10.1 + web3-providers-http: 1.10.1 + web3-providers-ipc: 1.10.1 + web3-providers-ws: 1.10.1 + checksum: c4890e34a2fbcee48272d97c575d21526d8e1af61cbce50ecd97498726a739505225f24c02db174fa2e8436b86afd5ae79cfd29b4ec4749150f4d7ec531d1c0b languageName: node linkType: hard -"web3-core-subscriptions@npm:1.10.0": - version: 1.10.0 - resolution: "web3-core-subscriptions@npm:1.10.0" +"web3-core-subscriptions@npm:1.10.1": + version: 1.10.1 + resolution: "web3-core-subscriptions@npm:1.10.1" dependencies: eventemitter3: 4.0.4 - web3-core-helpers: 1.10.0 - checksum: baca40f4d34da03bf4e6d64a13d9498a3ebfa37544869921671340d83581c87efbe3830998ae99db776fa22f0cdb529f9bb1fe7d516de1f9ce7b9da1c3a63859 + web3-core-helpers: 1.10.1 + checksum: c7987c2eca46e6df029d0c13f06398b0b86f36ed8601f63ac0bee48c40c025bbaafb59bb080c9142de909154a57e9b60b01491b1356b3746b393a0497cef1d97 languageName: node linkType: hard "web3-core@npm:^1.8.1": - version: 1.10.0 - resolution: "web3-core@npm:1.10.0" + version: 1.10.1 + resolution: "web3-core@npm:1.10.1" dependencies: "@types/bn.js": ^5.1.1 "@types/node": ^12.12.6 bignumber.js: ^9.0.0 - web3-core-helpers: 1.10.0 - web3-core-method: 1.10.0 - web3-core-requestmanager: 1.10.0 - web3-utils: 1.10.0 - checksum: 075b6dbf743e8cfad2aa1b9d603a45f0f30998c778af22cd0090d455a027e0658c398721a2a270c218dc2a561cbfd5cdbfe5ca14a6c2f5cd4afc8743e05a2e60 + web3-core-helpers: 1.10.1 + web3-core-method: 1.10.1 + web3-core-requestmanager: 1.10.1 + web3-utils: 1.10.1 + checksum: 3f849b5c657379291f095d435624681c262737304e35a7a48414612301c5c6db419d47d38bc373e1bbd1e2a996d51ddfb25860250a622417dce1e20f238899de languageName: node linkType: hard -"web3-eth-iban@npm:1.10.0": - version: 1.10.0 - resolution: "web3-eth-iban@npm:1.10.0" +"web3-eth-iban@npm:1.10.1": + version: 1.10.1 + resolution: "web3-eth-iban@npm:1.10.1" dependencies: bn.js: ^5.2.1 - web3-utils: 1.10.0 - checksum: ca0921f0a232a343a538f6376e55ef3e29e952fba613ecda09dde82149e8088581d8f93da2ed2d8b7e008abdf6610eecc0f4f25efba0ecf412156fd70e9869c0 + web3-utils: 1.10.1 + checksum: 2f51dd08f059926fe36aa0fb7cf7230924aedb0174acaef4579c5caac855dc158a3b7f44d3299f62f66c5668ca9dc3e872c1dbb0a2f44d0ed160e0713b926589 languageName: node linkType: hard -"web3-providers-http@npm:1.10.0": - version: 1.10.0 - resolution: "web3-providers-http@npm:1.10.0" +"web3-providers-http@npm:1.10.1": + version: 1.10.1 + resolution: "web3-providers-http@npm:1.10.1" dependencies: abortcontroller-polyfill: ^1.7.3 cross-fetch: ^3.1.4 es6-promise: ^4.2.8 - web3-core-helpers: 1.10.0 - checksum: 2fe7c3485626e5e7cb3dd54d05e74f35aec306afe25ae35047e4db1ad75a01a4490d8abf8caa2648400c597d8a252d8cca9950977af2dc242b0ba1f95ab2d2c2 + web3-core-helpers: 1.10.1 + checksum: a569e3b0528147bbaeb0d6599c1653b5640e224418ea5978d1d2bc33fca8f73ff51d168db019315b130ac977d9049390cb86d515550aaead8b2594af87a1da16 languageName: node linkType: hard -"web3-providers-ipc@npm:1.10.0": - version: 1.10.0 - resolution: "web3-providers-ipc@npm:1.10.0" +"web3-providers-ipc@npm:1.10.1": + version: 1.10.1 + resolution: "web3-providers-ipc@npm:1.10.1" dependencies: oboe: 2.1.5 - web3-core-helpers: 1.10.0 - checksum: 103cb6b26ced5c79f76178ae4339e867f09128a8bf5041553966dbc23fb63a4de638a619cadf1f4c4fdff4f352cd63bce54f1fe2eb582fc18cea11ea64067a71 + web3-core-helpers: 1.10.1 + checksum: 717be1af3fa7bb75bf2bb7bd1701c903bca0ba954d33c0e24a5078ca9dd5d8af9707f8d052adcde7bd7b80a358697334cf4ccfc13d6bd2ec9a3a12172d56586d languageName: node linkType: hard -"web3-providers-ws@npm:1.10.0": - version: 1.10.0 - resolution: "web3-providers-ws@npm:1.10.0" +"web3-providers-ws@npm:1.10.1": + version: 1.10.1 + resolution: "web3-providers-ws@npm:1.10.1" dependencies: eventemitter3: 4.0.4 - web3-core-helpers: 1.10.0 + web3-core-helpers: 1.10.1 websocket: ^1.0.32 - checksum: 0784334a9ad61c209468335bfed4f656e23b4aab8bddf834de29895fde79309bffe90bfbc65b975c6ea4870ef4521b90469aabeb3124b99d905d1a52ca7bcbe3 + checksum: f9f7f0e118c8b57f79004e9e8610e233aac4d2715b5b53b9a46593230cb4c5b0a76d3f42782068206e0349a2e14400deb6c87baffd98f27adddef1be65bd85e5 languageName: node linkType: hard -"web3-utils@npm:1.10.0, web3-utils@npm:^1.3.6, web3-utils@npm:^1.8.1": - version: 1.10.0 - resolution: "web3-utils@npm:1.10.0" +"web3-utils@npm:1.10.1, web3-utils@npm:^1.3.6, web3-utils@npm:^1.8.1": + version: 1.10.1 + resolution: "web3-utils@npm:1.10.1" dependencies: + "@ethereumjs/util": ^8.1.0 bn.js: ^5.2.1 ethereum-bloom-filters: ^1.0.6 - ethereumjs-util: ^7.1.0 + ethereum-cryptography: ^2.1.2 ethjs-unit: 0.1.6 number-to-bn: 1.7.0 randombytes: ^2.1.0 utf8: 3.0.0 - checksum: c6b7662359c0513b5cbfe02cdcb312ce9152778bb19d94d413d44f74cfaa93b7de97190ab6ba11af25a40855c949d2427dcb751929c6d0f257da268c55a3ba2a + checksum: 260a2efcbe3c241f2d3e1b5d77a3a33510ab270a5028a842f8262a5d0b9d8cb08a2da8e821b02765a3cc39de83502a7dc677124c02ed8e314fc45bc612e22c3e languageName: node linkType: hard @@ -20587,8 +20581,8 @@ __metadata: linkType: hard "webpack@npm:^5.64.4": - version: 5.88.1 - resolution: "webpack@npm:5.88.1" + version: 5.88.2 + resolution: "webpack@npm:5.88.2" dependencies: "@types/eslint-scope": ^3.7.3 "@types/estree": ^1.0.0 @@ -20619,7 +20613,7 @@ __metadata: optional: true bin: webpack: bin/webpack.js - checksum: 726e7e05ab2e7c142609a673dd6aa1a711ed97f349418a2a393d650c5ddad172d191257f60e1e37f6b2a77261571c202aabd5ce9240791a686774f0801cf5ec2 + checksum: 79476a782da31a21f6dd38fbbd06b68da93baf6a62f0d08ca99222367f3b8668f5a1f2086b7bb78e23172e31fa6df6fa7ab09b25e827866c4fc4dc2b30443ce2 languageName: node linkType: hard @@ -20665,9 +20659,9 @@ __metadata: linkType: hard "whatwg-fetch@npm:^3.6.2": - version: 3.6.2 - resolution: "whatwg-fetch@npm:3.6.2" - checksum: ee976b7249e7791edb0d0a62cd806b29006ad7ec3a3d89145921ad8c00a3a67e4be8f3fb3ec6bc7b58498724fd568d11aeeeea1f7827e7e1e5eae6c8a275afed + version: 3.6.17 + resolution: "whatwg-fetch@npm:3.6.17" + checksum: 0a8785dc2d1515c17ee9365d3f6438cf8fd281567426652fc6c55fc99e58cc6287ae5d1add5b8b1dd665f149e38d3de4ebe3812fd7170438ba0681d03b88b4dd languageName: node linkType: hard @@ -20723,6 +20717,26 @@ __metadata: languageName: node linkType: hard +"which-builtin-type@npm:^1.1.3": + version: 1.1.3 + resolution: "which-builtin-type@npm:1.1.3" + dependencies: + function.prototype.name: ^1.1.5 + has-tostringtag: ^1.0.0 + is-async-function: ^2.0.0 + is-date-object: ^1.0.5 + is-finalizationregistry: ^1.0.2 + is-generator-function: ^1.0.10 + is-regex: ^1.1.4 + is-weakref: ^1.0.2 + isarray: ^2.0.5 + which-boxed-primitive: ^1.0.2 + which-collection: ^1.0.1 + which-typed-array: ^1.1.9 + checksum: 43730f7d8660ff9e33d1d3f9f9451c4784265ee7bf222babc35e61674a11a08e1c2925019d6c03154fcaaca4541df43abe35d2720843b9b4cbcebdcc31408f36 + languageName: node + linkType: hard + "which-collection@npm:^1.0.1": version: 1.0.1 resolution: "which-collection@npm:1.0.1" @@ -20742,17 +20756,16 @@ __metadata: languageName: node linkType: hard -"which-typed-array@npm:^1.1.10, which-typed-array@npm:^1.1.2, which-typed-array@npm:^1.1.9": - version: 1.1.10 - resolution: "which-typed-array@npm:1.1.10" +"which-typed-array@npm:^1.1.10, which-typed-array@npm:^1.1.11, which-typed-array@npm:^1.1.2, which-typed-array@npm:^1.1.9": + version: 1.1.11 + resolution: "which-typed-array@npm:1.1.11" dependencies: available-typed-arrays: ^1.0.5 call-bind: ^1.0.2 for-each: ^0.3.3 gopd: ^1.0.1 has-tostringtag: ^1.0.0 - is-typed-array: ^1.1.10 - checksum: 149f54f5d11773ce938c60a2c36306720a1824eccb62bda0620170932c2783fa50ad0226254c5741a962e35c7ccba5f4e4c402b8618cb3b4f2cf47bf5e6ade31 + checksum: 711ffc8ef891ca6597b19539075ec3e08bb9b4c2ca1f78887e3c07a977ab91ac1421940505a197758fb5939aa9524976d0a5bbcac34d07ed6faa75cedbb17206 languageName: node linkType: hard @@ -20797,9 +20810,9 @@ __metadata: linkType: hard "word-wrap@npm:~1.2.3": - version: 1.2.3 - resolution: "word-wrap@npm:1.2.3" - checksum: 30b48f91fcf12106ed3186ae4fa86a6a1842416df425be7b60485de14bec665a54a68e4b5156647dec3a70f25e84d270ca8bc8cd23182ed095f5c7206a938c1f + version: 1.2.5 + resolution: "word-wrap@npm:1.2.5" + checksum: f93ba3586fc181f94afdaff3a6fef27920b4b6d9eaefed0f428f8e07adea2a7f54a5f2830ce59406c8416f033f86902b91eb824072354645eea687dff3691ccb languageName: node linkType: hard @@ -21395,18 +21408,21 @@ __metadata: linkType: hard "zustand@npm:^4.3.1": - version: 4.3.9 - resolution: "zustand@npm:4.3.9" + version: 4.4.1 + resolution: "zustand@npm:4.4.1" dependencies: use-sync-external-store: 1.2.0 peerDependencies: + "@types/react": ">=16.8" immer: ">=9.0" react: ">=16.8" peerDependenciesMeta: + "@types/react": + optional: true immer: optional: true react: optional: true - checksum: fc83d653913fa537c354ba8b95d3a4fdebe62d2ebd3d9f5aeff2edf062811c0f5af48e02ab4da32b666752fd4f3e78c2b44624e445254f48503595435d4a7d70 + checksum: 80acd0fbf633782996642802c8692bbb80ae5c80a8dff4c501b88250acd5ccd468fbc6398bdce198475a25e3839c91385b81da921274f33ffb5c2d08c3eab400 languageName: node linkType: hard From 5186a9c3602eabbb2aa683c7f94eee8bc772cf98 Mon Sep 17 00:00:00 2001 From: Jan-Felix Date: Mon, 28 Aug 2023 13:33:14 +0200 Subject: [PATCH 30/41] fix deploy scripts --- deploy/00_deploy_ERC6551Registry.ts | 31 +++++++++++++++++++ ... 01_deploy_mastercopy_ERC721Tokenbound.ts} | 16 ++++++++-- ...02_deploy_mastercopy_ERC1155Tokenbound.ts} | 14 +++++++-- ...diac.ts => 03_deploy_mastercopy_Zodiac.ts} | 14 +++++++-- test/utils.ts | 2 +- 5 files changed, 69 insertions(+), 8 deletions(-) create mode 100644 deploy/00_deploy_ERC6551Registry.ts rename deploy/{00_deploy_mastercopy_ERC721Tokenbound.ts => 01_deploy_mastercopy_ERC721Tokenbound.ts} (69%) rename deploy/{01_deploy_mastercopy_ERC1155Tokenbound.ts => 02_deploy_mastercopy_ERC1155Tokenbound.ts} (71%) rename deploy/{02_deploy_mastercopy_Zodiac.ts => 03_deploy_mastercopy_Zodiac.ts} (73%) diff --git a/deploy/00_deploy_ERC6551Registry.ts b/deploy/00_deploy_ERC6551Registry.ts new file mode 100644 index 0000000..b7b0cb3 --- /dev/null +++ b/deploy/00_deploy_ERC6551Registry.ts @@ -0,0 +1,31 @@ +import { DeployFunction } from "hardhat-deploy/types" + +const deployERC6551Registry: DeployFunction = async (hre) => { + // const [signer] = await hre.ethers.getSigners() + + const ERC6551Registry = await hre.ethers.getContractFactory("ERC6551Registry") + const erc6551Registry = await ERC6551Registry.deploy() + + try { + await hre.run("verify:verify", { + address: await erc6551Registry.getAddress(), + constructorArguments: [], + }) + } catch (e) { + if ( + e instanceof Error && + e.stack && + (e.stack.indexOf("Reason: Already Verified") > -1 || + e.stack.indexOf("Contract source code already verified") > -1) + ) { + console.log(" ✔ Contract is already verified") + } else { + console.log( + " ✘ Verifying the contract failed. This is probably because Etherscan is still indexing the contract. Try running this same command again in a few seconds." + ) + throw e + } + } +} + +export default deployERC6551Registry diff --git a/deploy/00_deploy_mastercopy_ERC721Tokenbound.ts b/deploy/01_deploy_mastercopy_ERC721Tokenbound.ts similarity index 69% rename from deploy/00_deploy_mastercopy_ERC721Tokenbound.ts rename to deploy/01_deploy_mastercopy_ERC721Tokenbound.ts index ef4e79b..8b5c2f4 100644 --- a/deploy/00_deploy_mastercopy_ERC721Tokenbound.ts +++ b/deploy/01_deploy_mastercopy_ERC721Tokenbound.ts @@ -1,15 +1,25 @@ import { DeployFunction } from "hardhat-deploy/types" +import { createWalletClient, custom as customTransport } from "viem" import { calculateERC721TokenboundMechMastercopyAddress, deployERC721TokenboundMechMastercopy, -} from "../sdk/build/cjs/sdk/src" +} from "../sdk" const deployMastercopyERC721Tokenbound: DeployFunction = async (hre) => { const [signer] = await hre.ethers.getSigners() - const deployer = hre.ethers.provider.getSigner(signer.address) + const deployer = await hre.ethers.provider.getSigner(signer.address) - await deployERC721TokenboundMechMastercopy(deployer) + const deployerClient = createWalletClient({ + account: deployer.address as `0x${string}`, + transport: customTransport({ + async request({ method, params }) { + return deployer.provider.send(method, params) + }, + }), + }) + + await deployERC721TokenboundMechMastercopy(deployerClient) const address = calculateERC721TokenboundMechMastercopyAddress() try { diff --git a/deploy/01_deploy_mastercopy_ERC1155Tokenbound.ts b/deploy/02_deploy_mastercopy_ERC1155Tokenbound.ts similarity index 71% rename from deploy/01_deploy_mastercopy_ERC1155Tokenbound.ts rename to deploy/02_deploy_mastercopy_ERC1155Tokenbound.ts index c4a9747..1609843 100644 --- a/deploy/01_deploy_mastercopy_ERC1155Tokenbound.ts +++ b/deploy/02_deploy_mastercopy_ERC1155Tokenbound.ts @@ -1,4 +1,5 @@ import { DeployFunction } from "hardhat-deploy/types" +import { createWalletClient, custom as customTransport } from "viem" import { calculateERC1155TokenboundMechMastercopyAddress, @@ -7,9 +8,18 @@ import { const deployMastercopyERC1155Tokenbound: DeployFunction = async (hre) => { const [signer] = await hre.ethers.getSigners() - const deployer = hre.ethers.provider.getSigner(signer.address) + const deployer = await hre.ethers.provider.getSigner(signer.address) - await deployERC1155TokenboundMechMastercopy(deployer) + const deployerClient = createWalletClient({ + account: deployer.address as `0x${string}`, + transport: customTransport({ + async request({ method, params }) { + return deployer.provider.send(method, params) + }, + }), + }) + + await deployERC1155TokenboundMechMastercopy(deployerClient) const address = calculateERC1155TokenboundMechMastercopyAddress() try { diff --git a/deploy/02_deploy_mastercopy_Zodiac.ts b/deploy/03_deploy_mastercopy_Zodiac.ts similarity index 73% rename from deploy/02_deploy_mastercopy_Zodiac.ts rename to deploy/03_deploy_mastercopy_Zodiac.ts index e366312..e1b2d33 100644 --- a/deploy/02_deploy_mastercopy_Zodiac.ts +++ b/deploy/03_deploy_mastercopy_Zodiac.ts @@ -1,9 +1,10 @@ import { DeployFunction } from "hardhat-deploy/types" +import { createWalletClient, custom as customTransport } from "viem" import { calculateZodiacMechMastercopyAddress, deployZodiacMechMastercopy, -} from "../sdk" +} from "../sdk/build/cjs/sdk/src" const deployMastercopyZodiac: DeployFunction = async (hre) => { // TODO disabled for now @@ -12,7 +13,16 @@ const deployMastercopyZodiac: DeployFunction = async (hre) => { const [signer] = await hre.ethers.getSigners() const deployer = await hre.ethers.provider.getSigner(signer.address) - await deployZodiacMechMastercopy(deployer) + const deployerClient = createWalletClient({ + account: deployer.address as `0x${string}`, + transport: customTransport({ + async request({ method, params }) { + return deployer.provider.send(method, params) + }, + }), + }) + + await deployZodiacMechMastercopy(deployerClient) const address = calculateZodiacMechMastercopyAddress() try { diff --git a/test/utils.ts b/test/utils.ts index fddf8a6..4640665 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -17,7 +17,7 @@ export async function deployFactories() { const ERC6551Registry = await ethers.getContractFactory("ERC6551Registry") const erc6551Registry = await ERC6551Registry.deploy() - deployer.populateTransaction + const deployerClient = createTestClient({ account: deployer.address as `0x${string}`, chain: hardhat, From 9fe7e052bfbafdfddacc165caa878f5506091118 Mon Sep 17 00:00:00 2001 From: Jan-Felix Date: Fri, 1 Sep 2023 18:30:32 +0200 Subject: [PATCH 31/41] migrate from n.xyz to sequencer --- frontend/package.json | 1 + frontend/src/chains.ts | 9 + frontend/src/components/NFTGrid/index.tsx | 64 +--- frontend/src/components/NFTGridItem/index.tsx | 33 +- frontend/src/components/NFTItem/index.tsx | 97 +++--- frontend/src/hooks/useAccountBalance.ts | 60 ---- frontend/src/hooks/useDeployMech.tsx | 8 +- frontend/src/hooks/useNFT.ts | 49 --- frontend/src/hooks/useNFTsByOwner.ts | 65 ---- frontend/src/hooks/useTokenBalances.ts | 49 +++ frontend/src/routes/Mech/index.tsx | 18 +- frontend/src/types/nxyzApiTypes.ts | 95 ------ frontend/src/utils/calculateMechAddress.ts | 10 +- frontend/src/utils/deployMech.ts | 11 +- yarn.lock | 287 +++++++++++++++++- 15 files changed, 449 insertions(+), 407 deletions(-) delete mode 100644 frontend/src/hooks/useAccountBalance.ts delete mode 100644 frontend/src/hooks/useNFT.ts delete mode 100644 frontend/src/hooks/useNFTsByOwner.ts create mode 100644 frontend/src/hooks/useTokenBalances.ts delete mode 100644 frontend/src/types/nxyzApiTypes.ts diff --git a/frontend/package.json b/frontend/package.json index 54e0924..c9c2175 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -3,6 +3,7 @@ "version": "1.0.0", "private": true, "devDependencies": { + "0xsequence": "^1.1.15", "@types/react": "^18.2.21", "@types/react-dom": "^18.2.7", "@walletconnect/client": "^1.8.0", diff --git a/frontend/src/chains.ts b/frontend/src/chains.ts index c0f3fc1..db37a33 100644 --- a/frontend/src/chains.ts +++ b/frontend/src/chains.ts @@ -1,3 +1,4 @@ +import { SequenceIndexerServices } from "@0xsequence/indexer" import { mainnet, goerli, @@ -23,3 +24,11 @@ export const CHAINS = { export type ChainId = keyof typeof CHAINS export const DEFAULT_CHAIN = CHAINS[5] + +export const SEQUENCER_ENDPOINTS: Record = { + 1: SequenceIndexerServices.MAINNET, + 5: SequenceIndexerServices.GOERLI, + 100: SequenceIndexerServices.GNOSIS, + 137: SequenceIndexerServices.POLYGON, + 80001: SequenceIndexerServices.POLYGON_MUMBAI, +} diff --git a/frontend/src/components/NFTGrid/index.tsx b/frontend/src/components/NFTGrid/index.tsx index b2576d7..5296270 100644 --- a/frontend/src/components/NFTGrid/index.tsx +++ b/frontend/src/components/NFTGrid/index.tsx @@ -1,63 +1,43 @@ -import { useEffect, useState } from "react" - -import useNFTsByOwner, { MechNFT } from "../../hooks/useNFTsByOwner" +import { ContractType, TokenBalance } from "@0xsequence/indexer" import NFTGridItem from "../NFTGridItem" import Spinner from "../Spinner" -import Button from "../Button" import classes from "./NFTGrid.module.css" import clsx from "clsx" import { useChainId } from "wagmi" import { useDeployedMechs } from "../../hooks/useDeployMech" import { calculateMechAddress } from "../../utils/calculateMechAddress" +import useTokenBalances from "../../hooks/useTokenBalances" interface Props { address: string } const NFTGrid: React.FC = ({ address }) => { - const [pageToken, setPageToken] = useState(undefined) - const chainId = useChainId() - const { data, isLoading } = useNFTsByOwner({ - walletAddress: address, + const { balances, isLoading } = useTokenBalances({ + accountAddress: address, chainId, - pageToken, }) - const [nftData, setNftData] = useState([]) - - useEffect(() => { - setNftData((nftData) => { - if (nftData.length === 0) { - return data?.assets || [] - } - const ids = new Set( - nftData.map((nft) => nft.nft.tokenID + nft.contractAddress) - ) - - // merge and dedupe - return [ - ...nftData, - ...data?.assets.filter( - (nft) => !ids.has(nft.nft.tokenID + nft.contractAddress) - ), - ] - }) - }, [data]) + const nftBalances = balances.filter( + (balance) => + balance.contractType === ContractType.ERC721 || + balance.contractType === ContractType.ERC1155 + ) - const deployedMechs = useDeployedMechs(nftData) + const deployedMechs = useDeployedMechs(nftBalances) - const isDeployed = (nft: MechNFT) => + const isDeployed = (nft: TokenBalance) => deployedMechs.some( (mech) => mech.chainId === chainId && mech.address.toLowerCase() === calculateMechAddress(nft).toLowerCase() ) - const deployed = nftData.filter(isDeployed) - const undeployed = nftData.filter((nft) => !isDeployed(nft)) + const deployed = nftBalances.filter(isDeployed) + const undeployed = nftBalances.filter((nft) => !isDeployed(nft)) return (
@@ -75,7 +55,7 @@ const NFTGrid: React.FC = ({ address }) => {
    {deployed.map((nft, index) => (
  • - +
  • ))}
@@ -89,24 +69,12 @@ const NFTGrid: React.FC = ({ address }) => {
    {undeployed.map((nft, index) => (
  • - +
  • ))}
)} - {isLoading ? ( - - ) : ( - - )} + {isLoading && }
) } diff --git a/frontend/src/components/NFTGridItem/index.tsx b/frontend/src/components/NFTGridItem/index.tsx index 6a1df48..4e4229f 100644 --- a/frontend/src/components/NFTGridItem/index.tsx +++ b/frontend/src/components/NFTGridItem/index.tsx @@ -1,3 +1,4 @@ +import { TokenBalance } from "@0xsequence/indexer" import { useState } from "react" import copy from "copy-to-clipboard" import clsx from "clsx" @@ -7,47 +8,49 @@ import classes from "./NFTItem.module.css" import Button from "../Button" import { shortenAddress } from "../../utils/shortenAddress" import Spinner from "../Spinner" -import { MechNFT } from "../../hooks/useNFTsByOwner" import ChainIcon from "../ChainIcon" import { calculateMechAddress } from "../../utils/calculateMechAddress" import { CHAINS, ChainId } from "../../chains" import { useDeployMech } from "../../hooks/useDeployMech" interface Props { - nftData: MechNFT + tokenBalance: TokenBalance } -const NFTGridItem: React.FC = ({ nftData }) => { +const NFTGridItem: React.FC = ({ tokenBalance }) => { const [imageError, setImageError] = useState(false) - const chain = CHAINS[parseInt(nftData.blockchain.shortChainID) as ChainId] + const chain = CHAINS[tokenBalance.chainId as ChainId] - const mechAddress = calculateMechAddress(nftData) - const { deploy, deployPending, deployed } = useDeployMech(nftData) + const mechAddress = calculateMechAddress(tokenBalance) + const { deploy, deployPending, deployed } = useDeployMech(tokenBalance) + + const name = + tokenBalance.tokenMetadata?.name || tokenBalance.contractInfo?.name return (

- {nftData.nft.title || nftData.nft.contractTitle || "..."} + {name || "..."}

- {nftData.nft.tokenID.length < 5 && ( -

{nftData.nft.tokenID || "..."}

+ {tokenBalance.tokenID.length < 5 && ( +

{tokenBalance.tokenID || "..."}

)}
- {(!nftData.nft.previews || imageError) && ( + {(imageError || !tokenBalance.tokenMetadata?.image) && (
)} - {!imageError && nftData.nft.previews && ( + {!imageError && tokenBalance.tokenMetadata?.image && (
{nftData.nft.contractTitle} setImageError(true)} /> @@ -68,7 +71,7 @@ const NFTGridItem: React.FC = ({ nftData }) => {
{deployed ? (