Browse Source

Merge branch 'master' into typo-fixes

Hadrien Croubois 2 months ago
parent
commit
0f5566d1c0
42 changed files with 523 additions and 193 deletions
  1. 5 0
      .changeset/fast-beans-pull.md
  2. 5 0
      .changeset/whole-cats-find.md
  3. 15 1
      contracts/utils/Bytes.sol
  4. 7 0
      contracts/utils/math/Math.sol
  5. 1 1
      foundry.toml
  6. 1 1
      fv-requirements.txt
  7. 1 0
      hardhat.config.js
  8. 0 69
      hardhat/common-contracts.js
  9. 244 61
      package-lock.json
  10. 4 3
      package.json
  11. 4 4
      test/account/Account.behavior.js
  12. 2 2
      test/account/Account.test.js
  13. 2 2
      test/account/AccountECDSA.test.js
  14. 12 2
      test/account/AccountERC7702.t.sol
  15. 2 2
      test/account/AccountERC7702.test.js
  16. 2 2
      test/account/AccountERC7913.test.js
  17. 2 2
      test/account/AccountMultiSigner.test.js
  18. 2 2
      test/account/AccountMultiSignerWeighted.test.js
  19. 2 2
      test/account/AccountP256.test.js
  20. 2 2
      test/account/AccountRSA.test.js
  21. 2 2
      test/account/AccountWebAuthn.test.js
  22. 2 2
      test/account/examples/AccountERC7702WithModulesMock.test.js
  23. 5 5
      test/account/extensions/AccountERC7579.behavior.js
  24. 2 2
      test/account/extensions/AccountERC7579.test.js
  25. 2 2
      test/account/extensions/AccountERC7579Hooked.test.js
  26. 8 8
      test/account/extensions/ERC7821.behavior.js
  27. 4 4
      test/account/utils/draft-ERC4337Utils.test.js
  28. 10 2
      test/account/utils/draft-ERC7579Utils.t.sol
  29. 0 0
      test/bin/EntryPoint070.abi
  30. BIN
      test/bin/EntryPoint070.bytecode
  31. 0 0
      test/bin/EntryPoint080.abi
  32. BIN
      test/bin/EntryPoint080.bytecode
  33. 0 1
      test/bin/SenderCreator070.abi
  34. BIN
      test/bin/SenderCreator070.bytecode
  35. 0 1
      test/bin/SenderCreator080.abi
  36. BIN
      test/bin/SenderCreator080.bytecode
  37. 3 3
      test/helpers/erc4337.js
  38. 3 3
      test/utils/Blockhash.test.js
  39. 28 0
      test/utils/Bytes.t.sol
  40. 87 0
      test/utils/Bytes.test.js
  41. 19 0
      test/utils/math/Math.t.sol
  42. 33 0
      test/utils/math/Math.test.js

+ 5 - 0
.changeset/fast-beans-pull.md

@@ -0,0 +1,5 @@
+---
+'openzeppelin-solidity': minor
+---
+
+`Bytes`: Add a `clz` function to count the leading zero bits in a `bytes` buffer.

+ 5 - 0
.changeset/whole-cats-find.md

@@ -0,0 +1,5 @@
+---
+'openzeppelin-solidity': minor
+---
+
+`Math`: Add a `clz` function to count the leading zero bits in a `uint256` value.

+ 15 - 1
contracts/utils/Bytes.sol

@@ -128,7 +128,7 @@ library Bytes {
         return buffer;
         return buffer;
     }
     }
 
 
-    /*
+    /**
      * @dev Returns true if the two byte buffers are equal.
      * @dev Returns true if the two byte buffers are equal.
      */
      */
     function equal(bytes memory a, bytes memory b) internal pure returns (bool) {
     function equal(bytes memory a, bytes memory b) internal pure returns (bool) {
@@ -187,6 +187,20 @@ library Bytes {
         return (value >> 8) | (value << 8);
         return (value >> 8) | (value << 8);
     }
     }
 
 
+    /**
+     * @dev Counts the number of leading zero bits a bytes array. Returns `8 * buffer.length`
+     * if the buffer is all zeros.
+     */
+    function clz(bytes memory buffer) internal pure returns (uint256) {
+        for (uint256 i = 0; i < buffer.length; i += 32) {
+            bytes32 chunk = _unsafeReadBytesOffset(buffer, i);
+            if (chunk != bytes32(0)) {
+                return Math.min(8 * i + Math.clz(uint256(chunk)), 8 * buffer.length);
+            }
+        }
+        return 8 * buffer.length;
+    }
+
     /**
     /**
      * @dev Reads a bytes32 from a bytes array without bounds checking.
      * @dev Reads a bytes32 from a bytes array without bounds checking.
      *
      *

+ 7 - 0
contracts/utils/math/Math.sol

@@ -746,4 +746,11 @@ library Math {
     function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
     function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
         return uint8(rounding) % 2 == 1;
         return uint8(rounding) % 2 == 1;
     }
     }
+
+    /**
+     * @dev Counts the number of leading zero bits in a uint256.
+     */
+    function clz(uint256 x) internal pure returns (uint256) {
+        return ternary(x == 0, 256, 255 - log2(x));
+    }
 }
 }

+ 1 - 1
foundry.toml

@@ -8,7 +8,7 @@ out = 'out'
 libs = ['node_modules', 'lib']
 libs = ['node_modules', 'lib']
 test = 'test'
 test = 'test'
 cache_path  = 'cache_forge'
 cache_path  = 'cache_forge'
-fs_permissions = [{ access = "read", path = "./test/bin" }]
+fs_permissions = [{ access = "read", path = "./node_modules/hardhat-predeploy/bin" }]
 
 
 [fuzz]
 [fuzz]
 runs = 5000
 runs = 5000

+ 1 - 1
fv-requirements.txt

@@ -1,4 +1,4 @@
 certora-cli==4.13.1
 certora-cli==4.13.1
 # File uses a custom name (fv-requirements.txt) so that it isn't picked by Netlify's build
 # File uses a custom name (fv-requirements.txt) so that it isn't picked by Netlify's build
 # whose latest Python version is 0.3.8, incompatible with most recent versions of Halmos
 # whose latest Python version is 0.3.8, incompatible with most recent versions of Halmos
-halmos==0.3.0
+halmos==0.3.1

+ 1 - 0
hardhat.config.js

@@ -61,6 +61,7 @@ require('@nomicfoundation/hardhat-ethers');
 require('hardhat-exposed');
 require('hardhat-exposed');
 require('hardhat-gas-reporter');
 require('hardhat-gas-reporter');
 require('hardhat-ignore-warnings');
 require('hardhat-ignore-warnings');
+require('hardhat-predeploy');
 require('solidity-coverage');
 require('solidity-coverage');
 require('solidity-docgen');
 require('solidity-docgen');
 
 

+ 0 - 69
hardhat/common-contracts.js

@@ -1,69 +0,0 @@
-const { task } = require('hardhat/config');
-const { TASK_TEST_SETUP_TEST_ENVIRONMENT } = require('hardhat/builtin-tasks/task-names');
-const { setCode } = require('@nomicfoundation/hardhat-network-helpers');
-
-const fs = require('fs');
-const path = require('path');
-
-const INSTANCES = {
-  // ERC-4337 Entrypoints
-  entrypoint: {
-    v07: {
-      address: '0x0000000071727De22E5E9d8BAf0edAc6f37da032',
-      abi: JSON.parse(fs.readFileSync(path.resolve(__dirname, '../test/bin/EntryPoint070.abi'), 'utf-8')),
-      bytecode: fs.readFileSync(path.resolve(__dirname, '../test/bin/EntryPoint070.bytecode'), 'hex'),
-    },
-    v08: {
-      address: '0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108',
-      abi: JSON.parse(fs.readFileSync(path.resolve(__dirname, '../test/bin/EntryPoint080.abi'), 'utf-8')),
-      bytecode: fs.readFileSync(path.resolve(__dirname, '../test/bin/EntryPoint080.bytecode'), 'hex'),
-    },
-  },
-  senderCreator: {
-    v07: {
-      address: '0xEFC2c1444eBCC4Db75e7613d20C6a62fF67A167C',
-      abi: JSON.parse(fs.readFileSync(path.resolve(__dirname, '../test/bin/SenderCreator070.abi'), 'utf-8')),
-      bytecode: fs.readFileSync(path.resolve(__dirname, '../test/bin/SenderCreator070.bytecode'), 'hex'),
-    },
-    v08: {
-      address: '0x449ED7C3e6Fee6a97311d4b55475DF59C44AdD33',
-      abi: JSON.parse(fs.readFileSync(path.resolve(__dirname, '../test/bin/SenderCreator080.abi'), 'utf-8')),
-      bytecode: fs.readFileSync(path.resolve(__dirname, '../test/bin/SenderCreator080.bytecode'), 'hex'),
-    },
-  },
-  deployer: {
-    // Arachnid's deterministic deployment proxy
-    // See: https://github.com/Arachnid/deterministic-deployment-proxy/tree/master
-    arachnid: {
-      address: '0x4e59b44847b379578588920cA78FbF26c0B4956C',
-      abi: [],
-      bytecode:
-        '0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3',
-    },
-    // Micah's deployer
-    micah: {
-      address: '0x7A0D94F55792C434d74a40883C6ed8545E406D12',
-      abi: [],
-      bytecode: '0x60003681823780368234f58015156014578182fd5b80825250506014600cf3',
-    },
-  },
-  eip2935: {
-    address: '0x0000F90827F1C53a10cb7A02335B175320002935',
-    abi: [],
-    bytecode:
-      '0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500',
-  },
-};
-
-const setup = (input, ethers) =>
-  input.address && input.abi && input.bytecode
-    ? setCode(input.address, '0x' + input.bytecode.replace(/0x/, '')).then(() =>
-        ethers.getContractAt(input.abi, input.address),
-      )
-    : Promise.all(
-        Object.entries(input).map(([name, entry]) => setup(entry, ethers).then(result => [name, result])),
-      ).then(Object.fromEntries);
-
-task(TASK_TEST_SETUP_TEST_ENVIRONMENT).setAction((_, env, runSuper) =>
-  runSuper().then(() => setup(INSTANCES, env.ethers).then(result => Object.assign(env, result))),
-);

+ 244 - 61
package-lock.json

@@ -32,6 +32,7 @@
         "hardhat-exposed": "^0.3.15",
         "hardhat-exposed": "^0.3.15",
         "hardhat-gas-reporter": "^2.1.0",
         "hardhat-gas-reporter": "^2.1.0",
         "hardhat-ignore-warnings": "^0.2.11",
         "hardhat-ignore-warnings": "^0.2.11",
+        "hardhat-predeploy": "^0.2.0",
         "husky": "^9.1.7",
         "husky": "^9.1.7",
         "interoperable-addresses": "^0.1.3",
         "interoperable-addresses": "^0.1.3",
         "lint-staged": "^16.0.0",
         "lint-staged": "^16.0.0",
@@ -42,7 +43,7 @@
         "prettier-plugin-solidity": "^2.0.0",
         "prettier-plugin-solidity": "^2.0.0",
         "rimraf": "^6.0.0",
         "rimraf": "^6.0.0",
         "semver": "^7.3.5",
         "semver": "^7.3.5",
-        "solhint": "^5.0.0",
+        "solhint": "^6.0.0",
         "solhint-plugin-openzeppelin": "file:scripts/solhint-custom",
         "solhint-plugin-openzeppelin": "file:scripts/solhint-custom",
         "solidity-ast": "^0.4.50",
         "solidity-ast": "^0.4.50",
         "solidity-coverage": "^0.8.14",
         "solidity-coverage": "^0.8.14",
@@ -1402,6 +1403,16 @@
         "url": "https://github.com/sponsors/nzakas"
         "url": "https://github.com/sponsors/nzakas"
       }
       }
     },
     },
+    "node_modules/@humanwhocodes/momoa": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/momoa/-/momoa-2.0.4.tgz",
+      "integrity": "sha512-RE815I4arJFtt+FVeU1Tgp9/Xvecacji8w/V6XtXsWWH/wz/eNkNbhb+ny/+PlVZjV0rxQpRSQKNKE3lcktHEA==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=10.10.0"
+      }
+    },
     "node_modules/@humanwhocodes/retry": {
     "node_modules/@humanwhocodes/retry": {
       "version": "0.4.2",
       "version": "0.4.2",
       "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz",
       "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz",
@@ -1723,28 +1734,28 @@
       }
       }
     },
     },
     "node_modules/@nomicfoundation/edr": {
     "node_modules/@nomicfoundation/edr": {
-      "version": "0.11.1",
-      "resolved": "https://registry.npmjs.org/@nomicfoundation/edr/-/edr-0.11.1.tgz",
-      "integrity": "sha512-P97XwcD9DdMMZm9aqw89+mzqzlKmqzSPM3feBES2WVRm5/LOiBYorhpeAX+ANj0X8532SKgxoZK/CN5OWv9vZA==",
+      "version": "0.11.3",
+      "resolved": "https://registry.npmjs.org/@nomicfoundation/edr/-/edr-0.11.3.tgz",
+      "integrity": "sha512-kqILRkAd455Sd6v8mfP3C1/0tCOynJWY+Ir+k/9Boocu2kObCrsFgG+ZWB7fSBVdd9cPVSNrnhWS+V+PEo637g==",
       "dev": true,
       "dev": true,
       "license": "MIT",
       "license": "MIT",
       "dependencies": {
       "dependencies": {
-        "@nomicfoundation/edr-darwin-arm64": "0.11.1",
-        "@nomicfoundation/edr-darwin-x64": "0.11.1",
-        "@nomicfoundation/edr-linux-arm64-gnu": "0.11.1",
-        "@nomicfoundation/edr-linux-arm64-musl": "0.11.1",
-        "@nomicfoundation/edr-linux-x64-gnu": "0.11.1",
-        "@nomicfoundation/edr-linux-x64-musl": "0.11.1",
-        "@nomicfoundation/edr-win32-x64-msvc": "0.11.1"
+        "@nomicfoundation/edr-darwin-arm64": "0.11.3",
+        "@nomicfoundation/edr-darwin-x64": "0.11.3",
+        "@nomicfoundation/edr-linux-arm64-gnu": "0.11.3",
+        "@nomicfoundation/edr-linux-arm64-musl": "0.11.3",
+        "@nomicfoundation/edr-linux-x64-gnu": "0.11.3",
+        "@nomicfoundation/edr-linux-x64-musl": "0.11.3",
+        "@nomicfoundation/edr-win32-x64-msvc": "0.11.3"
       },
       },
       "engines": {
       "engines": {
         "node": ">= 18"
         "node": ">= 18"
       }
       }
     },
     },
     "node_modules/@nomicfoundation/edr-darwin-arm64": {
     "node_modules/@nomicfoundation/edr-darwin-arm64": {
-      "version": "0.11.1",
-      "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.11.1.tgz",
-      "integrity": "sha512-vjca7gkl1o0yYqMjwxQpMEtdsb20nWHBnnxDO8ZBCTD5IwfYT5LiMxFaJo8NUJ7ODIRkF/zuEtAF3W7+ZlC5RA==",
+      "version": "0.11.3",
+      "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.11.3.tgz",
+      "integrity": "sha512-w0tksbdtSxz9nuzHKsfx4c2mwaD0+l5qKL2R290QdnN9gi9AV62p9DHkOgfBdyg6/a6ZlnQqnISi7C9avk/6VA==",
       "dev": true,
       "dev": true,
       "license": "MIT",
       "license": "MIT",
       "engines": {
       "engines": {
@@ -1752,9 +1763,9 @@
       }
       }
     },
     },
     "node_modules/@nomicfoundation/edr-darwin-x64": {
     "node_modules/@nomicfoundation/edr-darwin-x64": {
-      "version": "0.11.1",
-      "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.11.1.tgz",
-      "integrity": "sha512-0aGStHq9XePXX9UqdU1w60HGO9AfYCgkNEir5sBpntU5E0TvZEK6jwyYr667+s90n2mihdeP97QSA0O/6PT6PA==",
+      "version": "0.11.3",
+      "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.11.3.tgz",
+      "integrity": "sha512-QR4jAFrPbOcrO7O2z2ESg+eUeIZPe2bPIlQYgiJ04ltbSGW27FblOzdd5+S3RoOD/dsZGKAvvy6dadBEl0NgoA==",
       "dev": true,
       "dev": true,
       "license": "MIT",
       "license": "MIT",
       "engines": {
       "engines": {
@@ -1762,9 +1773,9 @@
       }
       }
     },
     },
     "node_modules/@nomicfoundation/edr-linux-arm64-gnu": {
     "node_modules/@nomicfoundation/edr-linux-arm64-gnu": {
-      "version": "0.11.1",
-      "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.11.1.tgz",
-      "integrity": "sha512-OWhCETc03PVdtzatW/c2tpOPx+GxlBfBaLmMuGRD1soAr1nMOmg2WZAlo4i6Up9fkQYl+paiYMMFVat1meaMvQ==",
+      "version": "0.11.3",
+      "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.11.3.tgz",
+      "integrity": "sha512-Ktjv89RZZiUmOFPspuSBVJ61mBZQ2+HuLmV67InNlh9TSUec/iDjGIwAn59dx0bF/LOSrM7qg5od3KKac4LJDQ==",
       "dev": true,
       "dev": true,
       "license": "MIT",
       "license": "MIT",
       "engines": {
       "engines": {
@@ -1772,9 +1783,9 @@
       }
       }
     },
     },
     "node_modules/@nomicfoundation/edr-linux-arm64-musl": {
     "node_modules/@nomicfoundation/edr-linux-arm64-musl": {
-      "version": "0.11.1",
-      "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.11.1.tgz",
-      "integrity": "sha512-p0qvtIvDA2eZ8pQ5XUKnWdW1IrwFzSrjyrO88oYx6Lkw8nYwf2JEeETo5o5W84DDfimfoBGP7RWPTPcTBKCaLQ==",
+      "version": "0.11.3",
+      "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.11.3.tgz",
+      "integrity": "sha512-B3sLJx1rL2E9pfdD4mApiwOZSrX0a/KQSBWdlq1uAhFKqkl00yZaY4LejgZndsJAa4iKGQJlGnw4HCGeVt0+jA==",
       "dev": true,
       "dev": true,
       "license": "MIT",
       "license": "MIT",
       "engines": {
       "engines": {
@@ -1782,9 +1793,9 @@
       }
       }
     },
     },
     "node_modules/@nomicfoundation/edr-linux-x64-gnu": {
     "node_modules/@nomicfoundation/edr-linux-x64-gnu": {
-      "version": "0.11.1",
-      "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.11.1.tgz",
-      "integrity": "sha512-V4Us7Q0E8kng3O/czd5GRcxmZxWX+USgqz9yQ3o7DVq7FP96idaKvtcbMQp64tjHf2zNtX2y77sGzgbVau7Bww==",
+      "version": "0.11.3",
+      "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.11.3.tgz",
+      "integrity": "sha512-D/4cFKDXH6UYyKPu6J3Y8TzW11UzeQI0+wS9QcJzjlrrfKj0ENW7g9VihD1O2FvXkdkTjcCZYb6ai8MMTCsaVw==",
       "dev": true,
       "dev": true,
       "license": "MIT",
       "license": "MIT",
       "engines": {
       "engines": {
@@ -1792,9 +1803,9 @@
       }
       }
     },
     },
     "node_modules/@nomicfoundation/edr-linux-x64-musl": {
     "node_modules/@nomicfoundation/edr-linux-x64-musl": {
-      "version": "0.11.1",
-      "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.11.1.tgz",
-      "integrity": "sha512-lCSXsF10Kjjvs5duGbM6pi1WciWHXFNWkMgDAY4pg6ZRIy4gh+uGC6CONMfP4BDZwfrALo2p6+LwyotrJEqpyg==",
+      "version": "0.11.3",
+      "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.11.3.tgz",
+      "integrity": "sha512-ergXuIb4nIvmf+TqyiDX5tsE49311DrBky6+jNLgsGDTBaN1GS3OFwFS8I6Ri/GGn6xOaT8sKu3q7/m+WdlFzg==",
       "dev": true,
       "dev": true,
       "license": "MIT",
       "license": "MIT",
       "engines": {
       "engines": {
@@ -1802,9 +1813,9 @@
       }
       }
     },
     },
     "node_modules/@nomicfoundation/edr-win32-x64-msvc": {
     "node_modules/@nomicfoundation/edr-win32-x64-msvc": {
-      "version": "0.11.1",
-      "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.11.1.tgz",
-      "integrity": "sha512-sNSmmRTURAd1sdKuyO5tqrFiJvHHVPZLM4HB53F21makGoyInFGhejdo3qZrkoinM8k0ewEJDbUp0YuMEgMOhQ==",
+      "version": "0.11.3",
+      "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.11.3.tgz",
+      "integrity": "sha512-snvEf+WB3OV0wj2A7kQ+ZQqBquMcrozSLXcdnMdEl7Tmn+KDCbmFKBt3Tk0X3qOU4RKQpLPnTxdM07TJNVtung==",
       "dev": true,
       "dev": true,
       "license": "MIT",
       "license": "MIT",
       "engines": {
       "engines": {
@@ -2491,13 +2502,23 @@
       "dev": true,
       "dev": true,
       "license": "MIT"
       "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",
-      "integrity": "sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==",
+    "node_modules/@types/lodash": {
+      "version": "4.17.20",
+      "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.20.tgz",
+      "integrity": "sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA==",
       "dev": true,
       "dev": true,
       "license": "MIT"
       "license": "MIT"
     },
     },
+    "node_modules/@types/lodash.merge": {
+      "version": "4.6.9",
+      "resolved": "https://registry.npmjs.org/@types/lodash.merge/-/lodash.merge-4.6.9.tgz",
+      "integrity": "sha512-23sHDPmzd59kUgWyKGiOMO2Qb9YtqRO/x4IhkgNUiPQ1+5MUVqi6bCZeq9nBJ17msjIMbEIO5u+XW4Kz6aGUhQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@types/lodash": "*"
+      }
+    },
     "node_modules/@types/minimatch": {
     "node_modules/@types/minimatch": {
       "version": "5.1.2",
       "version": "5.1.2",
       "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz",
       "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz",
@@ -2652,6 +2673,16 @@
         "url": "https://github.com/sponsors/epoberezkin"
         "url": "https://github.com/sponsors/epoberezkin"
       }
       }
     },
     },
+    "node_modules/ajv-errors": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz",
+      "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==",
+      "dev": true,
+      "license": "MIT",
+      "peerDependencies": {
+        "ajv": ">=5.0.0"
+      }
+    },
     "node_modules/amdefine": {
     "node_modules/amdefine": {
       "version": "1.0.1",
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
       "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
@@ -2855,6 +2886,43 @@
         "safe-buffer": "^5.0.1"
         "safe-buffer": "^5.0.1"
       }
       }
     },
     },
+    "node_modules/better-ajv-errors": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/better-ajv-errors/-/better-ajv-errors-2.0.2.tgz",
+      "integrity": "sha512-1cLrJXEq46n0hjV8dDYwg9LKYjDb3KbeW7nZTv4kvfoDD9c2DXHIE31nxM+Y/cIfXMggLUfmxbm6h/JoM/yotA==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@babel/code-frame": "^7.27.1",
+        "@humanwhocodes/momoa": "^2.0.4",
+        "chalk": "^4.1.2",
+        "jsonpointer": "^5.0.1",
+        "leven": "^3.1.0 < 4"
+      },
+      "engines": {
+        "node": ">= 18.20.6"
+      },
+      "peerDependencies": {
+        "ajv": "4.11.8 - 8"
+      }
+    },
+    "node_modules/better-ajv-errors/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
     "node_modules/better-path-resolve": {
     "node_modules/better-path-resolve": {
       "version": "1.0.0",
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/better-path-resolve/-/better-path-resolve-1.0.0.tgz",
       "resolved": "https://registry.npmjs.org/better-path-resolve/-/better-path-resolve-1.0.0.tgz",
@@ -5437,19 +5505,17 @@
       }
       }
     },
     },
     "node_modules/hardhat": {
     "node_modules/hardhat": {
-      "version": "2.24.3",
-      "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.24.3.tgz",
-      "integrity": "sha512-2dhniQ1wW8/Wh3mP91kKcEnVva93mWYRaYLkV+a0ATkUEKrByGF2P5hCrlNHbqYP//D7L0CGYLtDjPQY6ILaVA==",
+      "version": "2.26.0",
+      "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.26.0.tgz",
+      "integrity": "sha512-hwEUBvMJzl3Iuru5bfMOEDeF2d7cbMNNF46rkwdo8AeW2GDT4VxFLyYWTi6PTLrZiftHPDiKDlAdAiGvsR9FYA==",
       "dev": true,
       "dev": true,
       "license": "MIT",
       "license": "MIT",
       "dependencies": {
       "dependencies": {
         "@ethereumjs/util": "^9.1.0",
         "@ethereumjs/util": "^9.1.0",
         "@ethersproject/abi": "^5.1.2",
         "@ethersproject/abi": "^5.1.2",
-        "@nomicfoundation/edr": "^0.11.1",
+        "@nomicfoundation/edr": "^0.11.3",
         "@nomicfoundation/solidity-analyzer": "^0.1.0",
         "@nomicfoundation/solidity-analyzer": "^0.1.0",
         "@sentry/node": "^5.18.1",
         "@sentry/node": "^5.18.1",
-        "@types/bn.js": "^5.1.0",
-        "@types/lru-cache": "^5.1.0",
         "adm-zip": "^0.4.16",
         "adm-zip": "^0.4.16",
         "aggregate-error": "^3.0.0",
         "aggregate-error": "^3.0.0",
         "ansi-escapes": "^4.3.0",
         "ansi-escapes": "^4.3.0",
@@ -5468,7 +5534,7 @@
         "json-stream-stringify": "^3.1.4",
         "json-stream-stringify": "^3.1.4",
         "keccak": "^3.0.2",
         "keccak": "^3.0.2",
         "lodash": "^4.17.11",
         "lodash": "^4.17.11",
-        "micro-eth-signer": "^0.14.0",
+        "micro-eth-signer": "^0.16.0",
         "mnemonist": "^0.38.0",
         "mnemonist": "^0.38.0",
         "mocha": "^10.0.0",
         "mocha": "^10.0.0",
         "p-map": "^4.0.0",
         "p-map": "^4.0.0",
@@ -5723,6 +5789,39 @@
         "node": ">=10"
         "node": ">=10"
       }
       }
     },
     },
+    "node_modules/hardhat-predeploy": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/hardhat-predeploy/-/hardhat-predeploy-0.2.0.tgz",
+      "integrity": "sha512-/K261ESB4AuI/dkXpO7lv5SScK4MN7io55nJ5N10x6qX6EDddsG7u5rlcqn76CmEHcuHdsEOZAb2ze7TPIKMOw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@types/lodash.merge": "^4.6.9",
+        "@types/node": "^22.13.5",
+        "lodash.merge": "^4.6.2"
+      },
+      "peerDependencies": {
+        "@nomicfoundation/hardhat-ethers": "^3.0.8",
+        "hardhat": "^2.26.0"
+      }
+    },
+    "node_modules/hardhat-predeploy/node_modules/@types/node": {
+      "version": "22.16.4",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-22.16.4.tgz",
+      "integrity": "sha512-PYRhNtZdm2wH/NT2k/oAJ6/f2VD2N2Dag0lGlx2vWgMSJXGNmlce5MiTQzoWAiIJtso30mjnfQCOKVH+kAQC/g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "undici-types": "~6.21.0"
+      }
+    },
+    "node_modules/hardhat-predeploy/node_modules/undici-types": {
+      "version": "6.21.0",
+      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
+      "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
+      "dev": true,
+      "license": "MIT"
+    },
     "node_modules/hardhat/node_modules/@ethereumjs/rlp": {
     "node_modules/hardhat/node_modules/@ethereumjs/rlp": {
       "version": "5.0.2",
       "version": "5.0.2",
       "resolved": "https://registry.npmjs.org/@ethereumjs/rlp/-/rlp-5.0.2.tgz",
       "resolved": "https://registry.npmjs.org/@ethereumjs/rlp/-/rlp-5.0.2.tgz",
@@ -6689,6 +6788,16 @@
         "graceful-fs": "^4.1.6"
         "graceful-fs": "^4.1.6"
       }
       }
     },
     },
+    "node_modules/jsonpointer": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz",
+      "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/jsonschema": {
     "node_modules/jsonschema": {
       "version": "1.5.0",
       "version": "1.5.0",
       "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.5.0.tgz",
       "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.5.0.tgz",
@@ -6751,6 +6860,16 @@
         "url": "https://github.com/sponsors/sindresorhus"
         "url": "https://github.com/sponsors/sindresorhus"
       }
       }
     },
     },
+    "node_modules/leven": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
+      "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
     "node_modules/levn": {
     "node_modules/levn": {
       "version": "0.4.1",
       "version": "0.4.1",
       "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
       "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
@@ -7262,25 +7381,28 @@
       }
       }
     },
     },
     "node_modules/micro-eth-signer": {
     "node_modules/micro-eth-signer": {
-      "version": "0.14.0",
-      "resolved": "https://registry.npmjs.org/micro-eth-signer/-/micro-eth-signer-0.14.0.tgz",
-      "integrity": "sha512-5PLLzHiVYPWClEvZIXXFu5yutzpadb73rnQCpUqIHu3No3coFuWQNfE5tkBQJ7djuLYl6aRLaS0MgWJYGoqiBw==",
+      "version": "0.16.0",
+      "resolved": "https://registry.npmjs.org/micro-eth-signer/-/micro-eth-signer-0.16.0.tgz",
+      "integrity": "sha512-rsSJcMGfY+kt3ROlL3U6y5BcjkK2H0zDKUQV6soo1JvjrctKKe+X7rKB0YIuwhWjlhJIoVHLuRYF+GXyyuVXxQ==",
       "dev": true,
       "dev": true,
       "license": "MIT",
       "license": "MIT",
       "dependencies": {
       "dependencies": {
-        "@noble/curves": "~1.8.1",
-        "@noble/hashes": "~1.7.1",
-        "micro-packed": "~0.7.2"
+        "@noble/curves": "~1.9.2",
+        "@noble/hashes": "2.0.0-beta.1",
+        "micro-packed": "~0.7.3"
+      },
+      "engines": {
+        "node": ">= 20.19.0"
       }
       }
     },
     },
     "node_modules/micro-eth-signer/node_modules/@noble/curves": {
     "node_modules/micro-eth-signer/node_modules/@noble/curves": {
-      "version": "1.8.2",
-      "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.2.tgz",
-      "integrity": "sha512-vnI7V6lFNe0tLAuJMu+2sX+FcL14TaCWy1qiczg1VwRmPrpQCdq5ESXQMqUc2tluRNf6irBXrWbl1mGN8uaU/g==",
+      "version": "1.9.4",
+      "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.4.tgz",
+      "integrity": "sha512-2bKONnuM53lINoDrSmK8qP8W271ms7pygDhZt4SiLOoLwBtoHqeCFi6RG42V8zd3mLHuJFhU/Bmaqo4nX0/kBw==",
       "dev": true,
       "dev": true,
       "license": "MIT",
       "license": "MIT",
       "dependencies": {
       "dependencies": {
-        "@noble/hashes": "1.7.2"
+        "@noble/hashes": "1.8.0"
       },
       },
       "engines": {
       "engines": {
         "node": "^14.21.3 || >=16"
         "node": "^14.21.3 || >=16"
@@ -7289,10 +7411,10 @@
         "url": "https://paulmillr.com/funding/"
         "url": "https://paulmillr.com/funding/"
       }
       }
     },
     },
-    "node_modules/micro-eth-signer/node_modules/@noble/hashes": {
-      "version": "1.7.2",
-      "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.2.tgz",
-      "integrity": "sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ==",
+    "node_modules/micro-eth-signer/node_modules/@noble/curves/node_modules/@noble/hashes": {
+      "version": "1.8.0",
+      "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz",
+      "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==",
       "dev": true,
       "dev": true,
       "license": "MIT",
       "license": "MIT",
       "engines": {
       "engines": {
@@ -7302,6 +7424,19 @@
         "url": "https://paulmillr.com/funding/"
         "url": "https://paulmillr.com/funding/"
       }
       }
     },
     },
+    "node_modules/micro-eth-signer/node_modules/@noble/hashes": {
+      "version": "2.0.0-beta.1",
+      "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-2.0.0-beta.1.tgz",
+      "integrity": "sha512-xnnogJ6ccNZ55lLgWdjhBqKUdFoznjpFr3oy23n5Qm7h+ZMtt8v4zWvHg9zRW6jcETweplD5F4iUqb0SSPC+Dw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 20.19.0"
+      },
+      "funding": {
+        "url": "https://paulmillr.com/funding/"
+      }
+    },
     "node_modules/micro-ftch": {
     "node_modules/micro-ftch": {
       "version": "0.3.1",
       "version": "0.3.1",
       "resolved": "https://registry.npmjs.org/micro-ftch/-/micro-ftch-0.3.1.tgz",
       "resolved": "https://registry.npmjs.org/micro-ftch/-/micro-ftch-0.3.1.tgz",
@@ -9305,20 +9440,23 @@
       }
       }
     },
     },
     "node_modules/solhint": {
     "node_modules/solhint": {
-      "version": "5.0.5",
-      "resolved": "https://registry.npmjs.org/solhint/-/solhint-5.0.5.tgz",
-      "integrity": "sha512-WrnG6T+/UduuzSWsSOAbfq1ywLUDwNea3Gd5hg6PS+pLUm8lz2ECNr0beX609clBxmDeZ3676AiA9nPDljmbJQ==",
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/solhint/-/solhint-6.0.0.tgz",
+      "integrity": "sha512-PQGfwFqfeYdebi2tEG1fhVfMjqSzbW3Noz+LYf8UusKe5nkikCghdgEjYQPcGfFZj4snlVyJQt//AaxkubOtVQ==",
       "dev": true,
       "dev": true,
       "license": "MIT",
       "license": "MIT",
       "dependencies": {
       "dependencies": {
-        "@solidity-parser/parser": "^0.19.0",
+        "@solidity-parser/parser": "^0.20.0",
         "ajv": "^6.12.6",
         "ajv": "^6.12.6",
+        "ajv-errors": "^1.0.1",
         "antlr4": "^4.13.1-patch-1",
         "antlr4": "^4.13.1-patch-1",
         "ast-parents": "^0.0.1",
         "ast-parents": "^0.0.1",
+        "better-ajv-errors": "^2.0.2",
         "chalk": "^4.1.2",
         "chalk": "^4.1.2",
         "commander": "^10.0.0",
         "commander": "^10.0.0",
         "cosmiconfig": "^8.0.0",
         "cosmiconfig": "^8.0.0",
         "fast-diff": "^1.2.0",
         "fast-diff": "^1.2.0",
+        "fs-extra": "^11.1.0",
         "glob": "^8.0.3",
         "glob": "^8.0.3",
         "ignore": "^5.2.4",
         "ignore": "^5.2.4",
         "js-yaml": "^4.1.0",
         "js-yaml": "^4.1.0",
@@ -9341,6 +9479,13 @@
       "resolved": "scripts/solhint-custom",
       "resolved": "scripts/solhint-custom",
       "link": true
       "link": true
     },
     },
+    "node_modules/solhint/node_modules/@solidity-parser/parser": {
+      "version": "0.20.1",
+      "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.20.1.tgz",
+      "integrity": "sha512-58I2sRpzaQUN+jJmWbHfbWf9AKfzqCI8JAdFB0vbyY+u8tBRcuTt9LxzasvR0LGQpcRv97eyV7l61FQ3Ib7zVw==",
+      "dev": true,
+      "license": "MIT"
+    },
     "node_modules/solhint/node_modules/ajv": {
     "node_modules/solhint/node_modules/ajv": {
       "version": "6.12.6",
       "version": "6.12.6",
       "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
       "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@@ -9392,6 +9537,21 @@
         "node": ">=14"
         "node": ">=14"
       }
       }
     },
     },
+    "node_modules/solhint/node_modules/fs-extra": {
+      "version": "11.3.0",
+      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz",
+      "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "graceful-fs": "^4.2.0",
+        "jsonfile": "^6.0.1",
+        "universalify": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=14.14"
+      }
+    },
     "node_modules/solhint/node_modules/glob": {
     "node_modules/solhint/node_modules/glob": {
       "version": "8.1.0",
       "version": "8.1.0",
       "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
       "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
@@ -9433,6 +9593,19 @@
       "dev": true,
       "dev": true,
       "license": "MIT"
       "license": "MIT"
     },
     },
+    "node_modules/solhint/node_modules/jsonfile": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+      "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "universalify": "^2.0.0"
+      },
+      "optionalDependencies": {
+        "graceful-fs": "^4.1.6"
+      }
+    },
     "node_modules/solhint/node_modules/minimatch": {
     "node_modules/solhint/node_modules/minimatch": {
       "version": "5.1.6",
       "version": "5.1.6",
       "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
       "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
@@ -9463,6 +9636,16 @@
         "url": "https://github.com/prettier/prettier?sponsor=1"
         "url": "https://github.com/prettier/prettier?sponsor=1"
       }
       }
     },
     },
+    "node_modules/solhint/node_modules/universalify": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
+      "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 10.0.0"
+      }
+    },
     "node_modules/solidity-ast": {
     "node_modules/solidity-ast": {
       "version": "0.4.60",
       "version": "0.4.60",
       "resolved": "https://registry.npmjs.org/solidity-ast/-/solidity-ast-0.4.60.tgz",
       "resolved": "https://registry.npmjs.org/solidity-ast/-/solidity-ast-0.4.60.tgz",

+ 4 - 3
package.json

@@ -19,7 +19,7 @@
     "lint:fix": "npm run lint:js:fix && npm run lint:sol:fix",
     "lint:fix": "npm run lint:js:fix && npm run lint:sol:fix",
     "lint:js": "prettier --log-level warn --ignore-path .gitignore '**/*.{js,ts}' --check && eslint .",
     "lint:js": "prettier --log-level warn --ignore-path .gitignore '**/*.{js,ts}' --check && eslint .",
     "lint:js:fix": "prettier --log-level warn --ignore-path .gitignore '**/*.{js,ts}' --write && eslint . --fix",
     "lint:js:fix": "prettier --log-level warn --ignore-path .gitignore '**/*.{js,ts}' --write && eslint . --fix",
-    "lint:sol": "prettier --log-level warn --ignore-path .gitignore '{contracts,test}/**/*.sol' --check && solhint '{contracts,test}/**/*.sol'",
+    "lint:sol": "prettier --log-level warn --ignore-path .gitignore '{contracts,test}/**/*.sol' --check && solhint --config solhint.config.js --noPoster '{contracts,test}/**/*.sol'",
     "lint:sol:fix": "prettier --log-level warn --ignore-path .gitignore '{contracts,test}/**/*.sol' --write",
     "lint:sol:fix": "prettier --log-level warn --ignore-path .gitignore '{contracts,test}/**/*.sol' --write",
     "clean": "hardhat clean && rimraf build contracts/build",
     "clean": "hardhat clean && rimraf build contracts/build",
     "prepack": "scripts/prepack.sh",
     "prepack": "scripts/prepack.sh",
@@ -75,6 +75,7 @@
     "hardhat-exposed": "^0.3.15",
     "hardhat-exposed": "^0.3.15",
     "hardhat-gas-reporter": "^2.1.0",
     "hardhat-gas-reporter": "^2.1.0",
     "hardhat-ignore-warnings": "^0.2.11",
     "hardhat-ignore-warnings": "^0.2.11",
+    "hardhat-predeploy": "^0.2.0",
     "husky": "^9.1.7",
     "husky": "^9.1.7",
     "interoperable-addresses": "^0.1.3",
     "interoperable-addresses": "^0.1.3",
     "lint-staged": "^16.0.0",
     "lint-staged": "^16.0.0",
@@ -85,7 +86,7 @@
     "prettier-plugin-solidity": "^2.0.0",
     "prettier-plugin-solidity": "^2.0.0",
     "rimraf": "^6.0.0",
     "rimraf": "^6.0.0",
     "semver": "^7.3.5",
     "semver": "^7.3.5",
-    "solhint": "^5.0.0",
+    "solhint": "^6.0.0",
     "solhint-plugin-openzeppelin": "file:scripts/solhint-custom",
     "solhint-plugin-openzeppelin": "file:scripts/solhint-custom",
     "solidity-ast": "^0.4.50",
     "solidity-ast": "^0.4.50",
     "solidity-coverage": "^0.8.14",
     "solidity-coverage": "^0.8.14",
@@ -100,7 +101,7 @@
     ],
     ],
     "*.sol": [
     "*.sol": [
       "prettier --log-level warn --ignore-path .gitignore --check",
       "prettier --log-level warn --ignore-path .gitignore --check",
-      "solhint"
+      "solhint --config solhint.config.js --noPoster"
     ]
     ]
   }
   }
 }
 }

+ 4 - 4
test/account/Account.behavior.js

@@ -1,4 +1,4 @@
-const { ethers, entrypoint } = require('hardhat');
+const { ethers, predeploy } = require('hardhat');
 const { expect } = require('chai');
 const { expect } = require('chai');
 const { impersonate } = require('../helpers/account');
 const { impersonate } = require('../helpers/account');
 const { SIG_VALIDATION_SUCCESS, SIG_VALIDATION_FAILURE } = require('../helpers/erc4337');
 const { SIG_VALIDATION_SUCCESS, SIG_VALIDATION_FAILURE } = require('../helpers/erc4337');
@@ -8,7 +8,7 @@ function shouldBehaveLikeAccountCore() {
   describe('entryPoint', function () {
   describe('entryPoint', function () {
     it('should return the canonical entrypoint', async function () {
     it('should return the canonical entrypoint', async function () {
       await this.mock.deploy();
       await this.mock.deploy();
-      await expect(this.mock.entryPoint()).to.eventually.equal(entrypoint.v08);
+      await expect(this.mock.entryPoint()).to.eventually.equal(predeploy.entrypoint.v08);
     });
     });
   });
   });
 
 
@@ -30,7 +30,7 @@ function shouldBehaveLikeAccountCore() {
 
 
     describe('when the caller is the canonical entrypoint', function () {
     describe('when the caller is the canonical entrypoint', function () {
       beforeEach(async function () {
       beforeEach(async function () {
-        this.mockFromEntrypoint = this.mock.connect(await impersonate(entrypoint.v08.target));
+        this.mockFromEntrypoint = this.mock.connect(await impersonate(predeploy.entrypoint.v08.target));
       });
       });
 
 
       it('should return SIG_VALIDATION_SUCCESS if the signature is valid', async function () {
       it('should return SIG_VALIDATION_SUCCESS if the signature is valid', async function () {
@@ -59,7 +59,7 @@ function shouldBehaveLikeAccountCore() {
 
 
         await expect(
         await expect(
           this.mockFromEntrypoint.validateUserOp(operation.packed, operation.hash(), value),
           this.mockFromEntrypoint.validateUserOp(operation.packed, operation.hash(), value),
-        ).to.changeEtherBalances([this.mock, entrypoint.v08], [-value, value]);
+        ).to.changeEtherBalances([this.mock, predeploy.entrypoint.v08], [-value, value]);
       });
       });
     });
     });
   });
   });

+ 2 - 2
test/account/Account.test.js

@@ -1,4 +1,4 @@
-const { ethers, entrypoint } = require('hardhat');
+const { ethers, predeploy } = require('hardhat');
 const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
 const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
 
 
 const { getDomain } = require('../helpers/eip712');
 const { getDomain } = require('../helpers/eip712');
@@ -23,7 +23,7 @@ async function fixture() {
   const mock = await helper.newAccount('$AccountMock', ['Account', '1']);
   const mock = await helper.newAccount('$AccountMock', ['Account', '1']);
 
 
   // ERC-4337 Entrypoint domain
   // ERC-4337 Entrypoint domain
-  const entrypointDomain = await getDomain(entrypoint.v08);
+  const entrypointDomain = await getDomain(predeploy.entrypoint.v08);
 
 
   // domain cannot be fetched using getDomain(mock) before the mock is deployed
   // domain cannot be fetched using getDomain(mock) before the mock is deployed
   const domain = { name: 'Account', version: '1', chainId: entrypointDomain.chainId, verifyingContract: mock.address };
   const domain = { name: 'Account', version: '1', chainId: entrypointDomain.chainId, verifyingContract: mock.address };

+ 2 - 2
test/account/AccountECDSA.test.js

@@ -1,4 +1,4 @@
-const { ethers, entrypoint } = require('hardhat');
+const { ethers, predeploy } = require('hardhat');
 const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
 const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
 
 
 const { getDomain } = require('../helpers/eip712');
 const { getDomain } = require('../helpers/eip712');
@@ -22,7 +22,7 @@ async function fixture() {
   const mock = await helper.newAccount('$AccountECDSAMock', [signer, 'AccountECDSA', '1']);
   const mock = await helper.newAccount('$AccountECDSAMock', [signer, 'AccountECDSA', '1']);
 
 
   // ERC-4337 Entrypoint domain
   // ERC-4337 Entrypoint domain
-  const entrypointDomain = await getDomain(entrypoint.v08);
+  const entrypointDomain = await getDomain(predeploy.entrypoint.v08);
 
 
   // domain cannot be fetched using getDomain(mock) before the mock is deployed
   // domain cannot be fetched using getDomain(mock) before the mock is deployed
   const domain = {
   const domain = {

+ 12 - 2
test/account/AccountERC7702.t.sol

@@ -48,8 +48,18 @@ contract AccountERC7702Test is Test {
         vm.signAndAttachDelegation(address(new AccountERC7702MockConstructor()), _signerPrivateKey);
         vm.signAndAttachDelegation(address(new AccountERC7702MockConstructor()), _signerPrivateKey);
 
 
         // Setup entrypoint
         // Setup entrypoint
-        vm.deal(address(ERC4337Utils.ENTRYPOINT_V08), MAX_ETH);
-        vm.etch(address(ERC4337Utils.ENTRYPOINT_V08), vm.readFileBinary("test/bin/EntryPoint070.bytecode"));
+        address entrypoint = address(ERC4337Utils.ENTRYPOINT_V08);
+        vm.deal(entrypoint, MAX_ETH);
+        vm.etch(
+            entrypoint,
+            vm.readFileBinary(
+                string.concat(
+                    "node_modules/hardhat-predeploy/bin/",
+                    Strings.toChecksumHexString(entrypoint),
+                    ".bytecode"
+                )
+            )
+        );
     }
     }
 
 
     function testExecuteBatch(uint256 argA, uint256 argB) public {
     function testExecuteBatch(uint256 argA, uint256 argB) public {

+ 2 - 2
test/account/AccountERC7702.test.js

@@ -1,4 +1,4 @@
-const { ethers, entrypoint } = require('hardhat');
+const { ethers, predeploy } = require('hardhat');
 const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
 const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
 
 
 const { getDomain } = require('../helpers/eip712');
 const { getDomain } = require('../helpers/eip712');
@@ -22,7 +22,7 @@ async function fixture() {
   const mock = await helper.newAccount('$AccountERC7702Mock', ['AccountERC7702Mock', '1'], { erc7702signer: signer });
   const mock = await helper.newAccount('$AccountERC7702Mock', ['AccountERC7702Mock', '1'], { erc7702signer: signer });
 
 
   // ERC-4337 Entrypoint domain
   // ERC-4337 Entrypoint domain
-  const entrypointDomain = await getDomain(entrypoint.v08);
+  const entrypointDomain = await getDomain(predeploy.entrypoint.v08);
 
 
   // domain cannot be fetched using getDomain(mock) before the mock is deployed
   // domain cannot be fetched using getDomain(mock) before the mock is deployed
   const domain = {
   const domain = {

+ 2 - 2
test/account/AccountERC7913.test.js

@@ -1,4 +1,4 @@
-const { ethers, entrypoint } = require('hardhat');
+const { ethers, predeploy } = require('hardhat');
 const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
 const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
 
 
 const { getDomain } = require('../helpers/eip712');
 const { getDomain } = require('../helpers/eip712');
@@ -30,7 +30,7 @@ async function fixture() {
   // ERC-4337 env
   // ERC-4337 env
   const helper = new ERC4337Helper();
   const helper = new ERC4337Helper();
   await helper.wait();
   await helper.wait();
-  const entrypointDomain = await getDomain(entrypoint.v08);
+  const entrypointDomain = await getDomain(predeploy.entrypoint.v08);
   const domain = { name: 'AccountERC7913', version: '1', chainId: entrypointDomain.chainId }; // Missing verifyingContract,
   const domain = { name: 'AccountERC7913', version: '1', chainId: entrypointDomain.chainId }; // Missing verifyingContract,
 
 
   const makeMock = signer =>
   const makeMock = signer =>

+ 2 - 2
test/account/AccountMultiSigner.test.js

@@ -1,4 +1,4 @@
-const { ethers, entrypoint } = require('hardhat');
+const { ethers, predeploy } = require('hardhat');
 const { expect } = require('chai');
 const { expect } = require('chai');
 const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
 const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
 
 
@@ -33,7 +33,7 @@ async function fixture() {
   // ERC-4337 env
   // ERC-4337 env
   const helper = new ERC4337Helper();
   const helper = new ERC4337Helper();
   await helper.wait();
   await helper.wait();
-  const entrypointDomain = await getDomain(entrypoint.v08);
+  const entrypointDomain = await getDomain(predeploy.entrypoint.v08);
   const domain = { name: 'AccountMultiSigner', version: '1', chainId: entrypointDomain.chainId }; // Missing verifyingContract
   const domain = { name: 'AccountMultiSigner', version: '1', chainId: entrypointDomain.chainId }; // Missing verifyingContract
 
 
   const makeMock = (signers, threshold) =>
   const makeMock = (signers, threshold) =>

+ 2 - 2
test/account/AccountMultiSignerWeighted.test.js

@@ -1,4 +1,4 @@
-const { ethers, entrypoint } = require('hardhat');
+const { ethers, predeploy } = require('hardhat');
 const { expect } = require('chai');
 const { expect } = require('chai');
 const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
 const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
 
 
@@ -33,7 +33,7 @@ async function fixture() {
   // ERC-4337 env
   // ERC-4337 env
   const helper = new ERC4337Helper();
   const helper = new ERC4337Helper();
   await helper.wait();
   await helper.wait();
-  const entrypointDomain = await getDomain(entrypoint.v08);
+  const entrypointDomain = await getDomain(predeploy.entrypoint.v08);
   const domain = { name: 'AccountMultiSignerWeighted', version: '1', chainId: entrypointDomain.chainId }; // Missing verifyingContract
   const domain = { name: 'AccountMultiSignerWeighted', version: '1', chainId: entrypointDomain.chainId }; // Missing verifyingContract
 
 
   const makeMock = (signers, weights, threshold) =>
   const makeMock = (signers, weights, threshold) =>

+ 2 - 2
test/account/AccountP256.test.js

@@ -1,4 +1,4 @@
-const { ethers, entrypoint } = require('hardhat');
+const { ethers, predeploy } = require('hardhat');
 const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
 const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
 
 
 const { getDomain } = require('../helpers/eip712');
 const { getDomain } = require('../helpers/eip712');
@@ -28,7 +28,7 @@ async function fixture() {
   ]);
   ]);
 
 
   // ERC-4337 Entrypoint domain
   // ERC-4337 Entrypoint domain
-  const entrypointDomain = await getDomain(entrypoint.v08);
+  const entrypointDomain = await getDomain(predeploy.entrypoint.v08);
 
 
   // domain cannot be fetched using getDomain(mock) before the mock is deployed
   // domain cannot be fetched using getDomain(mock) before the mock is deployed
   const domain = {
   const domain = {

+ 2 - 2
test/account/AccountRSA.test.js

@@ -1,4 +1,4 @@
-const { ethers, entrypoint } = require('hardhat');
+const { ethers, predeploy } = require('hardhat');
 const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
 const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
 
 
 const { getDomain } = require('../helpers/eip712');
 const { getDomain } = require('../helpers/eip712');
@@ -28,7 +28,7 @@ async function fixture() {
   ]);
   ]);
 
 
   // ERC-4337 Entrypoint domain
   // ERC-4337 Entrypoint domain
-  const entrypointDomain = await getDomain(entrypoint.v08);
+  const entrypointDomain = await getDomain(predeploy.entrypoint.v08);
 
 
   // domain cannot be fetched using getDomain(mock) before the mock is deployed
   // domain cannot be fetched using getDomain(mock) before the mock is deployed
   const domain = {
   const domain = {

+ 2 - 2
test/account/AccountWebAuthn.test.js

@@ -1,4 +1,4 @@
-const { ethers, entrypoint } = require('hardhat');
+const { ethers, predeploy } = require('hardhat');
 const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
 const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
 
 
 const { getDomain } = require('../helpers/eip712');
 const { getDomain } = require('../helpers/eip712');
@@ -36,7 +36,7 @@ async function fixture() {
   ]);
   ]);
 
 
   // ERC-4337 Entrypoint domain
   // ERC-4337 Entrypoint domain
-  const entrypointDomain = await getDomain(entrypoint.v08);
+  const entrypointDomain = await getDomain(predeploy.entrypoint.v08);
 
 
   // domain cannot be fetched using getDomain(mock) before the mock is deployed
   // domain cannot be fetched using getDomain(mock) before the mock is deployed
   const domain = {
   const domain = {

+ 2 - 2
test/account/examples/AccountERC7702WithModulesMock.test.js

@@ -1,4 +1,4 @@
-const { ethers, entrypoint } = require('hardhat');
+const { ethers, predeploy } = require('hardhat');
 const { loadFixture, setBalance } = require('@nomicfoundation/hardhat-network-helpers');
 const { loadFixture, setBalance } = require('@nomicfoundation/hardhat-network-helpers');
 
 
 const { getDomain } = require('../../helpers/eip712');
 const { getDomain } = require('../../helpers/eip712');
@@ -32,7 +32,7 @@ async function fixture() {
   });
   });
 
 
   // ERC-4337 Entrypoint domain
   // ERC-4337 Entrypoint domain
-  const entrypointDomain = await getDomain(entrypoint.v08);
+  const entrypointDomain = await getDomain(predeploy.entrypoint.v08);
 
 
   // domain cannot be fetched using getDomain(mock) before the mock is deployed
   // domain cannot be fetched using getDomain(mock) before the mock is deployed
   const domain = {
   const domain = {

+ 5 - 5
test/account/extensions/AccountERC7579.behavior.js

@@ -1,4 +1,4 @@
-const { ethers, entrypoint } = require('hardhat');
+const { ethers, predeploy } = require('hardhat');
 const { expect } = require('chai');
 const { expect } = require('chai');
 const { impersonate } = require('../../helpers/account');
 const { impersonate } = require('../../helpers/account');
 const { selector } = require('../../helpers/methods');
 const { selector } = require('../../helpers/methods');
@@ -37,7 +37,7 @@ function shouldBehaveLikeAccountERC7579({ withHooks = false } = {}) {
       this.modules[MODULE_TYPE_FALLBACK] = await ethers.deployContract('$ERC7579ModuleMock', [MODULE_TYPE_FALLBACK]);
       this.modules[MODULE_TYPE_FALLBACK] = await ethers.deployContract('$ERC7579ModuleMock', [MODULE_TYPE_FALLBACK]);
       this.modules[MODULE_TYPE_HOOK] = await ethers.deployContract('$ERC7579HookMock');
       this.modules[MODULE_TYPE_HOOK] = await ethers.deployContract('$ERC7579HookMock');
 
 
-      this.mockFromEntrypoint = this.mock.connect(await impersonate(entrypoint.v08.target));
+      this.mockFromEntrypoint = this.mock.connect(await impersonate(predeploy.entrypoint.v08.target));
       this.mockFromExecutor = this.mock.connect(await impersonate(this.modules[MODULE_TYPE_EXECUTOR].target));
       this.mockFromExecutor = this.mock.connect(await impersonate(this.modules[MODULE_TYPE_EXECUTOR].target));
     });
     });
 
 
@@ -169,7 +169,7 @@ function shouldBehaveLikeAccountERC7579({ withHooks = false } = {}) {
 
 
             await expect(this.mockFromEntrypoint.installModule(MODULE_TYPE_EXECUTOR, instance, initData))
             await expect(this.mockFromEntrypoint.installModule(MODULE_TYPE_EXECUTOR, instance, initData))
               .to.emit(this.modules[MODULE_TYPE_HOOK], 'PreCheck')
               .to.emit(this.modules[MODULE_TYPE_HOOK], 'PreCheck')
-              .withArgs(entrypoint.v08, 0n, precheckData)
+              .withArgs(predeploy.entrypoint.v08, 0n, precheckData)
               .to.emit(this.modules[MODULE_TYPE_HOOK], 'PostCheck')
               .to.emit(this.modules[MODULE_TYPE_HOOK], 'PostCheck')
               .withArgs(precheckData);
               .withArgs(precheckData);
           });
           });
@@ -254,7 +254,7 @@ function shouldBehaveLikeAccountERC7579({ withHooks = false } = {}) {
             await this.mock.$_installModule(MODULE_TYPE_EXECUTOR, instance, initData);
             await this.mock.$_installModule(MODULE_TYPE_EXECUTOR, instance, initData);
             await expect(this.mockFromEntrypoint.uninstallModule(MODULE_TYPE_EXECUTOR, instance, initData))
             await expect(this.mockFromEntrypoint.uninstallModule(MODULE_TYPE_EXECUTOR, instance, initData))
               .to.emit(this.modules[MODULE_TYPE_HOOK], 'PreCheck')
               .to.emit(this.modules[MODULE_TYPE_HOOK], 'PreCheck')
-              .withArgs(entrypoint.v08, 0n, precheckData)
+              .withArgs(predeploy.entrypoint.v08, 0n, precheckData)
               .to.emit(this.modules[MODULE_TYPE_HOOK], 'PostCheck')
               .to.emit(this.modules[MODULE_TYPE_HOOK], 'PostCheck')
               .withArgs(precheckData);
               .withArgs(precheckData);
           });
           });
@@ -461,7 +461,7 @@ function shouldBehaveLikeAccountERC7579({ withHooks = false } = {}) {
               });
               });
 
 
               it(`should call the hook of the installed module when executing ${execFn}`, async function () {
               it(`should call the hook of the installed module when executing ${execFn}`, async function () {
-                const caller = execFn === 'execute' ? entrypoint.v08 : this.modules[MODULE_TYPE_EXECUTOR];
+                const caller = execFn === 'execute' ? predeploy.entrypoint.v08 : this.modules[MODULE_TYPE_EXECUTOR];
                 const value = 17;
                 const value = 17;
                 const data = this.target.interface.encodeFunctionData('mockFunctionWithArgs', [42, '0x1234']);
                 const data = this.target.interface.encodeFunctionData('mockFunctionWithArgs', [42, '0x1234']);
 
 

+ 2 - 2
test/account/extensions/AccountERC7579.test.js

@@ -1,4 +1,4 @@
-const { ethers, entrypoint } = require('hardhat');
+const { ethers, predeploy } = require('hardhat');
 const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
 const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
 
 
 const { getDomain } = require('../../helpers/eip712');
 const { getDomain } = require('../../helpers/eip712');
@@ -29,7 +29,7 @@ async function fixture() {
   ]);
   ]);
 
 
   // ERC-4337 Entrypoint domain
   // ERC-4337 Entrypoint domain
-  const entrypointDomain = await getDomain(entrypoint.v08);
+  const entrypointDomain = await getDomain(predeploy.entrypoint.v08);
 
 
   return { helper, validator, mock, entrypointDomain, signer, target, anotherTarget, other };
   return { helper, validator, mock, entrypointDomain, signer, target, anotherTarget, other };
 }
 }

+ 2 - 2
test/account/extensions/AccountERC7579Hooked.test.js

@@ -1,4 +1,4 @@
-const { ethers, entrypoint } = require('hardhat');
+const { ethers, predeploy } = require('hardhat');
 const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
 const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
 
 
 const { getDomain } = require('../../helpers/eip712');
 const { getDomain } = require('../../helpers/eip712');
@@ -29,7 +29,7 @@ async function fixture() {
   ]);
   ]);
 
 
   // ERC-4337 Entrypoint domain
   // ERC-4337 Entrypoint domain
-  const entrypointDomain = await getDomain(entrypoint.v08);
+  const entrypointDomain = await getDomain(predeploy.entrypoint.v08);
 
 
   return { helper, validator, mock, entrypointDomain, signer, target, anotherTarget, other };
   return { helper, validator, mock, entrypointDomain, signer, target, anotherTarget, other };
 }
 }

+ 8 - 8
test/account/extensions/ERC7821.behavior.js

@@ -1,4 +1,4 @@
-const { ethers, entrypoint } = require('hardhat');
+const { ethers, predeploy } = require('hardhat');
 const { expect } = require('chai');
 const { expect } = require('chai');
 
 
 const { CALL_TYPE_BATCH, encodeMode, encodeBatch } = require('../../helpers/erc7579');
 const { CALL_TYPE_BATCH, encodeMode, encodeBatch } = require('../../helpers/erc7579');
@@ -50,9 +50,9 @@ function shouldBehaveLikeERC7821({ deployable = true } = {}) {
             .then(op => this.signUserOp(op));
             .then(op => this.signUserOp(op));
 
 
           // Can't call the account to get its nonce before it's deployed
           // Can't call the account to get its nonce before it's deployed
-          await expect(entrypoint.v08.getNonce(this.mock.target, 0)).to.eventually.equal(0);
-          await expect(entrypoint.v08.handleOps([operation.packed], this.beneficiary))
-            .to.emit(entrypoint.v08, 'AccountDeployed')
+          await expect(predeploy.entrypoint.v08.getNonce(this.mock.target, 0)).to.eventually.equal(0);
+          await expect(predeploy.entrypoint.v08.handleOps([operation.packed], this.beneficiary))
+            .to.emit(predeploy.entrypoint.v08, 'AccountDeployed')
             .withArgs(operation.hash(), this.mock, this.helper.factory, ethers.ZeroAddress)
             .withArgs(operation.hash(), this.mock, this.helper.factory, ethers.ZeroAddress)
             .to.emit(this.target, 'MockFunctionCalledExtra')
             .to.emit(this.target, 'MockFunctionCalledExtra')
             .withArgs(this.mock, 17);
             .withArgs(this.mock, 17);
@@ -72,7 +72,7 @@ function shouldBehaveLikeERC7821({ deployable = true } = {}) {
 
 
           operation.signature = '0x00';
           operation.signature = '0x00';
 
 
-          await expect(entrypoint.v08.handleOps([operation.packed], this.beneficiary)).to.be.reverted;
+          await expect(predeploy.entrypoint.v08.handleOps([operation.packed], this.beneficiary)).to.be.reverted;
         });
         });
       });
       });
     }
     }
@@ -94,7 +94,7 @@ function shouldBehaveLikeERC7821({ deployable = true } = {}) {
           .then(op => this.signUserOp(op));
           .then(op => this.signUserOp(op));
 
 
         await expect(this.mock.getNonce()).to.eventually.equal(0);
         await expect(this.mock.getNonce()).to.eventually.equal(0);
-        await expect(entrypoint.v08.handleOps([operation.packed], this.beneficiary))
+        await expect(predeploy.entrypoint.v08.handleOps([operation.packed], this.beneficiary))
           .to.emit(this.target, 'MockFunctionCalledExtra')
           .to.emit(this.target, 'MockFunctionCalledExtra')
           .withArgs(this.mock, 42);
           .withArgs(this.mock, 42);
         await expect(this.mock.getNonce()).to.eventually.equal(1);
         await expect(this.mock.getNonce()).to.eventually.equal(1);
@@ -106,7 +106,7 @@ function shouldBehaveLikeERC7821({ deployable = true } = {}) {
           .then(op => this.signUserOp(op));
           .then(op => this.signUserOp(op));
 
 
         await expect(this.mock.getNonce()).to.eventually.equal(0);
         await expect(this.mock.getNonce()).to.eventually.equal(0);
-        await expect(entrypoint.v08.handleOps([operation.packed], this.beneficiary)).to.changeEtherBalance(
+        await expect(predeploy.entrypoint.v08.handleOps([operation.packed], this.beneficiary)).to.changeEtherBalance(
           this.other,
           this.other,
           42,
           42,
         );
         );
@@ -131,7 +131,7 @@ function shouldBehaveLikeERC7821({ deployable = true } = {}) {
           .then(op => this.signUserOp(op));
           .then(op => this.signUserOp(op));
 
 
         await expect(this.mock.getNonce()).to.eventually.equal(0);
         await expect(this.mock.getNonce()).to.eventually.equal(0);
-        const tx = entrypoint.v08.handleOps([operation.packed], this.beneficiary);
+        const tx = predeploy.entrypoint.v08.handleOps([operation.packed], this.beneficiary);
         await expect(tx).to.changeEtherBalances([this.other, this.target], [value1, value2]);
         await expect(tx).to.changeEtherBalances([this.other, this.target], [value1, value2]);
         await expect(tx).to.emit(this.target, 'MockFunctionCalledExtra').withArgs(this.mock, value2);
         await expect(tx).to.emit(this.target, 'MockFunctionCalledExtra').withArgs(this.mock, value2);
         await expect(this.mock.getNonce()).to.eventually.equal(1);
         await expect(this.mock.getNonce()).to.eventually.equal(1);

+ 4 - 4
test/account/utils/draft-ERC4337Utils.test.js

@@ -1,4 +1,4 @@
-const { ethers, entrypoint } = require('hardhat');
+const { ethers, predeploy } = require('hardhat');
 const { expect } = require('chai');
 const { expect } = require('chai');
 const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
 const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
 
 
@@ -22,11 +22,11 @@ describe('ERC4337Utils', function () {
 
 
   describe('entrypoint', function () {
   describe('entrypoint', function () {
     it('v0.7.0', async function () {
     it('v0.7.0', async function () {
-      await expect(this.utils.$ENTRYPOINT_V07()).to.eventually.equal(entrypoint.v07);
+      await expect(this.utils.$ENTRYPOINT_V07()).to.eventually.equal(predeploy.entrypoint.v07);
     });
     });
 
 
     it('v0.8.0', async function () {
     it('v0.8.0', async function () {
-      await expect(this.utils.$ENTRYPOINT_V08()).to.eventually.equal(entrypoint.v08);
+      await expect(this.utils.$ENTRYPOINT_V08()).to.eventually.equal(predeploy.entrypoint.v08);
     });
     });
   });
   });
 
 
@@ -176,7 +176,7 @@ describe('ERC4337Utils', function () {
   });
   });
 
 
   describe('hash', function () {
   describe('hash', function () {
-    for (const [version, instance] of Object.entries(entrypoint)) {
+    for (const [version, instance] of Object.entries(predeploy.entrypoint)) {
       it(`returns the operation hash for entrypoint ${version}`, async function () {
       it(`returns the operation hash for entrypoint ${version}`, async function () {
         const userOp = new UserOperation({ sender: this.sender, nonce: 1 });
         const userOp = new UserOperation({ sender: this.sender, nonce: 1 });
         const expected = await userOp.hash(instance);
         const expected = await userOp.hash(instance);

+ 10 - 2
test/account/utils/draft-ERC7579Utils.t.sol

@@ -119,8 +119,16 @@ contract ERC7579UtilsTest is Test {
     address private _recipient2;
     address private _recipient2;
 
 
     constructor() {
     constructor() {
-        vm.etch(0x0000000071727De22E5E9d8BAf0edAc6f37da032, vm.readFileBinary("test/bin/EntryPoint070.bytecode"));
-        vm.etch(0xEFC2c1444eBCC4Db75e7613d20C6a62fF67A167C, vm.readFileBinary("test/bin/SenderCreator070.bytecode"));
+        // EntryPoint070
+        vm.etch(
+            0x0000000071727De22E5E9d8BAf0edAc6f37da032,
+            vm.readFileBinary("node_modules/hardhat-predeploy/bin/0x0000000071727De22E5E9d8BAf0edAc6f37da032.bytecode")
+        );
+        // SenderCreator070
+        vm.etch(
+            0xEFC2c1444eBCC4Db75e7613d20C6a62fF67A167C,
+            vm.readFileBinary("node_modules/hardhat-predeploy/bin/0xEFC2c1444eBCC4Db75e7613d20C6a62fF67A167C.bytecode")
+        );
 
 
         // signing key
         // signing key
         (_owner, _ownerKey) = makeAddrAndKey("owner");
         (_owner, _ownerKey) = makeAddrAndKey("owner");

File diff suppressed because it is too large
+ 0 - 0
test/bin/EntryPoint070.abi


BIN
test/bin/EntryPoint070.bytecode


File diff suppressed because it is too large
+ 0 - 0
test/bin/EntryPoint080.abi


BIN
test/bin/EntryPoint080.bytecode


+ 0 - 1
test/bin/SenderCreator070.abi

@@ -1 +0,0 @@
-[{"inputs":[{"internalType":"bytes","name":"initCode","type":"bytes"}],"name":"createSender","outputs":[{"internalType":"address","name":"sender","type":"address"}],"stateMutability":"nonpayable","type":"function"}]

BIN
test/bin/SenderCreator070.bytecode


+ 0 - 1
test/bin/SenderCreator080.abi

@@ -1 +0,0 @@
-[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"opIndex","type":"uint256"},{"internalType":"string","name":"reason","type":"string"},{"internalType":"bytes","name":"inner","type":"bytes"}],"name":"FailedOpWithRevert","type":"error"},{"inputs":[{"internalType":"bytes","name":"initCode","type":"bytes"}],"name":"createSender","outputs":[{"internalType":"address","name":"sender","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"entryPoint","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"bytes","name":"initCallData","type":"bytes"}],"name":"initEip7702Sender","outputs":[],"stateMutability":"nonpayable","type":"function"}]

BIN
test/bin/SenderCreator080.bytecode


+ 3 - 3
test/helpers/erc4337.js

@@ -1,4 +1,4 @@
-const { ethers, config, entrypoint, senderCreator } = require('hardhat');
+const { ethers, config, predeploy } = require('hardhat');
 
 
 const SIG_VALIDATION_SUCCESS = '0x0000000000000000000000000000000000000000';
 const SIG_VALIDATION_SUCCESS = '0x0000000000000000000000000000000000000000';
 const SIG_VALIDATION_FAILURE = '0x0000000000000000000000000000000000000001';
 const SIG_VALIDATION_FAILURE = '0x0000000000000000000000000000000000000001';
@@ -101,8 +101,8 @@ class ERC4337Helper {
 
 
   async newAccount(name, extraArgs = [], params = {}) {
   async newAccount(name, extraArgs = [], params = {}) {
     const env = {
     const env = {
-      entrypoint: params.entrypoint ?? entrypoint.v08,
-      senderCreator: params.senderCreator ?? senderCreator.v08,
+      entrypoint: params.entrypoint ?? predeploy.entrypoint.v08,
+      senderCreator: params.senderCreator ?? predeploy.senderCreator.v08,
     };
     };
 
 
     const { factory } = await this.wait();
     const { factory } = await this.wait();

+ 3 - 3
test/utils/Blockhash.test.js

@@ -1,4 +1,4 @@
-const { ethers, eip2935 } = require('hardhat');
+const { ethers, predeploy } = require('hardhat');
 const { expect } = require('chai');
 const { expect } = require('chai');
 const { loadFixture, mineUpTo, setCode } = require('@nomicfoundation/hardhat-network-helpers');
 const { loadFixture, mineUpTo, setCode } = require('@nomicfoundation/hardhat-network-helpers');
 const { impersonate } = require('../helpers/account');
 const { impersonate } = require('../helpers/account');
@@ -24,9 +24,9 @@ describe('Blockhash', function () {
     describe(`${supported ? 'supported' : 'unsupported'} chain`, function () {
     describe(`${supported ? 'supported' : 'unsupported'} chain`, function () {
       beforeEach(async function () {
       beforeEach(async function () {
         if (supported) {
         if (supported) {
-          await this.systemSigner.sendTransaction({ to: eip2935, data: this.latestBlock.hash });
+          await this.systemSigner.sendTransaction({ to: predeploy.eip2935, data: this.latestBlock.hash });
         } else {
         } else {
-          await setCode(eip2935.target, '0x');
+          await setCode(predeploy.eip2935.target, '0x');
         }
         }
       });
       });
 
 

+ 28 - 0
test/utils/Bytes.t.sol

@@ -196,6 +196,34 @@ contract BytesTest is Test {
         assertEq(Bytes.reverseBytes2(_dirtyBytes2(Bytes.reverseBytes2(value))), value);
         assertEq(Bytes.reverseBytes2(_dirtyBytes2(Bytes.reverseBytes2(value))), value);
     }
     }
 
 
+    // CLZ (Count Leading Zeros)
+    function testClz(bytes memory buffer) public pure {
+        uint256 result = Bytes.clz(buffer);
+
+        // index and offset of the first non zero bit
+        uint256 index = result / 8;
+        uint256 offset = result % 8;
+
+        // Result should never exceed buffer length
+        assertLe(index, buffer.length);
+
+        // All bytes before index position must be zero
+        for (uint256 i = 0; i < index; ++i) {
+            assertEq(buffer[i], 0);
+        }
+
+        // If index < buffer.length, byte at index position must be non-zero
+        if (index < buffer.length) {
+            // bit at position offset must be non zero
+            bytes1 singleBitMask = bytes1(0x80) >> offset;
+            assertEq(buffer[index] & singleBitMask, singleBitMask);
+
+            // all bits before offset must be zero
+            bytes1 multiBitsMask = bytes1(0xff) << (8 - offset);
+            assertEq(buffer[index] & multiBitsMask, 0);
+        }
+    }
+
     // Helpers
     // Helpers
     function _dirtyBytes16(bytes16 value) private pure returns (bytes16 dirty) {
     function _dirtyBytes16(bytes16 value) private pure returns (bytes16 dirty) {
         assembly ("memory-safe") {
         assembly ("memory-safe") {

+ 87 - 0
test/utils/Bytes.test.js

@@ -112,6 +112,93 @@ describe('Bytes', function () {
     });
     });
   });
   });
 
 
+  describe('clz bytes', function () {
+    it('empty buffer', async function () {
+      await expect(this.mock.$clz('0x')).to.eventually.equal(0);
+    });
+
+    it('single zero byte', async function () {
+      await expect(this.mock.$clz('0x00')).to.eventually.equal(8);
+    });
+
+    it('single non-zero byte', async function () {
+      await expect(this.mock.$clz('0x01')).to.eventually.equal(7);
+      await expect(this.mock.$clz('0xff')).to.eventually.equal(0);
+    });
+
+    it('multiple leading zeros', async function () {
+      await expect(this.mock.$clz('0x0000000001')).to.eventually.equal(39);
+      await expect(
+        this.mock.$clz('0x0000000000000000000000000000000000000000000000000000000000000001'),
+      ).to.eventually.equal(255);
+    });
+
+    it('all zeros of various lengths', async function () {
+      await expect(this.mock.$clz('0x00000000')).to.eventually.equal(32);
+      await expect(
+        this.mock.$clz('0x0000000000000000000000000000000000000000000000000000000000000000'),
+      ).to.eventually.equal(256);
+
+      // Complete chunks
+      await expect(this.mock.$clz('0x' + '00'.repeat(32) + '01')).to.eventually.equal(263); // 32*8+7
+      await expect(this.mock.$clz('0x' + '00'.repeat(64) + '01')).to.eventually.equal(519); // 64*8+7
+
+      // Partial last chunk
+      await expect(this.mock.$clz('0x' + '00'.repeat(33) + '01')).to.eventually.equal(271); // 33*8+7
+      await expect(this.mock.$clz('0x' + '00'.repeat(34) + '01')).to.eventually.equal(279); // 34*8+7
+      await expect(this.mock.$clz('0x' + '00'.repeat(40) + '01' + '00'.repeat(9))).to.eventually.equal(327); // 40*8+7
+      await expect(this.mock.$clz('0x' + '00'.repeat(50))).to.eventually.equal(400); // 50*8
+
+      // First byte of each chunk non-zero
+      await expect(this.mock.$clz('0x80' + '00'.repeat(31))).to.eventually.equal(0);
+      await expect(this.mock.$clz('0x01' + '00'.repeat(31))).to.eventually.equal(7);
+      await expect(this.mock.$clz('0x' + '00'.repeat(32) + '80' + '00'.repeat(31))).to.eventually.equal(256); // 32*8
+      await expect(this.mock.$clz('0x' + '00'.repeat(32) + '01' + '00'.repeat(31))).to.eventually.equal(263); // 32*8+7
+
+      // Last byte of each chunk non-zero
+      await expect(this.mock.$clz('0x' + '00'.repeat(31) + '01')).to.eventually.equal(255); // 31*8+7
+      await expect(this.mock.$clz('0x' + '00'.repeat(63) + '01')).to.eventually.equal(511); // 63*8+7
+
+      // Middle byte of each chunk non-zero
+      await expect(this.mock.$clz('0x' + '00'.repeat(16) + '01' + '00'.repeat(15))).to.eventually.equal(135); // 16*8+7
+      await expect(this.mock.$clz('0x' + '00'.repeat(32) + '01' + '00'.repeat(31))).to.eventually.equal(263); // 32*8+7
+      await expect(this.mock.$clz('0x' + '00'.repeat(48) + '01' + '00'.repeat(47))).to.eventually.equal(391); // 48*8+7
+      await expect(this.mock.$clz('0x' + '00'.repeat(64) + '01' + '00'.repeat(63))).to.eventually.equal(519); // 64*8+7
+    });
+  });
+
+  describe('equal', function () {
+    it('identical buffers', async function () {
+      await expect(this.mock.$equal(lorem, lorem)).to.eventually.be.true;
+    });
+
+    it('same content', async function () {
+      const copy = new Uint8Array(lorem);
+      await expect(this.mock.$equal(lorem, copy)).to.eventually.be.true;
+    });
+
+    it('different content', async function () {
+      const different = ethers.toUtf8Bytes('Different content');
+      await expect(this.mock.$equal(lorem, different)).to.eventually.be.false;
+    });
+
+    it('different lengths', async function () {
+      const shorter = lorem.slice(0, 10);
+      await expect(this.mock.$equal(lorem, shorter)).to.eventually.be.false;
+    });
+
+    it('empty buffers', async function () {
+      const empty1 = new Uint8Array(0);
+      const empty2 = new Uint8Array(0);
+      await expect(this.mock.$equal(empty1, empty2)).to.eventually.be.true;
+    });
+
+    it('one empty one not', async function () {
+      const empty = new Uint8Array(0);
+      await expect(this.mock.$equal(lorem, empty)).to.eventually.be.false;
+    });
+  });
+
   describe('reverseBits', function () {
   describe('reverseBits', function () {
     describe('reverseBytes32', function () {
     describe('reverseBytes32', function () {
       it('reverses bytes correctly', async function () {
       it('reverses bytes correctly', async function () {

+ 19 - 0
test/utils/math/Math.t.sol

@@ -308,6 +308,25 @@ contract MathTest is Test {
         }
         }
     }
     }
 
 
+    function testSymbolicCountLeadingZeroes(uint256 x) public pure {
+        uint256 result = Math.clz(x);
+
+        if (x == 0) {
+            assertEq(result, 256);
+        } else {
+            // result in [0, 255]
+            assertLe(result, 255);
+
+            // bit at position offset must be non zero
+            uint256 singleBitMask = uint256(1) << (255 - result);
+            assertEq(x & singleBitMask, singleBitMask);
+
+            // all bits before offset must be zero
+            uint256 multiBitsMask = type(uint256).max << (256 - result);
+            assertEq(x & multiBitsMask, 0);
+        }
+    }
+
     // Helpers
     // Helpers
     function _asRounding(uint8 r) private pure returns (Math.Rounding) {
     function _asRounding(uint8 r) private pure returns (Math.Rounding) {
         vm.assume(r < uint8(type(Math.Rounding).max));
         vm.assume(r < uint8(type(Math.Rounding).max));

+ 33 - 0
test/utils/math/Math.test.js

@@ -710,4 +710,37 @@ describe('Math', function () {
       });
       });
     });
     });
   });
   });
+
+  describe('clz', function () {
+    it('zero value', async function () {
+      await expect(this.mock.$clz(0)).to.eventually.equal(256);
+    });
+
+    it('small values', async function () {
+      await expect(this.mock.$clz(1)).to.eventually.equal(255);
+      await expect(this.mock.$clz(255)).to.eventually.equal(248);
+    });
+
+    it('larger values', async function () {
+      await expect(this.mock.$clz(256)).to.eventually.equal(247);
+      await expect(this.mock.$clz(0xff00)).to.eventually.equal(240);
+      await expect(this.mock.$clz(0x10000)).to.eventually.equal(239);
+    });
+
+    it('max value', async function () {
+      await expect(this.mock.$clz(ethers.MaxUint256)).to.eventually.equal(0);
+    });
+
+    it('specific patterns', async function () {
+      await expect(
+        this.mock.$clz('0x0000000000000000000000000000000000000000000000000000000000000100'),
+      ).to.eventually.equal(247);
+      await expect(
+        this.mock.$clz('0x0000000000000000000000000000000000000000000000000000000000010000'),
+      ).to.eventually.equal(239);
+      await expect(
+        this.mock.$clz('0x0000000000000000000000000000000000000000000000000000000001000000'),
+      ).to.eventually.equal(231);
+    });
+  });
 });
 });

Some files were not shown because too many files changed in this diff