From 7f79aaf05c33df71d9cb687f0bc8a73fa39d25d5 Mon Sep 17 00:00:00 2001 From: Nicholas Rodrigues Lordello Date: Thu, 14 Nov 2024 17:10:30 +0100 Subject: [PATCH 01/38] Assembly Memory Safety (#859) This PR does a once-over on memory Safety for the 1.5.0 contracts. In particular, there were a couple of missing `memory-safe` tags for some assembly blocks which were preventing the IR assembler from working correctly. Additionally, since the `MultiSend*` contracts changed anyway in 1.5.0, I took this opportunity to change the assembly to be memory-safe so that we can tag it. Note that it only adds more code in the revert case, so it should not have a negative impact for most use-cases. Furthermore, I added a comment explaining why we did not make the `SafeProxy` contract memory-safe (that is one intentional). Lastly, I noticed that there were some `eq(..., 0)` assembly calls which can be written as `iszero(...)` to save some gas and code. Again, it was an opportunistic change as the affected contracts have changed anyway and will be re-audited. --------- Co-authored-by: Shebin John --- contracts/Safe.sol | 11 ++++++----- contracts/base/ModuleManager.sol | 8 ++++++-- contracts/handler/extensible/MarshalLib.sol | 8 ++++++-- .../handler/extensible/SignatureVerifierMuxer.sol | 4 +++- contracts/libraries/MultiSend.sol | 8 +++++--- contracts/libraries/MultiSendCallOnly.sol | 8 +++++--- contracts/proxies/SafeProxy.sol | 9 +++++++-- contracts/test/DelegateCaller.sol | 6 ++++-- docs/safe_tx_gas.md | 6 +++--- 9 files changed, 45 insertions(+), 23 deletions(-) diff --git a/contracts/Safe.sol b/contracts/Safe.sol index 82afe3be5..b08611354 100644 --- a/contracts/Safe.sol +++ b/contracts/Safe.sol @@ -179,9 +179,9 @@ contract Safe is /* solhint-disable no-inline-assembly */ /// @solidity memory-safe-assembly assembly { - let p := mload(0x40) - returndatacopy(p, 0, returndatasize()) - revert(p, returndatasize()) + let ptr := mload(0x40) + returndatacopy(ptr, 0, returndatasize()) + revert(ptr, returndatasize()) } /* solhint-enable no-inline-assembly */ } @@ -403,9 +403,10 @@ contract Safe is ) public view override returns (bytes32 txHash) { bytes32 domainHash = domainSeparator(); - // We opted out for using assembly code here, because the way Solidity compiler we use (0.7.6) - // allocates memory is inefficient. We only need to allocate memory for temporary variables to be used in the keccak256 call. + // We opted for using assembly code here, because the way Solidity compiler we use (0.7.6) allocates memory is + // inefficient. We do not need to allocate memory for temporary variables to be used in the keccak256 call. /* solhint-disable no-inline-assembly */ + /// @solidity memory-safe-assembly assembly { // Get the free memory pointer let ptr := mload(0x40) diff --git a/contracts/base/ModuleManager.sol b/contracts/base/ModuleManager.sol index 9f25eafad..b3985be85 100644 --- a/contracts/base/ModuleManager.sol +++ b/contracts/base/ModuleManager.sol @@ -260,10 +260,12 @@ abstract contract ModuleManager is SelfAuthorized, Executor, IModuleManager { revertWithError("GS301"); bytes32 slot = MODULE_GUARD_STORAGE_SLOT; - // solhint-disable-next-line no-inline-assembly + /* solhint-disable no-inline-assembly */ + /// @solidity memory-safe-assembly assembly { sstore(slot, moduleGuard) } + /* solhint-enable no-inline-assembly */ emit ChangedModuleGuard(moduleGuard); } @@ -273,10 +275,12 @@ abstract contract ModuleManager is SelfAuthorized, Executor, IModuleManager { */ function getModuleGuard() internal view returns (address moduleGuard) { bytes32 slot = MODULE_GUARD_STORAGE_SLOT; - // solhint-disable-next-line no-inline-assembly + /* solhint-disable no-inline-assembly */ + /// @solidity memory-safe-assembly assembly { moduleGuard := sload(slot) } + /* solhint-enable no-inline-assembly */ } /** diff --git a/contracts/handler/extensible/MarshalLib.sol b/contracts/handler/extensible/MarshalLib.sol index ca33cf678..b55436e7a 100644 --- a/contracts/handler/extensible/MarshalLib.sol +++ b/contracts/handler/extensible/MarshalLib.sol @@ -33,12 +33,14 @@ library MarshalLib { * @return handler The address of the handler contract implementing the `IFallbackMethod` or `IStaticFallbackMethod` interface */ function decode(bytes32 data) internal pure returns (bool isStatic, address handler) { - // solhint-disable-next-line no-inline-assembly + /* solhint-disable no-inline-assembly */ + /// @solidity memory-safe-assembly assembly { // set isStatic to true if the left-most byte of the data is 0x00 isStatic := iszero(shr(248, data)) handler := shr(96, shl(96, data)) } + /* solhint-enable no-inline-assembly */ } /** @@ -49,12 +51,14 @@ library MarshalLib { * @return handler The address of the handler contract implementing the `IFallbackMethod` or `IStaticFallbackMethod` interface */ function decodeWithSelector(bytes32 data) internal pure returns (bool isStatic, bytes4 selector, address handler) { - // solhint-disable-next-line no-inline-assembly + /* solhint-disable no-inline-assembly */ + /// @solidity memory-safe-assembly assembly { // set isStatic to true if the left-most byte of the data is 0x00 isStatic := iszero(shr(248, data)) handler := shr(96, shl(96, data)) selector := shl(168, shr(160, data)) } + /* solhint-enable no-inline-assembly */ } } diff --git a/contracts/handler/extensible/SignatureVerifierMuxer.sol b/contracts/handler/extensible/SignatureVerifierMuxer.sol index 17b3fc43e..8bc772d03 100644 --- a/contracts/handler/extensible/SignatureVerifierMuxer.sol +++ b/contracts/handler/extensible/SignatureVerifierMuxer.sol @@ -107,10 +107,12 @@ abstract contract SignatureVerifierMuxer is ExtensibleBase, ERC1271, ISignatureV // Check if the signature is for an `ISafeSignatureVerifier` and if it is valid for the domain. if (signature.length >= 4) { bytes4 sigSelector; - // solhint-disable-next-line no-inline-assembly + /* solhint-disable no-inline-assembly */ + /// @solidity memory-safe-assembly assembly { sigSelector := shl(224, shr(224, calldataload(signature.offset))) } + /* solhint-enable no-inline-assembly */ // Guard against short signatures that would cause abi.decode to revert. if (sigSelector == SAFE_SIGNATURE_MAGIC_VALUE && signature.length >= 68) { diff --git a/contracts/libraries/MultiSend.sol b/contracts/libraries/MultiSend.sol index 82b849e38..399148a4e 100644 --- a/contracts/libraries/MultiSend.sol +++ b/contracts/libraries/MultiSend.sol @@ -30,6 +30,7 @@ contract MultiSend { function multiSend(bytes memory transactions) public payable { require(address(this) != MULTISEND_SINGLETON, "MultiSend should only be called via delegatecall"); /* solhint-disable no-inline-assembly */ + /// @solidity memory-safe-assembly assembly { let length := mload(transactions) let i := 0x20 @@ -61,9 +62,10 @@ contract MultiSend { case 1 { success := delegatecall(gas(), to, data, dataLength, 0, 0) } - if eq(success, 0) { - returndatacopy(0, 0, returndatasize()) - revert(0, returndatasize()) + if iszero(success) { + let ptr := mload(0x40) + returndatacopy(ptr, 0, returndatasize()) + revert(ptr, returndatasize()) } // Next entry starts at 85 byte + data length i := add(i, add(0x55, dataLength)) diff --git a/contracts/libraries/MultiSendCallOnly.sol b/contracts/libraries/MultiSendCallOnly.sol index fc4dd2f2e..2c30e8821 100644 --- a/contracts/libraries/MultiSendCallOnly.sol +++ b/contracts/libraries/MultiSendCallOnly.sol @@ -24,6 +24,7 @@ contract MultiSendCallOnly { */ function multiSend(bytes memory transactions) public payable { /* solhint-disable no-inline-assembly */ + /// @solidity memory-safe-assembly assembly { let length := mload(transactions) let i := 0x20 @@ -56,9 +57,10 @@ contract MultiSendCallOnly { case 1 { revert(0, 0) } - if eq(success, 0) { - returndatacopy(0, 0, returndatasize()) - revert(0, returndatasize()) + if iszero(success) { + let ptr := mload(0x40) + returndatacopy(ptr, 0, returndatasize()) + revert(ptr, returndatasize()) } // Next entry starts at 85 byte + data length i := add(i, add(0x55, dataLength)) diff --git a/contracts/proxies/SafeProxy.sol b/contracts/proxies/SafeProxy.sol index 73f7daee5..a6b3cbbe5 100644 --- a/contracts/proxies/SafeProxy.sol +++ b/contracts/proxies/SafeProxy.sol @@ -31,7 +31,11 @@ contract SafeProxy { /// @dev Fallback function forwards all transactions and returns all received return data. fallback() external payable { - // solhint-disable-next-line no-inline-assembly + // Note that this assembly block is **intentionally** not marked as memory-safe. First of all, it isn't memory + // safe to begin with, and turning this into memory-safe assembly would just make it less gas efficient. + // Additionally, we noticed that converting this to memory-safe assembly had no affect on optimizations of other + // contracts (as it always gets compiled alone in its own compilation unit anyway). + /* solhint-disable no-inline-assembly */ assembly { let _singleton := sload(0) // 0xa619486e == keccak("masterCopy()"). The value is right padded to 32-bytes with 0s @@ -42,10 +46,11 @@ contract SafeProxy { calldatacopy(0, 0, calldatasize()) let success := delegatecall(gas(), _singleton, 0, calldatasize(), 0, 0) returndatacopy(0, 0, returndatasize()) - if eq(success, 0) { + if iszero(success) { revert(0, returndatasize()) } return(0, returndatasize()) } + /* solhint-enable no-inline-assembly */ } } diff --git a/contracts/test/DelegateCaller.sol b/contracts/test/DelegateCaller.sol index 6a513f5ca..969d0623f 100644 --- a/contracts/test/DelegateCaller.sol +++ b/contracts/test/DelegateCaller.sol @@ -14,9 +14,11 @@ contract DelegateCaller { (success, returnData) = _called.delegatecall(_calldata); if (!success) { /* solhint-disable no-inline-assembly */ + /// @solidity memory-safe-assembly assembly { - returndatacopy(0, 0, returndatasize()) - revert(0, returndatasize()) + let ptr := mload(0x40) + returndatacopy(ptr, 0, returndatasize()) + revert(ptr, returndatasize()) } /* solhint-enable no-inline-assembly */ } diff --git a/docs/safe_tx_gas.md b/docs/safe_tx_gas.md index cc8ac592f..a27ad5fa0 100644 --- a/docs/safe_tx_gas.md +++ b/docs/safe_tx_gas.md @@ -56,9 +56,9 @@ if (!success && safeTxGas == 0 && gasPrice == 0) { /* solhint-disable no-inline-assembly */ /// @solidity memory-safe-assembly assembly { - let p := mload(0x40) - returndatacopy(p, 0, returndatasize()) - revert(p, returndatasize()) + let ptr := mload(0x40) + returndatacopy(ptr, 0, returndatasize()) + revert(ptr, returndatasize()) } /* solhint-enable no-inline-assembly */ } From 937af5ff9d76ed5635e6bacb76629bf721c01cd9 Mon Sep 17 00:00:00 2001 From: Nicholas Rodrigues Lordello Date: Thu, 5 Dec 2024 09:48:56 +0100 Subject: [PATCH 02/38] Update Documented Latest Release (#861) It is now ~~1.4.1-2~~ 1.4.1-3 with the migration contracts. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index da07ae7ef..f696b4145 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ To add support for a new network follow the steps of the ``Deploy`` section and > :warning: **Make sure to use the correct commit when deploying the contracts.** Any change (even comments) within the contract files will result in different addresses. The tagged versions that are used by the Safe team can be found in the [releases](https://github.com/safe-global/safe-smart-account/releases). -> **Current version:** The latest release is [v1.4.1-build.0](https://github.com/safe-global/safe-smart-account/tree/v1.4.1-build.0) on the commit [192c7dc](https://github.com/safe-global/safe-smart-account/commit/192c7dc67290940fcbc75165522bb86a37187069) +> **Current version:** The latest release is [v1.4.1-3](https://github.com/safe-global/safe-smart-account/tree/v1.4.1-3) on the commit [21dc824](https://github.com/safe-global/safe-smart-account/commit/21dc82410445637820f600c7399a804ad55841d5) This will deploy the contracts deterministically and verify the contracts on etherscan using [Solidity 0.7.6](https://github.com/ethereum/solidity/releases/tag/v0.7.6) by default. From 691aa4f528b24b0e202720d78f136b0e9234aab2 Mon Sep 17 00:00:00 2001 From: Nicholas Rodrigues Lordello Date: Thu, 5 Dec 2024 12:07:01 +0100 Subject: [PATCH 03/38] Disable zkSync Tests (#862) Matter Labs recently renamed `era-test-node` to `zksync-anvil`. This causes the official `hardhat-zksync-node` package to stop working. It is possible to patch the NPM package so that it works with `sed`: ```sh find node_modules/@matterlabs/hardhat-zksync-node/ -type f -exec sed -i "s/era[_-]test[_-]node/anvil-zksync/g" '{}' ';' ``` However, the tests seem to be quite flaky (ran on my machine once, but the `anvil` node seems to crash quite often). --- .gitignore | 1 + package.json | 4 +- test/core/Safe.OwnerManager.spec.ts | 2 +- test/core/Safe.Signatures.spec.ts | 2 +- .../ExtensibleFallbackHandler.spec.ts | 83 ++++++++++--------- test/l2/Safe.Execution.spec.ts | 2 +- test/libraries/Migration.120.spec.ts | 2 +- 7 files changed, 49 insertions(+), 47 deletions(-) diff --git a/.gitignore b/.gitignore index 51be0e8c9..91d6cfba0 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,4 @@ typechain-types # zksync era node log era_test_node.log +anvil-zksync.log diff --git a/package.json b/package.json index 9ab9b2caa..13db74ac3 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "build:ts": "rimraf dist && tsc -p tsconfig.prod.json", "build:ts:dev": "rimraf dist && tsc -p tsconfig.json", "test:zk": "HARDHAT_ENABLE_ZKSYNC=1 hardhat test", - "test": "hardhat test --network hardhat && npm run test:L1 && npm run test:L2 && npm run test:zk", + "test": "hardhat test --network hardhat && npm run test:L1 && npm run test:L2", "test:parallel": "hardhat test --parallel", "test:L1": "HARDHAT_CHAIN_ID=1 hardhat test --grep '@L1'", "test:L2": "SAFE_CONTRACT_UNDER_TEST=SafeL2 hardhat test --network hardhat", @@ -32,7 +32,7 @@ "lint": "npm run lint:sol && npm run lint:ts", "lint:fix": "npm run lint:sol:fix && npm run lint:ts:fix", "lint:sol": "solhint 'contracts/**/*.sol'", - "lint:sol:fix": "solhint --fix 'contracts/**/*.sol'", + "lint:sol:fix": "solhint --fix 'contracts/**/*.sol' --noPrompt", "lint:sol:prettier": "prettier 'contracts/**/*.sol' --list-different", "lint:ts": "eslint 'src/**/*.ts' 'test/**/*.ts'", "lint:ts:fix": "eslint 'src/**/*.ts' 'test/**/*.ts' --fix", diff --git a/test/core/Safe.OwnerManager.spec.ts b/test/core/Safe.OwnerManager.spec.ts index f6903df2a..2d7e50e79 100644 --- a/test/core/Safe.OwnerManager.spec.ts +++ b/test/core/Safe.OwnerManager.spec.ts @@ -395,7 +395,7 @@ describe("OwnerManager", () => { }); }); - describe("changeThreshold", async () => { + describe("changeThreshold", () => { it("can only be called from Safe itself", async () => { const { safe } = await setupTests(); await expect(safe.changeThreshold(1)).to.be.revertedWith("GS031"); diff --git a/test/core/Safe.Signatures.spec.ts b/test/core/Safe.Signatures.spec.ts index 2941a3f41..97041848c 100644 --- a/test/core/Safe.Signatures.spec.ts +++ b/test/core/Safe.Signatures.spec.ts @@ -639,7 +639,7 @@ describe("Safe", () => { }); }); - describe("checkNSignatures", async () => { + describe("checkNSignatures", () => { it("should fail if signature points into static part", async () => { const { safe, diff --git a/test/handlers/ExtensibleFallbackHandler.spec.ts b/test/handlers/ExtensibleFallbackHandler.spec.ts index df7cee4e6..ff3b48376 100644 --- a/test/handlers/ExtensibleFallbackHandler.spec.ts +++ b/test/handlers/ExtensibleFallbackHandler.spec.ts @@ -7,11 +7,10 @@ import { chainId } from "../utils/encoding"; import { encodeHandler, decodeHandler, encodeCustomVerifier, encodeHandlerFunction } from "../utils/extensible"; import { killLibContract } from "../utils/contracts"; -describe("ExtensibleFallbackHandler", async () => { - const [user1, user2] = await hre.ethers.getSigners(); - +describe("ExtensibleFallbackHandler", () => { const setupTests = deployments.createFixture(async ({ deployments }) => { await deployments.fixture(); + const [user1, user2] = await hre.ethers.getSigners(); const signLib = await (await hre.ethers.getContractFactory("SignMessageLib")).deploy(); const handler = await getExtensibleFallbackHandler(); const handlerAddress = await handler.getAddress(); @@ -49,13 +48,13 @@ describe("ExtensibleFallbackHandler", async () => { const counterSource = ` contract Counter { uint256 public count = 0; - + function handle(address, address, uint256, bytes calldata) external returns (bytes memory result) { bytes4 selector; assembly { selector := calldataload(164) } - + require(selector == 0xdeadbeef, "Invalid data"); count = count + 1; } @@ -112,6 +111,8 @@ describe("ExtensibleFallbackHandler", async () => { ); return { + user1, + user2, safe, validator, otherSafe, @@ -128,8 +129,8 @@ describe("ExtensibleFallbackHandler", async () => { }; }); - describe("Token Callbacks", async () => { - describe("ERC1155", async () => { + describe("Token Callbacks", () => { + describe("ERC1155", () => { it("to handle onERC1155Received", async () => { const { handler } = await setupTests(); expect(await handler.onERC1155Received.staticCall(AddressZero, AddressZero, 0, 0, "0x")).to.be.eq("0xf23a6e61"); @@ -146,7 +147,7 @@ describe("ExtensibleFallbackHandler", async () => { }); }); - describe("ERC721", async () => { + describe("ERC721", () => { it("to handle onERC721Received", async () => { const { handler } = await setupTests(); expect(await handler.onERC721Received.staticCall(AddressZero, AddressZero, 0, "0x")).to.be.eq("0x150b7a02"); @@ -159,10 +160,10 @@ describe("ExtensibleFallbackHandler", async () => { }); }); - describe("Fallback Handler", async () => { - describe("fallback()", async () => { + describe("Fallback Handler", () => { + describe("fallback()", () => { it("should revert if call to safe is less than 4 bytes (method selector)", async () => { - const { validator } = await setupTests(); + const { user1, validator } = await setupTests(); const tx = { to: await validator.getAddress(), @@ -175,8 +176,8 @@ describe("ExtensibleFallbackHandler", async () => { }); }); - describe("Custom methods", async () => { - describe("setSafeMethod(bytes4,bytes32)", async () => { + describe("Custom methods", () => { + describe("setSafeMethod(bytes4,bytes32)", () => { it("should revert if called by non-safe", async () => { const { handler, mirror } = await setupTests(); await expect(handler.setSafeMethod("0xdeadbeef", encodeHandler(true, await mirror.getAddress()))).to.be.revertedWith( @@ -185,7 +186,7 @@ describe("ExtensibleFallbackHandler", async () => { }); it("should emit event when setting a new method", async () => { - const { safe, handler, validator, mirror } = await setupTests(); + const { user1, user2, safe, handler, validator, mirror } = await setupTests(); const safeAddress = await safe.getAddress(); const newHandler = encodeHandler(true, await mirror.getAddress()); await expect(executeContractCallWithSigners(safe, validator, "setSafeMethod", ["0xdededede", newHandler], [user1, user2])) @@ -197,7 +198,7 @@ describe("ExtensibleFallbackHandler", async () => { }); it("should emit event when updating a method", async () => { - const { otherSafe, handler, preconfiguredValidator, mirror } = await setupTests(); + const { user1, user2, otherSafe, handler, preconfiguredValidator, mirror } = await setupTests(); const otherSafeAddress = await otherSafe.getAddress(); const oldHandler = encodeHandler(true, await mirror.getAddress()); const newHandler = encodeHandler(true, "0xdeAdDeADDEaDdeaDdEAddEADDEAdDeadDEADDEaD"); @@ -218,7 +219,7 @@ describe("ExtensibleFallbackHandler", async () => { }); it("should emit event when removing a method", async () => { - const { otherSafe, handler, preconfiguredValidator } = await setupTests(); + const { user1, user2, otherSafe, handler, preconfiguredValidator } = await setupTests(); const otherSafeAddress = await otherSafe.getAddress(); await expect( executeContractCallWithSigners( @@ -237,7 +238,7 @@ describe("ExtensibleFallbackHandler", async () => { }); it("is correctly set", async () => { - const { safe, validator, mirror } = await setupTests(); + const { user1, user2, safe, validator, mirror } = await setupTests(); const safeAddress = await safe.getAddress(); const tx = { to: safeAddress, @@ -275,7 +276,7 @@ describe("ExtensibleFallbackHandler", async () => { }); it("should allow calling non-static methods", async () => { - const { safe, validator, counter } = await setupTests(); + const { user1, user2, safe, validator, counter } = await setupTests(); const tx = { to: await safe.getAddress(), @@ -302,7 +303,7 @@ describe("ExtensibleFallbackHandler", async () => { }); }); - describe("MarshalLib", async () => { + describe("MarshalLib", () => { it("should correctly encode a handler and static flag", async () => { const { testMarshalLib } = await setupTests(); const handler = "0xdeaddeaddeaddeaddeaddeaddeaddeaddeaddead"; @@ -358,15 +359,15 @@ describe("ExtensibleFallbackHandler", async () => { }); }); - describe("Signature Verifier Muxer", async () => { - describe("supportsInterface(bytes4)", async () => { + describe("Signature Verifier Muxer", () => { + describe("supportsInterface(bytes4)", () => { it("should return true for supporting ERC1271", async () => { const { handler } = await setupTests(); expect(await handler.supportsInterface.staticCall("0x1626ba7e")).to.be.eq(true); }); }); - describe("setDomainVerifier(bytes32,address)", async () => { + describe("setDomainVerifier(bytes32,address)", () => { it("should revert if called by non-safe", async () => { const { handler, mirror } = await setupTests(); const domainSeparator = ethers.keccak256("0xdeadbeef"); @@ -376,7 +377,7 @@ describe("ExtensibleFallbackHandler", async () => { }); it("should emit event when setting a new domain verifier", async () => { - const { safe, handler, validator, testVerifier } = await setupTests(); + const { user1, user2, safe, handler, validator, testVerifier } = await setupTests(); const safeAddress = await safe.getAddress(); const testVerifierAddress = await testVerifier.getAddress(); const domainSeparator = ethers.keccak256("0xdeadbeef"); @@ -396,7 +397,7 @@ describe("ExtensibleFallbackHandler", async () => { }); it("should emit event when updating a domain verifier", async () => { - const { otherSafe, handler, preconfiguredValidator, mirror } = await setupTests(); + const { user1, user2, otherSafe, handler, preconfiguredValidator, mirror } = await setupTests(); const otherSafeAddress = await otherSafe.getAddress(); const mirrorAddress = await mirror.getAddress(); const domainSeparator = ethers.keccak256("0xdeadbeef"); @@ -418,7 +419,7 @@ describe("ExtensibleFallbackHandler", async () => { }); it("should emit event when removing a domain verifier", async () => { - const { otherSafe, handler, preconfiguredValidator } = await setupTests(); + const { user1, user2, otherSafe, handler, preconfiguredValidator } = await setupTests(); const otherSafeAddress = await otherSafe.getAddress(); const domainSeparator = ethers.keccak256("0xdeadbeef"); await expect( @@ -437,7 +438,7 @@ describe("ExtensibleFallbackHandler", async () => { }); }); - describe("isValidSignature(bytes32,bytes)", async () => { + describe("isValidSignature(bytes32,bytes)", () => { it("should revert if called directly", async () => { const { handler } = await setupTests(); const dataHash = ethers.keccak256("0xbaddad"); @@ -463,14 +464,14 @@ describe("ExtensibleFallbackHandler", async () => { }); it("should return magic value if message was signed", async () => { - const { safe, validator, signLib } = await setupTests(); + const { user1, user2, safe, validator, signLib } = await setupTests(); const dataHash = ethers.keccak256("0xbaddad"); await executeContractCallWithSigners(safe, signLib, "signMessage", [dataHash], [user1, user2], true); expect(await validator.isValidSignature.staticCall(dataHash, "0x")).to.be.eq("0x1626ba7e"); }); it("should return magic value if enough owners signed with typed signatures", async () => { - const { validator } = await setupTests(); + const { user1, user2, validator } = await setupTests(); const validatorAddress = await validator.getAddress(); const dataHash = ethers.keccak256("0xbaddad"); const typedDataSig = { @@ -496,7 +497,7 @@ describe("ExtensibleFallbackHandler", async () => { }); it("should send EIP-712 context to custom verifier", async () => { - const { safe, validator, revertVerifier } = await setupTests(); + const { user1, user2, safe, validator, revertVerifier } = await setupTests(); const domainSeparator = ethers.keccak256("0xdeadbeef"); const typeHash = ethers.keccak256("0xbaddad"); // abi encode the message @@ -600,36 +601,36 @@ describe("ExtensibleFallbackHandler", async () => { }); }); - describe("IERC165", async () => { - describe("supportsInterface(bytes4)", async () => { + describe("IERC165", () => { + describe("supportsInterface(bytes4)", () => { it("should return true for ERC165", async () => { const { validator } = await setupTests(); expect(await validator.supportsInterface.staticCall("0x01ffc9a7")).to.be.true; }); }); - describe("setSupportedInterface(bytes4,bool)", async () => { + describe("setSupportedInterface(bytes4,bool)", () => { it("should revert if called by non-safe", async () => { const { handler } = await setupTests(); await expect(handler.setSupportedInterface("0xdeadbeef", true)).to.be.revertedWith("only safe can call this method"); }); it("should revert if trying to set an invalid interface", async () => { - const { validator, safe } = await setupTests(); + const { user1, user2, validator, safe } = await setupTests(); await expect( executeContractCallWithSigners(safe, validator, "setSupportedInterface", ["0xffffffff", true], [user1, user2]), ).to.be.revertedWith("invalid interface id"); }); it("should emit event when adding a newly supported interface", async () => { - const { validator, safe, handler } = await setupTests(); + const { user1, user2, validator, safe, handler } = await setupTests(); await expect(executeContractCallWithSigners(safe, validator, "setSupportedInterface", ["0xdeadbeef", true], [user1, user2])) .to.emit(handler, "AddedInterface") .withArgs(await safe.getAddress(), "0xdeadbeef"); }); it("should emit event when removing a supported interface", async () => { - const { handler, otherSafe, preconfiguredValidator } = await setupTests(); + const { user1, user2, handler, otherSafe, preconfiguredValidator } = await setupTests(); await expect( executeContractCallWithSigners( @@ -645,7 +646,7 @@ describe("ExtensibleFallbackHandler", async () => { }); it("should not emit event when removing an unsupported interface", async () => { - const { handler, otherSafe, preconfiguredValidator } = await setupTests(); + const { user1, user2, handler, otherSafe, preconfiguredValidator } = await setupTests(); await expect( executeContractCallWithSigners( @@ -659,7 +660,7 @@ describe("ExtensibleFallbackHandler", async () => { }); }); - describe("addSupportedInterfaceBatch(bytes4, bytes32[]", async () => { + describe("addSupportedInterfaceBatch(bytes4, bytes32[]", () => { it("should revert if called by non-safe", async () => { const { handler } = await setupTests(); await expect(handler.addSupportedInterfaceBatch("0xdeadbeef", [HashZero])).to.be.revertedWith( @@ -668,7 +669,7 @@ describe("ExtensibleFallbackHandler", async () => { }); it("should revert if batch contains an invalid interface", async () => { - const { validator, safe } = await setupTests(); + const { user1, user2, validator, safe } = await setupTests(); await expect( executeContractCallWithSigners( safe, @@ -681,7 +682,7 @@ describe("ExtensibleFallbackHandler", async () => { }); it("should add all handlers in batch", async () => { - const { validator, safe, handler, mirror } = await setupTests(); + const { user1, user2, validator, safe, handler, mirror } = await setupTests(); const safeAddress = await safe.getAddress(); // calculate the selector for each function @@ -713,7 +714,7 @@ describe("ExtensibleFallbackHandler", async () => { }); }); - describe("removeSupportedInterfaceBatch(bytes4, bytes4[]", async () => { + describe("removeSupportedInterfaceBatch(bytes4, bytes4[]", () => { it("should revert if called by non-safe", async () => { const { handler } = await setupTests(); await expect(handler.removeSupportedInterfaceBatch("0xdeadbeef", ["0xdeadbeef"])).to.be.revertedWith( @@ -722,7 +723,7 @@ describe("ExtensibleFallbackHandler", async () => { }); it("should remove all methods in a batch", async () => { - const { validator, safe, handler, mirror } = await setupTests(); + const { user1, user2, validator, safe, handler, mirror } = await setupTests(); const safeAddress = await safe.getAddress(); // calculate the selector for each function diff --git a/test/l2/Safe.Execution.spec.ts b/test/l2/Safe.Execution.spec.ts index fbaf3a263..6d36b903e 100644 --- a/test/l2/Safe.Execution.spec.ts +++ b/test/l2/Safe.Execution.spec.ts @@ -29,7 +29,7 @@ describe("SafeL2", () => { }; }); - describe("execTransactions", async () => { + describe("execTransactions", () => { it("should emit SafeMultiSigTransaction event", async () => { const { safe, diff --git a/test/libraries/Migration.120.spec.ts b/test/libraries/Migration.120.spec.ts index a5979922f..60770ca5b 100644 --- a/test/libraries/Migration.120.spec.ts +++ b/test/libraries/Migration.120.spec.ts @@ -36,7 +36,7 @@ describe("Migration 1.2.0", () => { signers, }; }); - describe("constructor", async () => { + describe("constructor", () => { it("can not use 0 Address", async () => { const { signers: [user1], From febab5e4e859e6e65914f17efddee415e4992961 Mon Sep 17 00:00:00 2001 From: Mikhail <16622558+mmv08@users.noreply.github.com> Date: Thu, 5 Dec 2024 15:11:12 +0100 Subject: [PATCH 04/38] enable zksync tests again (#863) This pull request includes a small but significant change to the `package.json` file to enhance the testing process. Enhancements to testing: * [`package.json`](diffhunk://#diff-7ae45ad102eab3b6d7e7896acd08c427a9b25b346470d7bc6507b6481575d519L22-R22): Modified the `test` script to include running `test:zk` to ensure zkSync tests are executed along with other tests. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 13db74ac3..71e4495d6 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "build:ts": "rimraf dist && tsc -p tsconfig.prod.json", "build:ts:dev": "rimraf dist && tsc -p tsconfig.json", "test:zk": "HARDHAT_ENABLE_ZKSYNC=1 hardhat test", - "test": "hardhat test --network hardhat && npm run test:L1 && npm run test:L2", + "test": "hardhat test --network hardhat && npm run test:L1 && npm run test:L2 && npm run test:zk", "test:parallel": "hardhat test --parallel", "test:L1": "HARDHAT_CHAIN_ID=1 hardhat test --grep '@L1'", "test:L2": "SAFE_CONTRACT_UNDER_TEST=SafeL2 hardhat test --network hardhat", From e9a75acf795c70949bde934fcad51d4711dad066 Mon Sep 17 00:00:00 2001 From: Nicholas Rodrigues Lordello Date: Wed, 11 Dec 2024 11:00:52 +0100 Subject: [PATCH 05/38] Fix Migration Test Definitions (#865) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The migration tests are defining `describe` blocks asyncronously within an `it` block. AFAIU, this is a no-no and causes ugly test formatting. This PR adjusts the test definitions so that they belong to the correct parent `describe` block (one per migration version).
Test formatting before: ``` addOwner ✔ should add owner and change threshold enableModule ✔ should enabled module and be able to use it multiSend ✔ execute multisend via delegatecall fallbackHandler ✔ should be correctly set execTransaction ✔ should be able to transfer ETH (48ms) addOwner ✔ should add owner and change threshold enableModule ✔ should enabled module and be able to use it multiSend ✔ execute multisend via delegatecall fallbackHandler ✔ should be correctly set execTransaction ✔ should be able to transfer ETH (48ms) addOwner ✔ should add owner and change threshold enableModule ✔ should enabled module and be able to use it multiSend ✔ execute multisend via delegatecall fallbackHandler ✔ should be correctly set execTransaction ✔ should be able to transfer ETH (45ms) addOwner ✔ should add owner and change threshold enableModule ✔ should enabled module and be able to use it multiSend ✔ execute multisend via delegatecall fallbackHandler ✔ should be correctly set execTransaction ✔ should be able to transfer ETH (49ms) addOwner ✔ should add owner and change threshold enableModule ✔ should enabled module and be able to use it multiSend ✔ execute multisend via delegatecall fallbackHandler ✔ should be correctly set execTransaction ✔ should be able to transfer ETH (52ms) addOwner ✔ should add owner and change threshold enableModule ✔ should enabled module and be able to use it multiSend ✔ execute multisend via delegatecall fallbackHandler ✔ should be correctly set ```
Test formatting after: ``` Upgrade from Safe 1.1.1 execTransaction ✔ should be able to transfer ETH (50ms) addOwner ✔ should add owner and change threshold enableModule ✔ should enabled module and be able to use it multiSend ✔ execute multisend via delegatecall fallbackHandler ✔ should be correctly set Upgrade from Safe 1.2.0 execTransaction ✔ should be able to transfer ETH (45ms) addOwner ✔ should add owner and change threshold enableModule ✔ should enabled module and be able to use it multiSend ✔ execute multisend via delegatecall fallbackHandler ✔ should be correctly set Upgrade from Safe 1.3.0 execTransaction ✔ should be able to transfer ETH (52ms) addOwner ✔ should add owner and change threshold enableModule ✔ should enabled module and be able to use it multiSend ✔ execute multisend via delegatecall fallbackHandler ✔ should be correctly set Upgrade from Safe 1.3.0 L2 execTransaction ✔ should be able to transfer ETH (50ms) addOwner ✔ should add owner and change threshold enableModule ✔ should enabled module and be able to use it multiSend ✔ execute multisend via delegatecall fallbackHandler ✔ should be correctly set Upgrade from Safe 1.4.1 execTransaction ✔ should be able to transfer ETH (52ms) addOwner ✔ should add owner and change threshold enableModule ✔ should enabled module and be able to use it multiSend ✔ execute multisend via delegatecall fallbackHandler ✔ should be correctly set Upgrade from Safe 1.4.1 L2 execTransaction ✔ should be able to transfer ETH (51ms) addOwner ✔ should add owner and change threshold enableModule ✔ should enabled module and be able to use it multiSend ✔ execute multisend via delegatecall fallbackHandler ✔ should be correctly set ```
--- test/migration/UpgradeFromSafe111.spec.ts | 8 +++--- test/migration/UpgradeFromSafe120.spec.ts | 8 +++--- test/migration/UpgradeFromSafe130.spec.ts | 8 +++--- test/migration/UpgradeFromSafe130L2.spec.ts | 8 +++--- test/migration/UpgradeFromSafe141.spec.ts | 8 +++--- test/migration/UpgradeFromSafe141L2.spec.ts | 8 +++--- test/migration/subTests.spec.ts | 29 ++++++++++++++++----- 7 files changed, 46 insertions(+), 31 deletions(-) diff --git a/test/migration/UpgradeFromSafe111.spec.ts b/test/migration/UpgradeFromSafe111.spec.ts index 2b867c111..54f6cbf40 100644 --- a/test/migration/UpgradeFromSafe111.spec.ts +++ b/test/migration/UpgradeFromSafe111.spec.ts @@ -19,7 +19,8 @@ describe("Upgrade from Safe 1.1.1", () => { // We migrate the Safe and run the verification tests const setupTests = deployments.createFixture(async ({ deployments }) => { - const [user1] = await hre.ethers.getSigners(); + const signers = await hre.ethers.getSigners(); + const [user1] = signers; await deployments.fixture(); const mock = await getMock(); const mockAddress = await mock.getAddress(); @@ -45,10 +46,9 @@ describe("Upgrade from Safe 1.1.1", () => { migratedSafe: safe, mock, multiSend: await getMultiSend(), + signers, }; }); - it("passes the Safe 1.1.1 tests", async () => { - await verificationTests(setupTests); - }); + verificationTests(setupTests); }); diff --git a/test/migration/UpgradeFromSafe120.spec.ts b/test/migration/UpgradeFromSafe120.spec.ts index 35ca0a37b..e4ba64b79 100644 --- a/test/migration/UpgradeFromSafe120.spec.ts +++ b/test/migration/UpgradeFromSafe120.spec.ts @@ -22,7 +22,8 @@ describe("Upgrade from Safe 1.2.0", () => { await deployments.fixture(); const mock = await getMock(); const mockAddress = await mock.getAddress(); - const [user1] = await hre.ethers.getSigners(); + const signers = await hre.ethers.getSigners(); + const [user1] = signers; const singleton120 = (await (await user1.sendTransaction({ data: deploymentData.safe120 })).wait())?.contractAddress; if (!singleton120) throw new Error("Could not deploy Safe 1.2.0"); @@ -46,10 +47,9 @@ describe("Upgrade from Safe 1.2.0", () => { migratedSafe: safe, mock, multiSend: await getMultiSend(), + signers, }; }); - it("passes the Safe 1.2.0 tests", async () => { - await verificationTests(setupTests); - }); + verificationTests(setupTests); }); diff --git a/test/migration/UpgradeFromSafe130.spec.ts b/test/migration/UpgradeFromSafe130.spec.ts index c4d88597e..5280d59fc 100644 --- a/test/migration/UpgradeFromSafe130.spec.ts +++ b/test/migration/UpgradeFromSafe130.spec.ts @@ -20,7 +20,8 @@ describe("Upgrade from Safe 1.3.0", () => { await deployments.fixture(); const mock = await getMock(); const mockAddress = await mock.getAddress(); - const [user1] = await hre.ethers.getSigners(); + const signers = await hre.ethers.getSigners(); + const [user1] = signers; const singleton130 = (await (await user1.sendTransaction({ data: deploymentData.safe130.evm })).wait())?.contractAddress; if (!singleton130) throw new Error("Could not deploy Safe 1.3.0"); @@ -45,10 +46,9 @@ describe("Upgrade from Safe 1.3.0", () => { migratedSafe: safe, mock, multiSend: await getMultiSend(), + signers, }; }); - it("passes the Safe 1.3.0 tests", async () => { - await verificationTests(setupTests); - }); + verificationTests(setupTests); }); diff --git a/test/migration/UpgradeFromSafe130L2.spec.ts b/test/migration/UpgradeFromSafe130L2.spec.ts index fadb4f5f2..83924eace 100644 --- a/test/migration/UpgradeFromSafe130L2.spec.ts +++ b/test/migration/UpgradeFromSafe130L2.spec.ts @@ -20,7 +20,8 @@ describe("Upgrade from Safe 1.3.0 L2", () => { await deployments.fixture(); const mock = await getMock(); const mockAddress = await mock.getAddress(); - const [user1] = await hre.ethers.getSigners(); + const signers = await hre.ethers.getSigners(); + const [user1] = signers; const singleton130L2 = (await (await user1.sendTransaction({ data: deploymentData.safe130l2.evm })).wait())?.contractAddress; if (!singleton130L2) throw new Error("Could not deploy Safe 1.3.0 L2"); @@ -45,10 +46,9 @@ describe("Upgrade from Safe 1.3.0 L2", () => { migratedSafe: safe, mock, multiSend: await getMultiSend(), + signers, }; }); - it("passes the Safe 1.3.0 tests", async () => { - await verificationTests(setupTests); - }); + verificationTests(setupTests); }); diff --git a/test/migration/UpgradeFromSafe141.spec.ts b/test/migration/UpgradeFromSafe141.spec.ts index 7af3da232..aab623216 100644 --- a/test/migration/UpgradeFromSafe141.spec.ts +++ b/test/migration/UpgradeFromSafe141.spec.ts @@ -13,7 +13,8 @@ describe("Upgrade from Safe 1.4.1", () => { await deployments.fixture(); const mock = await getMock(); const mockAddress = await mock.getAddress(); - const [user1] = await hre.ethers.getSigners(); + const signers = await hre.ethers.getSigners(); + const [user1] = signers; const safeDeploymentData = hre.network.zksync ? deploymentData.safe141.zksync : deploymentData.safe141.evm; const safeContractFactory = new hre.ethers.ContractFactory(await getAbi("Safe"), safeDeploymentData, user1); const singleton141 = await (await safeContractFactory.deploy()).getAddress(); @@ -40,10 +41,9 @@ describe("Upgrade from Safe 1.4.1", () => { migratedSafe: safe, mock, multiSend: await getMultiSend(), + signers, }; }); - it("passes the Safe 1.4.1 tests", async () => { - await verificationTests(setupTests); - }); + verificationTests(setupTests); }); diff --git a/test/migration/UpgradeFromSafe141L2.spec.ts b/test/migration/UpgradeFromSafe141L2.spec.ts index fa77dea66..085a49d47 100644 --- a/test/migration/UpgradeFromSafe141L2.spec.ts +++ b/test/migration/UpgradeFromSafe141L2.spec.ts @@ -13,7 +13,8 @@ describe("Upgrade from Safe 1.4.1 L2", () => { await deployments.fixture(); const mock = await getMock(); const mockAddress = await mock.getAddress(); - const [user1] = await hre.ethers.getSigners(); + const signers = await hre.ethers.getSigners(); + const [user1] = signers; const safeDeploymentData = hre.network.zksync ? deploymentData.safe141l2.zksync : deploymentData.safe141l2.evm; const safeContractFactory = new hre.ethers.ContractFactory(await getAbi("Safe"), safeDeploymentData, user1); const singleton141L2 = await (await safeContractFactory.deploy()).getAddress(); @@ -40,10 +41,9 @@ describe("Upgrade from Safe 1.4.1 L2", () => { migratedSafe: safe, mock, multiSend: await getMultiSend(), + signers, }; }); - it("passes the Safe 1.4.1 tests", async () => { - await verificationTests(setupTests); - }); + verificationTests(setupTests); }); diff --git a/test/migration/subTests.spec.ts b/test/migration/subTests.spec.ts index a34b98202..24bb778a6 100644 --- a/test/migration/subTests.spec.ts +++ b/test/migration/subTests.spec.ts @@ -1,3 +1,4 @@ +import type { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers"; import { expect } from "chai"; import hre, { ethers } from "hardhat"; import { AddressOne } from "../../src/utils/constants"; @@ -9,14 +10,16 @@ interface TestSetup { migratedSafe: Safe; mock: MockContract; multiSend: MultiSend; + signers: HardhatEthersSigner[]; } -export const verificationTests = async (setupTests: () => Promise) => { - const [user1, user2, user3] = await ethers.getSigners(); - +export const verificationTests = (setupTests: () => Promise) => { describe("execTransaction", () => { it("should be able to transfer ETH", async () => { - const { migratedSafe } = await setupTests(); + const { + migratedSafe, + signers: [user1, user2], + } = await setupTests(); const migrateSafeAddress = await migratedSafe.getAddress(); await user1.sendTransaction({ to: migrateSafeAddress, value: ethers.parseEther("1") }); const nonce = await migratedSafe.nonce(); @@ -34,7 +37,10 @@ export const verificationTests = async (setupTests: () => Promise) => describe("addOwner", () => { it("should add owner and change threshold", async () => { - const { migratedSafe } = await setupTests(); + const { + migratedSafe, + signers: [user1, user2, user3], + } = await setupTests(); await expect(executeContractCallWithSigners(migratedSafe, migratedSafe, "addOwnerWithThreshold", [user2.address, 2], [user1])) .to.emit(migratedSafe, "AddedOwner") @@ -62,7 +68,11 @@ export const verificationTests = async (setupTests: () => Promise) => describe("enableModule", () => { it("should enabled module and be able to use it", async () => { - const { migratedSafe, mock } = await setupTests(); + const { + migratedSafe, + mock, + signers: [user1, user2], + } = await setupTests(); const mockAddress = await mock.getAddress(); await expect(executeContractCallWithSigners(migratedSafe, migratedSafe, "enableModule", [user2.address], [user1])) @@ -82,7 +92,12 @@ export const verificationTests = async (setupTests: () => Promise) => describe("multiSend", () => { it("execute multisend via delegatecall", async () => { - const { migratedSafe, mock, multiSend } = await setupTests(); + const { + migratedSafe, + mock, + multiSend, + signers: [user1, user2], + } = await setupTests(); const migratedSafeAddress = await migratedSafe.getAddress(); const mockAddress = await mock.getAddress(); From e9a58ce0840a314f18ecb7fc17d4eb6a17ac70dd Mon Sep 17 00:00:00 2001 From: Nicholas Rodrigues Lordello Date: Fri, 13 Dec 2024 09:54:06 +0100 Subject: [PATCH 06/38] Disable Pre-approved IsValidSignature (#866) This commit disables support for pre-approved signatures from `msg.sender` for `isValidSignature` calls. Note that we remove the new 1.5.0-only `checkSignatures` interface in favour of one with `executor` explicitly provided to avoid issues for contracts that make use of this function. --- certora/specs/NativeTokenRefund.spec | 2 +- certora/specs/Safe.spec | 2 +- certora/specs/Signatures.spec | 17 +++-- contracts/Safe.sol | 12 ++-- .../handler/CompatibilityFallbackHandler.sol | 4 +- .../handler/extensible/ERC165Handler.sol | 18 ++--- .../handler/extensible/ExtensibleBase.sol | 22 +++---- .../handler/extensible/FallbackHandler.sol | 6 +- .../extensible/SignatureVerifierMuxer.sol | 22 +++---- contracts/interfaces/ISafe.sol | 7 +- contracts/test/TestSafeSignatureVerifier.sol | 4 +- test/core/Safe.Signatures.spec.ts | 66 ++++++++++--------- .../CompatibilityFallbackHandler.spec.ts | 34 +++++++++- .../ExtensibleFallbackHandler.spec.ts | 21 ++++++ 14 files changed, 149 insertions(+), 88 deletions(-) diff --git a/certora/specs/NativeTokenRefund.spec b/certora/specs/NativeTokenRefund.spec index 45b092153..04a59890d 100644 --- a/certora/specs/NativeTokenRefund.spec +++ b/certora/specs/NativeTokenRefund.spec @@ -1,7 +1,7 @@ // This spec is a separate file because we summarize checkSignatures here methods { - function checkSignatures(bytes32, bytes memory) internal => NONDET; + function checkSignatures(address, bytes32, bytes memory) internal => NONDET; function getNativeTokenBalanceFor(address) external returns (uint256) envfree; function getSafeGuard() external returns (address) envfree; diff --git a/certora/specs/Safe.spec b/certora/specs/Safe.spec index 5149a637d..cdb749726 100644 --- a/certora/specs/Safe.spec +++ b/certora/specs/Safe.spec @@ -18,7 +18,7 @@ methods { function execTransactionFromModule(address,uint256,bytes,Enum.Operation) external returns (bool); function execTransaction(address,uint256,bytes,Enum.Operation,uint256,uint256,uint256,address,address,bytes) external returns (bool); - function checkSignatures(bytes32, bytes memory) internal => NONDET; + function checkSignatures(address, bytes32, bytes memory) internal => NONDET; } definition reachableOnly(method f) returns bool = diff --git a/certora/specs/Signatures.spec b/certora/specs/Signatures.spec index 4b485bfb6..489275a45 100644 --- a/certora/specs/Signatures.spec +++ b/certora/specs/Signatures.spec @@ -2,6 +2,8 @@ methods { function getThreshold() external returns (uint256) envfree; function nonce() external returns (uint256) envfree; function isOwner(address) external returns (bool) envfree; + function checkSignatures(address, bytes32, bytes) external envfree; + function checkNSignatures(address, bytes32, bytes, uint256) external envfree; // harnessed function signatureSplitPublic(bytes,uint256) external returns (uint8,bytes32,bytes32) envfree; @@ -27,8 +29,7 @@ methods { ) internal returns (bytes32) => CONSTANT; // optional - function checkSignatures(bytes32,bytes) external; - function execTransaction(address,uint256,bytes,Enum.Operation,uint256,uint256,uint256,address,address,bytes) external returns (bool); + function execTransaction(address, uint256, bytes, Enum.Operation, uint256, uint256, uint256, address, address, bytes) external returns (bool); } definition MAX_UINT256() returns uint256 = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; @@ -46,7 +47,6 @@ function signatureSplitGhost(bytes signatures, uint256 pos) returns (uint8,bytes rule checkSignatures() { bytes32 dataHash; address executor; - env e; bytes signaturesAB; bytes signaturesA; bytes signaturesB; @@ -66,14 +66,13 @@ rule checkSignatures() { require !isOwner(currentContract); require getThreshold() == 2; require getCurrentOwner(dataHash, vA, rA, sA) < getCurrentOwner(dataHash, vB, rB, sB); - require executor == e.msg.sender; - checkNSignatures@withrevert(e, executor, dataHash, signaturesA, 1); + checkNSignatures@withrevert(executor, dataHash, signaturesA, 1); bool successA = !lastReverted; - checkNSignatures@withrevert(e, executor, dataHash, signaturesB, 1); + checkNSignatures@withrevert(executor, dataHash, signaturesB, 1); bool successB = !lastReverted; - checkSignatures@withrevert(e, dataHash, signaturesAB); + checkSignatures@withrevert(executor, dataHash, signaturesAB); bool successAB = !lastReverted; assert (successA && successB) <=> successAB, "checkNSignatures called twice separately must be equivalent to checkSignatures"; @@ -107,8 +106,8 @@ rule ownerSignaturesAreProvidedForExecTransaction( ); env e; - require e.msg.value == 0; - checkSignatures@withrevert(e, transactionHash, signatures); + + checkSignatures@withrevert(e.msg.sender, transactionHash, signatures); bool checkSignaturesOk = !lastReverted; execTransaction(e, to, value, data, operation, safeTxGas, baseGas, gasPrice, gasToken, refundReceiver, signatures); diff --git a/contracts/Safe.sol b/contracts/Safe.sol index b08611354..241cfc4fd 100644 --- a/contracts/Safe.sol +++ b/contracts/Safe.sol @@ -139,7 +139,7 @@ contract Safe is // We use the post-increment here, so the current nonce value is used and incremented afterwards. nonce++ ); - checkSignatures(txHash, signatures); + checkSignatures(msg.sender, txHash, signatures); } address guard = getGuard(); { @@ -267,12 +267,12 @@ contract Safe is /** * @inheritdoc ISafe */ - function checkSignatures(bytes32 dataHash, bytes memory signatures) public view override { + function checkSignatures(address executor, bytes32 dataHash, bytes memory signatures) public view override { // Load threshold to avoid multiple storage loads uint256 _threshold = threshold; // Check that a threshold is set if (_threshold == 0) revertWithError("GS001"); - checkNSignatures(msg.sender, dataHash, signatures, _threshold); + checkNSignatures(executor, dataHash, signatures, _threshold); } /** @@ -335,7 +335,8 @@ contract Safe is * @notice Checks whether the signature provided is valid for the provided hash. Reverts otherwise. * The `data` parameter is completely ignored during signature verification. * @dev This function is provided for compatibility with previous versions. - * Use `checkSignatures(bytes32,bytes)` instead. + * Use `checkSignatures(address,bytes32,bytes)` instead. + * ⚠️⚠️⚠️ If the caller is an owner of the Safe, it can trivially sign any hash with a pre-approve signature and may reduce the threshold of the signature by 1. ⚠️⚠️⚠️ * @param dataHash Hash of the data (could be either a message hash or transaction hash). * @param data **IGNORED** The data pre-image. * @param signatures Signature data that should be verified. @@ -343,7 +344,7 @@ contract Safe is */ function checkSignatures(bytes32 dataHash, bytes calldata data, bytes memory signatures) external view { data; - checkSignatures(dataHash, signatures); + checkSignatures(msg.sender, dataHash, signatures); } /** @@ -351,6 +352,7 @@ contract Safe is * The `data` parameter is completely ignored during signature verification. * @dev This function is provided for compatibility with previous versions. * Use `checkNSignatures(address,bytes32,bytes,uint256)` instead. + * ⚠️⚠️⚠️ If the caller is an owner of the Safe, it can trivially sign any hash with a pre-approve signature and may reduce the threshold of the signature by 1. ⚠️⚠️⚠️ * @param dataHash Hash of the data (could be either a message hash or transaction hash) * @param data **IGNORED** The data pre-image. * @param signatures Signature data that should be verified. diff --git a/contracts/handler/CompatibilityFallbackHandler.sol b/contracts/handler/CompatibilityFallbackHandler.sol index e9517080a..3b90f68a9 100644 --- a/contracts/handler/CompatibilityFallbackHandler.sol +++ b/contracts/handler/CompatibilityFallbackHandler.sol @@ -62,7 +62,9 @@ contract CompatibilityFallbackHandler is TokenCallbackHandler, ISignatureValidat if (_signature.length == 0) { require(safe.signedMessages(messageHash) != 0, "Hash not approved"); } else { - safe.checkSignatures(messageHash, _signature); + // We explicitly do not allow caller approved signatures for EIP-1271 to prevent unexpected behaviour. This + // is done by setting the executor address to `0` which can never be an owner of the Safe. + safe.checkSignatures(address(0), messageHash, _signature); } return EIP1271_MAGIC_VALUE; } diff --git a/contracts/handler/extensible/ERC165Handler.sol b/contracts/handler/extensible/ERC165Handler.sol index a5f85b9cc..4833ddcdf 100644 --- a/contracts/handler/extensible/ERC165Handler.sol +++ b/contracts/handler/extensible/ERC165Handler.sol @@ -2,10 +2,10 @@ pragma solidity >=0.7.0 <0.9.0; import {IERC165} from "../../interfaces/IERC165.sol"; -import {Safe, MarshalLib, ExtensibleBase} from "./ExtensibleBase.sol"; +import {ISafe, MarshalLib, ExtensibleBase} from "./ExtensibleBase.sol"; interface IERC165Handler { - function safeInterfaces(Safe safe, bytes4 interfaceId) external view returns (bool); + function safeInterfaces(ISafe safe, bytes4 interfaceId) external view returns (bool); function setSupportedInterface(bytes4 interfaceId, bool supported) external; @@ -17,12 +17,12 @@ interface IERC165Handler { abstract contract ERC165Handler is ExtensibleBase, IERC165Handler { // --- events --- - event AddedInterface(Safe indexed safe, bytes4 interfaceId); - event RemovedInterface(Safe indexed safe, bytes4 interfaceId); + event AddedInterface(ISafe indexed safe, bytes4 interfaceId); + event RemovedInterface(ISafe indexed safe, bytes4 interfaceId); // --- storage --- - mapping(Safe => mapping(bytes4 => bool)) public override safeInterfaces; + mapping(ISafe => mapping(bytes4 => bool)) public override safeInterfaces; // --- setters --- @@ -32,7 +32,7 @@ abstract contract ERC165Handler is ExtensibleBase, IERC165Handler { * @param supported True if the interface is supported, false otherwise */ function setSupportedInterface(bytes4 interfaceId, bool supported) public override onlySelf { - Safe safe = Safe(payable(_manager())); + ISafe safe = ISafe(payable(_manager())); // invalid interface id per ERC165 spec require(interfaceId != 0xffffffff, "invalid interface id"); bool current = safeInterfaces[safe][interfaceId]; @@ -51,7 +51,7 @@ abstract contract ERC165Handler is ExtensibleBase, IERC165Handler { * @param handlerWithSelectors The handlers encoded with the 4-byte selectors of the methods */ function addSupportedInterfaceBatch(bytes4 _interfaceId, bytes32[] calldata handlerWithSelectors) external override onlySelf { - Safe safe = Safe(payable(_msgSender())); + ISafe safe = ISafe(payable(_msgSender())); bytes4 interfaceId; for (uint256 i = 0; i < handlerWithSelectors.length; i++) { (bool isStatic, bytes4 selector, address handlerAddress) = MarshalLib.decodeWithSelector(handlerWithSelectors[i]); @@ -73,7 +73,7 @@ abstract contract ERC165Handler is ExtensibleBase, IERC165Handler { * @param selectors The selectors of the methods to remove */ function removeSupportedInterfaceBatch(bytes4 _interfaceId, bytes4[] calldata selectors) external override onlySelf { - Safe safe = Safe(payable(_msgSender())); + ISafe safe = ISafe(payable(_msgSender())); bytes4 interfaceId; for (uint256 i = 0; i < selectors.length; i++) { _setSafeMethod(safe, selectors[i], bytes32(0)); @@ -99,7 +99,7 @@ abstract contract ERC165Handler is ExtensibleBase, IERC165Handler { interfaceId == type(IERC165).interfaceId || interfaceId == type(IERC165Handler).interfaceId || _supportsInterface(interfaceId) || - safeInterfaces[Safe(payable(_manager()))][interfaceId]; + safeInterfaces[ISafe(payable(_manager()))][interfaceId]; } // --- internal --- diff --git a/contracts/handler/extensible/ExtensibleBase.sol b/contracts/handler/extensible/ExtensibleBase.sol index 9aa9d301e..6c1e19a7c 100644 --- a/contracts/handler/extensible/ExtensibleBase.sol +++ b/contracts/handler/extensible/ExtensibleBase.sol @@ -1,16 +1,16 @@ // SPDX-License-Identifier: LGPL-3.0-only pragma solidity >=0.7.0 <0.9.0; -import {Safe} from "../../Safe.sol"; +import {ISafe} from "../../interfaces/ISafe.sol"; import {HandlerContext} from "../HandlerContext.sol"; import {MarshalLib} from "./MarshalLib.sol"; interface IFallbackMethod { - function handle(Safe safe, address sender, uint256 value, bytes calldata data) external returns (bytes memory result); + function handle(ISafe safe, address sender, uint256 value, bytes calldata data) external returns (bytes memory result); } interface IStaticFallbackMethod { - function handle(Safe safe, address sender, uint256 value, bytes calldata data) external view returns (bytes memory result); + function handle(ISafe safe, address sender, uint256 value, bytes calldata data) external view returns (bytes memory result); } /** @@ -20,9 +20,9 @@ interface IStaticFallbackMethod { */ abstract contract ExtensibleBase is HandlerContext { // --- events --- - event AddedSafeMethod(Safe indexed safe, bytes4 selector, bytes32 method); - event ChangedSafeMethod(Safe indexed safe, bytes4 selector, bytes32 oldMethod, bytes32 newMethod); - event RemovedSafeMethod(Safe indexed safe, bytes4 selector); + event AddedSafeMethod(ISafe indexed safe, bytes4 selector, bytes32 method); + event ChangedSafeMethod(ISafe indexed safe, bytes4 selector, bytes32 oldMethod, bytes32 newMethod); + event RemovedSafeMethod(ISafe indexed safe, bytes4 selector); // --- storage --- @@ -31,7 +31,7 @@ abstract contract ExtensibleBase is HandlerContext { // - The first byte is 0x00 if the method is static and 0x01 if the method is not static // - The last 20 bytes are the address of the handler contract // The method is encoded / decoded using the MarshalLib - mapping(Safe => mapping(bytes4 => bytes32)) public safeMethods; + mapping(ISafe => mapping(bytes4 => bytes32)) public safeMethods; // --- modifiers --- modifier onlySelf() { @@ -44,7 +44,7 @@ abstract contract ExtensibleBase is HandlerContext { // --- internal --- - function _setSafeMethod(Safe safe, bytes4 selector, bytes32 newMethod) internal { + function _setSafeMethod(ISafe safe, bytes4 selector, bytes32 newMethod) internal { (, address newHandler) = MarshalLib.decode(newMethod); bytes32 oldMethod = safeMethods[safe][selector]; (, address oldHandler) = MarshalLib.decode(oldMethod); @@ -67,8 +67,8 @@ abstract contract ExtensibleBase is HandlerContext { * @return safe The safe whose FallbackManager is making this call * @return sender The original `msg.sender` (as received by the FallbackManager) */ - function _getContext() internal view returns (Safe safe, address sender) { - safe = Safe(payable(_manager())); + function _getContext() internal view returns (ISafe safe, address sender) { + safe = ISafe(payable(_manager())); sender = _msgSender(); } @@ -79,7 +79,7 @@ abstract contract ExtensibleBase is HandlerContext { * @return isStatic Whether the method is static (`view`) or not * @return handler the address of the handler contract */ - function _getContextAndHandler() internal view returns (Safe safe, address sender, bool isStatic, address handler) { + function _getContextAndHandler() internal view returns (ISafe safe, address sender, bool isStatic, address handler) { (safe, sender) = _getContext(); (isStatic, handler) = MarshalLib.decode(safeMethods[safe][msg.sig]); } diff --git a/contracts/handler/extensible/FallbackHandler.sol b/contracts/handler/extensible/FallbackHandler.sol index 8565c30d5..5dd29a492 100644 --- a/contracts/handler/extensible/FallbackHandler.sol +++ b/contracts/handler/extensible/FallbackHandler.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: LGPL-3.0-only pragma solidity >=0.7.0 <0.9.0; -import {Safe, IStaticFallbackMethod, IFallbackMethod, ExtensibleBase} from "./ExtensibleBase.sol"; +import {ISafe, IStaticFallbackMethod, IFallbackMethod, ExtensibleBase} from "./ExtensibleBase.sol"; interface IFallbackHandler { function setSafeMethod(bytes4 selector, bytes32 newMethod) external; @@ -22,7 +22,7 @@ abstract contract FallbackHandler is ExtensibleBase, IFallbackHandler { * @param newMethod A contract that implements the `IFallbackMethod` or `IStaticFallbackMethod` interface */ function setSafeMethod(bytes4 selector, bytes32 newMethod) public override onlySelf { - _setSafeMethod(Safe(payable(_msgSender())), selector, newMethod); + _setSafeMethod(ISafe(payable(_msgSender())), selector, newMethod); } // --- fallback --- @@ -30,7 +30,7 @@ abstract contract FallbackHandler is ExtensibleBase, IFallbackHandler { // solhint-disable-next-line fallback(bytes calldata) external returns (bytes memory result) { require(msg.data.length >= 24, "invalid method selector"); - (Safe safe, address sender, bool isStatic, address handler) = _getContextAndHandler(); + (ISafe safe, address sender, bool isStatic, address handler) = _getContextAndHandler(); require(handler != address(0), "method handler not set"); if (isStatic) { diff --git a/contracts/handler/extensible/SignatureVerifierMuxer.sol b/contracts/handler/extensible/SignatureVerifierMuxer.sol index 8bc772d03..c93efb45f 100644 --- a/contracts/handler/extensible/SignatureVerifierMuxer.sol +++ b/contracts/handler/extensible/SignatureVerifierMuxer.sol @@ -2,7 +2,7 @@ // solhint-disable one-contract-per-file pragma solidity >=0.7.0 <0.9.0; -import {Safe, ExtensibleBase} from "./ExtensibleBase.sol"; +import {ISafe, ExtensibleBase} from "./ExtensibleBase.sol"; interface ERC1271 { function isValidSignature(bytes32 hash, bytes calldata signature) external view returns (bytes4 magicValue); @@ -28,7 +28,7 @@ interface ISafeSignatureVerifier { * @return magic The magic value that should be returned if the signature is valid (0x1626ba7e) */ function isValidSafeSignature( - Safe safe, + ISafe safe, address sender, bytes32 _hash, bytes32 domainSeparator, @@ -39,7 +39,7 @@ interface ISafeSignatureVerifier { } interface ISignatureVerifierMuxer { - function domainVerifiers(Safe safe, bytes32 domainSeparator) external view returns (ISafeSignatureVerifier); + function domainVerifiers(ISafe safe, bytes32 domainSeparator) external view returns (ISafeSignatureVerifier); function setDomainVerifier(bytes32 domainSeparator, ISafeSignatureVerifier verifier) external; } @@ -61,17 +61,17 @@ abstract contract SignatureVerifierMuxer is ExtensibleBase, ERC1271, ISignatureV bytes4 private constant SAFE_SIGNATURE_MAGIC_VALUE = 0x5fd7e97d; // --- storage --- - mapping(Safe => mapping(bytes32 => ISafeSignatureVerifier)) public override domainVerifiers; + mapping(ISafe => mapping(bytes32 => ISafeSignatureVerifier)) public override domainVerifiers; // --- events --- - event AddedDomainVerifier(Safe indexed safe, bytes32 domainSeparator, ISafeSignatureVerifier verifier); + event AddedDomainVerifier(ISafe indexed safe, bytes32 domainSeparator, ISafeSignatureVerifier verifier); event ChangedDomainVerifier( - Safe indexed safe, + ISafe indexed safe, bytes32 domainSeparator, ISafeSignatureVerifier oldVerifier, ISafeSignatureVerifier newVerifier ); - event RemovedDomainVerifier(Safe indexed safe, bytes32 domainSeparator); + event RemovedDomainVerifier(ISafe indexed safe, bytes32 domainSeparator); /** * Setter for the signature muxer @@ -79,7 +79,7 @@ abstract contract SignatureVerifierMuxer is ExtensibleBase, ERC1271, ISignatureV * @param newVerifier A contract that implements `ISafeSignatureVerifier` */ function setDomainVerifier(bytes32 domainSeparator, ISafeSignatureVerifier newVerifier) public override onlySelf { - Safe safe = Safe(payable(_msgSender())); + ISafe safe = ISafe(payable(_msgSender())); ISafeSignatureVerifier oldVerifier = domainVerifiers[safe][domainSeparator]; if (address(newVerifier) == address(0) && address(oldVerifier) != address(0)) { delete domainVerifiers[safe][domainSeparator]; @@ -102,7 +102,7 @@ abstract contract SignatureVerifierMuxer is ExtensibleBase, ERC1271, ISignatureV * @return magic Standardised ERC1271 return value */ function isValidSignature(bytes32 _hash, bytes calldata signature) external view override returns (bytes4 magic) { - (Safe safe, address sender) = _getContext(); + (ISafe safe, address sender) = _getContext(); // Check if the signature is for an `ISafeSignatureVerifier` and if it is valid for the domain. if (signature.length >= 4) { @@ -153,7 +153,7 @@ abstract contract SignatureVerifierMuxer is ExtensibleBase, ERC1271, ISignatureV * @param _hash Hash of the data that is signed * @param signature The signature to be verified */ - function defaultIsValidSignature(Safe safe, bytes32 _hash, bytes memory signature) internal view returns (bytes4 magic) { + function defaultIsValidSignature(ISafe safe, bytes32 _hash, bytes memory signature) internal view returns (bytes4 magic) { bytes memory messageData = EIP712.encodeMessageData( safe.domainSeparator(), SAFE_MSG_TYPEHASH, @@ -165,7 +165,7 @@ abstract contract SignatureVerifierMuxer is ExtensibleBase, ERC1271, ISignatureV require(safe.signedMessages(messageHash) != 0, "Hash not approved"); } else { // threshold signatures - safe.checkSignatures(messageHash, messageData, signature); + safe.checkSignatures(address(0), messageHash, signature); } magic = ERC1271.isValidSignature.selector; } diff --git a/contracts/interfaces/ISafe.sol b/contracts/interfaces/ISafe.sol index 32c439931..9cfc971c0 100644 --- a/contracts/interfaces/ISafe.sol +++ b/contracts/interfaces/ISafe.sol @@ -76,12 +76,15 @@ interface ISafe is IModuleManager, IGuardManager, IOwnerManager, IFallbackManage ) external payable returns (bool success); /** - * @notice Checks whether the signature provided is valid for the provided data and hash. Reverts otherwise. + * @notice Checks whether the signature provided is valid for the provided data and hash and executor. Reverts otherwise. + * @param executor Address that executes the transaction. + * ⚠️⚠️⚠️ Make sure that the executor address is a legitimate executor. + * Incorrectly passed the executor might reduce the threshold by 1 signature. ⚠️⚠️⚠️ * @param dataHash Hash of the data (could be either a message hash or transaction hash) * @param signatures Signature data that should be verified. * Can be packed ECDSA signature ({bytes32 r}{bytes32 s}{uint8 v}), contract signature (EIP-1271) or approved hash. */ - function checkSignatures(bytes32 dataHash, bytes memory signatures) external view; + function checkSignatures(address executor, bytes32 dataHash, bytes memory signatures) external view; /** * @notice Checks whether the signature provided is valid for the provided data and hash. Reverts otherwise. diff --git a/contracts/test/TestSafeSignatureVerifier.sol b/contracts/test/TestSafeSignatureVerifier.sol index 5b8020358..e6313f574 100644 --- a/contracts/test/TestSafeSignatureVerifier.sol +++ b/contracts/test/TestSafeSignatureVerifier.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: LGPL-3.0-only pragma solidity >=0.7.0 <0.9.0; -import {Safe, EIP712, ISafeSignatureVerifier} from "../handler/extensible/SignatureVerifierMuxer.sol"; +import {ISafe, EIP712, ISafeSignatureVerifier} from "../handler/extensible/SignatureVerifierMuxer.sol"; /** * @title TestSafeSignatureVerifier - A simple test contract that implements the ISafeSignatureVerifier interface @@ -16,7 +16,7 @@ contract TestSafeSignatureVerifier is ISafeSignatureVerifier { * @return magic The magic value that should be returned if the signature is valid (0x1626ba7e) */ function isValidSafeSignature( - Safe, + ISafe, address, bytes32 _hash, bytes32 domainSeparator, diff --git a/test/core/Safe.Signatures.spec.ts b/test/core/Safe.Signatures.spec.ts index 97041848c..60b7d6c4e 100644 --- a/test/core/Safe.Signatures.spec.ts +++ b/test/core/Safe.Signatures.spec.ts @@ -333,7 +333,9 @@ describe("Safe", () => { "0000000000000000000000000000000000000000000000000000000000000020" + "00" + // r, s, v "0000000000000000000000000000000000000000000000000000000000000000"; // Some data to read - await expect(safe["checkSignatures(bytes32,bytes)"](txHash, signatures)).to.be.revertedWith("GS021"); + await expect(safe["checkSignatures(address,bytes32,bytes)"](hre.ethers.ZeroAddress, txHash, signatures)).to.be.revertedWith( + "GS021", + ); }); it("should fail if signatures data is not present", async () => { @@ -352,7 +354,9 @@ describe("Safe", () => { "0000000000000000000000000000000000000000000000000000000000000041" + "00"; // r, s, v - await expect(safe["checkSignatures(bytes32,bytes)"](txHash, signatures)).to.be.revertedWith("GS022"); + await expect(safe["checkSignatures(address,bytes32,bytes)"](hre.ethers.ZeroAddress, txHash, signatures)).to.be.revertedWith( + "GS022", + ); }); it("should fail if signatures data is too short", async () => { @@ -372,7 +376,9 @@ describe("Safe", () => { "00" + // r, s, v "0000000000000000000000000000000000000000000000000000000000000020"; // length - await expect(safe["checkSignatures(bytes32,bytes)"](txHash, signatures)).to.be.revertedWith("GS023"); + await expect(safe["checkSignatures(address,bytes32,bytes)"](hre.ethers.ZeroAddress, txHash, signatures)).to.be.revertedWith( + "GS023", + ); }); it("should not be able to use different chainId for signing", async () => { @@ -384,7 +390,9 @@ describe("Safe", () => { const tx = buildSafeTransaction({ to: safeAddress, nonce: await safe.nonce() }); const txHash = calculateSafeTransactionHash(safeAddress, tx, await chainId()); const signatures = buildSignatureBytes([await safeSignTypedData(user1, safeAddress, tx, 1)]); - await expect(safe["checkSignatures(bytes32,bytes)"](txHash, signatures)).to.be.revertedWith("GS026"); + await expect(safe["checkSignatures(address,bytes32,bytes)"](hre.ethers.ZeroAddress, txHash, signatures)).to.be.revertedWith( + "GS026", + ); }); it("if not msg.sender on-chain approval is required", async () => { @@ -397,7 +405,9 @@ describe("Safe", () => { const tx = buildSafeTransaction({ to: safeAddress, nonce: await safe.nonce() }); const txHash = calculateSafeTransactionHash(safeAddress, tx, await chainId()); const signatures = buildSignatureBytes([await safeApproveHash(user1, safe, tx, true)]); - await expect(user2Safe["checkSignatures(bytes32,bytes)"](txHash, signatures)).to.be.revertedWith("GS025"); + await expect( + user2Safe["checkSignatures(address,bytes32,bytes)"](hre.ethers.ZeroAddress, txHash, signatures), + ).to.be.revertedWith("GS025"); }); it("should revert if threshold is not set", async () => { @@ -406,7 +416,7 @@ describe("Safe", () => { const safeAddress = await safe.getAddress(); const tx = buildSafeTransaction({ to: safeAddress, nonce: await safe.nonce() }); const txHash = calculateSafeTransactionHash(safeAddress, tx, await chainId()); - await expect(safe["checkSignatures(bytes32,bytes)"](txHash, "0x")).to.be.revertedWith("GS001"); + await expect(safe["checkSignatures(address,bytes32,bytes)"](hre.ethers.ZeroAddress, txHash, "0x")).to.be.revertedWith("GS001"); }); it("should revert if not the required amount of signature data is provided", async () => { @@ -417,7 +427,7 @@ describe("Safe", () => { const safeAddress = await safe.getAddress(); const tx = buildSafeTransaction({ to: safeAddress, nonce: await safe.nonce() }); const txHash = calculateSafeTransactionHash(safeAddress, tx, await chainId()); - await expect(safe["checkSignatures(bytes32,bytes)"](txHash, "0x")).to.be.revertedWith("GS020"); + await expect(safe["checkSignatures(address,bytes32,bytes)"](hre.ethers.ZeroAddress, txHash, "0x")).to.be.revertedWith("GS020"); }); it("should not be able to use different signature type of same owner", async () => { @@ -433,7 +443,9 @@ describe("Safe", () => { await safeSignTypedData(user1, safeAddress, tx), await safeSignTypedData(user3, safeAddress, tx), ]); - await expect(safe["checkSignatures(bytes32,bytes)"](txHash, signatures)).to.be.revertedWith("GS026"); + await expect(safe["checkSignatures(address,bytes32,bytes)"](hre.ethers.ZeroAddress, txHash, signatures)).to.be.revertedWith( + "GS026", + ); }); it("should be able to mix all signature types", async () => { @@ -448,11 +460,9 @@ describe("Safe", () => { fallbackHandler: compatFallbackHandlerAddress, }); const signerSafeAddress = await signerSafe.getAddress(); - const safe = ( - await getSafe({ - owners: [user1.address, user2.address, user3.address, user4.address, signerSafeAddress], - }) - ).connect(user1); + const safe = await getSafe({ + owners: [user1.address, user2.address, user3.address, user4.address, signerSafeAddress], + }); const safeAddress = await safe.getAddress(); const tx = buildSafeTransaction({ to: safeAddress, nonce: await safe.nonce() }); const txHash = calculateSafeTransactionHash(safeAddress, tx, await chainId()); @@ -469,7 +479,7 @@ describe("Safe", () => { signerSafeSig, ]); - await safe["checkSignatures(bytes32,bytes)"](txHash, signatures); + await safe["checkSignatures(address,bytes32,bytes)"](user1.address, txHash, signatures); }); }); @@ -612,13 +622,11 @@ describe("Safe", () => { fallbackHandler: compatFallbackHandlerAddress, }); const signerSafeAddress = await signerSafe.getAddress(); - const safe = ( - await getSafe({ - owners: [user1.address, user2.address, user3.address, user4.address, signerSafeAddress], - threshold: 5, - fallbackHandler: compatFallbackHandlerAddress, - }) - ).connect(user1); + const safe = await getSafe({ + owners: [user1.address, user2.address, user3.address, user4.address, signerSafeAddress], + threshold: 5, + fallbackHandler: compatFallbackHandlerAddress, + }); const safeAddress = await safe.getAddress(); const tx = buildSafeTransaction({ to: safeAddress, nonce: await safe.nonce() }); const txHash = calculateSafeTransactionHash(safeAddress, tx, await chainId()); @@ -635,7 +643,7 @@ describe("Safe", () => { signerSafeSig, ]); - await safe["checkSignatures(bytes32,bytes,bytes)"](txHash, "0x", signatures); + await safe.connect(user1)["checkSignatures(bytes32,bytes,bytes)"](txHash, "0x", signatures); }); }); @@ -1021,13 +1029,11 @@ describe("Safe", () => { fallbackHandler: compatFallbackHandlerAddress, }); const signerSafeAddress = await signerSafe.getAddress(); - const safe = ( - await getSafe({ - owners: [user1.address, user2.address, user3.address, user4.address, signerSafeAddress], - threshold: 5, - fallbackHandler: compatFallbackHandlerAddress, - }) - ).connect(user1); + const safe = await getSafe({ + owners: [user1.address, user2.address, user3.address, user4.address, signerSafeAddress], + threshold: 5, + fallbackHandler: compatFallbackHandlerAddress, + }); const safeAddress = await safe.getAddress(); const tx = buildSafeTransaction({ to: safeAddress, nonce: await safe.nonce() }); const txHash = calculateSafeTransactionHash(safeAddress, tx, await chainId()); @@ -1044,7 +1050,7 @@ describe("Safe", () => { signerSafeSig, ]); - await safe["checkNSignatures(bytes32,bytes,bytes,uint256)"](txHash, "0x", signatures, 5); + await safe.connect(user1)["checkNSignatures(bytes32,bytes,bytes,uint256)"](txHash, "0x", signatures, 5); }); it("should be able to require no signatures", async () => { diff --git a/test/handlers/CompatibilityFallbackHandler.spec.ts b/test/handlers/CompatibilityFallbackHandler.spec.ts index a2c8d87d0..94ff2707f 100644 --- a/test/handlers/CompatibilityFallbackHandler.spec.ts +++ b/test/handlers/CompatibilityFallbackHandler.spec.ts @@ -124,9 +124,37 @@ describe("CompatibilityFallbackHandler", () => { const signerSafeSig = buildContractSignature(signerSafeAddress, signerSafeOwnerSignature.data); - expect( - await validator.isValidSignature.staticCall(dataHash, buildSignatureBytes([typedDataSig, ethSignSig, signerSafeSig])), - ).to.be.eq("0x1626ba7e"); + for (const signatures of [ + [typedDataSig, ethSignSig], + [typedDataSig, signerSafeSig], + [ethSignSig, signerSafeSig], + ]) { + expect(await validator.isValidSignature.staticCall(dataHash, buildSignatureBytes(signatures))).to.be.eq("0x1626ba7e"); + } + }); + + it("should not accept pre-approved signatures", async () => { + const { + validator, + signers: [user1, user2], + } = await setupTests(); + const validatorAddress = await validator.getAddress(); + const dataHash = ethers.keccak256("0xbaddad"); + const user1Signature = { + signer: user1.address, + data: ethers.solidityPacked(["uint256", "uint256", "uint8"], [user1.address, 0, 1]), + }; + const user2Signature = { + signer: user2.address, + data: await user2.signTypedData( + { verifyingContract: validatorAddress, chainId: await chainId() }, + EIP712_SAFE_MESSAGE_TYPE, + { message: dataHash }, + ), + }; + + const signatures = buildSignatureBytes([user1Signature, user2Signature]); + await expect(validator.connect(user1).isValidSignature.staticCall(dataHash, signatures)).to.be.reverted; }); }); diff --git a/test/handlers/ExtensibleFallbackHandler.spec.ts b/test/handlers/ExtensibleFallbackHandler.spec.ts index ff3b48376..766d75136 100644 --- a/test/handlers/ExtensibleFallbackHandler.spec.ts +++ b/test/handlers/ExtensibleFallbackHandler.spec.ts @@ -496,6 +496,27 @@ describe("ExtensibleFallbackHandler", () => { ); }); + it("should not accept pre-approved signatures", async () => { + const { user1, user2, validator } = await setupTests(); + const validatorAddress = await validator.getAddress(); + const dataHash = ethers.keccak256("0xbaddad"); + const user1Signature = { + signer: user1.address, + data: ethers.solidityPacked(["uint256", "uint256", "uint8"], [user1.address, 0, 1]), + }; + const user2Signature = { + signer: user2.address, + data: await user2.signTypedData( + { verifyingContract: validatorAddress, chainId: await chainId() }, + EIP712_SAFE_MESSAGE_TYPE, + { message: dataHash }, + ), + }; + + const signatures = buildSignatureBytes([user1Signature, user2Signature]); + await expect(validator.connect(user1).isValidSignature.staticCall(dataHash, signatures)).to.be.reverted; + }); + it("should send EIP-712 context to custom verifier", async () => { const { user1, user2, safe, validator, revertVerifier } = await setupTests(); const domainSeparator = ethers.keccak256("0xdeadbeef"); From 834e798aa51291cccaf0594921194928716e9892 Mon Sep 17 00:00:00 2001 From: Nicholas Rodrigues Lordello Date: Sat, 14 Dec 2024 10:14:39 +0100 Subject: [PATCH 07/38] Fix Shift Amount in Proxy (#868) This PR fixes the shift amounts in the `SafeProxy` implementation. It also slightly optimizes how we do the masking by 2 instructions (removes the need to `PUSH 0` and `SHR`). I added some additional tests to make sure the masking works as expected and a comment explaining why we only mask for handling the `masterCopy()` call. --------- Co-authored-by: Mikhail <16622558+mmv08@users.noreply.github.com> --- contracts/proxies/SafeProxy.sol | 8 +++++- test/factory/Proxy.spec.ts | 51 +++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/contracts/proxies/SafeProxy.sol b/contracts/proxies/SafeProxy.sol index a6b3cbbe5..42e0f477c 100644 --- a/contracts/proxies/SafeProxy.sol +++ b/contracts/proxies/SafeProxy.sol @@ -40,7 +40,13 @@ contract SafeProxy { let _singleton := sload(0) // 0xa619486e == keccak("masterCopy()"). The value is right padded to 32-bytes with 0s if eq(calldataload(0), 0xa619486e00000000000000000000000000000000000000000000000000000000) { - mstore(0, shr(12, shl(12, _singleton))) + // We mask the singleton address when handling the `masterCopy()` call to ensure that it is correctly + // ABI-encoded. We do this by shifting the address left by 96 bits (or 12 bytes) and then storing it in + // memory with a 12 byte offset from where the return data starts. Note that we **intentionally** only + // do this for the `masterCopy()` call, since the EVM `DELEGATECALL` opcode ignores the most-significant + // 12 bytes from the address, so we do not need to make sure the top bytes are cleared when proxying + // calls to the `singleton`. This saves us a tiny amount of gas per proxied call. + mstore(0x0c, shl(96, _singleton)) return(0, 0x20) } calldatacopy(0, 0, calldatasize()) diff --git a/test/factory/Proxy.spec.ts b/test/factory/Proxy.spec.ts index a60d368c8..0b51faa3c 100644 --- a/test/factory/Proxy.spec.ts +++ b/test/factory/Proxy.spec.ts @@ -1,6 +1,7 @@ import { expect } from "chai"; import hre from "hardhat"; import { AddressZero } from "@ethersproject/constants"; +import { deployContractFromSource } from "../utils/setup"; describe("Proxy", () => { describe("constructor", () => { @@ -9,4 +10,54 @@ describe("Proxy", () => { await expect(Proxy.deploy(AddressZero)).to.be.revertedWith("Invalid singleton address provided"); }); }); + + describe("masterCopy", () => { + const SINGLETON_SOURCE = ` + contract Test { + uint256 _singletonSlot; + function masterCopy() public pure returns (address) { + return address(0); + } + function overwriteSingletonSlot(uint256 value) public { + _singletonSlot = value; + } + function theAnswerToLifeTheUniverseAndEverything() public pure returns (uint256) { + return 42; + } + }`; + + const setupTests = hre.deployments.createFixture(async () => { + const [deployer] = await hre.ethers.getSigners(); + const singleton = await deployContractFromSource(deployer, SINGLETON_SOURCE); + const Proxy = await hre.ethers.getContractFactory("SafeProxy"); + const proxyDeployment = await Proxy.deploy(singleton.target); + const proxy = singleton.attach(proxyDeployment) as typeof singleton; + return { + singleton, + proxy, + }; + }); + + it("should return the master copy address regardless of implementation", async () => { + const { singleton, proxy } = await setupTests(); + expect(await singleton.masterCopy()).to.equal(hre.ethers.ZeroAddress); + expect(await proxy.masterCopy()).to.equal(await singleton.getAddress()); + }); + + it("should correctly mask the address value", async () => { + const { proxy } = await setupTests(); + await proxy.overwriteSingletonSlot(hre.ethers.MaxUint256); + expect(await proxy.masterCopy()).to.equal(hre.ethers.getAddress(`0x${"ff".repeat(20)}`)); + }); + + it("should ignore most significant bits when calling singleton", async () => { + const { singleton, proxy } = await setupTests(); + const singletonAddressAsUint = BigInt(await singleton.getAddress()); + const mask = 0xffffffffffffffffffffffffn << 160n; + + expect(await proxy.theAnswerToLifeTheUniverseAndEverything()).to.equal(42); + await proxy.overwriteSingletonSlot(singletonAddressAsUint | mask); + expect(await proxy.theAnswerToLifeTheUniverseAndEverything()).to.equal(42); + }); + }); }); From 489b2bc205e94d76957dd0dcc8ae2662fbd0f988 Mon Sep 17 00:00:00 2001 From: Yusuf <56938716+yusufky63@users.noreply.github.com> Date: Sun, 15 Dec 2024 22:00:19 +0300 Subject: [PATCH 08/38] Fix minor typos in documentation (#870) Co-authored-by: Nicholas Rodrigues Lordello --- CHANGELOG.md | 6 +++--- README.md | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4fbe68b62..e41a6f920 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -479,7 +479,7 @@ File: [`contracts/libraries/SignMessage.sol`](https://github.com/safe-global/saf Expected behaviour: -The library is meant as a compatibility tool for the removed `signMessage` function from the pre-1.3.0 Safe contracts. It has the same signature and assumes the same storage layout as the previous Safe contract versions. After calling this function with a massage, the hash of that message should be marked as executed in the `signedMessages` mapping. +The library is meant as a compatibility tool for the removed `signMessage` function from the pre-1.3.0 Safe contracts. It has the same signature and assumes the same storage layout as the previous Safe contract versions. After calling this function with a message, the hash of that message should be marked as executed in the `signedMessages` mapping. #### GnosisSafeStorage @@ -714,7 +714,7 @@ Expected behaviour: The `multiSend` is now payable therefore will enforce anymore that `msg.value` is 0. ETH that is not transferred out again will remain in `this` (the calling contract when used via a delegatecall or the contract when used via call, only possible with `MultiSendCallOnly`) -#### Add MuliSend that disallows delegate operation +#### Add MultiSend that disallows delegate operation File: [`contracts/libraries/MultiSendCallOnly.sol`](https://github.com/safe-global/safe-smart-account/blob/ad6c7355d5bdf4f7fa348fbfcb9f07431769a3c9/contracts/libraries/MultiSendCallOnly.sol) @@ -741,7 +741,7 @@ Note: **This contract is meant as an example to demonstrate how to mark Safe mes Expected behaviour: -The library is meant as a compatibility tool for the removed `signMessage` function from the pre-1.3.0 Safe contracts. It has the same signature and assumes the same storage layout as the previous Safe contract versions. After calling this function with a massage, the hash of that message should be marked as executed in the `signedMessages` mapping. +The library is meant as a compatibility tool for the removed `signMessage` function from the pre-1.3.0 Safe contracts. It has the same signature and assumes the same storage layout as the previous Safe contract versions. After calling this function with a message, the hash of that message should be marked as executed in the `signedMessages` mapping. #### Add Migration example to downgrade from 1.3.0 to 1.2.0 diff --git a/README.md b/README.md index f696b4145..d858ad7c2 100644 --- a/README.md +++ b/README.md @@ -96,7 +96,7 @@ This command will use the deployment artifacts to compile the contracts and comp npx hardhat --network local-verify ``` -This command will upload the contract source to Etherescan +This command will upload the contract source to Etherscan ```bash npx hardhat --network etherscan-verify ``` From 43097762c2833aabc7c881c069b7cf92d08af7a0 Mon Sep 17 00:00:00 2001 From: Mikhail <16622558+mmv08@users.noreply.github.com> Date: Wed, 18 Dec 2024 10:03:40 +0100 Subject: [PATCH 09/38] Add a warning comment about potential dirty bits in `getTransactionHash` (#872) This commit adds a detailed warning in the `Safe.sol` contract regarding potential dirty bits in assembly code for types smaller than 256 bits. It emphasizes the importance of considering this for future changes while explaining the rationale behind using assembly for memory efficiency. No functional changes were made to the contract logic. This update aims to improve code clarity and maintainability. Originally reported by @jhoenicke --- contracts/Safe.sol | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/contracts/Safe.sol b/contracts/Safe.sol index 241cfc4fd..b75eedb50 100644 --- a/contracts/Safe.sol +++ b/contracts/Safe.sol @@ -407,6 +407,11 @@ contract Safe is // We opted for using assembly code here, because the way Solidity compiler we use (0.7.6) allocates memory is // inefficient. We do not need to allocate memory for temporary variables to be used in the keccak256 call. + // + // WARNING: We do not clean potential dirty bits in types that are less than 256 bits (addresses and Enum.Operation) + // The solidity assembly types that are smaller than 256 bit can have dirty high bits according to the spec (see the Warning in https://docs.soliditylang.org/en/latest/assembly.html#access-to-external-variables-functions-and-libraries). + // However, we read most of the data from calldata, where the variables are not packed, and the only variable we read from storage is uint256 nonce. + // This is not a problem, however, we must consider this for potential future changes. /* solhint-disable no-inline-assembly */ /// @solidity memory-safe-assembly assembly { From dcf20a6eb599e59fa9deb962b31b809820d246a0 Mon Sep 17 00:00:00 2001 From: chloefeal <188809157+chloefeal@users.noreply.github.com> Date: Thu, 2 Jan 2025 18:24:36 +0800 Subject: [PATCH 10/38] Fix typos (#876) This PR focuses on correcting typos and improving clarity in documentation files. Signed-off-by: chloefeal <188809157+chloefeal@users.noreply.github.com> --- test/factory/ProxyFactory.spec.ts | 4 ++-- test/handlers/ExtensibleFallbackHandler.spec.ts | 2 +- tests_deprecated/utils/execution.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/factory/ProxyFactory.spec.ts b/test/factory/ProxyFactory.spec.ts index ba35d7b71..a97575adf 100644 --- a/test/factory/ProxyFactory.spec.ts +++ b/test/factory/ProxyFactory.spec.ts @@ -318,7 +318,7 @@ describe("ProxyFactory", () => { ).to.be.reverted; await mock.reset(); - // Should be successfull now + // Should be successful now const proxyAddress = await calculateProxyAddressWithCallback( factory, singletonAddress, @@ -405,7 +405,7 @@ describe("ProxyFactory", () => { ).to.be.reverted; await mock.reset(); - // Should be successfull now + // Should be successful now const proxyAddress = await calculateProxyAddressWithCallback( factory, singletonAddress, diff --git a/test/handlers/ExtensibleFallbackHandler.spec.ts b/test/handlers/ExtensibleFallbackHandler.spec.ts index 766d75136..df54be86d 100644 --- a/test/handlers/ExtensibleFallbackHandler.spec.ts +++ b/test/handlers/ExtensibleFallbackHandler.spec.ts @@ -63,7 +63,7 @@ describe("ExtensibleFallbackHandler", () => { const revertVerifierSource = ` contract RevertVerifier { function iToHex(bytes memory buffer) public pure returns (string memory) { - // Fixed buffer size for hexadecimal convertion + // Fixed buffer size for hexadecimal conversion bytes memory converted = new bytes(buffer.length * 2); bytes memory _base = "0123456789abcdef"; for (uint256 i = 0; i < buffer.length; i++) { diff --git a/tests_deprecated/utils/execution.js b/tests_deprecated/utils/execution.js index 6e66f43df..f457c1f71 100644 --- a/tests_deprecated/utils/execution.js +++ b/tests_deprecated/utils/execution.js @@ -68,7 +68,7 @@ let executeTransactionWithSigner = async function(signer, safe, subject, account if (txGasEstimate > 0) { let estimateDataGasCosts = calcDataGasCosts(estimateData) let additionalGas = 10000 - // To check if the transaction is successfull with the given safeTxGas we try to set a gasLimit so that only safeTxGas is available, + // To check if the transaction is successful with the given safeTxGas we try to set a gasLimit so that only safeTxGas is available, // when `execute` is triggered in `requiredTxGas`. If the response is `0x` then the inner transaction reverted and we need to increase the amount. for (let i = 0; i < 100; i++) { try { From 4121b4114e72b2c18d40a669d0eef3cd47c94854 Mon Sep 17 00:00:00 2001 From: "fuder.eth" <139509124+vtjl10@users.noreply.github.com> Date: Thu, 2 Jan 2025 13:45:14 +0200 Subject: [PATCH 11/38] fix: typos in documentation files (#874) Corrected `considely` to `concisely` Corrected `hhttps` to `https` --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- docs/safe_tx_gas.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index cd36ec0a5..9c340e33a 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -14,7 +14,7 @@ about: Bug report about the Safe smart contracts ## Description -Please describe considely the bug you have found, and what you expect instead. +Please describe concisely the bug you have found, and what you expect instead. ## Environment diff --git a/docs/safe_tx_gas.md b/docs/safe_tx_gas.md index a27ad5fa0..ac7152c94 100644 --- a/docs/safe_tx_gas.md +++ b/docs/safe_tx_gas.md @@ -30,7 +30,7 @@ If `gasPrice` is set to `0` then the Safe Smart Account will **not** issue a ref Therefore it is not necessary to be as strict on the gas being passed along with the execution of the Safe transaction. As no refund is triggered the Safe will not pay for the execution costs, based on this the Safe Smart Account will send along all available case when no refund is used. -Before the execution the Safe Smart Account always check if enough gas is available to satisfy the `safeTxGas`. This can be seen in [`Safe.sol`](hhttps://github.com/safe-global/safe-smart-account/blob/main/contracts/Safe.sol#L168-L170): +Before the execution the Safe Smart Account always check if enough gas is available to satisfy the `safeTxGas`. This can be seen in [`Safe.sol`](https://github.com/safe-global/safe-smart-account/blob/main/contracts/Safe.sol#L168-L170): ```js require(gasleft() >= From 3e8aa81f5605fcb612d082bfd9553feb068317be Mon Sep 17 00:00:00 2001 From: oliveredget <188809800+oliveredget@users.noreply.github.com> Date: Thu, 2 Jan 2025 22:40:36 +0800 Subject: [PATCH 12/38] fix: typos in comments (#878) This PR focuses on correcting typos and improving clarity in comments. Thank you very much. Signed-off-by: oliveredget <188809800+oliveredget@users.noreply.github.com> --- certora/specs/NativeTokenRefund.spec | 2 +- tests_deprecated/utils/execution.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/certora/specs/NativeTokenRefund.spec b/certora/specs/NativeTokenRefund.spec index 04a59890d..9eef6cf4a 100644 --- a/certora/specs/NativeTokenRefund.spec +++ b/certora/specs/NativeTokenRefund.spec @@ -41,7 +41,7 @@ rule nativeTokenRefundIsSentToRefundReceiver( // and adding pre-requirements is tricky // also, it shouldn't be the safe itself require refundReceiver != 0 && refundReceiver != currentContract; - // // We're being optimistic about the delegatecall and in the munged contracts the actuall call was removed + // // We're being optimistic about the delegatecall and in the munged contracts the actual call was removed // // So it's possible the gas used to be 0 in the munged contracts, so no refund would be sent (a counterexample) // require operation == Enum.Operation.Call; diff --git a/tests_deprecated/utils/execution.js b/tests_deprecated/utils/execution.js index f457c1f71..487f0e66b 100644 --- a/tests_deprecated/utils/execution.js +++ b/tests_deprecated/utils/execution.js @@ -32,7 +32,7 @@ let estimateBaseGas = function(safe, to, value, data, operation, txGasEstimate, let baseGasEstimate = calcDataGasCosts(payload) + signatureCost + (nonce > 0 ? 5000 : 20000) baseGasEstimate += 1500 // 1500 -> hash generation costs baseGasEstimate += 1000 // 1000 -> Event emission - return baseGasEstimate + 32000; // Add aditional gas costs (e.g. base tx costs, transfer costs) + return baseGasEstimate + 32000; // Add additional gas costs (e.g. base tx costs, transfer costs) } let executeTransactionWithSigner = async function(signer, safe, subject, accounts, to, value, data, operation, executor, opts) { From 721acb157ae780d5304efae867b81889dd9624f1 Mon Sep 17 00:00:00 2001 From: calciumbe <192480234+calciumbe@users.noreply.github.com> Date: Thu, 2 Jan 2025 23:18:02 +0800 Subject: [PATCH 13/38] Fix typos (#880) Hello, I fix some typos to improve clarity and correctness. Thank you very much. Signed-off-by: calciumbe <192480234+calciumbe@users.noreply.github.com> --- test/accessors/SimulateTxAccessor.spec.ts | 12 ++++++------ test/libraries/SafeToL2Setup.spec.ts | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/test/accessors/SimulateTxAccessor.spec.ts b/test/accessors/SimulateTxAccessor.spec.ts index 37d54e02f..ae8b10bc4 100644 --- a/test/accessors/SimulateTxAccessor.spec.ts +++ b/test/accessors/SimulateTxAccessor.spec.ts @@ -53,8 +53,8 @@ describe("SimulateTxAccessor", () => { const accessorAddress = await accessor.getAddress(); const tx = await buildContractCall(safe, "getOwners", [], 0); const simulationData = accessor.interface.encodeFunctionData("simulate", [tx.to, tx.value, tx.data, tx.operation]); - const acccessibleData = await simulator.simulate.staticCall(accessorAddress, simulationData); - const simulation = accessor.interface.decodeFunctionResult("simulate", acccessibleData); + const accessibleData = await simulator.simulate.staticCall(accessorAddress, simulationData); + const simulation = accessor.interface.decodeFunctionResult("simulate", accessibleData); expect(safe.interface.decodeFunctionResult("getOwners", simulation.returnData)[0]).to.be.deep.eq([user1.address]); expect(simulation.success).to.be.true; expect(simulation.estimate).to.be.lte(10000n); @@ -69,8 +69,8 @@ describe("SimulateTxAccessor", () => { const userBalance = await hre.ethers.provider.getBalance(user2.address); const tx = await buildContractCall(interactor, "sendAndReturnBalance", [user2.address, ethers.parseEther("1")], 0, true); const simulationData = accessor.interface.encodeFunctionData("simulate", [tx.to, tx.value, tx.data, tx.operation]); - const acccessibleData = await simulator.simulate.staticCall(accessorAddress, simulationData); - const simulation = accessor.interface.decodeFunctionResult("simulate", acccessibleData); + const accessibleData = await simulator.simulate.staticCall(accessorAddress, simulationData); + const simulation = accessor.interface.decodeFunctionResult("simulate", accessibleData); expect(interactor.interface.decodeFunctionResult("sendAndReturnBalance", simulation.returnData)[0]).to.be.deep.eq( userBalance + ethers.parseEther("1"), ); @@ -85,8 +85,8 @@ describe("SimulateTxAccessor", () => { const accessorAddress = await accessor.getAddress(); const tx = await buildContractCall(interactor, "sendAndReturnBalance", [user2.address, ethers.parseEther("1")], 0, true); const simulationData = accessor.interface.encodeFunctionData("simulate", [tx.to, tx.value, tx.data, tx.operation]); - const acccessibleData = await simulator.simulate.staticCall(accessorAddress, simulationData); - const simulation = accessor.interface.decodeFunctionResult("simulate", acccessibleData); + const accessibleData = await simulator.simulate.staticCall(accessorAddress, simulationData); + const simulation = accessor.interface.decodeFunctionResult("simulate", accessibleData); expect(simulation.returnData).to.be.deep.eq( "0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000f5472616e73666572206661696c65640000000000000000000000000000000000", ); diff --git a/test/libraries/SafeToL2Setup.spec.ts b/test/libraries/SafeToL2Setup.spec.ts index 23d724ad1..1353032a4 100644 --- a/test/libraries/SafeToL2Setup.spec.ts +++ b/test/libraries/SafeToL2Setup.spec.ts @@ -231,7 +231,7 @@ describe("SafeToL2Setup", () => { signers: [user1], safeToL2SetupLib, } = await setupTests(); - const safeSingeltonAddress = await safeSingleton.getAddress(); + const safeSingletonAddress = await safeSingleton.getAddress(); const safeL2SingletonAddress = await safeL2.getAddress(); const safeToL2SetupCall = safeToL2SetupLib.interface.encodeFunctionData("setupToL2", [safeL2SingletonAddress]); @@ -247,12 +247,12 @@ describe("SafeToL2Setup", () => { ]); const safeAddress = await proxyFactory.createProxyWithNonce.staticCall(safeSingleton.target, setupData, 0); - await expect(proxyFactory.createProxyWithNonce(safeSingeltonAddress, setupData, 0)).to.not.emit( + await expect(proxyFactory.createProxyWithNonce(safeSingletonAddress, setupData, 0)).to.not.emit( safeToL2SetupLib.attach(safeAddress), "ChangedMasterCopy", ); const singletonInStorage = await hre.ethers.provider.getStorage(safeAddress, ethers.zeroPadValue("0x00", 32)); - expect(sameHexString(singletonInStorage, ethers.zeroPadValue(safeSingeltonAddress, 32))).to.be.true; + expect(sameHexString(singletonInStorage, ethers.zeroPadValue(safeSingletonAddress, 32))).to.be.true; }); }); }); From 77bab0d37b78c26482f94662344c9af0994253f7 Mon Sep 17 00:00:00 2001 From: dxsullivan <193140725+dxsullivan@users.noreply.github.com> Date: Sun, 5 Jan 2025 17:57:17 +0800 Subject: [PATCH 14/38] fix: typos (#884) This pull request contains changes to improve clarity and correctness. Description correction: typo fix. Thank you very much. Signed-off-by: dxsullivan <193140725+dxsullivan@users.noreply.github.com> --- test/core/Safe.Execution.spec.ts | 4 ++-- test/core/Safe.Setup.spec.ts | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/test/core/Safe.Execution.spec.ts b/test/core/Safe.Execution.spec.ts index 4a9e2e5d5..c5445577a 100644 --- a/test/core/Safe.Execution.spec.ts +++ b/test/core/Safe.Execution.spec.ts @@ -271,7 +271,7 @@ describe("Safe", () => { if (hre.network.zksync) { // This test fails in zksync because of (allegedly) enormous gas cost differences // a call to useGas(8) costs ~400k gas in evm but ~28m gas in zksync. - // I suspect the gas cost difference to play a role but the zksync docs do not mention any numbers so i cant confirm this: + // I suspect the gas cost difference to play a role but the zksync docs do not mention any numbers so i can't confirm this: // https://docs.zksync.io/zk-stack/concepts/fee-mechanism // From zkSync team: // Update: in-memory node when in standalone mode assumes very high l1 gas price resulting in a very high gas consumption, @@ -333,7 +333,7 @@ describe("Safe", () => { if (hre.network.zksync) { // This test fails in zksync because of (allegedly) enormous gas cost differences // a call to useGas(8) costs ~400k gas in evm but ~28m gas in zksync. - // I suspect the gas cost difference to play a role but the zksync docs do not mention any numbers so i cant confirm this: + // I suspect the gas cost difference to play a role but the zksync docs do not mention any numbers so i can't confirm this: // https://docs.zksync.io/zk-stack/concepts/fee-mechanism // From zkSync team: // Update: in-memory node when in standalone mode assumes very high l1 gas price resulting in a very high gas consumption, diff --git a/test/core/Safe.Setup.spec.ts b/test/core/Safe.Setup.spec.ts index 06c72df9d..50eb651da 100644 --- a/test/core/Safe.Setup.spec.ts +++ b/test/core/Safe.Setup.spec.ts @@ -231,14 +231,14 @@ describe("Safe", () => { /* solhint-enable no-inline-assembly */ } }`; - const testIntializer = await deployContractFromSource(user1, source); - const testIntializerAddress = await testIntializer.getAddress(); - const initData = testIntializer.interface.encodeFunctionData("init", ["0x42baddad"]); + const testInitializer = await deployContractFromSource(user1, source); + const testInitializerAddress = await testInitializer.getAddress(); + const initData = testInitializer.interface.encodeFunctionData("init", ["0x42baddad"]); await expect( template.setup( [user1.address, user2.address, user3.address], 2, - testIntializerAddress, + testInitializerAddress, initData, AddressOne, AddressZero, @@ -247,7 +247,7 @@ describe("Safe", () => { ), ) .to.emit(template, "SafeSetup") - .withArgs(safeMsgSender, [user1.address, user2.address, user3.address], 2, testIntializerAddress, AddressOne); + .withArgs(safeMsgSender, [user1.address, user2.address, user3.address], 2, testInitializerAddress, AddressOne); await expect(await template.domainSeparator()).to.be.eq(calculateSafeDomainSeparator(templateAddress, await chainId())); await expect(await template.getOwners()).to.be.deep.eq([user1.address, user2.address, user3.address]); await expect(await template.getThreshold()).to.eq(2n); @@ -272,14 +272,14 @@ describe("Safe", () => { require(false, "Computer says nah"); } }`; - const testIntializer = await deployContractFromSource(user1, source); - const testIntializerAddress = await testIntializer.getAddress(); - const initData = testIntializer.interface.encodeFunctionData("init", ["0x42baddad"]); + const testInitializer = await deployContractFromSource(user1, source); + const testInitializerAddress = await testInitializer.getAddress(); + const initData = testInitializer.interface.encodeFunctionData("init", ["0x42baddad"]); await expect( template.setup( [user1.address, user2.address, user3.address], 2, - testIntializerAddress, + testInitializerAddress, initData, AddressZero, AddressZero, From 2fd69b06fc3f4324b652c46618563e9ff02dcd92 Mon Sep 17 00:00:00 2001 From: Shebin John Date: Thu, 9 Jan 2025 15:25:35 +0100 Subject: [PATCH 15/38] [Certora Audit] G-02. `OwnerManager.changeThreshold()` event update (#889) This pull request includes a change which allows 1 SLOAD to be saved by emitting an existing memory variable instead of reading from storage. * [`contracts/base/OwnerManager.sol`](diffhunk://#diff-795fb06764b4c2d991707584a31509badf0b036c9401bfbcb82d6bc9fdebab82L113-R113): Modified the `emit` statement in the `setThreshold` function to use the `_threshold` parameter instead of `threshold`, ensuring the value from memory is emitted. --- contracts/base/OwnerManager.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/base/OwnerManager.sol b/contracts/base/OwnerManager.sol index a74493b40..cdb8df63e 100644 --- a/contracts/base/OwnerManager.sol +++ b/contracts/base/OwnerManager.sol @@ -110,7 +110,7 @@ abstract contract OwnerManager is SelfAuthorized, IOwnerManager { // There has to be at least one Safe owner. if (_threshold == 0) revertWithError("GS202"); threshold = _threshold; - emit ChangedThreshold(threshold); + emit ChangedThreshold(_threshold); } /** From ff36adb946a500139dd397e780355ff28bf1c8bb Mon Sep 17 00:00:00 2001 From: Mikhail <16622558+mmv08@users.noreply.github.com> Date: Thu, 9 Jan 2025 16:03:48 +0100 Subject: [PATCH 16/38] Update comments in SignatureVerifierMuxer to reflect correct byte ranges for encodeData and payload lengths (#873) This pull request includes modifying the `SignatureVerifierMuxer` contract to correct the byte offsets for encoding and payload data. Changes to byte offsets: * [`contracts/handler/extensible/SignatureVerifierMuxer.sol`](diffhunk://#diff-62f21ce8850527f34ef2acdacd96d4a2a1150e3e2a7e16457e82236bbd4259d2L124-R127): Updated the byte offset ranges for `encodeData length`, `encodeData`, and `payload length` to correct values. --- .../handler/extensible/SignatureVerifierMuxer.sol | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/contracts/handler/extensible/SignatureVerifierMuxer.sol b/contracts/handler/extensible/SignatureVerifierMuxer.sol index c93efb45f..a2b5a0532 100644 --- a/contracts/handler/extensible/SignatureVerifierMuxer.sol +++ b/contracts/handler/extensible/SignatureVerifierMuxer.sol @@ -118,13 +118,13 @@ abstract contract SignatureVerifierMuxer is ExtensibleBase, ERC1271, ISignatureV if (sigSelector == SAFE_SIGNATURE_MAGIC_VALUE && signature.length >= 68) { // Signature is for an `ISafeSignatureVerifier` - decode the signature. // Layout of the `signature`: - // 0x00 - 0x04: selector - // 0x04 - 0x36: domainSeparator - // 0x36 - 0x68: typeHash - // 0x68 - 0x6C: encodeData length - // 0x6C - 0x6C + encodeData length: encodeData - // 0x6C + encodeData length - 0x6C + encodeData length + 0x20: payload length - // 0x6C + encodeData length + 0x20 - end: payload + // 0x00 to 0x04: selector + // 0x04 to 0x36: domainSeparator + // 0x36 to 0x68: typeHash + // 0x68 to 0x88: encodeData length + // 0x88 to 0x88 + encodeData length: encodeData + // 0x88 + encodeData length to 0x88 + encodeData length + 0x20: payload length + // 0x88 + encodeData length + 0x20 to end: payload // // Get the domainSeparator from the signature. (bytes32 domainSeparator, bytes32 typeHash) = abi.decode(signature[4:68], (bytes32, bytes32)); From c6cd4b9b0e5ff28ac14246b236679b72566c4c50 Mon Sep 17 00:00:00 2001 From: Mikhail <16622558+mmv08@users.noreply.github.com> Date: Thu, 9 Jan 2025 16:37:14 +0100 Subject: [PATCH 17/38] docs: enhance fallback handler documentation in `Safe.sol` and `IFallbackManager.sol` (#879) Updated the documentation for the fallback handler in both `Safe.sol` and `IFallbackManager.sol` to improve clarity and highlight security risks associated with setting the fallback handler. Added a warning about the potential for bypassing access control mechanisms when using untrusted addresses. --- contracts/Safe.sol | 2 +- contracts/interfaces/IFallbackManager.sol | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/contracts/Safe.sol b/contracts/Safe.sol index b75eedb50..a05499a33 100644 --- a/contracts/Safe.sol +++ b/contracts/Safe.sol @@ -28,7 +28,7 @@ import {Enum} from "./libraries/Enum.sol"; * 1. Transaction Guard: managed in `GuardManager` for transactions executed with `execTransaction`. * 2. Module Guard: managed in `ModuleManager` for transactions executed with `execTransactionFromModule` * - Modules: Modules are contracts that can be used to extend the write functionality of a Safe. Managed in `ModuleManager`. - * - Fallback: Fallback handler is a contract that can provide additional read-only functionality for Safe. Managed in `FallbackManager`. + * - Fallback: Fallback handler is a contract that can provide additional functionality for Safe. Managed in `FallbackManager`. Please read the security risks in the `IFallbackManager` interface. * Note: This version of the implementation contract doesn't emit events for the sake of gas efficiency and therefore requires a tracing node for indexing/ * For the events-based implementation see `SafeL2.sol`. * @author Stefan George - @Georgi87 diff --git a/contracts/interfaces/IFallbackManager.sol b/contracts/interfaces/IFallbackManager.sol index 45b626d87..5e696465e 100644 --- a/contracts/interfaces/IFallbackManager.sol +++ b/contracts/interfaces/IFallbackManager.sol @@ -10,9 +10,12 @@ interface IFallbackManager { /** * @notice Set Fallback Handler to `handler` for the Safe. - * @dev Only fallback calls without value and with data will be forwarded. - * This can only be done via a Safe transaction. - * Cannot be set to the Safe itself. + * @dev 1. Only fallback calls without value and with data will be forwarded. + * 2. Changing the fallback handler can only be done via a Safe transaction. + * 3. Cannot be set to the Safe itself. + * 4. IMPORTANT! SECURITY RISK! The fallback handler can be set to any address and all the calls will be forwarded to it, + * bypassing all the Safe's access control mechanisms. When setting the fallback handler, make sure to check the address + * is a trusted contract and if it supports state changes, it implements the necessary checks. * @param handler contract to handle fallback calls. */ function setFallbackHandler(address handler) external; From c92ddefe70bc067fc34e549fb939bbc3ffef4ab1 Mon Sep 17 00:00:00 2001 From: Mikhail <16622558+mmv08@users.noreply.github.com> Date: Thu, 9 Jan 2025 16:57:21 +0100 Subject: [PATCH 18/38] Enhance documentation in TokenCallbackHandler with ERC-1820 registration details (#885) This PR adds a detailed comment in the TokenCallbackHandler contract, clarifying the requirement for accounts to register the implementer via the ERC-1820 interface registry to receive ERC777 tokens. This update aims to improve clarity and understanding of the token reception process. No functional changes were made to the contract logic. --- contracts/handler/TokenCallbackHandler.sol | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/contracts/handler/TokenCallbackHandler.sol b/contracts/handler/TokenCallbackHandler.sol index 4373d2448..4f8bc5557 100644 --- a/contracts/handler/TokenCallbackHandler.sol +++ b/contracts/handler/TokenCallbackHandler.sol @@ -13,7 +13,7 @@ import {IERC165} from "../interfaces/IERC165.sol"; contract TokenCallbackHandler is ERC1155TokenReceiver, ERC777TokensRecipient, ERC721TokenReceiver, IERC165 { /** * @notice Handles ERC1155 Token callback. - * return Standardized onERC1155Received return value. + * @return Standardized onERC1155Received return value. */ function onERC1155Received(address, address, uint256, uint256, bytes calldata) external pure override returns (bytes4) { return 0xf23a6e61; @@ -21,7 +21,7 @@ contract TokenCallbackHandler is ERC1155TokenReceiver, ERC777TokensRecipient, ER /** * @notice Handles ERC1155 Token batch callback. - * return Standardized onERC1155BatchReceived return value. + * @return Standardized onERC1155BatchReceived return value. */ function onERC1155BatchReceived( address, @@ -35,7 +35,7 @@ contract TokenCallbackHandler is ERC1155TokenReceiver, ERC777TokensRecipient, ER /** * @notice Handles ERC721 Token callback. - * return Standardized onERC721Received return value. + * @return Standardized onERC721Received return value. */ function onERC721Received(address, address, uint256, bytes calldata) external pure override returns (bytes4) { return 0x150b7a02; @@ -43,7 +43,10 @@ contract TokenCallbackHandler is ERC1155TokenReceiver, ERC777TokensRecipient, ER /** * @notice Handles ERC777 Token callback. - * return nothing (not standardized) + * @dev Account that wishes to receive the tokens also needs to register the implementer (this contract) via the ERC-1820 interface registry. + * From the standard: "This is done by calling the setInterfaceImplementer function on the ERC-1820 registry with the holder address as + * the address, the keccak256 hash of ERC777TokensSender (0x29ddb589b1fb5fc7cf394961c1adf5f8c6454761adf795e67fe149f658abe895) as the + * interface hash, and the address of the contract implementing the ERC777TokensSender as the implementer." */ function tokensReceived(address, address, address, uint256, bytes calldata, bytes calldata) external pure override { // We implement this for completeness, doesn't really have any value From a1925742072e17ed8b2ed3213fb8caacb17aea84 Mon Sep 17 00:00:00 2001 From: Shebin John Date: Thu, 9 Jan 2025 17:08:19 +0100 Subject: [PATCH 19/38] [Certora Audit] I-02. Some comments say `keccak` instead of `keccak256` (#886) This pull request includes updates to comments in the Solidity smart contracts to clarify the usage of the `keccak256` function. The changes ensure that the comments accurately reflect the encoding process used in the contracts. Changes to comments for clarity: * [`contracts/common/SecuredTokenTransfer.sol`](diffhunk://#diff-7a34930a339acfe3b45e163bee3e08df2132c01826e6e03771827a4181c6f567L19-R19): Updated the comment to specify that `0xa9059cbb` is the `bytes4` encoding of `keccak256("transfer(address,uint256)")`. * [`contracts/proxies/SafeProxy.sol`](diffhunk://#diff-754f853ea53666aa85b2d27bbcc0623b7cfd83449e0b949eed39dde8f01ba1cdL41-R41): Updated the comment to specify that `0xa619486e` is the `bytes4` encoding of `keccak256("masterCopy()")`. Co-authored-by: Mikhail <16622558+mmv08@users.noreply.github.com> --- contracts/common/SecuredTokenTransfer.sol | 2 +- contracts/proxies/SafeProxy.sol | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/common/SecuredTokenTransfer.sol b/contracts/common/SecuredTokenTransfer.sol index 359eb231a..382bcb059 100644 --- a/contracts/common/SecuredTokenTransfer.sol +++ b/contracts/common/SecuredTokenTransfer.sol @@ -16,7 +16,7 @@ abstract contract SecuredTokenTransfer { * @return transferred Returns true if the transfer was successful */ function transferToken(address token, address receiver, uint256 amount) internal returns (bool transferred) { - // 0xa9059cbb - keccak("transfer(address,uint256)") + // 0xa9059cbb - bytes4(keccak256("transfer(address,uint256)")) bytes memory data = abi.encodeWithSelector(0xa9059cbb, receiver, amount); /* solhint-disable no-inline-assembly */ /// @solidity memory-safe-assembly diff --git a/contracts/proxies/SafeProxy.sol b/contracts/proxies/SafeProxy.sol index 42e0f477c..10c4931af 100644 --- a/contracts/proxies/SafeProxy.sol +++ b/contracts/proxies/SafeProxy.sol @@ -38,7 +38,7 @@ contract SafeProxy { /* solhint-disable no-inline-assembly */ assembly { let _singleton := sload(0) - // 0xa619486e == keccak("masterCopy()"). The value is right padded to 32-bytes with 0s + // 0xa619486e == bytes4(keccak256("masterCopy()")). The value is right padded to 32-bytes with 0s if eq(calldataload(0), 0xa619486e00000000000000000000000000000000000000000000000000000000) { // We mask the singleton address when handling the `masterCopy()` call to ensure that it is correctly // ABI-encoded. We do this by shifting the address left by 96 bits (or 12 bytes) and then storing it in From 183a588fe942d851d697dc5f6d6bd2d0e9654bb5 Mon Sep 17 00:00:00 2001 From: Shebin John Date: Thu, 9 Jan 2025 17:19:36 +0100 Subject: [PATCH 20/38] [Certora Audit] G-01. `OwnerManager.removeOwner()`: 1 SLOAD can be saved in the normal path (#888) This pull request includes a small but important change to the `removeOwner` function in the `OwnerManager` contract. The change optimizes the decrement operation for the `ownerCount` variable. The previous code reads from storage twice with the `ownerCount` variable. By doing pre-decrement (which is cheaper than post-decrement), we can save on 1 SLOAD. Optimization: * [`contracts/base/OwnerManager.sol`](diffhunk://#diff-795fb06764b4c2d991707584a31509badf0b036c9401bfbcb82d6bc9fdebab82L74-L80): Modified the `removeOwner` function to use pre-decrement for `ownerCount` to improve efficiency and ensure the threshold check is performed correctly. --- contracts/base/OwnerManager.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/base/OwnerManager.sol b/contracts/base/OwnerManager.sol index cdb8df63e..725ea8d3d 100644 --- a/contracts/base/OwnerManager.sol +++ b/contracts/base/OwnerManager.sol @@ -71,13 +71,13 @@ abstract contract OwnerManager is SelfAuthorized, IOwnerManager { */ function removeOwner(address prevOwner, address owner, uint256 _threshold) public override authorized { // Only allow to remove an owner, if threshold can still be reached. - if (ownerCount - 1 < _threshold) revertWithError("GS201"); + // Here we do pre-decrement as it is cheaper and allows us to check if the threshold is still reachable. + if (--ownerCount < _threshold) revertWithError("GS201"); // Validate owner address and check that it corresponds to owner index. if (owner == address(0) || owner == SENTINEL_OWNERS) revertWithError("GS203"); if (owners[prevOwner] != owner) revertWithError("GS205"); owners[prevOwner] = owners[owner]; owners[owner] = address(0); - ownerCount--; emit RemovedOwner(owner); // Change threshold if threshold was changed. if (threshold != _threshold) changeThreshold(_threshold); From 95f8cb9c906db17384604f6eb978acf07264d11f Mon Sep 17 00:00:00 2001 From: Shebin John Date: Thu, 9 Jan 2025 17:20:32 +0100 Subject: [PATCH 21/38] [Certora Audit] G-03. `ERC165Handler.setSupportedInterface()`: Logic and storage access optimization (#890) This pull request includes an important update to the `ERC165Handler` contract to improve the handling of interface support and streamline the code. The most significant changes are as follows: ### The following optimizes the logic and minimizes storage accesses: * [`contracts/handler/extensible/ERC165Handler.sol`](diffhunk://#diff-aa0838f20fd3f37b00dc661645b4641500e68762b9b624addb99465fcc65a3e0L38-R48): Refactored the logic for checking and updating the support status of interfaces by introducing a local `mapping` reference. This change simplifies the code and ensures that the interface support status is updated correctly. --- contracts/handler/extensible/ERC165Handler.sol | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/contracts/handler/extensible/ERC165Handler.sol b/contracts/handler/extensible/ERC165Handler.sol index 4833ddcdf..cf3ece3ed 100644 --- a/contracts/handler/extensible/ERC165Handler.sol +++ b/contracts/handler/extensible/ERC165Handler.sol @@ -35,13 +35,15 @@ abstract contract ERC165Handler is ExtensibleBase, IERC165Handler { ISafe safe = ISafe(payable(_manager())); // invalid interface id per ERC165 spec require(interfaceId != 0xffffffff, "invalid interface id"); - bool current = safeInterfaces[safe][interfaceId]; - if (supported && !current) { - safeInterfaces[safe][interfaceId] = true; - emit AddedInterface(safe, interfaceId); - } else if (!supported && current) { - delete safeInterfaces[safe][interfaceId]; - emit RemovedInterface(safe, interfaceId); + mapping(bytes4 => bool) storage safeInterface = safeInterfaces[safe]; + bool current = safeInterface[interfaceId]; + if (supported != current) { + safeInterface[interfaceId] = supported; + if (supported) { + emit AddedInterface(safe, interfaceId); + } else { + emit RemovedInterface(safe, interfaceId); + } } } From 25365fcad1658b608a7cb783ed56a397666157d6 Mon Sep 17 00:00:00 2001 From: Shebin John Date: Thu, 9 Jan 2025 17:21:13 +0100 Subject: [PATCH 22/38] [Certora Audit] G-04. `ExtensibleBase._setSafeMethod()`: storage access optimization (#891) This pull request includes a refactor to the `_setSafeMethod` function in the `ExtensibleBase` contract to improve memory access. The following optimizes the logic and minimizes storage accesses: * [`contracts/handler/extensible/ExtensibleBase.sol`](diffhunk://#diff-e395e05c7e2951461c2e599137367a6a3304e849f3c522903d74f1a50f23b577L49-R57): Modified the `_setSafeMethod` function to use a local variable `safeMethod` for accessing the `safeMethods` mapping, which simplifies and clarifies the code. --- contracts/handler/extensible/ExtensibleBase.sol | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/contracts/handler/extensible/ExtensibleBase.sol b/contracts/handler/extensible/ExtensibleBase.sol index 6c1e19a7c..75c7c924c 100644 --- a/contracts/handler/extensible/ExtensibleBase.sol +++ b/contracts/handler/extensible/ExtensibleBase.sol @@ -46,14 +46,15 @@ abstract contract ExtensibleBase is HandlerContext { function _setSafeMethod(ISafe safe, bytes4 selector, bytes32 newMethod) internal { (, address newHandler) = MarshalLib.decode(newMethod); - bytes32 oldMethod = safeMethods[safe][selector]; + mapping(bytes4 => bytes32) storage safeMethod = safeMethods[safe]; + bytes32 oldMethod = safeMethod[selector]; (, address oldHandler) = MarshalLib.decode(oldMethod); if (address(newHandler) == address(0) && address(oldHandler) != address(0)) { - delete safeMethods[safe][selector]; + delete safeMethod[selector]; emit RemovedSafeMethod(safe, selector); } else { - safeMethods[safe][selector] = newMethod; + safeMethod[selector] = newMethod; if (address(oldHandler) == address(0)) { emit AddedSafeMethod(safe, selector, newMethod); } else { From 0e061e24d8d7042c44968158430f0027e4b9df83 Mon Sep 17 00:00:00 2001 From: Shebin John Date: Thu, 9 Jan 2025 17:21:56 +0100 Subject: [PATCH 23/38] [Certora Audit] G-05. Use `iszero` instead of `eq(*, 0)` (#892) This pull request includes a critical update to the `SafeProxyFactory` contract in the `contracts/proxies/SafeProxyFactory.sol` file. The change improves the gas cost of the assembly code by replacing the `eq` function with the `iszero` function. Key change: * [`contracts/proxies/SafeProxyFactory.sol`](diffhunk://#diff-53aac98a01e16743466b00bdcb233208f95e1113cc90b95181187d9862b4ad6eL43-R43): Replaced the `eq` function with the `iszero` function in the assembly block to improve code readability and reliability. --- contracts/proxies/SafeProxyFactory.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/proxies/SafeProxyFactory.sol b/contracts/proxies/SafeProxyFactory.sol index bd470ced9..b8f6f1ce6 100644 --- a/contracts/proxies/SafeProxyFactory.sol +++ b/contracts/proxies/SafeProxyFactory.sol @@ -40,7 +40,7 @@ contract SafeProxyFactory { /* solhint-disable no-inline-assembly */ /// @solidity memory-safe-assembly assembly { - if eq(call(gas(), proxy, 0, add(initializer, 0x20), mload(initializer), 0, 0), 0) { + if iszero(call(gas(), proxy, 0, add(initializer, 0x20), mload(initializer), 0, 0)) { revert(0, 0) } } From e35793d5fbbfb884c048f1fc5c5b2d70fecd80d5 Mon Sep 17 00:00:00 2001 From: Shebin John Date: Thu, 9 Jan 2025 17:23:01 +0100 Subject: [PATCH 24/38] [Certora Audit] G-06. `ExtensibleFallbackHandler._supportsInterface()`: save gas via short-circuit evaluation (#893) This pull request includes a change to the `ExtensibleFallbackHandler` contract in the `contracts/handler/ExtensibleFallbackHandler.sol` file. The change modifies the `_supportsInterface` function to reorder the interface checks for `ERC721TokenReceiver`, `ERC1155TokenReceiver`, and `IFallbackHandler`. This helps in taking advantage of the short-circuit evaluation. Changes to interface support order: * [`contracts/handler/ExtensibleFallbackHandler.sol`](diffhunk://#diff-aa345618c4d3f173b09e211d0bd0eec0747177aab345bf8b9f5bbc874a765fe3R21-R26): Reordered the interface checks in the `_supportsInterface` function to place `ERC721TokenReceiver` and `ERC1155TokenReceiver` before `IFallbackHandler`. --- contracts/handler/ExtensibleFallbackHandler.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/handler/ExtensibleFallbackHandler.sol b/contracts/handler/ExtensibleFallbackHandler.sol index 7843af4b2..694474c48 100644 --- a/contracts/handler/ExtensibleFallbackHandler.sol +++ b/contracts/handler/ExtensibleFallbackHandler.sol @@ -18,11 +18,11 @@ contract ExtensibleFallbackHandler is FallbackHandler, SignatureVerifierMuxer, T */ function _supportsInterface(bytes4 interfaceId) internal pure override returns (bool) { return + interfaceId == type(ERC721TokenReceiver).interfaceId || + interfaceId == type(ERC1155TokenReceiver).interfaceId || interfaceId == type(ERC1271).interfaceId || interfaceId == type(ISignatureVerifierMuxer).interfaceId || interfaceId == type(ERC165Handler).interfaceId || - interfaceId == type(IFallbackHandler).interfaceId || - interfaceId == type(ERC721TokenReceiver).interfaceId || - interfaceId == type(ERC1155TokenReceiver).interfaceId; + interfaceId == type(IFallbackHandler).interfaceId; } } From b2c60870a9d95aa77f75a605b63c22798aaf9938 Mon Sep 17 00:00:00 2001 From: Shebin John Date: Thu, 9 Jan 2025 17:48:02 +0100 Subject: [PATCH 25/38] [Certora Audit] G-09. Cache array length outside of loop (#896) This pull request includes several optimizations to the `OwnerManager` and `ERC165Handler` contracts by reducing the number of times array lengths are accessed within loops. These changes aim to improve the efficiency of the code by storing the array lengths in variables before the loops. If not cached, the solidity compiler will always read the length of the array during each iteration. That is, if it is a storage array, this is an extra sload operation (100 additional extra gas for each iteration except for the first) and if it is a memory array, this is an extra mload operation (3 additional gas for each iteration except for the first). Optimizations in `OwnerManager` contract: * [`contracts/base/OwnerManager.sol`](diffhunk://#diff-795fb06764b4c2d991707584a31509badf0b036c9401bfbcb82d6bc9fdebab82L38-R39): Stored `_owners.length` in a variable `ownersLength` before the loop to avoid repeatedly accessing the array length. * [`contracts/base/OwnerManager.sol`](diffhunk://#diff-795fb06764b4c2d991707584a31509badf0b036c9401bfbcb82d6bc9fdebab82L49-R50): Updated `ownerCount` to use the `ownersLength` variable instead of accessing `_owners.length` again. Optimizations in `ERC165Handler` contract: * [`contracts/handler/extensible/ERC165Handler.sol`](diffhunk://#diff-aa0838f20fd3f37b00dc661645b4641500e68762b9b624addb99465fcc65a3e0L56-R57): Stored `handlerWithSelectors.length` in a variable `len` before the loop in `addSupportedInterfaceBatch` to avoid repeatedly accessing the array length. * [`contracts/handler/extensible/ERC165Handler.sol`](diffhunk://#diff-aa0838f20fd3f37b00dc661645b4641500e68762b9b624addb99465fcc65a3e0L78-R80): Stored `selectors.length` in a variable `len` before the loop in `removeSupportedInterfaceBatch` to avoid repeatedly accessing the array length. --- contracts/base/OwnerManager.sol | 5 +++-- contracts/handler/extensible/ERC165Handler.sol | 6 ++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/contracts/base/OwnerManager.sol b/contracts/base/OwnerManager.sol index 725ea8d3d..77821523a 100644 --- a/contracts/base/OwnerManager.sol +++ b/contracts/base/OwnerManager.sol @@ -35,7 +35,8 @@ abstract contract OwnerManager is SelfAuthorized, IOwnerManager { if (_threshold == 0) revertWithError("GS202"); // Initializing Safe owners. address currentOwner = SENTINEL_OWNERS; - for (uint256 i = 0; i < _owners.length; i++) { + uint256 ownersLength = _owners.length; + for (uint256 i = 0; i < ownersLength; i++) { // Owner address cannot be null. address owner = _owners[i]; if (owner == address(0) || owner == SENTINEL_OWNERS || owner == address(this) || currentOwner == owner) @@ -46,7 +47,7 @@ abstract contract OwnerManager is SelfAuthorized, IOwnerManager { currentOwner = owner; } owners[currentOwner] = SENTINEL_OWNERS; - ownerCount = _owners.length; + ownerCount = ownersLength; threshold = _threshold; } diff --git a/contracts/handler/extensible/ERC165Handler.sol b/contracts/handler/extensible/ERC165Handler.sol index cf3ece3ed..bc19fe624 100644 --- a/contracts/handler/extensible/ERC165Handler.sol +++ b/contracts/handler/extensible/ERC165Handler.sol @@ -55,7 +55,8 @@ abstract contract ERC165Handler is ExtensibleBase, IERC165Handler { function addSupportedInterfaceBatch(bytes4 _interfaceId, bytes32[] calldata handlerWithSelectors) external override onlySelf { ISafe safe = ISafe(payable(_msgSender())); bytes4 interfaceId; - for (uint256 i = 0; i < handlerWithSelectors.length; i++) { + uint256 len = handlerWithSelectors.length; + for (uint256 i = 0; i < len; i++) { (bool isStatic, bytes4 selector, address handlerAddress) = MarshalLib.decodeWithSelector(handlerWithSelectors[i]); _setSafeMethod(safe, selector, MarshalLib.encode(isStatic, handlerAddress)); if (i > 0) { @@ -77,7 +78,8 @@ abstract contract ERC165Handler is ExtensibleBase, IERC165Handler { function removeSupportedInterfaceBatch(bytes4 _interfaceId, bytes4[] calldata selectors) external override onlySelf { ISafe safe = ISafe(payable(_msgSender())); bytes4 interfaceId; - for (uint256 i = 0; i < selectors.length; i++) { + uint256 len = selectors.length; + for (uint256 i = 0; i < len; i++) { _setSafeMethod(safe, selectors[i], bytes32(0)); if (i > 0) { interfaceId ^= selectors[i]; From 8aa455162b279c7ba629fa35267bdc9ac41cecff Mon Sep 17 00:00:00 2001 From: Shebin John Date: Thu, 9 Jan 2025 18:08:57 +0100 Subject: [PATCH 26/38] [Certora Audit] I-03. Inconsistency in formula for `performCreate` and `performCreate2` (#887) Commutativity makes the two additions equivalent but Certora recommend the fix below for readability and to follow the standard given that: - `deploymentData` gives a pointer to the start of the array (length position). - Adding `0x20` skips the first 32 bytes (length field) to point directly to the start of the payload. Change: * [`contracts/libraries/CreateCall.sol`](diffhunk://#diff-d5d801f238d69f94974c4f4628197fcc2df478f608c18c5f691f73dfd552e36eL25-R25): Changed the order of parameters in the `create2` function call to correctly add the offset to `deploymentData`. Co-authored-by: Mikhail <16622558+mmv08@users.noreply.github.com> --- contracts/libraries/CreateCall.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/libraries/CreateCall.sol b/contracts/libraries/CreateCall.sol index 735d6f118..8054c8356 100644 --- a/contracts/libraries/CreateCall.sol +++ b/contracts/libraries/CreateCall.sol @@ -22,7 +22,7 @@ contract CreateCall { /* solhint-disable no-inline-assembly */ /// @solidity memory-safe-assembly assembly { - newContract := create2(value, add(0x20, deploymentData), mload(deploymentData), salt) + newContract := create2(value, add(deploymentData, 0x20), mload(deploymentData), salt) } /* solhint-enable no-inline-assembly */ require(newContract != address(0), "Could not deploy contract"); From 19e1d63341315c7655a584f01b675b5855f59505 Mon Sep 17 00:00:00 2001 From: Mikhail <16622558+mmv08@users.noreply.github.com> Date: Thu, 9 Jan 2025 18:23:43 +0100 Subject: [PATCH 27/38] Enhance Safe.sol with ECDSA malleability warning (#877) Added a comment in the Safe contract to clarify that the `s` value of ECDSA signatures is not enforced to be in the lower half of the curve. This note explains the implications of ECDSA malleability and reassures that existing mechanisms are in place to prevent duplicate signatures and replay attacks. No functional changes were made to the contract logic. --- contracts/Safe.sol | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/contracts/Safe.sol b/contracts/Safe.sol index a05499a33..975dc836f 100644 --- a/contracts/Safe.sol +++ b/contracts/Safe.sol @@ -291,6 +291,10 @@ contract Safe is address currentOwner; uint256 v; // Implicit conversion from uint8 to uint256 will be done for v received from signatureSplit(...). bytes32 r; + // NOTE: We do not enforce the `s` to be from the lower half of the curve + // This essentially means that for every signature, there's another valid signature (known as ECDSA malleability) + // Since we have other mechanisms to prevent duplicated signatures (ordered owners array) and replay protection (nonce), + // we can safely ignore this malleability. bytes32 s; uint256 i; for (i = 0; i < requiredSignatures; i++) { From 8137b6895f7d51f119838a5470ece51fa5a01d66 Mon Sep 17 00:00:00 2001 From: Shebin John Date: Fri, 10 Jan 2025 12:46:37 +0100 Subject: [PATCH 28/38] [Certora Audit] G-10. ++i costs less gas compared to i++ or i+=1 (#897) This pull request includes several changes to increment and decrement operations in various Solidity contract files. The primary goal is to decrease gas usage. Pre-increments and pre-decrements are cheaper. For a uint256 i variable, the following is true with the Optimizer enabled at 10k: Increment: - i += 1 is the most expensive form - i++ costs 6 gas less than i += 1 - ++i costs 5 gas less than i++ (11 gas less than i += 1) Decrement: - i -= 1 is the most expensive form - i-- costs 11 gas less than i -= 1 - --i costs 5 gas less than i-- (16 gas less than i -= 1) Changes to increment and decrement operations: * [`contracts/Safe.sol`](diffhunk://#diff-587b494ea631bb6b7adf4fc3e1a2e6a277a385ff16e1163b26e39de24e9483deL296-R296): Updated the for loop to use the prefix increment operator in the `Safe` contract. * [`contracts/base/ModuleManager.sol`](diffhunk://#diff-82762908b9416ddadffb149ee4d25f328078fc27f938d454d8a207aad1ec3839L215-R215): Changed the increment operation to use the prefix increment operator in the `ModuleManager` contract. * [`contracts/base/OwnerManager.sol`](diffhunk://#diff-795fb06764b4c2d991707584a31509badf0b036c9401bfbcb82d6bc9fdebab82L38-R38): Multiple updates to use prefix increment and decrement operators in the `OwnerManager` contract. [[1]](diffhunk://#diff-795fb06764b4c2d991707584a31509badf0b036c9401bfbcb82d6bc9fdebab82L38-R38) [[2]](diffhunk://#diff-795fb06764b4c2d991707584a31509badf0b036c9401bfbcb82d6bc9fdebab82L63-R63) [[3]](diffhunk://#diff-795fb06764b4c2d991707584a31509badf0b036c9401bfbcb82d6bc9fdebab82L80-R80) [[4]](diffhunk://#diff-795fb06764b4c2d991707584a31509badf0b036c9401bfbcb82d6bc9fdebab82L142-R142) * [`contracts/common/StorageAccessible.sol`](diffhunk://#diff-a7dd65d90b0567bb9ba14ecd4ff414529a934cd3752ccf309800fad93fba354eL19-R19): Modified the for loop to use the prefix increment operator in the `StorageAccessible` contract. * [`contracts/handler/extensible/ERC165Handler.sol`](diffhunk://#diff-aa0838f20fd3f37b00dc661645b4641500e68762b9b624addb99465fcc65a3e0L56-R56): Updated for loops to use the prefix increment operator in the `ERC165Handler` contract. [[1]](diffhunk://#diff-aa0838f20fd3f37b00dc661645b4641500e68762b9b624addb99465fcc65a3e0L56-R56) [[2]](diffhunk://#diff-aa0838f20fd3f37b00dc661645b4641500e68762b9b624addb99465fcc65a3e0L78-R78) * [`contracts/libraries/SafeToL2Migration.sol`](diffhunk://#diff-925588b812f729cc164d14a48e571ce813e2f0ae6f5c5420fc0382c767287fd0L188-R188): Changed the increment operation to use the prefix increment operator in the `SafeToL2Migration` contract. --- contracts/Safe.sol | 2 +- contracts/base/ModuleManager.sol | 2 +- contracts/base/OwnerManager.sol | 6 +++--- contracts/common/StorageAccessible.sol | 2 +- contracts/handler/extensible/ERC165Handler.sol | 4 ++-- contracts/libraries/SafeToL2Migration.sol | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/contracts/Safe.sol b/contracts/Safe.sol index 975dc836f..3632b3dd3 100644 --- a/contracts/Safe.sol +++ b/contracts/Safe.sol @@ -297,7 +297,7 @@ contract Safe is // we can safely ignore this malleability. bytes32 s; uint256 i; - for (i = 0; i < requiredSignatures; i++) { + for (i = 0; i < requiredSignatures; ++i) { (v, r, s) = signatureSplit(signatures, i); if (v == 0) { // If v is 0 then it is a contract signature diff --git a/contracts/base/ModuleManager.sol b/contracts/base/ModuleManager.sol index b3985be85..9b1c9d409 100644 --- a/contracts/base/ModuleManager.sol +++ b/contracts/base/ModuleManager.sol @@ -212,7 +212,7 @@ abstract contract ModuleManager is SelfAuthorized, Executor, IModuleManager { while (next != address(0) && next != SENTINEL_MODULES && moduleCount < pageSize) { array[moduleCount] = next; next = modules[next]; - moduleCount++; + ++moduleCount; } /** diff --git a/contracts/base/OwnerManager.sol b/contracts/base/OwnerManager.sol index 77821523a..671909fb1 100644 --- a/contracts/base/OwnerManager.sol +++ b/contracts/base/OwnerManager.sol @@ -36,7 +36,7 @@ abstract contract OwnerManager is SelfAuthorized, IOwnerManager { // Initializing Safe owners. address currentOwner = SENTINEL_OWNERS; uint256 ownersLength = _owners.length; - for (uint256 i = 0; i < ownersLength; i++) { + for (uint256 i = 0; i < ownersLength; ++i) { // Owner address cannot be null. address owner = _owners[i]; if (owner == address(0) || owner == SENTINEL_OWNERS || owner == address(this) || currentOwner == owner) @@ -61,7 +61,7 @@ abstract contract OwnerManager is SelfAuthorized, IOwnerManager { if (owners[owner] != address(0)) revertWithError("GS204"); owners[owner] = owners[SENTINEL_OWNERS]; owners[SENTINEL_OWNERS] = owner; - ownerCount++; + ++ownerCount; emit AddedOwner(owner); // Change threshold if threshold was changed. if (threshold != _threshold) changeThreshold(_threshold); @@ -140,7 +140,7 @@ abstract contract OwnerManager is SelfAuthorized, IOwnerManager { while (currentOwner != SENTINEL_OWNERS) { array[index] = currentOwner; currentOwner = owners[currentOwner]; - index++; + ++index; } return array; } diff --git a/contracts/common/StorageAccessible.sol b/contracts/common/StorageAccessible.sol index 9b4e6a9c3..c9862910f 100644 --- a/contracts/common/StorageAccessible.sol +++ b/contracts/common/StorageAccessible.sol @@ -16,7 +16,7 @@ abstract contract StorageAccessible { */ function getStorageAt(uint256 offset, uint256 length) public view returns (bytes memory) { bytes memory result = new bytes(length * 32); - for (uint256 index = 0; index < length; index++) { + for (uint256 index = 0; index < length; ++index) { /* solhint-disable no-inline-assembly */ /// @solidity memory-safe-assembly assembly { diff --git a/contracts/handler/extensible/ERC165Handler.sol b/contracts/handler/extensible/ERC165Handler.sol index bc19fe624..004e1cb18 100644 --- a/contracts/handler/extensible/ERC165Handler.sol +++ b/contracts/handler/extensible/ERC165Handler.sol @@ -56,7 +56,7 @@ abstract contract ERC165Handler is ExtensibleBase, IERC165Handler { ISafe safe = ISafe(payable(_msgSender())); bytes4 interfaceId; uint256 len = handlerWithSelectors.length; - for (uint256 i = 0; i < len; i++) { + for (uint256 i = 0; i < len; ++i) { (bool isStatic, bytes4 selector, address handlerAddress) = MarshalLib.decodeWithSelector(handlerWithSelectors[i]); _setSafeMethod(safe, selector, MarshalLib.encode(isStatic, handlerAddress)); if (i > 0) { @@ -79,7 +79,7 @@ abstract contract ERC165Handler is ExtensibleBase, IERC165Handler { ISafe safe = ISafe(payable(_msgSender())); bytes4 interfaceId; uint256 len = selectors.length; - for (uint256 i = 0; i < len; i++) { + for (uint256 i = 0; i < len; ++i) { _setSafeMethod(safe, selectors[i], bytes32(0)); if (i > 0) { interfaceId ^= selectors[i]; diff --git a/contracts/libraries/SafeToL2Migration.sol b/contracts/libraries/SafeToL2Migration.sol index 680b17385..176f2e926 100644 --- a/contracts/libraries/SafeToL2Migration.sol +++ b/contracts/libraries/SafeToL2Migration.sol @@ -185,7 +185,7 @@ contract SafeToL2Migration is SafeStorage { while (currentOwner != sentinelOwners) { array[index] = currentOwner; currentOwner = owners[currentOwner]; - index++; + ++index; } return array; } From 5c8c6c0601206ca12829f7f5337b31b4d64885b2 Mon Sep 17 00:00:00 2001 From: Shebin John Date: Fri, 10 Jan 2025 12:46:56 +0100 Subject: [PATCH 29/38] [Certora Audit] G07. Use a mask instead of shifting left and right (#894) This pull request includes changes to the `contracts/handler/extensible` directory, specifically in the `MarshalLib.sol` and `SignatureVerifierMuxer.sol` files. The changes focus on improving the handling of data and selectors within assembly code blocks to decrease gas usage. Improvements to data handling and selector extraction: * [`contracts/handler/extensible/MarshalLib.sol`](diffhunk://#diff-7122c44132b6fc89cd7c9f3c48519c88aaf7308705a1170d307d72465eb9e1c9L41-R41): Modified the way the `handler` is extracted from `data` by using a bitwise AND operation to ensure proper extraction of the handler address. [[1]](diffhunk://#diff-7122c44132b6fc89cd7c9f3c48519c88aaf7308705a1170d307d72465eb9e1c9L41-R41) [[2]](diffhunk://#diff-7122c44132b6fc89cd7c9f3c48519c88aaf7308705a1170d307d72465eb9e1c9L59-R59) * [`contracts/handler/extensible/SignatureVerifierMuxer.sol`](diffhunk://#diff-62f21ce8850527f34ef2acdacd96d4a2a1150e3e2a7e16457e82236bbd4259d2L113-R113): Changed the extraction of `sigSelector` from `calldataload` to use a bitwise AND operation for more accurate and secure selector extraction. --- contracts/handler/extensible/MarshalLib.sol | 4 ++-- contracts/handler/extensible/SignatureVerifierMuxer.sol | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/handler/extensible/MarshalLib.sol b/contracts/handler/extensible/MarshalLib.sol index b55436e7a..82b041394 100644 --- a/contracts/handler/extensible/MarshalLib.sol +++ b/contracts/handler/extensible/MarshalLib.sol @@ -38,7 +38,7 @@ library MarshalLib { assembly { // set isStatic to true if the left-most byte of the data is 0x00 isStatic := iszero(shr(248, data)) - handler := shr(96, shl(96, data)) + handler := and(data, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) } /* solhint-enable no-inline-assembly */ } @@ -56,7 +56,7 @@ library MarshalLib { assembly { // set isStatic to true if the left-most byte of the data is 0x00 isStatic := iszero(shr(248, data)) - handler := shr(96, shl(96, data)) + handler := and(data, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) selector := shl(168, shr(160, data)) } /* solhint-enable no-inline-assembly */ diff --git a/contracts/handler/extensible/SignatureVerifierMuxer.sol b/contracts/handler/extensible/SignatureVerifierMuxer.sol index a2b5a0532..a1ee509f3 100644 --- a/contracts/handler/extensible/SignatureVerifierMuxer.sol +++ b/contracts/handler/extensible/SignatureVerifierMuxer.sol @@ -110,7 +110,7 @@ abstract contract SignatureVerifierMuxer is ExtensibleBase, ERC1271, ISignatureV /* solhint-disable no-inline-assembly */ /// @solidity memory-safe-assembly assembly { - sigSelector := shl(224, shr(224, calldataload(signature.offset))) + sigSelector := calldataload(signature.offset) } /* solhint-enable no-inline-assembly */ From 7e760ef4965daa67de9737d2ebf7b0d26b74b94e Mon Sep 17 00:00:00 2001 From: Shebin John Date: Fri, 10 Jan 2025 13:08:26 +0100 Subject: [PATCH 30/38] [Certora Audit] G-08. Use shift right/left instead of division/multiplication if possible (#895) This pull request includes optimizations to the gas usage in the `Safe.sol` and `StorageAccessible.sol` contracts by replacing multiplication operations with bitwise shift operations. While the `DIV / MUL` opcode uses 5 gas, the `SHR / SHL` opcode only uses 3 gas. Gas optimization changes: * [`contracts/Safe.sol`](diffhunk://#diff-587b494ea631bb6b7adf4fc3e1a2e6a277a385ff16e1163b26e39de24e9483deL168-R169): Replaced the multiplication operation `* 64` with the bitwise shift operation `<< 6` to reduce gas costs in the `gasleft` check. * [`contracts/common/StorageAccessible.sol`](diffhunk://#diff-a7dd65d90b0567bb9ba14ecd4ff414529a934cd3752ccf309800fad93fba354eL18-R18): Replaced the multiplication operation `* 32` with the bitwise shift operation `<< 5` to reduce gas costs when creating a new bytes array. --- contracts/Safe.sol | 3 ++- contracts/common/StorageAccessible.sol | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/contracts/Safe.sol b/contracts/Safe.sol index 3632b3dd3..2e13aed3a 100644 --- a/contracts/Safe.sol +++ b/contracts/Safe.sol @@ -165,7 +165,8 @@ contract Safe is // We require some gas to emit the events (at least 2500) after the execution and some to perform code until the execution (500) // We also include the 1/64 in the check that is not sent along with a call to counteract potential shortings because of EIP-150 - if (gasleft() < ((safeTxGas * 64) / 63).max(safeTxGas + 2500) + 500) revertWithError("GS010"); + // We use `<< 6` instead of `* 64` as SHR / SHL opcode only uses 3 gas, while DIV / MUL opcode uses 5 gas. + if (gasleft() < ((safeTxGas << 6) / 63).max(safeTxGas + 2500) + 500) revertWithError("GS010"); // Use scope here to limit variable lifetime and prevent `stack too deep` errors { uint256 gasUsed = gasleft(); diff --git a/contracts/common/StorageAccessible.sol b/contracts/common/StorageAccessible.sol index c9862910f..d4081e96f 100644 --- a/contracts/common/StorageAccessible.sol +++ b/contracts/common/StorageAccessible.sol @@ -15,7 +15,8 @@ abstract contract StorageAccessible { * @return the bytes that were read. */ function getStorageAt(uint256 offset, uint256 length) public view returns (bytes memory) { - bytes memory result = new bytes(length * 32); + // We use `<< 5` instead of `* 32` as SHR / SHL opcode only uses 3 gas, while DIV / MUL opcode uses 5 gas. + bytes memory result = new bytes(length << 5); for (uint256 index = 0; index < length; ++index) { /* solhint-disable no-inline-assembly */ /// @solidity memory-safe-assembly From 70268e7ba1410c3ee438e94765804ae267116415 Mon Sep 17 00:00:00 2001 From: Mikhail <16622558+mmv08@users.noreply.github.com> Date: Tue, 14 Jan 2025 12:25:03 +0300 Subject: [PATCH 31/38] An attempt to fix flaky zksync test (#898) - Upgraded several development dependencies related to Hardhat and zkSync: - `@matterlabs/hardhat-zksync-deploy` from `^1.5.0` to `^1.6.0` - `@matterlabs/hardhat-zksync-node` from `^1.1.1` to `^1.2.1` - `@matterlabs/hardhat-zksync-verify` from `^1.6.0` to `^1.7.1` - `zksync-ethers` from `6.12.1` to `6.15.3` - Refactored the test setup in `SafeToL2Setup.spec.ts` to retrieve the deployed contract instance using `getContractAt` instead of deploying a new instance, enhancing test reliability and efficiency. --- hardhat.config.ts | 6 +- package-lock.json | 2018 ++++++++++++++------------ package.json | 12 +- test/libraries/SafeToL2Setup.spec.ts | 3 +- 4 files changed, 1062 insertions(+), 977 deletions(-) diff --git a/hardhat.config.ts b/hardhat.config.ts index 29d46f307..be87a79b2 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -89,8 +89,10 @@ const userConfig: HardhatUserConfig = { compilers: [{ version: primarySolidityVersion, settings: soliditySettings }, { version: defaultSolidityVersion }], }, zksolc: { - version: "1.5.3", - settings: {}, + version: "1.5.9", + settings: { + suppressedErrors: ["assemblycreate"], + }, }, networks: { hardhat: { diff --git a/package-lock.json b/package-lock.json index ffe05567f..23b8f325a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,11 +10,11 @@ "license": "LGPL-3.0", "devDependencies": { "@eslint/js": "^9.9.1", - "@matterlabs/hardhat-zksync-deploy": "^1.5.0", + "@matterlabs/hardhat-zksync-deploy": "^1.6.0", "@matterlabs/hardhat-zksync-ethers": "^1.2.1", - "@matterlabs/hardhat-zksync-node": "^1.1.1", - "@matterlabs/hardhat-zksync-solc": "^1.2.4", - "@matterlabs/hardhat-zksync-verify": "^1.6.0", + "@matterlabs/hardhat-zksync-node": "^1.2.1", + "@matterlabs/hardhat-zksync-solc": "^1.2.5", + "@matterlabs/hardhat-zksync-verify": "^1.7.1", "@nomicfoundation/hardhat-toolbox": "^5.0.0", "@openzeppelin/contracts": "^3.4.0", "@safe-global/mock-contract": "^4.1.0", @@ -31,7 +31,7 @@ "eslint-config-prettier": "^9.1.0", "eslint-plugin-no-only-tests": "^3.3.0", "eslint-plugin-prettier": "^5.2.1", - "hardhat": "^2.22.10", + "hardhat": "^2.22.17", "hardhat-deploy": "^0.12.4", "husky": "^9.1.5", "prettier": "^3.3.3", @@ -43,7 +43,7 @@ "typescript": "^5.5.4", "typescript-eslint": "^8.4.0", "yargs": "^17.7.2", - "zksync-ethers": "6.12.1" + "zksync-ethers": "6.15.3" } }, "node_modules/@adraffy/ens-normalize": { @@ -55,13 +55,14 @@ "peer": true }, "node_modules/@babel/code-frame": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", - "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/highlight": "^7.24.7", + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", "picocolors": "^1.0.0" }, "engines": { @@ -69,109 +70,15 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", - "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", "dev": true, "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.24.7", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" - }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@balena/dockerignore": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@balena/dockerignore/-/dockerignore-1.0.2.tgz", @@ -193,25 +100,28 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", + "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", "dev": true, "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.3" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, + "funding": { + "url": "https://opencollective.com/eslint" + }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "node_modules/@eslint-community/regexpp": { - "version": "4.11.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.1.tgz", - "integrity": "sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", "dev": true, "license": "MIT", "engines": { @@ -219,13 +129,13 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz", - "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.1.tgz", + "integrity": "sha512-fo6Mtm5mWyKjA/Chy1BYTdn5mGJoDNjC7C64ug20ADsRDGrA85bN3uK3MaKbeRkRuuIEAR5N33Jr1pbm411/PA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/object-schema": "^2.1.4", + "@eslint/object-schema": "^2.1.5", "debug": "^4.3.1", "minimatch": "^3.1.2" }, @@ -257,10 +167,23 @@ "node": "*" } }, + "node_modules/@eslint/core": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.9.1.tgz", + "integrity": "sha512-GuUdqkyyzQI5RMIWkHhvTWLCyLo1jNK3vzkSyaExH5kHPDHcuL2VOpHjmMY+y3+NC69qAKToBqldTBgYeLSr9Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@eslint/eslintrc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", - "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz", + "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", "dev": true, "license": "MIT", "dependencies": { @@ -306,9 +229,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.10.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.10.0.tgz", - "integrity": "sha512-fuXtbiP5GWIn8Fz+LWoOMVf/Jxm+aajZYkhi6CuEm4SxymFM+eUWzbO9qXT+L0iCkL5+KGYMCSGxo686H19S1g==", + "version": "9.17.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.17.0.tgz", + "integrity": "sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==", "dev": true, "license": "MIT", "engines": { @@ -316,9 +239,9 @@ } }, "node_modules/@eslint/object-schema": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", - "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.5.tgz", + "integrity": "sha512-o0bhxnL89h5Bae5T318nFoFzGy+YE5i/gGkoPAgkmTVdRKTiv3p8JHevPiPaMwoloKfEiiaHlawCqaZMqRm+XQ==", "dev": true, "license": "Apache-2.0", "engines": { @@ -326,9 +249,9 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.1.0.tgz", - "integrity": "sha512-autAXT203ixhqei9xt+qkYOvY8l6LAFIdT2UXc/RPNeUVfqRF1BV94GTJyVPFKT8nFM6MyVJhjLj9E8JWvf5zQ==", + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.4.tgz", + "integrity": "sha512-zSkKow6H5Kdm0ZUQUB2kV5JIXqoG0+uH5YADhaEHswm664N9Db8dXSi0nMJpacpMf+MyyglF1vnZohpEg5yUtg==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -1180,6 +1103,77 @@ "node": ">=14" } }, + "node_modules/@grpc/grpc-js": { + "version": "1.12.5", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.12.5.tgz", + "integrity": "sha512-d3iiHxdpg5+ZcJ6jnDSOT8Z0O0VMVGy34jAnYLUX8yd36b1qn8f1TwOA/Lc7TsOh03IkPJ38eGI5qD2EjNkoEA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@grpc/proto-loader": "^0.7.13", + "@js-sdsl/ordered-map": "^4.4.2" + }, + "engines": { + "node": ">=12.10.0" + } + }, + "node_modules/@grpc/proto-loader": { + "version": "0.7.13", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.13.tgz", + "integrity": "sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "lodash.camelcase": "^4.3.0", + "long": "^5.0.0", + "protobufjs": "^7.2.5", + "yargs": "^17.7.2" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -1195,9 +1189,9 @@ } }, "node_modules/@humanwhocodes/retry": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", - "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz", + "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -1339,14 +1333,25 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@js-sdsl/ordered-map": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", + "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, "node_modules/@matterlabs/hardhat-zksync-deploy": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@matterlabs/hardhat-zksync-deploy/-/hardhat-zksync-deploy-1.5.0.tgz", - "integrity": "sha512-7LAgYYwoKWHeR+3CyWEvA3NKBKtt7ktcr7SX6ZPgbEYqHAdXH02vxJZGwNADtMWpyYm8h+fEQkpPIgErD4NhmA==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@matterlabs/hardhat-zksync-deploy/-/hardhat-zksync-deploy-1.6.0.tgz", + "integrity": "sha512-yaOfhw7hmLOriBc+TnHrFOVKyi79XFqJN5D1Z4T6CadaSNLeq7pgBV81kkgVzaCJVoA/La2RGxPowsG7riZGbw==", "dev": true, "license": "MIT", "dependencies": { - "@matterlabs/hardhat-zksync-solc": "^1.2.0", + "@matterlabs/hardhat-zksync-solc": "^1.2.5", "chai": "^4.3.4", "chalk": "^4.1.2", "fs-extra": "^11.2.0", @@ -1359,7 +1364,7 @@ "peerDependencies": { "ethers": "^6.12.2", "hardhat": "^2.22.5", - "zksync-ethers": "^6.8.0" + "zksync-ethers": "^6.11.2" } }, "node_modules/@matterlabs/hardhat-zksync-ethers": { @@ -1382,20 +1387,23 @@ } }, "node_modules/@matterlabs/hardhat-zksync-node": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@matterlabs/hardhat-zksync-node/-/hardhat-zksync-node-1.1.1.tgz", - "integrity": "sha512-cDN4PbntNRAu9CRCwWY1qNxA7Nsr5lLGC2MT80p/h7/FR9AT4USUgnRCeYsgNOKwa6c9mRNwD/CxJhgreYrUbA==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@matterlabs/hardhat-zksync-node/-/hardhat-zksync-node-1.2.1.tgz", + "integrity": "sha512-BZDJyEB9iu54D6sOKTGeJrN5TRFLrg6k9E1x3lEwpOfewPwg1eTfb9e/LKGSCePbSremZIHzK3eDRr80hVdDjA==", "dev": true, "license": "MIT", "dependencies": { - "@matterlabs/hardhat-zksync-solc": "^1.2.1", + "@matterlabs/hardhat-zksync-solc": "^1.2.5", "axios": "^1.7.2", "chai": "^4.3.4", "chalk": "^4.1.2", + "debug": "^4.3.5", "fs-extra": "^11.2.0", "proxyquire": "^2.1.3", + "semver": "^7.6.2", "sinon": "^18.0.0", "sinon-chai": "^3.7.0", + "source-map-support": "^0.5.21", "undici": "^6.18.2" }, "peerDependencies": { @@ -1403,9 +1411,9 @@ } }, "node_modules/@matterlabs/hardhat-zksync-solc": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@matterlabs/hardhat-zksync-solc/-/hardhat-zksync-solc-1.2.4.tgz", - "integrity": "sha512-9Nk95kxOZ9rl26trP/pXDLw5MqFAd0CD8FMTGDvA5HBGk6CL2wg4tS0gmucYz5R4qj09KUYOO4FW4rgd/atcGg==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@matterlabs/hardhat-zksync-solc/-/hardhat-zksync-solc-1.2.5.tgz", + "integrity": "sha512-iZyznWl1Hoe/Z46hnUe1s2drBZBjJOS/eN+Ql2lIBX9B6NevBl9DYzkKzH5HEIMCLGnX9sWpRAJqUQJWy9UB6w==", "dev": true, "license": "MIT", "dependencies": { @@ -1426,15 +1434,15 @@ } }, "node_modules/@matterlabs/hardhat-zksync-verify": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@matterlabs/hardhat-zksync-verify/-/hardhat-zksync-verify-1.6.0.tgz", - "integrity": "sha512-RsWlQbI23BDXMsxTtvHXpzx1dBotI2p2trvdG+r1uN/KAmMJBOKIqxce2UNXl8skd5Gtysa4GPjXEp4yaf2KrA==", + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@matterlabs/hardhat-zksync-verify/-/hardhat-zksync-verify-1.7.1.tgz", + "integrity": "sha512-FtibELgllkyAZORDW4/s/7XSC5DaqAXG0KXMqGipQyXuIXQ9l1kpaHMpoEtHvQL7xxmkgZqCcSZgATnKl91nDg==", "dev": true, "license": "MIT", "dependencies": { "@ethersproject/abi": "^5.7.0", "@ethersproject/address": "5.7.0", - "@matterlabs/hardhat-zksync-solc": "^1.2.1", + "@matterlabs/hardhat-zksync-solc": "^1.2.5", "@nomicfoundation/hardhat-verify": "^2.0.8", "axios": "^1.7.2", "cbor": "^9.0.2", @@ -1478,9 +1486,9 @@ } }, "node_modules/@metamask/eth-sig-util/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", "dev": true, "license": "MIT" }, @@ -1580,28 +1588,28 @@ } }, "node_modules/@nomicfoundation/edr": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr/-/edr-0.5.2.tgz", - "integrity": "sha512-hW/iLvUQZNTVjFyX/I40rtKvvDOqUEyIi96T28YaLfmPL+3LW2lxmYLUXEJ6MI14HzqxDqrLyhf6IbjAa2r3Dw==", + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr/-/edr-0.6.5.tgz", + "integrity": "sha512-tAqMslLP+/2b2sZP4qe9AuGxG3OkQ5gGgHE4isUuq6dUVjwCRPFhAOhpdFl+OjY5P3yEv3hmq9HjUGRa2VNjng==", "dev": true, "license": "MIT", "dependencies": { - "@nomicfoundation/edr-darwin-arm64": "0.5.2", - "@nomicfoundation/edr-darwin-x64": "0.5.2", - "@nomicfoundation/edr-linux-arm64-gnu": "0.5.2", - "@nomicfoundation/edr-linux-arm64-musl": "0.5.2", - "@nomicfoundation/edr-linux-x64-gnu": "0.5.2", - "@nomicfoundation/edr-linux-x64-musl": "0.5.2", - "@nomicfoundation/edr-win32-x64-msvc": "0.5.2" + "@nomicfoundation/edr-darwin-arm64": "0.6.5", + "@nomicfoundation/edr-darwin-x64": "0.6.5", + "@nomicfoundation/edr-linux-arm64-gnu": "0.6.5", + "@nomicfoundation/edr-linux-arm64-musl": "0.6.5", + "@nomicfoundation/edr-linux-x64-gnu": "0.6.5", + "@nomicfoundation/edr-linux-x64-musl": "0.6.5", + "@nomicfoundation/edr-win32-x64-msvc": "0.6.5" }, "engines": { "node": ">= 18" } }, "node_modules/@nomicfoundation/edr-darwin-arm64": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.5.2.tgz", - "integrity": "sha512-Gm4wOPKhbDjGTIRyFA2QUAPfCXA1AHxYOKt3yLSGJkQkdy9a5WW+qtqKeEKHc/+4wpJSLtsGQfpzyIzggFfo/A==", + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.6.5.tgz", + "integrity": "sha512-A9zCCbbNxBpLgjS1kEJSpqxIvGGAX4cYbpDYCU2f3jVqOwaZ/NU761y1SvuCRVpOwhoCXqByN9b7HPpHi0L4hw==", "dev": true, "license": "MIT", "engines": { @@ -1609,9 +1617,9 @@ } }, "node_modules/@nomicfoundation/edr-darwin-x64": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.5.2.tgz", - "integrity": "sha512-ClyABq2dFCsrYEED3/UIO0c7p4H1/4vvlswFlqUyBpOkJccr75qIYvahOSJRM62WgUFRhbSS0OJXFRwc/PwmVg==", + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.6.5.tgz", + "integrity": "sha512-x3zBY/v3R0modR5CzlL6qMfFMdgwd6oHrWpTkuuXnPFOX8SU31qq87/230f4szM+ukGK8Hi+mNq7Ro2VF4Fj+w==", "dev": true, "license": "MIT", "engines": { @@ -1619,9 +1627,9 @@ } }, "node_modules/@nomicfoundation/edr-linux-arm64-gnu": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.5.2.tgz", - "integrity": "sha512-HWMTVk1iOabfvU2RvrKLDgtFjJZTC42CpHiw2h6rfpsgRqMahvIlx2jdjWYzFNy1jZKPTN1AStQ/91MRrg5KnA==", + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.6.5.tgz", + "integrity": "sha512-HGpB8f1h8ogqPHTyUpyPRKZxUk2lu061g97dOQ/W4CxevI0s/qiw5DB3U3smLvSnBHKOzYS1jkxlMeGN01ky7A==", "dev": true, "license": "MIT", "engines": { @@ -1629,9 +1637,9 @@ } }, "node_modules/@nomicfoundation/edr-linux-arm64-musl": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.5.2.tgz", - "integrity": "sha512-CwsQ10xFx/QAD5y3/g5alm9+jFVuhc7uYMhrZAu9UVF+KtVjeCvafj0PaVsZ8qyijjqVuVsJ8hD1x5ob7SMcGg==", + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.6.5.tgz", + "integrity": "sha512-ESvJM5Y9XC03fZg9KaQg3Hl+mbx7dsSkTIAndoJS7X2SyakpL9KZpOSYrDk135o8s9P9lYJdPOyiq+Sh+XoCbQ==", "dev": true, "license": "MIT", "engines": { @@ -1639,9 +1647,9 @@ } }, "node_modules/@nomicfoundation/edr-linux-x64-gnu": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.5.2.tgz", - "integrity": "sha512-CWVCEdhWJ3fmUpzWHCRnC0/VLBDbqtqTGTR6yyY1Ep3S3BOrHEAvt7h5gx85r2vLcztisu2vlDq51auie4IU1A==", + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.6.5.tgz", + "integrity": "sha512-HCM1usyAR1Ew6RYf5AkMYGvHBy64cPA5NMbaeY72r0mpKaH3txiMyydcHibByOGdQ8iFLWpyUdpl1egotw+Tgg==", "dev": true, "license": "MIT", "engines": { @@ -1649,9 +1657,9 @@ } }, "node_modules/@nomicfoundation/edr-linux-x64-musl": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.5.2.tgz", - "integrity": "sha512-+aJDfwhkddy2pP5u1ISg3IZVAm0dO836tRlDTFWtvvSMQ5hRGqPcWwlsbobhDQsIxhPJyT7phL0orCg5W3WMeA==", + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.6.5.tgz", + "integrity": "sha512-nB2uFRyczhAvWUH7NjCsIO6rHnQrof3xcCe6Mpmnzfl2PYcGyxN7iO4ZMmRcQS7R1Y670VH6+8ZBiRn8k43m7A==", "dev": true, "license": "MIT", "engines": { @@ -1659,9 +1667,9 @@ } }, "node_modules/@nomicfoundation/edr-win32-x64-msvc": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.5.2.tgz", - "integrity": "sha512-CcvvuA3sAv7liFNPsIR/68YlH6rrybKzYttLlMr80d4GKJjwJ5OKb3YgE6FdZZnOfP19HEHhsLcE0DPLtY3r0w==", + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.6.5.tgz", + "integrity": "sha512-B9QD/4DSSCFtWicO8A3BrsnitO1FPv7axB62wq5Q+qeJ50yJlTmyeGY3cw62gWItdvy2mh3fRM6L1LpnHiB77A==", "dev": true, "license": "MIT", "engines": { @@ -1738,9 +1746,9 @@ } }, "node_modules/@nomicfoundation/hardhat-chai-matchers": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-chai-matchers/-/hardhat-chai-matchers-2.0.7.tgz", - "integrity": "sha512-RQfsiTwdf0SP+DtuNYvm4921X6VirCQq0Xyh+mnuGlTwEFSPZ/o27oQC+l+3Y/l48DDU7+ZcYBR+Fp+Rp94LfQ==", + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-chai-matchers/-/hardhat-chai-matchers-2.0.8.tgz", + "integrity": "sha512-Z5PiCXH4xhNLASROlSUOADfhfpfhYO6D7Hn9xp8PddmHey0jq704cr6kfU8TRrQ4PUZbpfsZadPj+pCfZdjPIg==", "dev": true, "license": "MIT", "peer": true, @@ -1773,18 +1781,19 @@ } }, "node_modules/@nomicfoundation/hardhat-ignition": { - "version": "0.15.5", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ignition/-/hardhat-ignition-0.15.5.tgz", - "integrity": "sha512-Y5nhFXFqt4owA6Ooag8ZBFDF2RAZElMXViknVIsi3m45pbQimS50ti6FU8HxfRkDnBARa40CIn7UGV0hrelzDw==", + "version": "0.15.9", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ignition/-/hardhat-ignition-0.15.9.tgz", + "integrity": "sha512-lSWqhaDOBt6gsqMadkRLvH6HdoFV1v8/bx7z+12cghaOloVwwn48CPoTH2iXXnkqilPGw8rdH5eVTE6UM+2v6Q==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "@nomicfoundation/ignition-core": "^0.15.5", - "@nomicfoundation/ignition-ui": "^0.15.5", + "@nomicfoundation/ignition-core": "^0.15.9", + "@nomicfoundation/ignition-ui": "^0.15.9", "chalk": "^4.0.0", "debug": "^4.3.2", "fs-extra": "^10.0.0", + "json5": "^2.2.3", "prompts": "^2.4.2" }, "peerDependencies": { @@ -1793,16 +1802,16 @@ } }, "node_modules/@nomicfoundation/hardhat-ignition-ethers": { - "version": "0.15.5", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ignition-ethers/-/hardhat-ignition-ethers-0.15.5.tgz", - "integrity": "sha512-W6s1QN9CFxzSVZS6w9Jcj3WLaK32z2FP5MxNU2OKY1Fn9ZzLr+miXbUbWYuRHl6dxrrl6sE8cv33Cybv19pmCg==", + "version": "0.15.9", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ignition-ethers/-/hardhat-ignition-ethers-0.15.9.tgz", + "integrity": "sha512-9PwwgLv3z2ec3B26mK0IjiFezHFFBcBcs1qKaRu8SanARE4b7RvrfiLIy8ZXE7HaxgPt32kSsQzehhzAwAIj1Q==", "dev": true, "license": "MIT", "peer": true, "peerDependencies": { "@nomicfoundation/hardhat-ethers": "^3.0.4", - "@nomicfoundation/hardhat-ignition": "^0.15.5", - "@nomicfoundation/ignition-core": "^0.15.5", + "@nomicfoundation/hardhat-ignition": "^0.15.9", + "@nomicfoundation/ignition-core": "^0.15.9", "ethers": "^6.7.0", "hardhat": "^2.18.0" } @@ -1824,9 +1833,9 @@ } }, "node_modules/@nomicfoundation/hardhat-network-helpers": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-network-helpers/-/hardhat-network-helpers-1.0.11.tgz", - "integrity": "sha512-uGPL7QSKvxrHRU69dx8jzoBvuztlLCtyFsbgfXIwIjnO3dqZRz2GNMHJoO3C3dIiUNM6jdNF4AUnoQKDscdYrA==", + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-network-helpers/-/hardhat-network-helpers-1.0.12.tgz", + "integrity": "sha512-xTNQNI/9xkHvjmCJnJOTyqDSl8uq1rKb2WOVmixQxFtRd7Oa3ecO8zM0cyC2YmOK+jHB9WPZ+F/ijkHg1CoORA==", "dev": true, "license": "MIT", "peer": true, @@ -1865,18 +1874,18 @@ } }, "node_modules/@nomicfoundation/hardhat-verify": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-verify/-/hardhat-verify-2.0.10.tgz", - "integrity": "sha512-3zoTZGQhpeOm6piJDdsGb6euzZAd7N5Tk0zPQvGnfKQ0+AoxKz/7i4if12goi8IDTuUGElAUuZyQB8PMQoXA5g==", + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-verify/-/hardhat-verify-2.0.12.tgz", + "integrity": "sha512-Lg3Nu7DCXASQRVI/YysjuAX2z8jwOCbS0w5tz2HalWGSTZThqA0v9N0v0psHbKNqzPJa8bNOeapIVSziyJTnAg==", "dev": true, "license": "MIT", "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", + "picocolors": "^1.1.0", "semver": "^6.3.0", "table": "^6.8.0", "undici": "^5.14.0" @@ -1885,19 +1894,6 @@ "hardhat": "^2.0.4" } }, - "node_modules/@nomicfoundation/hardhat-verify/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@nomicfoundation/hardhat-verify/node_modules/cbor": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/cbor/-/cbor-8.1.0.tgz", @@ -1911,58 +1907,6 @@ "node": ">=12.19" } }, - "node_modules/@nomicfoundation/hardhat-verify/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@nomicfoundation/hardhat-verify/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@nomicfoundation/hardhat-verify/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@nomicfoundation/hardhat-verify/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@nomicfoundation/hardhat-verify/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/@nomicfoundation/hardhat-verify/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -1973,19 +1917,6 @@ "semver": "bin/semver.js" } }, - "node_modules/@nomicfoundation/hardhat-verify/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@nomicfoundation/hardhat-verify/node_modules/undici": { "version": "5.28.4", "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz", @@ -2000,9 +1931,9 @@ } }, "node_modules/@nomicfoundation/ignition-core": { - "version": "0.15.5", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ignition-core/-/ignition-core-0.15.5.tgz", - "integrity": "sha512-FgvuoIXhakRSP524JzNQ4BviyzBBKpsFaOWubPZ4XACLT4/7vGqlJ/7DIn0D2NL2anQ2qs98/BNBY9WccXUX1Q==", + "version": "0.15.9", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ignition-core/-/ignition-core-0.15.9.tgz", + "integrity": "sha512-X8W+7UP/UQPorpHUnGvA1OdsEr/edGi8tDpNwEqzaLm83FMZVbRWdOsr3vNICHN2XMzNY/xIm18Cx7xGKL2PQw==", "dev": true, "license": "MIT", "peer": true, @@ -2060,9 +1991,9 @@ } }, "node_modules/@nomicfoundation/ignition-ui": { - "version": "0.15.5", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ignition-ui/-/ignition-ui-0.15.5.tgz", - "integrity": "sha512-ZcE4rIn10qKahR4OqS8rl8NM2Fbg2QYiBXgMgj74ZI0++LlCcZgB5HyaBbX+lsnKHjTXtjYD3b+2mtg7jFbAMQ==", + "version": "0.15.9", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ignition-ui/-/ignition-ui-0.15.9.tgz", + "integrity": "sha512-8lzbT7gpJ5PoowPQDQilkwdyqBviUKDMoHp/5rhgnwG1bDslnCS+Lxuo6s9R2akWu9LtEL14dNyqQb6WsURTag==", "dev": true, "peer": true }, @@ -2473,24 +2404,98 @@ "node": ">=12" } }, - "node_modules/@safe-global/mock-contract": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@safe-global/mock-contract/-/mock-contract-4.1.0.tgz", - "integrity": "sha512-EGLpdNDdA1nx/DDjPmHSDZS2Zrlu3v4EsNw1zbM1Netk8Vf7oMwQetyqtfb8+ZYHhufkumVves3ED/jRlJPwLw==", + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", "dev": true, - "license": "MIT" + "license": "BSD-3-Clause" }, - "node_modules/@safe-global/safe-singleton-factory": { - "version": "1.0.33", - "resolved": "https://registry.npmjs.org/@safe-global/safe-singleton-factory/-/safe-singleton-factory-1.0.33.tgz", - "integrity": "sha512-rc5Ebqkq+mAER6hnLHZ90MhsQoYU8MMgpOuTfnY8HT3bkNfyLxB0ZeWM9dSu5e0IyS/Vi4z+cyZ49F0HzLep2g==", + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", "dev": true, - "license": "MIT" + "license": "BSD-3-Clause" }, - "node_modules/@scure/base": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", - "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@safe-global/mock-contract": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@safe-global/mock-contract/-/mock-contract-4.1.0.tgz", + "integrity": "sha512-EGLpdNDdA1nx/DDjPmHSDZS2Zrlu3v4EsNw1zbM1Netk8Vf7oMwQetyqtfb8+ZYHhufkumVves3ED/jRlJPwLw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@safe-global/safe-singleton-factory": { + "version": "1.0.37", + "resolved": "https://registry.npmjs.org/@safe-global/safe-singleton-factory/-/safe-singleton-factory-1.0.37.tgz", + "integrity": "sha512-aRlp3HrXmce2A/E8NN6YAcoLkVR3VxbnXqiM4IRQdh+0LXJqp5zZbLF/GIwHiXaSDgbNjxskU8i2LyPOc1FyiQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@scure/base": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", + "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", "dev": true, "license": "MIT", "funding": { @@ -2926,9 +2931,9 @@ } }, "node_modules/@types/chai": { - "version": "4.3.19", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.19.tgz", - "integrity": "sha512-2hHHvQBVE2FiSK4eN0Br6snX9MtolHaTo/batnLjlGRhoQzlCL61iVpxoqO7SfFyOw+P/pwv+0zNHzKoGWz9Cw==", + "version": "4.3.20", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.20.tgz", + "integrity": "sha512-/pC9HAB5I/xMlc5FP77qjCnI16ChlJfW0tGa0IUcFn38VJrTV6DeZ60NU5KZBtaOZqjdpwTWohz5HU1RrhiYxQ==", "dev": true, "license": "MIT" }, @@ -2954,6 +2959,13 @@ "@types/node": "*" } }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/form-data": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-0.0.33.tgz", @@ -2984,6 +2996,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/@types/lru-cache/-/lru-cache-5.1.1.tgz", @@ -3000,16 +3019,16 @@ "peer": true }, "node_modules/@types/mocha": { - "version": "10.0.8", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.8.tgz", - "integrity": "sha512-HfMcUmy9hTMJh66VNcmeC9iVErIZJli2bszuXc6julh5YGuRb/W5OnkHjwLNYdFlMis0sY3If5SEAp+PktdJjw==", + "version": "10.0.10", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.10.tgz", + "integrity": "sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q==", "dev": true, "license": "MIT" }, "node_modules/@types/node": { - "version": "20.16.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.5.tgz", - "integrity": "sha512-VwYCweNo3ERajwy0IUlqqcyZ8/A7Zwa9ZP3MnENWcB11AejO+tLy3pu850goUW2FC/IJMdZUfKpX/yxL1gymCA==", + "version": "20.17.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.12.tgz", + "integrity": "sha512-vo/wmBgMIiEA23A/knMfn/cf37VnuF52nZh5ZoW0GWt4e4sxNquibrMRJ7UQsA06+MBx9r/H1jsI9grYjQCQlw==", "dev": true, "license": "MIT", "dependencies": { @@ -3035,9 +3054,9 @@ "peer": true }, "node_modules/@types/qs": { - "version": "6.9.16", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.16.tgz", - "integrity": "sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A==", + "version": "6.9.17", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.17.tgz", + "integrity": "sha512-rX4/bPcfmvxHDv0XjfJELTTr+iB+tn032nPILqHm5wbthUUUuVtNGGqzhya9XUxjTP8Fpr0qYgSZZKxGY++svQ==", "dev": true, "license": "MIT" }, @@ -3069,21 +3088,21 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.6.0.tgz", - "integrity": "sha512-UOaz/wFowmoh2G6Mr9gw60B1mm0MzUtm6Ic8G2yM1Le6gyj5Loi/N+O5mocugRGY+8OeeKmkMmbxNqUCq3B4Sg==", + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.19.1.tgz", + "integrity": "sha512-tJzcVyvvb9h/PB96g30MpxACd9IrunT7GF9wfA9/0TJ1LxGOJx1TdPzSbBBnNED7K9Ka8ybJsnEpiXPktolTLg==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.6.0", - "@typescript-eslint/type-utils": "8.6.0", - "@typescript-eslint/utils": "8.6.0", - "@typescript-eslint/visitor-keys": "8.6.0", + "@typescript-eslint/scope-manager": "8.19.1", + "@typescript-eslint/type-utils": "8.19.1", + "@typescript-eslint/utils": "8.19.1", + "@typescript-eslint/visitor-keys": "8.19.1", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", - "ts-api-utils": "^1.3.0" + "ts-api-utils": "^2.0.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3094,25 +3113,21 @@ }, "peerDependencies": { "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.6.0.tgz", - "integrity": "sha512-eQcbCuA2Vmw45iGfcyG4y6rS7BhWfz9MQuk409WD47qMM+bKCGQWXxvoOs1DUp+T7UBMTtRTVT+kXr7Sh4O9Ow==", + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.19.1.tgz", + "integrity": "sha512-67gbfv8rAwawjYx3fYArwldTQKoYfezNUT4D5ioWetr/xCrxXxvleo3uuiFuKfejipvq+og7mjz3b0G2bVyUCw==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.6.0", - "@typescript-eslint/types": "8.6.0", - "@typescript-eslint/typescript-estree": "8.6.0", - "@typescript-eslint/visitor-keys": "8.6.0", + "@typescript-eslint/scope-manager": "8.19.1", + "@typescript-eslint/types": "8.19.1", + "@typescript-eslint/typescript-estree": "8.19.1", + "@typescript-eslint/visitor-keys": "8.19.1", "debug": "^4.3.4" }, "engines": { @@ -3123,23 +3138,19 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.6.0.tgz", - "integrity": "sha512-ZuoutoS5y9UOxKvpc/GkvF4cuEmpokda4wRg64JEia27wX+PysIE9q+lzDtlHHgblwUWwo5/Qn+/WyTUvDwBHw==", + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.19.1.tgz", + "integrity": "sha512-60L9KIuN/xgmsINzonOcMDSB8p82h95hoBfSBtXuO4jlR1R9L1xSkmVZKgCPVfavDlXihh4ARNjXhh1gGnLC7Q==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.6.0", - "@typescript-eslint/visitor-keys": "8.6.0" + "@typescript-eslint/types": "8.19.1", + "@typescript-eslint/visitor-keys": "8.19.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3150,16 +3161,16 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.6.0.tgz", - "integrity": "sha512-dtePl4gsuenXVwC7dVNlb4mGDcKjDT/Ropsk4za/ouMBPplCLyznIaR+W65mvCvsyS97dymoBRrioEXI7k0XIg==", + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.19.1.tgz", + "integrity": "sha512-Rp7k9lhDKBMRJB/nM9Ksp1zs4796wVNyihG9/TU9R6KCJDNkQbc2EOKjrBtLYh3396ZdpXLtr/MkaSEmNMtykw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.6.0", - "@typescript-eslint/utils": "8.6.0", + "@typescript-eslint/typescript-estree": "8.19.1", + "@typescript-eslint/utils": "8.19.1", "debug": "^4.3.4", - "ts-api-utils": "^1.3.0" + "ts-api-utils": "^2.0.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3168,16 +3179,15 @@ "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, "node_modules/@typescript-eslint/types": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.6.0.tgz", - "integrity": "sha512-rojqFZGd4MQxw33SrOy09qIDS8WEldM8JWtKQLAjf/X5mGSeEFh5ixQlxssMNyPslVIk9yzWqXCsV2eFhYrYUw==", + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.19.1.tgz", + "integrity": "sha512-JBVHMLj7B1K1v1051ZaMMgLW4Q/jre5qGK0Ew6UgXz1Rqh+/xPzV1aW581OM00X6iOfyr1be+QyW8LOUf19BbA==", "dev": true, "license": "MIT", "engines": { @@ -3189,20 +3199,20 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.6.0.tgz", - "integrity": "sha512-MOVAzsKJIPIlLK239l5s06YXjNqpKTVhBVDnqUumQJja5+Y94V3+4VUFRA0G60y2jNnTVwRCkhyGQpavfsbq/g==", + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.19.1.tgz", + "integrity": "sha512-jk/TZwSMJlxlNnqhy0Eod1PNEvCkpY6MXOXE/WLlblZ6ibb32i2We4uByoKPv1d0OD2xebDv4hbs3fm11SMw8Q==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.6.0", - "@typescript-eslint/visitor-keys": "8.6.0", + "@typescript-eslint/types": "8.19.1", + "@typescript-eslint/visitor-keys": "8.19.1", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" + "ts-api-utils": "^2.0.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3211,23 +3221,21 @@ "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "peerDependencies": { + "typescript": ">=4.8.4 <5.8.0" } }, "node_modules/@typescript-eslint/utils": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.6.0.tgz", - "integrity": "sha512-eNp9cWnYf36NaOVjkEUznf6fEgVy1TWpE0o52e4wtojjBx7D1UV2WAWGzR+8Y5lVFtpMLPwNbC67T83DWSph4A==", + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.19.1.tgz", + "integrity": "sha512-IxG5gLO0Ne+KaUc8iW1A+XuKLd63o4wlbI1Zp692n1xojCl/THvgIKXJXBZixTh5dd5+yTJ/VXH7GJaaw21qXA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.6.0", - "@typescript-eslint/types": "8.6.0", - "@typescript-eslint/typescript-estree": "8.6.0" + "@typescript-eslint/scope-manager": "8.19.1", + "@typescript-eslint/types": "8.19.1", + "@typescript-eslint/typescript-estree": "8.19.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3237,18 +3245,19 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.6.0.tgz", - "integrity": "sha512-wapVFfZg9H0qOYh4grNVQiMklJGluQrOUiOhYRrQWhx7BY/+I1IYb8BczWNbbUpO+pqy0rDciv3lQH5E1bCLrg==", + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.19.1.tgz", + "integrity": "sha512-fzmjU8CHK853V/avYZAvuVut3ZTfwN5YtMaoi+X9Y9MA9keaWNHC3zEQ9zvyX/7Hj+5JkNyK1l7TOR2hevHB6Q==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.6.0", - "eslint-visitor-keys": "^3.4.3" + "@typescript-eslint/types": "8.19.1", + "eslint-visitor-keys": "^4.2.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3258,6 +3267,19 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/abbrev": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", @@ -3267,9 +3289,9 @@ "peer": true }, "node_modules/acorn": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", - "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", "dev": true, "license": "MIT", "bin": { @@ -3589,9 +3611,9 @@ } }, "node_modules/axios": { - "version": "1.7.7", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", - "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", + "version": "1.7.9", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", + "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", "dev": true, "license": "MIT", "dependencies": { @@ -3924,18 +3946,29 @@ "node": ">=14.16" } }, - "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "node_modules/call-bind-apply-helpers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz", + "integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==", "dev": true, "license": "MIT", "dependencies": { - "es-define-property": "^1.0.0", "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz", + "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "get-intrinsic": "^1.2.6" }, "engines": { "node": ">= 0.4" @@ -4063,41 +4096,19 @@ } }, "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", "dev": true, "license": "MIT", "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" + "readdirp": "^4.0.1" }, "engines": { - "node": ">= 8.10.0" + "node": ">= 14.16.0" }, "funding": { "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" } }, "node_modules/chownr": { @@ -4115,14 +4126,17 @@ "license": "MIT" }, "node_modules/cipher-base": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.6.tgz", + "integrity": "sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw==", "dev": true, "license": "MIT", "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" } }, "node_modules/clean-stack": { @@ -4233,9 +4247,9 @@ } }, "node_modules/code-block-writer": { - "version": "13.0.2", - "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-13.0.2.tgz", - "integrity": "sha512-XfXzAGiStXSmCIwrkdfvc7FS5Dtj8yelCtyOf2p2skCAfvLd6zu0rGzuS9NSCO3bq1JKpFZ7tbKdKlcd5occQA==", + "version": "13.0.3", + "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-13.0.3.tgz", + "integrity": "sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==", "dev": true, "license": "MIT" }, @@ -4608,9 +4622,9 @@ "license": "MIT" }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "license": "MIT", "dependencies": { @@ -4641,9 +4655,9 @@ "peer": true }, "node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "dev": true, "license": "MIT", "dependencies": { @@ -4740,24 +4754,6 @@ "node": ">=10" } }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -4816,9 +4812,9 @@ } }, "node_modules/docker-modem": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/docker-modem/-/docker-modem-5.0.3.tgz", - "integrity": "sha512-89zhop5YVhcPEt5FpUFGr3cDyceGhq/F9J+ZndQ4KfqNvfbJpPMfgeixFgUj5OjCYAboElqODxY5Z1EBsSa6sg==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/docker-modem/-/docker-modem-5.0.5.tgz", + "integrity": "sha512-Cxw8uEcvNTRmsQuGqzzfiCnfGgf96tVJItLh8taOX0miTcIBALKH5TckCSuZbpbjP7uhAl81dOL9sxfa6HgCIg==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -4832,24 +4828,28 @@ } }, "node_modules/dockerode": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/dockerode/-/dockerode-4.0.2.tgz", - "integrity": "sha512-9wM1BVpVMFr2Pw3eJNXrYYt6DT9k0xMcsSCjtPvyQ+xa1iPg/Mo3T/gUcwI0B2cczqCeCYRPF8yFYDwtFXT0+w==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/dockerode/-/dockerode-4.0.3.tgz", + "integrity": "sha512-QSXJFcBQNaGZO6U3qWW4B7p8yRIJn/dWmvL2AQWfO/bjptBBO6QYdVkYSYFz9qoivP2jsOHZfmXMAfrK0BMKyg==", "dev": true, "license": "Apache-2.0", "dependencies": { "@balena/dockerignore": "^1.0.2", - "docker-modem": "^5.0.3", - "tar-fs": "~2.0.1" + "@grpc/grpc-js": "^1.11.1", + "@grpc/proto-loader": "^0.7.13", + "docker-modem": "^5.0.5", + "protobufjs": "^7.3.2", + "tar-fs": "~2.0.1", + "uuid": "^10.0.0" }, "engines": { "node": ">= 8.0" } }, "node_modules/dotenv": { - "version": "16.4.5", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", - "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "version": "16.4.7", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", + "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -4859,6 +4859,21 @@ "url": "https://dotenvx.com" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -4883,9 +4898,9 @@ } }, "node_modules/elliptic/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", "dev": true, "license": "MIT" }, @@ -4948,14 +4963,11 @@ } }, "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "dev": true, "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.2.4" - }, "engines": { "node": ">= 0.4" } @@ -4970,6 +4982,19 @@ "node": ">= 0.4" } }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -5086,29 +5111,32 @@ } }, "node_modules/eslint": { - "version": "9.10.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.10.0.tgz", - "integrity": "sha512-Y4D0IgtBZfOcOUAIQTSXBKoNGfY0REGqHJG6+Q81vNippW5YlKjHFj4soMxamKK1NXHUWuBZTLdU3Km+L/pcHw==", + "version": "9.17.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.17.0.tgz", + "integrity": "sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.11.0", - "@eslint/config-array": "^0.18.0", - "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.10.0", - "@eslint/plugin-kit": "^0.1.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.19.0", + "@eslint/core": "^0.9.0", + "@eslint/eslintrc": "^3.2.0", + "@eslint/js": "9.17.0", + "@eslint/plugin-kit": "^0.2.3", + "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.3.0", - "@nodelib/fs.walk": "^1.2.8", + "@humanwhocodes/retry": "^0.4.1", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", + "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.0.2", - "eslint-visitor-keys": "^4.0.0", - "espree": "^10.1.0", + "eslint-scope": "^8.2.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -5118,14 +5146,11 @@ "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", "json-stable-stringify-without-jsonify": "^1.0.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" + "optionator": "^0.9.3" }, "bin": { "eslint": "bin/eslint.js" @@ -5200,9 +5225,9 @@ } }, "node_modules/eslint-scope": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.2.tgz", - "integrity": "sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", + "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -5241,9 +5266,9 @@ } }, "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", - "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", "dev": true, "license": "Apache-2.0", "engines": { @@ -5267,15 +5292,15 @@ } }, "node_modules/espree": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", - "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.12.0", + "acorn": "^8.14.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.0.0" + "eslint-visitor-keys": "^4.2.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -5285,9 +5310,9 @@ } }, "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", - "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", "dev": true, "license": "Apache-2.0", "engines": { @@ -5516,9 +5541,9 @@ } }, "node_modules/ethereum-bloom-filters/node_modules/@noble/hashes": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.5.0.tgz", - "integrity": "sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.0.tgz", + "integrity": "sha512-HXydb0DgzTpDPwbVeDGCG1gIu7X6+AuU6Zl6av/E/KG8LMsvPntvq+w17CHRpKBmN6Ybdrt1eP3k4cj8DJa78w==", "dev": true, "license": "MIT", "peer": true, @@ -5557,6 +5582,7 @@ "version": "0.6.8", "resolved": "https://registry.npmjs.org/ethereumjs-abi/-/ethereumjs-abi-0.6.8.tgz", "integrity": "sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA==", + "deprecated": "This library has been deprecated and usage is discouraged.", "dev": true, "license": "MIT", "dependencies": { @@ -5575,9 +5601,9 @@ } }, "node_modules/ethereumjs-abi/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", "dev": true, "license": "MIT" }, @@ -5616,9 +5642,9 @@ } }, "node_modules/ethers": { - "version": "6.13.2", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.13.2.tgz", - "integrity": "sha512-9VkriTTed+/27BGuY1s0hf441kqwHJ1wtN2edksEtiRvXx+soxRX3iSXTfFqq2+YwrOqbDoTHjIhQnjJRlzKmg==", + "version": "6.13.5", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.13.5.tgz", + "integrity": "sha512-+knKNieu5EKRThQJWwqaJ10a6HE9sSehGeqWN65//wE7j47ZpFhKAnHB/JJFibwwg61I/koxaPsXbXpD/skNOQ==", "dev": true, "funding": [ { @@ -5636,9 +5662,9 @@ "@adraffy/ens-normalize": "1.10.1", "@noble/curves": "1.2.0", "@noble/hashes": "1.3.2", - "@types/node": "18.15.13", + "@types/node": "22.7.5", "aes-js": "4.0.0-beta.5", - "tslib": "2.4.0", + "tslib": "2.7.0", "ws": "8.17.1" }, "engines": { @@ -5646,12 +5672,15 @@ } }, "node_modules/ethers/node_modules/@types/node": { - "version": "18.15.13", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.13.tgz", - "integrity": "sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q==", + "version": "22.7.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz", + "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==", "dev": true, "license": "MIT", - "peer": true + "peer": true, + "dependencies": { + "undici-types": "~6.19.2" + } }, "node_modules/ethjs-unit": { "version": "0.1.6", @@ -5718,9 +5747,9 @@ "license": "Apache-2.0" }, "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "dev": true, "license": "MIT", "dependencies": { @@ -5728,7 +5757,7 @@ "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "micromatch": "^4.0.8" }, "engines": { "node": ">=8.6.0" @@ -5762,16 +5791,26 @@ "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", - "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.5.tgz", + "integrity": "sha512-5JnBCWpFlMo0a3ciDy/JckMzzv1U9coZrIhedq+HXxxUfDTAiS0LA8OKVao4G9BxmCVck/jtA5r3KAtRWEyD8Q==", "dev": true, - "license": "MIT" + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" }, "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.18.0.tgz", + "integrity": "sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==", "dev": true, "license": "ISC", "dependencies": { @@ -5874,9 +5913,9 @@ } }, "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", + "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", "dev": true, "license": "ISC" }, @@ -5929,9 +5968,9 @@ } }, "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", "dev": true, "license": "MIT", "dependencies": { @@ -6043,17 +6082,22 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.7.tgz", + "integrity": "sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==", "dev": true, "license": "MIT", "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "get-proto": "^1.0.0", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -6073,6 +6117,20 @@ "node": ">=4" } }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/get-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", @@ -6348,13 +6406,13 @@ } }, "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "dev": true, "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.1.3" + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -6435,15 +6493,15 @@ } }, "node_modules/hardhat": { - "version": "2.22.10", - "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.22.10.tgz", - "integrity": "sha512-JRUDdiystjniAvBGFmJRsiIZSOP2/6s++8xRDe3TzLeQXlWWHsXBrd9wd3JWFyKXvgMqMeLL5Sz/oNxXKYw9vg==", + "version": "2.22.17", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.22.17.tgz", + "integrity": "sha512-tDlI475ccz4d/dajnADUTRc1OJ3H8fpP9sWhXhBPpYsQOg8JHq5xrDimo53UhWPl7KJmAeDCm1bFG74xvpGRpg==", "dev": true, "license": "MIT", "dependencies": { "@ethersproject/abi": "^5.1.2", "@metamask/eth-sig-util": "^4.0.0", - "@nomicfoundation/edr": "^0.5.2", + "@nomicfoundation/edr": "^0.6.5", "@nomicfoundation/ethereumjs-common": "4.0.4", "@nomicfoundation/ethereumjs-tx": "5.0.4", "@nomicfoundation/ethereumjs-util": "9.0.4", @@ -6455,31 +6513,32 @@ "aggregate-error": "^3.0.0", "ansi-escapes": "^4.3.0", "boxen": "^5.1.2", - "chalk": "^2.4.2", - "chokidar": "^3.4.0", + "chokidar": "^4.0.0", "ci-info": "^2.0.0", "debug": "^4.1.1", "enquirer": "^2.3.0", "env-paths": "^2.2.0", "ethereum-cryptography": "^1.0.3", "ethereumjs-abi": "^0.6.8", - "find-up": "^2.1.0", + "find-up": "^5.0.0", "fp-ts": "1.19.3", "fs-extra": "^7.0.1", - "glob": "7.2.0", "immutable": "^4.0.0-rc.12", "io-ts": "1.10.4", + "json-stream-stringify": "^3.1.4", "keccak": "^3.0.2", "lodash": "^4.17.11", "mnemonist": "^0.38.0", "mocha": "^10.0.0", "p-map": "^4.0.0", + "picocolors": "^1.1.0", "raw-body": "^2.4.1", "resolve": "1.17.0", "semver": "^6.3.0", "solc": "0.8.26", "source-map-support": "^0.5.13", "stacktrace-parser": "^0.1.10", + "tinyglobby": "^0.2.6", "tsort": "0.0.1", "undici": "^5.14.0", "uuid": "^8.3.2", @@ -6544,6 +6603,31 @@ "follow-redirects": "^1.14.0" } }, + "node_modules/hardhat-deploy/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, "node_modules/hardhat-deploy/node_modules/ethers": { "version": "5.7.2", "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz", @@ -6608,10 +6692,36 @@ "node": ">=12" } }, + "node_modules/hardhat-deploy/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/hardhat-deploy/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, "node_modules/hardhat-deploy/node_modules/zksync-ethers": { - "version": "5.9.2", - "resolved": "https://registry.npmjs.org/zksync-ethers/-/zksync-ethers-5.9.2.tgz", - "integrity": "sha512-Y2Mx6ovvxO6UdC2dePLguVzvNToOY8iLWeq5ne+jgGSJxAi/f4He/NF6FNsf6x1aWX0o8dy4Df8RcOQXAkj5qw==", + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/zksync-ethers/-/zksync-ethers-5.10.0.tgz", + "integrity": "sha512-OAjTGAHF9wbdkRGkj7XZuF/a1Sk/FVbwH4pmLjAKlR7mJ7sQtQhBhrPU2dCc67xLaNvEESPfwil19ES5wooYFg==", "dev": true, "license": "MIT", "dependencies": { @@ -6688,62 +6798,6 @@ "@scure/base": "~1.1.0" } }, - "node_modules/hardhat/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/hardhat/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/hardhat/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/hardhat/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/hardhat/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true, - "license": "MIT" - }, "node_modules/hardhat/node_modules/commander": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", @@ -6754,16 +6808,6 @@ "node": ">= 12" } }, - "node_modules/hardhat/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/hardhat/node_modules/ethereum-cryptography": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz", @@ -6777,19 +6821,6 @@ "@scure/bip39": "1.1.1" } }, - "node_modules/hardhat/node_modules/find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/hardhat/node_modules/fs-extra": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", @@ -6805,38 +6836,6 @@ "node": ">=6 <7 || >=8" } }, - "node_modules/hardhat/node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/hardhat/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/hardhat/node_modules/jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", @@ -6847,69 +6846,6 @@ "graceful-fs": "^4.1.6" } }, - "node_modules/hardhat/node_modules/locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/hardhat/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/hardhat/node_modules/p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-try": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/hardhat/node_modules/p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/hardhat/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/hardhat/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -6952,19 +6888,6 @@ "semver": "bin/semver" } }, - "node_modules/hardhat/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/hardhat/node_modules/undici": { "version": "5.28.4", "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz", @@ -6988,6 +6911,16 @@ "node": ">= 4.0.0" } }, + "node_modules/hardhat/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/hardhat/node_modules/ws": { "version": "7.5.10", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", @@ -7014,42 +6947,16 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" } }, "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "dev": true, "license": "MIT", "engines": { @@ -7217,9 +7124,9 @@ } }, "node_modules/husky": { - "version": "9.1.6", - "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.6.tgz", - "integrity": "sha512-sqbjZKK7kf44hfdE94EoX8MZNk0n7HeW37O4YrVGCF4wzgQjp+akPAkfUK5LZ6KuR/6sqeAVuXHji+RzQgOn5A==", + "version": "9.1.7", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", + "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", "dev": true, "license": "MIT", "bin": { @@ -7473,16 +7380,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/is-plain-obj": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", @@ -7591,6 +7488,16 @@ "dev": true, "license": "MIT" }, + "node_modules/json-stream-stringify": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/json-stream-stringify/-/json-stream-stringify-3.1.6.tgz", + "integrity": "sha512-x7fpwxOkbhFCaJDJ8vb1fBY3DdSa4AlITaz+HHILQJzdPMnHEFjxPwVUi1ALIbcIxDE0PNe/0i7frnY8QnBQog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=7.10.1" + } + }, "node_modules/json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -7599,6 +7506,20 @@ "license": "ISC", "peer": true }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", @@ -7623,9 +7544,9 @@ "license": "MIT" }, "node_modules/jsonschema": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.1.tgz", - "integrity": "sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.5.0.tgz", + "integrity": "sha512-K+A9hhqbn0f3pJX17Q/7H6yQfD/5OXgdrR5UE12gMXCiN9D5Xq2o5mddV2QEcX/bjla99ASsAAQUyMCCRWAEhw==", "dev": true, "license": "MIT", "peer": true, @@ -7780,8 +7701,7 @@ "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/lodash.clonedeep": { "version": "4.5.0", @@ -7835,6 +7755,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/long": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.4.tgz", + "integrity": "sha512-qtzLbJE8hq7VabR3mISmVGtoXP8KGc2Z/AT8OuqlYD7JTR3oqrgwdjnk07wpj1twXxYmgDXgoKVWUG/fReSzHg==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/loupe": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", @@ -7894,6 +7821,16 @@ "dev": true, "license": "MIT" }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", @@ -8074,9 +8011,9 @@ } }, "node_modules/mocha": { - "version": "10.7.3", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.7.3.tgz", - "integrity": "sha512-uQWxAu44wwiACGqjbPYmjo7Lg8sFrS3dQe7PP2FQI+woptP4vZXSMcfMyFL/e1yFEeEpV4RtyTpZROOKmxis+A==", + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.8.2.tgz", + "integrity": "sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg==", "dev": true, "license": "MIT", "dependencies": { @@ -8109,6 +8046,31 @@ "node": ">= 14.0.0" } }, + "node_modules/mocha/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, "node_modules/mocha/node_modules/cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -8142,6 +8104,19 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/mocha/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/mocha/node_modules/minimatch": { "version": "5.1.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", @@ -8155,6 +8130,19 @@ "node": ">=10" } }, + "node_modules/mocha/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, "node_modules/mocha/node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", @@ -8217,9 +8205,9 @@ } }, "node_modules/nan": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.20.0.tgz", - "integrity": "sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw==", + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.22.0.tgz", + "integrity": "sha512-nbajikzWTMwsW+eSsNm3QwlOs7het9gGJU5dDZzRTQGk03vyBOauxgI4VakDzE0PtsGTmXPsXTbbjVhRwR5mpw==", "dev": true, "license": "MIT", "optional": true @@ -8275,9 +8263,9 @@ } }, "node_modules/nise/node_modules/@sinonjs/fake-timers": { - "version": "13.0.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.2.tgz", - "integrity": "sha512-4Bb+oqXZTSTZ1q27Izly9lv8B9dlV61CROxPiVtywwzv5SnytJqhvYe6FclHYuXml4cd1VHPo1zd5PmTeJozvA==", + "version": "13.0.5", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz", + "integrity": "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -8324,9 +8312,9 @@ } }, "node_modules/node-gyp-build": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.2.tgz", - "integrity": "sha512-IRUxE4BVsHWXkV/SFOut4qTlagw2aM8T5/vnTsmrHJvVoKueJHRc/JaFND7QDDc61kLYUJ6qlZM3sqTSyx2dTw==", + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", "dev": true, "license": "MIT", "bin": { @@ -8418,9 +8406,9 @@ } }, "node_modules/object-inspect": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", - "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", + "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", "dev": true, "license": "MIT", "engines": { @@ -8431,9 +8419,9 @@ } }, "node_modules/obliterator": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.4.tgz", - "integrity": "sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.5.tgz", + "integrity": "sha512-42CPE9AhahZRsMNslczq0ctAEtqk8Eka26QofnqC346BZdHDySk3LWka23LI7ULIw11NmltpiLagIq8gBozxTw==", "dev": true, "license": "MIT" }, @@ -8541,16 +8529,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/package-json": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/package-json/-/package-json-8.1.1.tgz", @@ -8571,9 +8549,9 @@ } }, "node_modules/package-json-from-dist": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", - "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", "dev": true, "license": "BlueOak-1.0.0" }, @@ -8678,9 +8656,9 @@ } }, "node_modules/path-to-regexp": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.1.0.tgz", - "integrity": "sha512-Bqn3vc8CMHty6zuD+tG23s6v2kwxslHEhTj4eYaVKGIEB+YX/2wd0/rgXLFD9G9id9KCtbVy/3ZgmvZjpa0UdQ==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", + "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==", "dev": true, "license": "MIT", "engines": { @@ -8725,9 +8703,9 @@ } }, "node_modules/picocolors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", - "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "dev": true, "license": "ISC" }, @@ -8776,9 +8754,9 @@ } }, "node_modules/prettier": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", - "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz", + "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==", "dev": true, "license": "MIT", "bin": { @@ -8805,26 +8783,26 @@ } }, "node_modules/prettier-plugin-solidity": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.4.1.tgz", - "integrity": "sha512-Mq8EtfacVZ/0+uDKTtHZGW3Aa7vEbX/BNx63hmVg6YTiTXSiuKP0amj0G6pGwjmLaOfymWh3QgXEZkjQbU8QRg==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.4.2.tgz", + "integrity": "sha512-VVD/4XlDjSzyPWWCPW8JEleFa8JNKFYac5kNlMjVXemQyQZKfpekPMhFZSePuXB6L+RixlFvWe20iacGjFYrLw==", "dev": true, "license": "MIT", "dependencies": { - "@solidity-parser/parser": "^0.18.0", - "semver": "^7.5.4" + "@solidity-parser/parser": "^0.19.0", + "semver": "^7.6.3" }, "engines": { - "node": ">=16" + "node": ">=18" }, "peerDependencies": { "prettier": ">=2.3.0" } }, "node_modules/prettier-plugin-solidity/node_modules/@solidity-parser/parser": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.18.0.tgz", - "integrity": "sha512-yfORGUIPgLck41qyN7nbwJRAx17/jAIXCTanHOJZhB6PJ1iAk/84b/xlsVKFSyNyLXIj0dhppoE0+CRws7wlzA==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.19.0.tgz", + "integrity": "sha512-RV16k/qIxW/wWc+mLzV3ARyKUaMUTBy9tOLMzFhtNSKYeTAanQ3a5MudJKf/8arIFnA2L27SNjarQKmFg0w/jA==", "dev": true, "license": "MIT" }, @@ -8887,6 +8865,31 @@ "dev": true, "license": "ISC" }, + "node_modules/protobufjs": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.4.0.tgz", + "integrity": "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==", + "dev": true, + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", @@ -8928,9 +8931,9 @@ } }, "node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "version": "6.13.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.1.tgz", + "integrity": "sha512-EJPeIn0CYrGu+hli1xilKAPXODtJ12T0sP63Ijx2/khC2JtuaN3JyNIpvmnkmaEtha9ocbG4A4cMcr+TvqvwQg==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -9045,16 +9048,17 @@ } }, "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz", + "integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==", "dev": true, "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, "engines": { - "node": ">=8.10.0" + "node": ">= 14.16.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, "node_modules/rechoir": { @@ -9122,9 +9126,9 @@ } }, "node_modules/registry-auth-token": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.2.tgz", - "integrity": "sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==", + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.3.tgz", + "integrity": "sha512-1bpc9IyC+e+CNFRaWyn77tk4xGG4PPUyfakSmA6F6cvUDjrm58dfyJ3II+9yb10EDkHoy1LaPSmHaWLOH3m6HA==", "dev": true, "license": "MIT", "dependencies": { @@ -9297,9 +9301,9 @@ } }, "node_modules/rimraf/node_modules/glob": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.0.tgz", - "integrity": "sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==", + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.1.tgz", + "integrity": "sha512-zrQDm8XPnYEKawJScsnM0QzobJxlT/kHOOlRTio8IH/GrmxRE5fjllkzdaHclIuNjUQTJYH2xHNIGfdpJkDJUw==", "dev": true, "license": "ISC", "dependencies": { @@ -9321,9 +9325,9 @@ } }, "node_modules/rimraf/node_modules/jackspeak": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.0.1.tgz", - "integrity": "sha512-cub8rahkh0Q/bw1+GxP7aeSe29hHHn2V4m29nnDlvCdlgU+3UGxkZp7Z53jLUdpX3jdTO0nJZUDl3xvbWc2Xog==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.0.2.tgz", + "integrity": "sha512-bZsjR/iRjl1Nk1UkjGpAzLNfQtzuijhn2g+pbZb98HQ1Gk8vM9hfbxeMBP+M2/UUdwj0RqGG3mlvk2MsAqwvEw==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -9334,15 +9338,12 @@ }, "funding": { "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" } }, "node_modules/rimraf/node_modules/lru-cache": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.1.tgz", - "integrity": "sha512-CgeuL5uom6j/ZVrg7G/+1IXqRY8JXX4Hghfy5YE0EhoYQWvndP1kufu58cmZLNIDKnRhZrXfdS9urVWx98AipQ==", + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.2.tgz", + "integrity": "sha512-123qHRfJBmo2jXDbo/a5YOQrJoHF/GNQTLzQ5+IdK5pWpceK17yRc6ozlWd25FxvGKQbIUs91fDFkXmDHTKcyA==", "dev": true, "license": "ISC", "engines": { @@ -9631,6 +9632,7 @@ "integrity": "sha512-6JfvwvjUOn8F/jUoBY2Q1v5WY5XS+rj8qSe0v8Y4ezH4InLgTEeOOPQsRll9OV429Pvo6BCHGavIyJfr3TAhsw==", "dev": true, "hasInstallScript": true, + "license": "MIT", "dependencies": { "elliptic": "^6.5.7", "node-addon-api": "^5.0.0", @@ -9641,16 +9643,18 @@ } }, "node_modules/secp256k1/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", + "dev": true, + "license": "MIT" }, "node_modules/secp256k1/node_modules/elliptic": { - "version": "6.5.7", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.7.tgz", - "integrity": "sha512-ESVCtTwiA+XhY3wyh24QqRGBoP3rEdDUl3EDUUo9tft074fi19IrdpH7hLCMMP3CIj7jb3W96rn8lt/BqIlt5Q==", + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", + "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", "dev": true, + "license": "MIT", "dependencies": { "bn.js": "^4.11.9", "brorand": "^1.1.0", @@ -9665,7 +9669,8 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/semver": { "version": "7.6.3", @@ -9690,24 +9695,6 @@ "randombytes": "^2.1.0" } }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", @@ -9843,16 +9830,73 @@ } }, "node_modules/side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bound": "^1.0.2", "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -10060,13 +10104,13 @@ } }, "node_modules/solhint": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/solhint/-/solhint-5.0.3.tgz", - "integrity": "sha512-OLCH6qm/mZTCpplTXzXTJGId1zrtNuDYP5c2e6snIv/hdRVxPfBBz/bAlL91bY/Accavkayp2Zp2BaDSrLVXTQ==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/solhint/-/solhint-5.0.4.tgz", + "integrity": "sha512-GzKBjJ8S2utRsEOCJXhY2H35gwHGmoQY2rQXcPGT4XdDlzwgGYz0Ovo9Xm7cmWYgSo121uF+5tiwrqQT2b+Rtw==", "dev": true, "license": "MIT", "dependencies": { - "@solidity-parser/parser": "^0.18.0", + "@solidity-parser/parser": "^0.19.0", "ajv": "^6.12.6", "antlr4": "^4.13.1-patch-1", "ast-parents": "^0.0.1", @@ -10093,9 +10137,9 @@ } }, "node_modules/solhint/node_modules/@solidity-parser/parser": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.18.0.tgz", - "integrity": "sha512-yfORGUIPgLck41qyN7nbwJRAx17/jAIXCTanHOJZhB6PJ1iAk/84b/xlsVKFSyNyLXIj0dhppoE0+CRws7wlzA==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.19.0.tgz", + "integrity": "sha512-RV16k/qIxW/wWc+mLzV3ARyKUaMUTBy9tOLMzFhtNSKYeTAanQ3a5MudJKf/8arIFnA2L27SNjarQKmFg0w/jA==", "dev": true, "license": "MIT" }, @@ -10161,15 +10205,15 @@ } }, "node_modules/solidity-coverage": { - "version": "0.8.13", - "resolved": "https://registry.npmjs.org/solidity-coverage/-/solidity-coverage-0.8.13.tgz", - "integrity": "sha512-RiBoI+kF94V3Rv0+iwOj3HQVSqNzA9qm/qDP1ZDXK5IX0Cvho1qiz8hAXTsAo6KOIUeP73jfscq0KlLqVxzGWA==", + "version": "0.8.14", + "resolved": "https://registry.npmjs.org/solidity-coverage/-/solidity-coverage-0.8.14.tgz", + "integrity": "sha512-ItAAObe5GaEOp20kXC2BZRnph+9P7Rtoqg2mQc2SXGEHgSDF2wWd1Wxz3ntzQWXkbCtIIGdJT918HG00cObwbA==", "dev": true, "license": "ISC", "peer": true, "dependencies": { "@ethersproject/abi": "^5.0.9", - "@solidity-parser/parser": "^0.18.0", + "@solidity-parser/parser": "^0.19.0", "chalk": "^2.4.2", "death": "^1.1.0", "difflib": "^0.2.4", @@ -10196,9 +10240,9 @@ } }, "node_modules/solidity-coverage/node_modules/@solidity-parser/parser": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.18.0.tgz", - "integrity": "sha512-yfORGUIPgLck41qyN7nbwJRAx17/jAIXCTanHOJZhB6PJ1iAk/84b/xlsVKFSyNyLXIj0dhppoE0+CRws7wlzA==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.19.0.tgz", + "integrity": "sha512-RV16k/qIxW/wWc+mLzV3ARyKUaMUTBy9tOLMzFhtNSKYeTAanQ3a5MudJKf/8arIFnA2L27SNjarQKmFg0w/jA==", "dev": true, "license": "MIT", "peer": true @@ -10582,9 +10626,9 @@ } }, "node_modules/synckit": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.1.tgz", - "integrity": "sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==", + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.2.tgz", + "integrity": "sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==", "dev": true, "license": "MIT", "dependencies": { @@ -10598,17 +10642,10 @@ "url": "https://opencollective.com/unts" } }, - "node_modules/synckit/node_modules/tslib": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", - "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", - "dev": true, - "license": "0BSD" - }, "node_modules/table": { - "version": "6.8.2", - "resolved": "https://registry.npmjs.org/table/-/table-6.8.2.tgz", - "integrity": "sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA==", + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz", + "integrity": "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -10755,16 +10792,17 @@ "peer": true }, "node_modules/then-request/node_modules/form-data": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", - "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.2.tgz", + "integrity": "sha512-GgwY0PS7DbXqajuGf4OYlsrIu3zgxD6Vvql43IBhm6MahqA5SK/7mwhtNj2AdH2z35YR34ujJ7BN+3fFC3jP5Q==", "dev": true, "license": "MIT", "peer": true, "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" + "mime-types": "^2.1.12", + "safe-buffer": "^5.2.1" }, "engines": { "node": ">= 0.12" @@ -10788,6 +10826,48 @@ "readable-stream": "3" } }, + "node_modules/tinyglobby": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.10.tgz", + "integrity": "sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.4.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.2.tgz", + "integrity": "sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -10839,16 +10919,16 @@ "license": "MIT" }, "node_modules/ts-api-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", - "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.0.tgz", + "integrity": "sha512-xCt/TOAc+EOHS1XPnijD3/yzpH6qg2xppZO1YDqGoVsNXfQfzHpOdNuXwrwOU8u4ITXJyDCTyt8w5g1sZv9ynQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=16" + "node": ">=18.12" }, "peerDependencies": { - "typescript": ">=4.2.0" + "typescript": ">=4.8.4" } }, "node_modules/ts-command-line-args": { @@ -10945,12 +11025,11 @@ } }, "node_modules/tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", "dev": true, - "license": "0BSD", - "peer": true + "license": "0BSD" }, "node_modules/tsort": { "version": "0.0.1", @@ -11161,9 +11240,9 @@ "license": "MIT" }, "node_modules/typescript": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", - "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", + "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -11175,15 +11254,15 @@ } }, "node_modules/typescript-eslint": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.6.0.tgz", - "integrity": "sha512-eEhhlxCEpCd4helh3AO1hk0UP2MvbRi9CtIAJTVPQjuSXOOO2jsEacNi4UdcJzZJbeuVg1gMhtZ8UYb+NFYPrA==", + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.19.1.tgz", + "integrity": "sha512-LKPUQpdEMVOeKluHi8md7rwLcoXHhwvWp3x+sJkMuq3gGm9yaYJtPo8sRZSblMFJ5pcOGCAak/scKf1mvZDlQw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.6.0", - "@typescript-eslint/parser": "8.6.0", - "@typescript-eslint/utils": "8.6.0" + "@typescript-eslint/eslint-plugin": "8.19.1", + "@typescript-eslint/parser": "8.19.1", + "@typescript-eslint/utils": "8.19.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -11192,10 +11271,9 @@ "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, "node_modules/typical": { @@ -11225,9 +11303,9 @@ } }, "node_modules/undici": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.19.8.tgz", - "integrity": "sha512-U8uCCl2x9TK3WANvmBavymRzxbfFYG+tAu+fgx3zxQy3qdagQqBLwJVrdyO1TBfUXvfKveMKJZhpvUYoOjM+4g==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.21.0.tgz", + "integrity": "sha512-BUgJXc752Kou3oOIuU1i+yZZypyZRqNPW0vqoMPl8VaoalSfeR0D8/t4iAS3yirs79SSMTxTag+ZC86uswv+Cw==", "dev": true, "license": "MIT", "engines": { @@ -11287,10 +11365,14 @@ "license": "MIT" }, "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], "license": "MIT", "bin": { "uuid": "dist/bin/uuid" @@ -11630,9 +11712,9 @@ } }, "node_modules/zksync-ethers": { - "version": "6.12.1", - "resolved": "https://registry.npmjs.org/zksync-ethers/-/zksync-ethers-6.12.1.tgz", - "integrity": "sha512-dBUx1LLgo5Gs4+lI+w9/rI+RxQOo1hMGeXB5qJ/e73qIZKgP/q/Hx1rDfDA9mm+F2QE0IZ+mN2YkA47qbydIog==", + "version": "6.15.3", + "resolved": "https://registry.npmjs.org/zksync-ethers/-/zksync-ethers-6.15.3.tgz", + "integrity": "sha512-AAFf5HKlkGpLRSE1CB8gBIlswbnWBPHD2ex4bcFG8GJFr1iQuq+LbMrisDm17jNR4Msi1WkNgIartS7nXcOrTg==", "dev": true, "license": "MIT", "engines": { diff --git a/package.json b/package.json index 71e4495d6..f1667b968 100644 --- a/package.json +++ b/package.json @@ -59,11 +59,11 @@ }, "devDependencies": { "@eslint/js": "^9.9.1", - "@matterlabs/hardhat-zksync-deploy": "^1.5.0", + "@matterlabs/hardhat-zksync-deploy": "^1.6.0", "@matterlabs/hardhat-zksync-ethers": "^1.2.1", - "@matterlabs/hardhat-zksync-node": "^1.1.1", - "@matterlabs/hardhat-zksync-solc": "^1.2.4", - "@matterlabs/hardhat-zksync-verify": "^1.6.0", + "@matterlabs/hardhat-zksync-node": "^1.2.1", + "@matterlabs/hardhat-zksync-solc": "^1.2.5", + "@matterlabs/hardhat-zksync-verify": "^1.7.1", "@nomicfoundation/hardhat-toolbox": "^5.0.0", "@openzeppelin/contracts": "^3.4.0", "@safe-global/mock-contract": "^4.1.0", @@ -80,7 +80,7 @@ "eslint-config-prettier": "^9.1.0", "eslint-plugin-no-only-tests": "^3.3.0", "eslint-plugin-prettier": "^5.2.1", - "hardhat": "^2.22.10", + "hardhat": "^2.22.17", "hardhat-deploy": "^0.12.4", "husky": "^9.1.5", "prettier": "^3.3.3", @@ -92,6 +92,6 @@ "typescript": "^5.5.4", "typescript-eslint": "^8.4.0", "yargs": "^17.7.2", - "zksync-ethers": "6.12.1" + "zksync-ethers": "6.15.3" } } diff --git a/test/libraries/SafeToL2Setup.spec.ts b/test/libraries/SafeToL2Setup.spec.ts index 1353032a4..12388fe55 100644 --- a/test/libraries/SafeToL2Setup.spec.ts +++ b/test/libraries/SafeToL2Setup.spec.ts @@ -26,7 +26,8 @@ type HardhatTrace = { describe("SafeToL2Setup", () => { const setupTests = deployments.createFixture(async ({ deployments }) => { await deployments.fixture(); - const safeToL2SetupLib = await (await hre.ethers.getContractFactory("SafeToL2Setup")).deploy(); + const safeToL2SetupAddress = (await deployments.get("SafeToL2Setup")).address; + const safeToL2SetupLib = await hre.ethers.getContractAt("SafeToL2Setup", safeToL2SetupAddress); const signers = await hre.ethers.getSigners(); const safeSingleton = await getSafeSingleton(); const safeL2 = await getSafeL2Singleton(); From 0372c8a1a4a134c51f4a72c32bda94799857275e Mon Sep 17 00:00:00 2001 From: piguagua Date: Wed, 15 Jan 2025 16:34:09 +0800 Subject: [PATCH 32/38] Fix broken link (#900) Replace broken link with new one. Signed-off-by: piguagua --- docs/signatures.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/signatures.md b/docs/signatures.md index f047fa822..6aebefad0 100644 --- a/docs/signatures.md +++ b/docs/signatures.md @@ -64,7 +64,7 @@ The method `signMessage` can be used to mark a message as signed on-chain. `{32-bytes hash validator}{32-bytes ignored}{1-byte signature type}` -**Hash validator** - Padded address of the account that pre-validated the hash that should be validated. The Safe keeps track of all hashes that have been pre validated. This is done with a **mapping address to mapping of bytes32 to boolean** where it is possible to set a hash as validated by a certain address \(hash validator\). To add an entry to this mapping use `approveHash`. Also if the validator is the sender of transaction that executed the Safe transaction it is **not** required to use `approveHash` to add an entry to the mapping. \(This can be seen in the [Team Edition tests](https://github.com/gnosis/safe-smart-account/blob/v1.0.0/test/gnosisSafeTeamEdition.js)\) +**Hash validator** - Padded address of the account that pre-validated the hash that should be validated. The Safe keeps track of all hashes that have been pre validated. This is done with a **mapping address to mapping of bytes32 to boolean** where it is possible to set a hash as validated by a certain address \(hash validator\). To add an entry to this mapping use `approveHash`. Also if the validator is the sender of transaction that executed the Safe transaction it is **not** required to use `approveHash` to add an entry to the mapping. \(This can be seen in the [Team Edition tests](https://github.com/safe-global/safe-smart-account/blob/v1.0.0/test/gnosisSafeTeamEdition.js)\) **Signature type** - 1 From 8677f3239d2707c35d41293a00c6c806d64a6240 Mon Sep 17 00:00:00 2001 From: Derek <158146599+derek-certora@users.noreply.github.com> Date: Thu, 16 Jan 2025 08:45:56 +0000 Subject: [PATCH 33/38] Formal Verification for Safe v1.5 Audit (#901) This pull request corresponds to the formal verification aspect of the Safe v1.5 audit done by Certora. ## Summary of Changes ### Added Configuration and Specification files corresponding to new rules: * `execute.conf` and `Execute.spec` * `extensible.conf` and `Extensible.spec` * `fallback.conf` and `Fallback.spec` * `guards.conf` and `Guards.spec` * `hash.conf` and `Hash.spec` * `setup.conf` and `Setup.spec` Harness: * `ExtensibleFallbackHandlerHarness.sol` to reason about the fallback handler Mocks: * `DummyHandler.sol` for reasoning about the fallback handler * `TxnGuardMock.sol` and `TxnGuardMockDuplicate.sol` for reasoning about the transaction guard * `ModuleGuardMock.sol` and `ModuleGuardMockDuplicate.sol` for reasoning about the module guard ### Modified * `applyHarness.patch` - added some minor munging as explained in the audit report * `run.conf` - remove a deprecated configuration tag that was giving errors to the Prover * `Safe.spec` - moved a rule about guards to `Guard.spec` for logical continuity * `SafeHarness.sol` - added some view functionality to the Safe harness for some rules Co-authored-by: Derek Sorensen --- certora/applyHarness.patch | 48 +++- certora/conf/execute.conf | 27 +++ certora/conf/extensible.conf | 27 +++ certora/conf/fallback.conf | 27 +++ certora/conf/guards.conf | 35 +++ certora/conf/hash.conf | 25 ++ certora/conf/run.conf | 1 - certora/conf/setup.conf | 25 ++ .../ExtensibleFallbackHandlerHarness.sol | 11 + certora/harnesses/SafeHarness.sol | 32 +++ certora/mocks/DummyHandler.sol | 24 ++ certora/mocks/ModuleGuardMock.sol | 71 ++++++ certora/mocks/ModuleGuardMockDuplicate.sol | 71 ++++++ certora/mocks/TxnGuardMock.sol | 78 +++++++ certora/mocks/TxnGuardMockDuplicate.sol | 78 +++++++ certora/specs/Execute.spec | 161 +++++++++++++ certora/specs/Extensible.spec | 74 ++++++ certora/specs/Fallback.spec | 84 +++++++ certora/specs/Guards.spec | 219 ++++++++++++++++++ certora/specs/Hash.spec | 43 ++++ certora/specs/Safe.spec | 15 -- certora/specs/Setup.spec | 43 ++++ 22 files changed, 1191 insertions(+), 28 deletions(-) create mode 100644 certora/conf/execute.conf create mode 100644 certora/conf/extensible.conf create mode 100644 certora/conf/fallback.conf create mode 100644 certora/conf/guards.conf create mode 100644 certora/conf/hash.conf create mode 100644 certora/conf/setup.conf create mode 100644 certora/harnesses/ExtensibleFallbackHandlerHarness.sol create mode 100644 certora/mocks/DummyHandler.sol create mode 100644 certora/mocks/ModuleGuardMock.sol create mode 100644 certora/mocks/ModuleGuardMockDuplicate.sol create mode 100644 certora/mocks/TxnGuardMock.sol create mode 100644 certora/mocks/TxnGuardMockDuplicate.sol create mode 100644 certora/specs/Execute.spec create mode 100644 certora/specs/Extensible.spec create mode 100644 certora/specs/Fallback.spec create mode 100644 certora/specs/Guards.spec create mode 100644 certora/specs/Hash.spec create mode 100644 certora/specs/Setup.spec diff --git a/certora/applyHarness.patch b/certora/applyHarness.patch index 3f6742286..662b4dda5 100644 --- a/certora/applyHarness.patch +++ b/certora/applyHarness.patch @@ -1,6 +1,6 @@ diff -druN Safe.sol Safe.sol ---- Safe.sol 2024-10-23 15:00:06 -+++ Safe.sol 2024-10-23 15:04:05 +--- Safe.sol 2024-12-16 07:43:06 ++++ Safe.sol 2025-01-13 11:58:17 @@ -75,22 +75,24 @@ * so we create a Safe with 0 owners and threshold 1. * This is an unusable Safe, perfect for the singleton @@ -30,7 +30,7 @@ diff -druN Safe.sol Safe.sol // setupOwners checks if the Threshold is already set, therefore preventing this method from being called more than once setupOwners(_owners, _threshold); if (fallbackHandler != address(0)) internalSetFallbackHandler(fallbackHandler); -@@ -386,9 +388,6 @@ +@@ -388,9 +390,6 @@ return keccak256(abi.encode(DOMAIN_SEPARATOR_TYPEHASH, chainId, this)); } @@ -40,7 +40,7 @@ diff -druN Safe.sol Safe.sol function getTransactionHash( address to, uint256 value, -@@ -400,7 +399,9 @@ +@@ -402,7 +401,9 @@ address gasToken, address refundReceiver, uint256 _nonce @@ -50,10 +50,21 @@ diff -druN Safe.sol Safe.sol + bytes32 domainHash = domainSeparator(); - // We opted out for using assembly code here, because the way Solidity compiler we use (0.7.6) + // We opted for using assembly code here, because the way Solidity compiler we use (0.7.6) allocates memory is +@@ -452,7 +453,8 @@ + // Store the domain separator + mstore(add(ptr, 32), domainHash) + // Calculate the hash +- txHash := keccak256(add(ptr, 30), 66) ++ //txHash := keccak256(add(ptr, 30), 66) // old ++ txHash := keccak256(add(ptr, 0), 128) // new + } + /* solhint-enable no-inline-assembly */ + } + diff -druN base/Executor.sol base/Executor.sol ---- base/Executor.sol 2024-10-18 15:20:48 -+++ base/Executor.sol 2024-10-23 15:03:22 +--- base/Executor.sol 2024-12-16 07:43:06 ++++ base/Executor.sol 2025-01-13 11:58:17 @@ -26,12 +26,8 @@ uint256 txGas ) internal returns (bool success) { @@ -69,10 +80,23 @@ diff -druN base/Executor.sol base/Executor.sol } else { /* solhint-disable no-inline-assembly */ /// @solidity memory-safe-assembly +diff -druN base/FallbackManager.sol base/FallbackManager.sol +--- base/FallbackManager.sol 2024-12-16 07:43:06 ++++ base/FallbackManager.sol 2025-01-13 12:07:42 +@@ -63,7 +63,8 @@ + // not going beyond the scratch space, etc) + // Solidity docs: https://docs.soliditylang.org/en/latest/assembly.html#memory-safety + +- let handler := sload(FALLBACK_HANDLER_STORAGE_SLOT) ++ // let handler := sload(FALLBACK_HANDLER_STORAGE_SLOT) ++ let handler := and(0xffffffffffffffffffffffffffffffffffffffff, sload(FALLBACK_HANDLER_STORAGE_SLOT)) + + if iszero(handler) { + return(0, 0) diff -druN interfaces/ISafe.sol interfaces/ISafe.sol ---- interfaces/ISafe.sol 2024-10-18 15:20:48 -+++ interfaces/ISafe.sol 2024-10-23 15:03:22 -@@ -110,7 +110,7 @@ +--- interfaces/ISafe.sol 2024-12-16 07:43:06 ++++ interfaces/ISafe.sol 2025-01-13 11:58:17 +@@ -113,7 +113,7 @@ */ function domainSeparator() external view returns (bytes32); @@ -81,7 +105,7 @@ diff -druN interfaces/ISafe.sol interfaces/ISafe.sol * @notice Returns transaction hash to be signed by owners. * @param to Destination address. * @param value Ether value. -@@ -123,7 +123,6 @@ +@@ -126,7 +126,6 @@ * @param refundReceiver Address of receiver of gas payment (or 0 if tx.origin). * @param _nonce Transaction nonce. * @return Transaction hash. @@ -89,7 +113,7 @@ diff -druN interfaces/ISafe.sol interfaces/ISafe.sol function getTransactionHash( address to, uint256 value, -@@ -136,6 +135,8 @@ +@@ -139,6 +138,8 @@ address refundReceiver, uint256 _nonce ) external view returns (bytes32); diff --git a/certora/conf/execute.conf b/certora/conf/execute.conf new file mode 100644 index 000000000..69af1c53d --- /dev/null +++ b/certora/conf/execute.conf @@ -0,0 +1,27 @@ +{ + "files": [ + "certora/harnesses/SafeHarness.sol", + "certora/mocks/ModuleGuardMock.sol", // a module guard + "certora/mocks/TxnGuardMock.sol", // a (safe) guard + ], + "link": [ + + ], + "verify": "SafeHarness:certora/specs/Execute.spec", + + "assert_autofinder_success": true, + "optimistic_summary_recursion": true, + "optimistic_contract_recursion": true, + + "summary_recursion_limit": "2", + "contract_recursion_limit": "2", + "loop_iter": "3", + "optimistic_loop": true, + "optimistic_hashing": true, + "optimistic_fallback": true, + + "rule_sanity": "basic", + + "solc": "solc7.6", + "solc_via_ir": false, +} \ No newline at end of file diff --git a/certora/conf/extensible.conf b/certora/conf/extensible.conf new file mode 100644 index 000000000..beb336137 --- /dev/null +++ b/certora/conf/extensible.conf @@ -0,0 +1,27 @@ +{ + "files": [ + "certora/harnesses/SafeHarness.sol", + "certora/harnesses/ExtensibleFallbackHandlerHarness.sol", + "certora/mocks/DummyHandler.sol" + ], + "link": [ + + ], + "verify": "SafeHarness:certora/specs/Extensible.spec", + + "assert_autofinder_success": true, + "optimistic_summary_recursion": true, + "optimistic_contract_recursion": true, + + "summary_recursion_limit": "2", + "contract_recursion_limit": "2", + "loop_iter": "3", + "optimistic_loop": true, + "optimistic_hashing": true, + "optimistic_fallback": true, + + "rule_sanity": "basic", + + "solc": "solc7.6", + "solc_via_ir": false, +} \ No newline at end of file diff --git a/certora/conf/fallback.conf b/certora/conf/fallback.conf new file mode 100644 index 000000000..1c8ecf8b3 --- /dev/null +++ b/certora/conf/fallback.conf @@ -0,0 +1,27 @@ +{ + "files": [ + "certora/harnesses/SafeHarness.sol", + "certora/harnesses/ExtensibleFallbackHandlerHarness.sol", + "certora/mocks/DummyHandler.sol" + ], + "link": [ + + ], + "verify": "SafeHarness:certora/specs/Fallback.spec", + + "assert_autofinder_success": true, + "optimistic_summary_recursion": true, + "optimistic_contract_recursion": true, + + "summary_recursion_limit": "2", + "contract_recursion_limit": "2", + "loop_iter": "3", + "optimistic_loop": true, + "optimistic_hashing": true, + "optimistic_fallback": true, + + "rule_sanity": "basic", + + "solc": "solc7.6", + "solc_via_ir": false, +} \ No newline at end of file diff --git a/certora/conf/guards.conf b/certora/conf/guards.conf new file mode 100644 index 000000000..e367ba943 --- /dev/null +++ b/certora/conf/guards.conf @@ -0,0 +1,35 @@ +// a conf file for safe module guards +{ + "files": [ + "certora/harnesses/SafeHarness.sol", + "certora/mocks/ModuleGuardMock.sol", // a module guard + "certora/mocks/ModuleGuardMockDuplicate.sol", + "certora/mocks/TxnGuardMock.sol", // a (safe) guard + "certora/mocks/TxnGuardMockDuplicate.sol", + ], + "link": [ + + ], + "verify": "SafeHarness:certora/specs/Guards.spec", + + "assert_autofinder_success": true, + "optimistic_summary_recursion": true, + "optimistic_contract_recursion": true, + + "summary_recursion_limit": "2", + "contract_recursion_limit": "2", + "loop_iter": "3", + "optimistic_loop": true, + "optimistic_hashing": true, + "optimistic_fallback": true, + + "rule_sanity": "basic", + + "solc": "solc7.6", + "solc_via_ir": false, + + "prover_args": [ + " -verifyCache -verifyTACDumps -testMode -checkRuleDigest -callTraceHardFail on", + "-enableSolidityBasedInlining true" + ], +} \ No newline at end of file diff --git a/certora/conf/hash.conf b/certora/conf/hash.conf new file mode 100644 index 000000000..527d89415 --- /dev/null +++ b/certora/conf/hash.conf @@ -0,0 +1,25 @@ +{ + "files": [ + "certora/harnesses/SafeHarness.sol" + ], + "link": [ + + ], + "verify": "SafeHarness:certora/specs/Hash.spec", + + "assert_autofinder_success": true, + "optimistic_summary_recursion": true, + "optimistic_contract_recursion": true, + + "summary_recursion_limit": "2", + "contract_recursion_limit": "2", + "loop_iter": "3", + "optimistic_loop": true, + "optimistic_hashing": true, + "optimistic_fallback": true, + + "rule_sanity": "basic", + + "solc": "solc7.6", + "solc_via_ir": false, +} \ No newline at end of file diff --git a/certora/conf/run.conf b/certora/conf/run.conf index c3137e83d..4a27a8c15 100644 --- a/certora/conf/run.conf +++ b/certora/conf/run.conf @@ -14,7 +14,6 @@ ], "rule_sanity": "basic", "run_source": "MUTATION", - "send_only": true, "solc": "solc7.6", "verify": "SafeHarness:certora/specs/Safe.spec" } \ No newline at end of file diff --git a/certora/conf/setup.conf b/certora/conf/setup.conf new file mode 100644 index 000000000..8b0407ff0 --- /dev/null +++ b/certora/conf/setup.conf @@ -0,0 +1,25 @@ +{ + "files": [ + "certora/harnesses/SafeHarness.sol" + ], + "link": [ + + ], + "verify": "SafeHarness:certora/specs/Setup.spec", + + "assert_autofinder_success": true, + "optimistic_summary_recursion": true, + "optimistic_contract_recursion": true, + + "summary_recursion_limit": "2", + "contract_recursion_limit": "2", + "loop_iter": "3", + "optimistic_loop": true, + "optimistic_hashing": true, + "optimistic_fallback": true, + + "rule_sanity": "basic", + + "solc": "solc7.6", + "solc_via_ir": false, +} \ No newline at end of file diff --git a/certora/harnesses/ExtensibleFallbackHandlerHarness.sol b/certora/harnesses/ExtensibleFallbackHandlerHarness.sol new file mode 100644 index 000000000..02c1730d7 --- /dev/null +++ b/certora/harnesses/ExtensibleFallbackHandlerHarness.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: LGPL-3.0-only +import "../munged/handler/ExtensibleFallbackHandler.sol"; +import {ISafe} from "../munged/interfaces/ISafe.sol"; + +contract ExtensibleFallbackHandlerHarness is ExtensibleFallbackHandler { + + function getSafeMethod(ISafe safe, bytes4 selector) public view returns (bytes32) { + return safeMethods[safe][selector]; + } + +} \ No newline at end of file diff --git a/certora/harnesses/SafeHarness.sol b/certora/harnesses/SafeHarness.sol index c3380ac73..f2d100e27 100644 --- a/certora/harnesses/SafeHarness.sol +++ b/certora/harnesses/SafeHarness.sol @@ -1,5 +1,9 @@ // SPDX-License-Identifier: LGPL-3.0-only import "../munged/Safe.sol"; +import {SafeMath} from "../munged/external/SafeMath.sol"; +import {ISafe, IStaticFallbackMethod, IFallbackMethod, ExtensibleBase} from "../munged/handler/extensible/ExtensibleBase.sol"; +import {IFallbackHandler, FallbackHandler} from "../munged/handler/extensible/FallbackHandler.sol"; + contract SafeHarness is Safe { constructor( @@ -31,6 +35,10 @@ contract SafeHarness is Safe { } } + function numSigsSufficient(bytes memory signatures,uint256 requiredSignatures) public pure returns (bool) { + return (signatures.length >= SafeMath.mul(requiredSignatures,65)); + } + // harnessed getters function getModule(address module) public view returns (address) { return modules[module]; @@ -40,6 +48,10 @@ contract SafeHarness is Safe { return getGuard(); } + function getModuleGuardExternal() public view returns (address) { + return getModuleGuard(); + } + function getNativeTokenBalance() public view returns (uint256) { return address(this).balance; } @@ -56,6 +68,26 @@ contract SafeHarness is Safe { return getOwners().length; } + function approvedHashVal(address a, bytes32 hashInQuestion) public view returns (uint256) { + return approvedHashes[a][hashInQuestion]; + } + + function getFallbackHandler() public view returns (address) { + address handler; + assembly{ + handler := sload(FALLBACK_HANDLER_STORAGE_SLOT) + } + return handler ; + } + + function callSetSafeMethod(bytes4 selector, bytes32 newMethod) public { + IFallbackHandler(address(this)).setSafeMethod(selector,newMethod); + } + + function callDummyHandler(bytes4 selector) public { + address(this).call(abi.encodeWithSelector(selector)); + } + function getTransactionHashPublic( address to, uint256 value, diff --git a/certora/mocks/DummyHandler.sol b/certora/mocks/DummyHandler.sol new file mode 100644 index 000000000..6a121cb94 --- /dev/null +++ b/certora/mocks/DummyHandler.sol @@ -0,0 +1,24 @@ +// a dummy handler contract +import {ISafe, IStaticFallbackMethod, IFallbackMethod, ExtensibleBase} from "../munged/handler/extensible/ExtensibleBase.sol"; + +contract DummyHandler is IFallbackMethod { + constructor(){ + methodCalled = false ; + } + + bool public methodCalled ; + function resetMethodCalled() public { + methodCalled = false; + } + + // the DUMMY method + function handle(ISafe safe, address sender, uint256 value, bytes calldata data) external override returns (bytes memory result) { + methodCalled = true ; + + return "Hello, world!"; + } + + function dummyMethod() public { + methodCalled = true ; + } +} \ No newline at end of file diff --git a/certora/mocks/ModuleGuardMock.sol b/certora/mocks/ModuleGuardMock.sol new file mode 100644 index 000000000..299d29c9a --- /dev/null +++ b/certora/mocks/ModuleGuardMock.sol @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: LGPL-3.0-only +/* solhint-disable one-contract-per-file */ +pragma solidity >=0.7.0 <0.9.0; +import {IModuleGuard} from "../munged/base/ModuleManager.sol"; +import {IERC165} from "../munged/interfaces/IERC165.sol"; +import "../munged/libraries/Enum.sol"; + +contract ModuleGuardMock is IModuleGuard { + + constructor(){ + preCheckedTransactions = false ; + postCheckedTransactions = false ; + } + + // some mock variables + bool public preCheckedTransactions ; + bool public postCheckedTransactions ; + + function resetChecks() external { + preCheckedTransactions = false ; + postCheckedTransactions = false ; + } + + /** + * @notice Checks the module transaction details. + * @dev The function needs to implement module transaction validation logic. + * @param to The address to which the transaction is intended. + * @param value The value of the transaction in Wei. + * @param data The transaction data. + * @param operation The type of operation of the module transaction. + * @param module The module involved in the transaction. + * @return moduleTxHash The hash of the module transaction. + */ + function checkModuleTransaction( + address to, + uint256 value, + bytes memory data, + Enum.Operation operation, + address module + ) external override returns (bytes32 moduleTxHash) { + // updates transaction checked + preCheckedTransactions = true ; + // if it passes, it returns a string of bytes + return bytes32(0); + } + + /** + * @notice Checks after execution of module transaction. + * @dev The function needs to implement a check after the execution of the module transaction. + * @param txHash The hash of the module transaction. + * @param success The status of the module transaction execution. + */ + function checkAfterModuleExecution(bytes32 txHash, bool success) external override { + postCheckedTransactions = true; + } + + /** + * @dev Returns true if this contract implements the interface defined by `interfaceId`. + * See the corresponding EIP section + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view virtual override returns (bool) { + return + interfaceId == type(IModuleGuard).interfaceId || // 0x58401ed8 + interfaceId == type(IERC165).interfaceId; // 0x01ffc9a7 + } + +} \ No newline at end of file diff --git a/certora/mocks/ModuleGuardMockDuplicate.sol b/certora/mocks/ModuleGuardMockDuplicate.sol new file mode 100644 index 000000000..0bb7e3420 --- /dev/null +++ b/certora/mocks/ModuleGuardMockDuplicate.sol @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: LGPL-3.0-only +/* solhint-disable one-contract-per-file */ +pragma solidity >=0.7.0 <0.9.0; +import {IModuleGuard} from "../munged/base/ModuleManager.sol"; +import {IERC165} from "../munged/interfaces/IERC165.sol"; +import "../munged/libraries/Enum.sol"; + +contract ModuleGuardMockDuplicate is IModuleGuard { + + constructor(){ + preCheckedTransactions = false ; + postCheckedTransactions = false ; + } + + // some mock variables + bool public preCheckedTransactions ; + bool public postCheckedTransactions ; + + function resetChecks() external { + preCheckedTransactions = false ; + postCheckedTransactions = false ; + } + + /** + * @notice Checks the module transaction details. + * @dev The function needs to implement module transaction validation logic. + * @param to The address to which the transaction is intended. + * @param value The value of the transaction in Wei. + * @param data The transaction data. + * @param operation The type of operation of the module transaction. + * @param module The module involved in the transaction. + * @return moduleTxHash The hash of the module transaction. + */ + function checkModuleTransaction( + address to, + uint256 value, + bytes memory data, + Enum.Operation operation, + address module + ) external override returns (bytes32 moduleTxHash) { + // updates transaction checked + preCheckedTransactions = true ; + // if it passes, it returns a string of bytes + return bytes32(0); + } + + /** + * @notice Checks after execution of module transaction. + * @dev The function needs to implement a check after the execution of the module transaction. + * @param txHash The hash of the module transaction. + * @param success The status of the module transaction execution. + */ + function checkAfterModuleExecution(bytes32 txHash, bool success) external override { + postCheckedTransactions = true; + } + + /** + * @dev Returns true if this contract implements the interface defined by `interfaceId`. + * See the corresponding EIP section + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view virtual override returns (bool) { + return + interfaceId == type(IModuleGuard).interfaceId || // 0x58401ed8 + interfaceId == type(IERC165).interfaceId; // 0x01ffc9a7 + } + +} \ No newline at end of file diff --git a/certora/mocks/TxnGuardMock.sol b/certora/mocks/TxnGuardMock.sol new file mode 100644 index 000000000..7d8c921be --- /dev/null +++ b/certora/mocks/TxnGuardMock.sol @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: LGPL-3.0-only +/* solhint-disable one-contract-per-file */ +pragma solidity >=0.7.0 <0.9.0; +import {ITransactionGuard} from "../munged/base/GuardManager.sol"; +import {IERC165} from "../munged/interfaces/IERC165.sol"; +import "../munged/libraries/Enum.sol"; + +contract TxnGuardMock is ITransactionGuard { + + constructor(){} + + // some mock variables + bool public preCheckedTransactions ; + bool public postCheckedTransactions ; + + function resetChecks() external { + preCheckedTransactions = false ; + postCheckedTransactions = false ; + } + + /** + * @notice Checks the transaction details. + * @dev The function needs to implement transaction validation logic. + * @param to The address to which the transaction is intended. + * @param value The value of the transaction in Wei. + * @param data The transaction data. + * @param operation The type of operation of the transaction. + * @param safeTxGas Gas used for the transaction. + * @param baseGas The base gas for the transaction. + * @param gasPrice The price of gas in Wei for the transaction. + * @param gasToken The token used to pay for gas. + * @param refundReceiver The address which should receive the refund. + * @param signatures The signatures of the transaction. + * @param msgSender The address of the message sender. + */ + function checkTransaction( + address to, + uint256 value, + bytes memory data, + Enum.Operation operation, + uint256 safeTxGas, + uint256 baseGas, + uint256 gasPrice, + address gasToken, + address payable refundReceiver, + bytes memory signatures, + address msgSender + ) external override { + // updates transaction checked + preCheckedTransactions = true; + } + + /** + * @notice Checks after execution of the transaction. + * @dev The function needs to implement a check after the execution of the transaction. + * @param hash The hash of the transaction. + * @param success The status of the transaction execution. + */ + function checkAfterExecution(bytes32 hash, bool success) external override { + // updates transaction checked + postCheckedTransactions = true ; + } + + /** + * @dev Returns true if this contract implements the interface defined by `interfaceId`. + * See the corresponding EIP section + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view virtual override returns (bool) { + return + interfaceId == type(ITransactionGuard).interfaceId || // 0xe6d7a83a + interfaceId == type(IERC165).interfaceId; // 0x01ffc9a7 + } + +} \ No newline at end of file diff --git a/certora/mocks/TxnGuardMockDuplicate.sol b/certora/mocks/TxnGuardMockDuplicate.sol new file mode 100644 index 000000000..8b7ad8a27 --- /dev/null +++ b/certora/mocks/TxnGuardMockDuplicate.sol @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: LGPL-3.0-only +/* solhint-disable one-contract-per-file */ +pragma solidity >=0.7.0 <0.9.0; +import {ITransactionGuard} from "../munged/base/GuardManager.sol"; +import {IERC165} from "../munged/interfaces/IERC165.sol"; +import "../munged/libraries/Enum.sol"; + +contract TxnGuardMockDuplicate is ITransactionGuard { + + constructor(){} + + // some mock variables + bool public preCheckedTransactions ; + bool public postCheckedTransactions ; + + function resetChecks() external { + preCheckedTransactions = false ; + postCheckedTransactions = false ; + } + + /** + * @notice Checks the transaction details. + * @dev The function needs to implement transaction validation logic. + * @param to The address to which the transaction is intended. + * @param value The value of the transaction in Wei. + * @param data The transaction data. + * @param operation The type of operation of the transaction. + * @param safeTxGas Gas used for the transaction. + * @param baseGas The base gas for the transaction. + * @param gasPrice The price of gas in Wei for the transaction. + * @param gasToken The token used to pay for gas. + * @param refundReceiver The address which should receive the refund. + * @param signatures The signatures of the transaction. + * @param msgSender The address of the message sender. + */ + function checkTransaction( + address to, + uint256 value, + bytes memory data, + Enum.Operation operation, + uint256 safeTxGas, + uint256 baseGas, + uint256 gasPrice, + address gasToken, + address payable refundReceiver, + bytes memory signatures, + address msgSender + ) external override { + // updates transaction checked + preCheckedTransactions = true; + } + + /** + * @notice Checks after execution of the transaction. + * @dev The function needs to implement a check after the execution of the transaction. + * @param hash The hash of the transaction. + * @param success The status of the transaction execution. + */ + function checkAfterExecution(bytes32 hash, bool success) external override { + // updates transaction checked + postCheckedTransactions = true ; + } + + /** + * @dev Returns true if this contract implements the interface defined by `interfaceId`. + * See the corresponding EIP section + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view virtual override returns (bool) { + return + interfaceId == type(ITransactionGuard).interfaceId || // 0xe6d7a83a + interfaceId == type(IERC165).interfaceId; // 0x01ffc9a7 + } + +} \ No newline at end of file diff --git a/certora/specs/Execute.spec b/certora/specs/Execute.spec new file mode 100644 index 000000000..5271f339b --- /dev/null +++ b/certora/specs/Execute.spec @@ -0,0 +1,161 @@ +/* A specification for the exstensible fallback handler */ + + +// ---- Methods block ---------------------------------------------------------- +methods { + + // envfree + function numSigsSufficient(bytes signatures,uint256 requiredSignatures) external returns (bool) envfree; + + function _.checkTransaction( + address to, + uint256 value, + bytes data, + Enum.Operation operation, + uint256 safeTxGas, + uint256 baseGas, + uint256 gasPrice, + address gasToken, + address refundReceiver, + bytes signatures, + address msgSender + ) external => DISPATCHER(true) ; + + function _.checkAfterExecution(bytes32 hash, bool success) external + => DISPATCHER(true); + + function Executor.execute( + address to, + uint256 value, + bytes memory data, + Enum.Operation operation, + uint256 txGas + ) internal returns (bool) => execute_summary(); + + function SecuredTokenTransfer.transferToken(address token, address receiver, uint256 amount) internal returns (bool) => NONDET ; + function Safe.handlePayment( + uint256 gasUsed, + uint256 baseGas, + uint256 gasPrice, + address gasToken, + address refundReceiver + ) internal returns (uint256) => NONDET ; + +} + +// ---- Functions and ghosts --------------------------------------------------- + +persistent ghost bool execute_called { init_state axiom execute_called == false; } + +function execute_summary() returns bool { + execute_called = true ; + bool new_var ; + return new_var ; +} + +// ---- Invariants ------------------------------------------------------------- + + +// ---- Rules ------------------------------------------------------------------ + +/// @dev a successful call to execTransactionFromModule must be from enabled module +rule execTxnModulePermissions( + address to, + uint256 value, + bytes data, + Enum.Operation operation) { + env e; + bool module_enabled = isModuleEnabled(e,e.msg.sender) ; + + // execTxn from module passes + execTransactionFromModule(e,to,value,data,operation); + + // msg sender is the module + assert (module_enabled); +} + +/// @dev a successful call to execTransactionFromModuleReturnData must be from enabled module +rule execTxnModuleReturnDataPermissions( + address to, + uint256 value, + bytes data, + Enum.Operation operation) { + env e; + bool module_enabled = isModuleEnabled(e,e.msg.sender) ; + + // execTxn from module passes + execTransactionFromModuleReturnData(e,to,value,data,operation); + + // msg sender is the module + assert (module_enabled); +} + + +/// @dev execute can only be called by execTransaction or execTransactionFromModule +rule executePermissions(method f) filtered { + f -> f.selector != sig:simulateAndRevert(address,bytes).selector && + f.selector != sig:getStorageAt(uint256,uint256).selector +} { + env e; + require !execute_called; + + calldataarg args; + f(e, args); + + assert (execute_called => + f.selector == sig:execTransaction( + address, + uint256, + bytes, + Enum.Operation, + uint256, + uint256, + uint256, + address, + address, + bytes).selector || + f.selector == sig:execTransactionFromModule( + address, + uint256, + bytes, + Enum.Operation).selector) || + f.selector == sig:execTransactionFromModuleReturnData( + address, + uint256, + bytes, + Enum.Operation).selector || + f.selector == sig:setup( + address[], + uint256, + address, + bytes, + address, + address, + uint256, + address).selector; +} + + +/// @dev at least "threshold" signatures provided +rule executeThresholdMet( + address to, + uint256 value, + bytes data, + Enum.Operation operation, + uint256 safeTxGas, + uint256 baseGas, + uint256 gasPrice, + address gasToken, + address refundReceiver, + bytes signatures +) { + env e; + uint256 threshold = getThreshold(e); + + // a call to execTxn succeeds + execTransaction(e,to,value,data,operation,safeTxGas,baseGas, + gasPrice,gasToken,refundReceiver,signatures); + + // an added function to the harness SafeHarness.sol that checks signature numbers + assert (numSigsSufficient(signatures,threshold)); +} \ No newline at end of file diff --git a/certora/specs/Extensible.spec b/certora/specs/Extensible.spec new file mode 100644 index 000000000..9044b9dc9 --- /dev/null +++ b/certora/specs/Extensible.spec @@ -0,0 +1,74 @@ +/* A specification for the exstensible fallback handler */ + +using ExtensibleFallbackHandlerHarness as fallbackHandler; +using DummyHandler as dummyHandler; +using SafeHarness as safe; + +// ---- Methods block ---------------------------------------------------------- +methods { + + function getFallbackHandler() external returns (address) envfree; + function _.handle(address _safe, address sender, uint256 value, bytes data) external => DISPATCHER(true); + + unresolved external in safe._ => DISPATCH(use_fallback=true) [ + fallbackHandler._ + ] default NONDET; + + unresolved external in callDummyHandler(bytes4) => DISPATCH(use_fallback=true) [ + safe._ + ] default NONDET; + +} + +// ---- Functions and ghosts --------------------------------------------------- + + + +// ---- Invariants ------------------------------------------------------------- + + + +// ---- Rules ------------------------------------------------------------------ + +/// @dev a handler, once set via setSafeMethod, is possible to call +rule handlerCallableIfSet(method f, bytes4 selector) filtered { f -> f.isFallback } { + env e; + + // the fallback handler is in the scene + require (getFallbackHandler() == fallbackHandler); + + // the dummy (sub) handler is a valid handler for this safe + bytes32 dummy_bytes = to_bytes32(assert_uint256(dummyHandler)); + fallbackHandler.setSafeMethod(e,selector,dummy_bytes); // we've set the dummy as a handler + + // reset the check to see if dummy handler has been called + dummyHandler.resetMethodCalled(e); + + // call the fallback method of the Safe contract + calldataarg args ; + f(e,args); + + // there is an execution path that calls the connected dummy handler + satisfy (dummyHandler.methodCalled(e)); +} + +/// @dev a handler is called under expected conditions +rule handlerCalledIfSet() { + env e; + + // the fallback handler is in the scene + require (getFallbackHandler() == fallbackHandler); + + // the dummy (sub) handler is a valid handler for this safe + bytes32 dummy = to_bytes32(assert_uint256(dummyHandler)); + bytes4 selector = to_bytes4(sig:dummyHandler.dummyMethod().selector); + callSetSafeMethod(e,selector,dummy); // we've set the dummy as a handler + + // reset the check to see if dummy handler has been called + dummyHandler.resetMethodCalled(e); + + callDummyHandler(e,selector); + + // there is an execution path that calls the connected dummy handler + assert (dummyHandler.methodCalled(e)); +} \ No newline at end of file diff --git a/certora/specs/Fallback.spec b/certora/specs/Fallback.spec new file mode 100644 index 000000000..07c02164d --- /dev/null +++ b/certora/specs/Fallback.spec @@ -0,0 +1,84 @@ +/* A specification for the exstensible fallback handler */ + +using ExtensibleFallbackHandlerHarness as fallbackHandler; +using SafeHarness as safe; + +// ---- Methods block ---------------------------------------------------------- +methods { + + function getFallbackHandler() external returns (address) envfree; + function _.handle(address _safe, address sender, uint256 value, bytes data) external => DISPATCHER(true); + +} + +// ---- Functions and ghosts --------------------------------------------------- + + + +// ---- Invariants ------------------------------------------------------------- + + + +// ---- Rules ------------------------------------------------------------------ + +/// @dev fallback handler gets set by setFallbackHandler +rule setFallbackIntegrity(address handler) { + env e; + + setFallbackHandler(e,handler); + address this_handler = getFallbackHandler(); + + assert (this_handler == handler); +} + +/// @dev invariant: the address in fallback handler slot is never self +invariant fallbackHandlerNeverSelf() + getFallbackHandler() != safe + filtered { + f -> f.selector != sig:simulateAndRevert(address,bytes).selector + } + +/// @dev for soundness of fallbackHandlerNeverSelf, we prove a rule that simulateAndRevert always reverts +rule simulateAndRevertReverts(address caddr, bytes b) { + env e; + simulateAndRevert@withrevert(e,caddr,b); + assert lastReverted; +} + +/// @dev setSafeMethod sets the handler +rule setSafeMethodSets(bytes4 selector, address newMethodCaddr) { + env e; + + bytes32 newMethod = to_bytes32(assert_uint256(newMethodCaddr)); + + fallbackHandler.setSafeMethod(e,selector,newMethod); + bytes32 thisMethod = fallbackHandler.getSafeMethod(e,e.msg.sender,selector); + + assert (thisMethod == newMethod); +} + +/// @dev setSafeMethod removes the handler +rule setSafeMethodRemoves(bytes4 selector) { + env e; + + bytes32 newMethod = to_bytes32(0); // call setSafeMethod with the zero address + + fallbackHandler.setSafeMethod(e,selector,newMethod); + bytes32 thisMethod = fallbackHandler.getSafeMethod(e,e.msg.sender,selector); + + assert (thisMethod == to_bytes32(0)); // there is nothing stored +} + +/// @dev setSafeMethod changes the handler +rule setSafeMethodChanges(bytes4 selector, address newMethodCaddr) { + env e; + + bytes32 newMethod = to_bytes32(assert_uint256(newMethodCaddr)); + bytes32 oldMethod = fallbackHandler.getSafeMethod(e,e.msg.sender,selector); + require (newMethod != oldMethod); // we are changing the method address + + fallbackHandler.setSafeMethod(e,selector,newMethod); + bytes32 thisMethod = fallbackHandler.getSafeMethod(e,e.msg.sender,selector); + + assert (thisMethod == newMethod); +} \ No newline at end of file diff --git a/certora/specs/Guards.spec b/certora/specs/Guards.spec new file mode 100644 index 000000000..b32999d70 --- /dev/null +++ b/certora/specs/Guards.spec @@ -0,0 +1,219 @@ +/* A specification of the safe guard and module guard */ + +using ModuleGuardMock as modGuardMock; +using ModuleGuardMockDuplicate as modGuardMock2; +using TxnGuardMock as txnGuardMock; +using TxnGuardMockDuplicate as txnGuardMock2; +using SafeHarness as safe; + +// ---- Methods block ---------------------------------------------------------- +methods { + function getModuleGuardExternal() external returns (address) envfree; + function getSafeGuard() external returns (address) envfree; + + function txnGuardMock.preCheckedTransactions() external returns (bool) envfree; + function txnGuardMock.postCheckedTransactions() external returns (bool) envfree; + function modGuardMock.preCheckedTransactions() external returns (bool) envfree; + function modGuardMock.postCheckedTransactions() external returns (bool) envfree; + + function _.checkModuleTransaction( + address to, + uint256 value, + bytes data, + Enum.Operation operation, + address module + ) external => DISPATCHER(true) ; + + function _.checkAfterModuleExecution(bytes32 txHash, bool success) external + => DISPATCHER(true) ; + + function _.checkTransaction( + address to, + uint256 value, + bytes data, + Enum.Operation operation, + uint256 safeTxGas, + uint256 baseGas, + uint256 gasPrice, + address gasToken, + address refundReceiver, + bytes signatures, + address msgSender + ) external => DISPATCHER(true) ; + + function _.checkAfterExecution(bytes32 hash, bool success) external + => DISPATCHER(true); + + function Executor.execute( + address to, + uint256 value, + bytes memory data, + Enum.Operation operation, + uint256 txGas + ) internal returns (bool) => NONDET; + + function SecuredTokenTransfer.transferToken(address token, address receiver, uint256 amount) internal returns (bool) => NONDET ; + function Safe.handlePayment( + uint256 gasUsed, + uint256 baseGas, + uint256 gasPrice, + address gasToken, + address refundReceiver + ) internal returns (uint256) => NONDET ; + +} + +// ---- Functions and ghosts --------------------------------------------------- + + +// ---- Invariants ------------------------------------------------------------- + + +// ---- Rules ------------------------------------------------------------------ + +/// @dev the only method that can change the guard is setGuard +rule guardAddressChange(method f) filtered { + f -> f.selector != sig:simulateAndRevert(address,bytes).selector && + f.selector != sig:getStorageAt(uint256,uint256).selector +} { + address guardBefore = getSafeGuard(); + + calldataarg args; env e; + f(e, args); + + address guardAfter = getSafeGuard(); + + assert guardBefore != guardAfter => + f.selector == sig:setGuard(address).selector; +} + +/// @dev the only method that can change the module guard is setModuleGuard +rule moduleGuardAddressChange(method f) filtered { + f -> f.selector != sig:simulateAndRevert(address,bytes).selector && + f.selector != sig:getStorageAt(uint256,uint256).selector +} { + address guardBefore = getModuleGuardExternal(); + + calldataarg args; env e; + f(e,args); + + address guardAfter = getModuleGuardExternal(); + + assert guardBefore != guardAfter => + f.selector == sig:setModuleGuard(address).selector; +} + +/// @dev set-get correspondence for (regular) guard +rule setGetCorrespondenceGuard(address guard) { + env e; + setGuard(e,guard); + address gotGuard = getSafeGuard(); + assert guard == gotGuard; +} + +/// @dev set-get correspodnence for module guard +rule setGetCorrespondenceModuleGuard(address guard) { + env e; + setModuleGuard(e,guard); + address gotGuard = getModuleGuardExternal(); + assert guard == gotGuard; +} + +/// @dev setGuard can only be called by contract itself. +rule setGuardReentrant(address guard) { + env e; + setGuard(e,guard); // a successful call to setGuard + assert (e.msg.sender == safe); +} + +/// @dev setModuleGuard can only be called by contract itself. +rule setModuleGuardReentrant(address guard) { + env e; + setModuleGuard(e,guard); + assert(e.msg.sender == safe); +} + + +/// @dev the transaction guard gets called both pre- and post- any execTransaction +rule txnGuardCalled( + address to, + uint256 value, + bytes data, + Enum.Operation operation, + uint256 safeTxGas, + uint256 baseGas, + uint256 gasPrice, + address gasToken, + address refundReceiver, + bytes signatures +) { + env e; + // the txn guard is the mock + require (getSafeGuard() == txnGuardMock); + + txnGuardMock.resetChecks(e); // reset the check triggers + txnGuardMock2.resetChecks(e); + + execTransaction(e,to,value,data,operation,safeTxGas,baseGas, + gasPrice,gasToken,refundReceiver,signatures); + + // the pre- and post- module transaction guards were called + assert ( + txnGuardMock.preCheckedTransactions() && + txnGuardMock.postCheckedTransactions() && + // the right guard was called + !txnGuardMock2.preCheckedTransactions(e) && + !txnGuardMock2.postCheckedTransactions(e) + ); +} + +/// @dev the module guard gets called both pre- and post- any execTransactionFromModule +rule moduleGuardCalled( + address to, + uint256 value, + bytes data, + Enum.Operation operation) { + env e; + // the module guard is the mock + require (getModuleGuardExternal() == modGuardMock); + + modGuardMock.resetChecks(e); // reset the check triggers + modGuardMock2.resetChecks(e); + + execTransactionFromModule(e,to,value,data,operation); + + // the pre- and post- module transaction guards were called + assert ( + modGuardMock.preCheckedTransactions() && + modGuardMock.postCheckedTransactions() && + // the correct guard was called + !modGuardMock2.preCheckedTransactions(e) && + !modGuardMock2.postCheckedTransactions(e) + ); +} + +/// @dev the module guard gets called both pre- and post- any execTransactionFromModuleReturnData +rule moduleGuardCalledReturn( + address to, + uint256 value, + bytes data, + Enum.Operation operation) { + env e; + // the module guard is the mock + require (getModuleGuardExternal() == modGuardMock); + + modGuardMock.resetChecks(e); // reset the check triggers + modGuardMock2.resetChecks(e); + + execTransactionFromModuleReturnData(e,to,value,data,operation); + + // the pre- and post- module transaction guards were called + assert ( + modGuardMock.preCheckedTransactions() && + modGuardMock.postCheckedTransactions() && + // the correct guard was called + !modGuardMock2.preCheckedTransactions(e) && + !modGuardMock2.postCheckedTransactions(e) + ); +} + diff --git a/certora/specs/Hash.spec b/certora/specs/Hash.spec new file mode 100644 index 000000000..218ebdc4a --- /dev/null +++ b/certora/specs/Hash.spec @@ -0,0 +1,43 @@ +/* A specification for the Safe setup function */ + + +// ---- Methods block ---------------------------------------------------------- +methods { + function getThreshold() external returns (uint256) envfree; + + function SecuredTokenTransfer.transferToken(address token, address receiver, uint256 amount) internal returns (bool) => NONDET ; +} + +// ---- Functions and ghosts --------------------------------------------------- + + +// ---- Invariants ------------------------------------------------------------- + + +// ---- Rules ------------------------------------------------------------------ + +/// @dev approvedHashes[user][hash] can only be changed by msg.sender==user +rule approvedHashesUpdate(method f,bytes32 userHash,address user) filtered { + f -> f.selector != sig:simulateAndRevert(address,bytes).selector +} { + env e; + + uint256 hashBefore = approvedHashVal(e,user,userHash); + + calldataarg args; + f(e,args); + + uint256 hashAfter = approvedHashVal(e,user,userHash); + + assert (hashBefore != hashAfter => + (e.msg.sender == user) + ); +} + + +/// @dev approvedHashes is set when calling approveHash +rule approvedHashesSet(bytes32 hashToApprove) { + env e; + approveHash(e,hashToApprove); + assert(approvedHashVal(e,e.msg.sender,hashToApprove) == 1); +} \ No newline at end of file diff --git a/certora/specs/Safe.spec b/certora/specs/Safe.spec index cdb749726..2795523d8 100644 --- a/certora/specs/Safe.spec +++ b/certora/specs/Safe.spec @@ -131,21 +131,6 @@ rule setupCorrectlyConfiguresSafe( } -rule guardAddressChange(method f) filtered { - f -> f.selector != sig:simulateAndRevert(address,bytes).selector && - f.selector != sig:getStorageAt(uint256,uint256).selector -} { - address guardBefore = getSafeGuard(); - - calldataarg args; env e; - f(e, args); - - address guardAfter = getSafeGuard(); - - assert guardBefore != guardAfter => - f.selector == sig:setGuard(address).selector; -} - invariant noSignedMessages(bytes32 message) signedMessages(message) == 0 filtered { f -> reachableOnly(f) } diff --git a/certora/specs/Setup.spec b/certora/specs/Setup.spec new file mode 100644 index 000000000..9b413fd61 --- /dev/null +++ b/certora/specs/Setup.spec @@ -0,0 +1,43 @@ +/* A specification for the Safe setup function */ + + +// ---- Methods block ---------------------------------------------------------- +methods { + function getThreshold() external returns (uint256) envfree; + + function SecuredTokenTransfer.transferToken(address token, address receiver, uint256 amount) internal returns (bool) => NONDET ; +} + +// ---- Functions and ghosts --------------------------------------------------- + + +// ---- Invariants ------------------------------------------------------------- + + +// ---- Rules ------------------------------------------------------------------ + +/// @dev setup can only be called if threshold = 0 and setup sets threshold > 0 +rule setupThresholdZeroAndSetsPositiveThreshold( + address[] _owners, + uint256 _threshold, + address to, + bytes data, + address fallbackHandler, + address paymentToken, + uint256 payment, + address paymentReceiver) { + env e; + + uint256 old_threshold = getThreshold(); + + // a successful call to setup + setup(e,_owners,_threshold,to,data,fallbackHandler, + paymentToken,payment,paymentReceiver); + + uint256 new_threshold = getThreshold(); + + assert ( + new_threshold > 0 && + old_threshold == 0 + ); +} From 2a599c423f772c4d404be9adbe270a28f4ee722a Mon Sep 17 00:00:00 2001 From: ericlehong <193237094+ericlehong@users.noreply.github.com> Date: Thu, 16 Jan 2025 22:14:52 +0800 Subject: [PATCH 34/38] chore: fix typo in certora/specs/OwnerReach.spec (#902) Hello, I found a typo error in `certora/specs/OwnerReach.spec`: `isOwnerNotSelfOrSentinal ` -> `isOwnerNotSelfOrSentinel` Thank you. Signed-off-by: ericlehong <193237094+ericlehong@users.noreply.github.com> --- certora/specs/OwnerReach.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certora/specs/OwnerReach.spec b/certora/specs/OwnerReach.spec index a9d758f65..a2224a3e6 100644 --- a/certora/specs/OwnerReach.spec +++ b/certora/specs/OwnerReach.spec @@ -289,7 +289,7 @@ rule isOwnerDoesNotRevert { assert !lastReverted, "isOwner should not revert"; } -rule isOwnerNotSelfOrSentinal { +rule isOwnerNotSelfOrSentinel { address addr; require addr == currentContract || addr == SENTINEL; requireInvariant self_not_owner(); From 8ebd5059a24e00e24e4481dd9a90b732fde150dc Mon Sep 17 00:00:00 2001 From: Shebin John Date: Tue, 21 Jan 2025 11:12:15 +0100 Subject: [PATCH 35/38] Certora Workfile Updated (#904) This PR adds the FV rules introduced in #901 to the workflow. --- .github/workflows/certora.yml | 2 +- certora/requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/certora.yml b/.github/workflows/certora.yml index acabfb8aa..96580b4bd 100644 --- a/.github/workflows/certora.yml +++ b/.github/workflows/certora.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - rule: ["owner", "safe", "module", "nativeTokenRefund", "signatures", "safeMigration", "safeToL2Migration", "safeToL2Setup"] + rule: ["execute", "extensible", "fallback", "guards", "hash", "module", "nativeTokenRefund", "owner", "safe", "safeMigration", "safeToL2Migration", "safeToL2Setup", "setup", "signatures"] steps: - uses: actions/checkout@v4 diff --git a/certora/requirements.txt b/certora/requirements.txt index df37fea8f..6ab909e71 100644 --- a/certora/requirements.txt +++ b/certora/requirements.txt @@ -1 +1 @@ -certora-cli==7.10.1 +certora-cli==7.22.2 From e9b7de97803ff287f218d055dd06fae31ccf251d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 Jan 2025 10:38:30 +0300 Subject: [PATCH 36/38] Bump undici (#906) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps and [undici](https://github.com/nodejs/undici). These dependencies needed to be updated together. Updates `undici` from 5.28.4 to 6.21.1
Release notes

Sourced from undici's releases.

v6.21.1

⚠️ Security Release ⚠️

Fixes CVE CVE-2025-22150 https://github.com/nodejs/undici/security/advisories/GHSA-c76h-2ccp-4975 (embargoed until 22-01-2025).

What's Changed

Full Changelog: https://github.com/nodejs/undici/compare/v6.21.0...v6.21.1

v6.21.0

What's Changed

Full Changelog: https://github.com/nodejs/undici/compare/v6.20.1...v6.21.0

v6.20.1

What's Changed

Full Changelog: https://github.com/nodejs/undici/compare/v6.20.0...v6.20.1

v6.20.0

What's Changed

... (truncated)

Commits

Updates `undici` from 6.21.0 to 6.21.1
Release notes

Sourced from undici's releases.

v6.21.1

⚠️ Security Release ⚠️

Fixes CVE CVE-2025-22150 https://github.com/nodejs/undici/security/advisories/GHSA-c76h-2ccp-4975 (embargoed until 22-01-2025).

What's Changed

Full Changelog: https://github.com/nodejs/undici/compare/v6.21.0...v6.21.1

v6.21.0

What's Changed

Full Changelog: https://github.com/nodejs/undici/compare/v6.20.1...v6.21.0

v6.20.1

What's Changed

Full Changelog: https://github.com/nodejs/undici/compare/v6.20.0...v6.20.1

v6.20.0

What's Changed

... (truncated)

Commits

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/safe-global/safe-smart-account/network/alerts).
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index 23b8f325a..69e8d41e0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1918,9 +1918,9 @@ } }, "node_modules/@nomicfoundation/hardhat-verify/node_modules/undici": { - "version": "5.28.4", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz", - "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==", + "version": "5.28.5", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.5.tgz", + "integrity": "sha512-zICwjrDrcrUE0pyyJc1I2QzBkLM8FINsgOrt6WjA+BgajVq9Nxu2PbFFXUrAggLfDXlZGZBVZYw7WNV5KiBiBA==", "dev": true, "license": "MIT", "dependencies": { @@ -6889,9 +6889,9 @@ } }, "node_modules/hardhat/node_modules/undici": { - "version": "5.28.4", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz", - "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==", + "version": "5.28.5", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.5.tgz", + "integrity": "sha512-zICwjrDrcrUE0pyyJc1I2QzBkLM8FINsgOrt6WjA+BgajVq9Nxu2PbFFXUrAggLfDXlZGZBVZYw7WNV5KiBiBA==", "dev": true, "license": "MIT", "dependencies": { @@ -11303,9 +11303,9 @@ } }, "node_modules/undici": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.21.0.tgz", - "integrity": "sha512-BUgJXc752Kou3oOIuU1i+yZZypyZRqNPW0vqoMPl8VaoalSfeR0D8/t4iAS3yirs79SSMTxTag+ZC86uswv+Cw==", + "version": "6.21.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.21.1.tgz", + "integrity": "sha512-q/1rj5D0/zayJB2FraXdaWxbhWiNKDvu8naDT2dl1yTlvJp4BLtOcp2a5BvgGNQpYYJzau7tf1WgKv3b+7mqpQ==", "dev": true, "license": "MIT", "engines": { From 1d12d3527bbd567dd137524819d66f1f17889183 Mon Sep 17 00:00:00 2001 From: fanqiaojun <166898955+fanqiaojun@users.noreply.github.com> Date: Wed, 22 Jan 2025 20:40:56 +0800 Subject: [PATCH 37/38] chore: fix param typo (#907) Signed-off-by: fanqiaojun --- src/utils/proxies.ts | 12 ++++++------ test/core/Safe.Setup.spec.ts | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/utils/proxies.ts b/src/utils/proxies.ts index 85b325290..95e1a7a90 100644 --- a/src/utils/proxies.ts +++ b/src/utils/proxies.ts @@ -26,11 +26,11 @@ export const getZkSyncBytecodeHashFromDeployerCallHeader = (proxyCreationCode: s export const calculateProxyAddress = async ( factory: SafeProxyFactory, singleton: string, - inititalizer: string, + initializer: string, nonce: number | string, zkSync: boolean = false, ) => { - const salt = ethers.solidityPackedKeccak256(["bytes32", "uint256"], [ethers.solidityPackedKeccak256(["bytes"], [inititalizer]), nonce]); + const salt = ethers.solidityPackedKeccak256(["bytes32", "uint256"], [ethers.solidityPackedKeccak256(["bytes"], [initializer]), nonce]); const factoryAddress = await factory.getAddress(); const proxyCreationCode = await factory.proxyCreationCode(); @@ -47,26 +47,26 @@ export const calculateProxyAddress = async ( export const calculateProxyAddressWithCallback = async ( factory: SafeProxyFactory, singleton: string, - inititalizer: string, + initializer: string, nonce: number | string, callback: string, zkSync: boolean = false, ) => { const saltNonceWithCallback = ethers.solidityPackedKeccak256(["uint256", "address"], [nonce, callback]); - return calculateProxyAddress(factory, singleton, inititalizer, saltNonceWithCallback, zkSync); + return calculateProxyAddress(factory, singleton, initializer, saltNonceWithCallback, zkSync); }; export const calculateChainSpecificProxyAddress = async ( factory: SafeProxyFactory, singleton: string, - inititalizer: string, + initializer: string, nonce: number | string, chainId: BigNumberish, zkSync: boolean = false, ) => { const salt = ethers.solidityPackedKeccak256( ["bytes32", "uint256", "uint256"], - [ethers.solidityPackedKeccak256(["bytes"], [inititalizer]), nonce, chainId], + [ethers.solidityPackedKeccak256(["bytes"], [initializer]), nonce, chainId], ); const factoryAddress = await factory.getAddress(); const proxyCreationCode = await factory.proxyCreationCode(); diff --git a/test/core/Safe.Setup.spec.ts b/test/core/Safe.Setup.spec.ts index 50eb651da..4b24bd40f 100644 --- a/test/core/Safe.Setup.spec.ts +++ b/test/core/Safe.Setup.spec.ts @@ -211,7 +211,7 @@ describe("Safe", () => { await expect(template.setup([], 0, AddressZero, "0x", AddressZero, AddressZero, 0, AddressZero)).to.be.revertedWith("GS202"); }); - it("should set fallback handler and call sub inititalizer", async () => { + it("should set fallback handler and call sub initializer", async () => { const { template, signers: [user1, user2, user3], From 1c8b24a0a438e8c2cd089a9d830d1688a47a28d5 Mon Sep 17 00:00:00 2001 From: Shebin John Date: Thu, 23 Jan 2025 11:52:17 +0100 Subject: [PATCH 38/38] Adding Code Owners (#905) This pull request includes a small change to the `.github/CODEOWNERS` file. The change assigns ownership of all files to the specified team members. --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 000000000..bd173ad33 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @safe-global/safe-protocol