diff --git a/.gitignore b/.gitignore index a99c12ece..9c18d308e 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,6 @@ node_modules # hardhat artifacts cache -typechain-types \ No newline at end of file +typechain-types + +.env \ No newline at end of file diff --git a/packages/contracts/.env.example b/packages/contracts/.env.example deleted file mode 100644 index 3377314dd..000000000 --- a/packages/contracts/.env.example +++ /dev/null @@ -1,18 +0,0 @@ -# L1 -L1_PROVIDER_URL=https://goerli.infura.io/v3/ -L1_ENS_DOMAIN=lineatest.eth -GATEWAY_URL=http://localhost:8080/{sender}/{data}.json - -# # L2 -L2_PROVIDER_URL=https://linea-goerli.infura.io/v3/ -L2_ENS_SUBDOMAIN_TEST=test.lineatest.eth -L2_RESOLVER_NFT_NAME=Lineatest -L2_RESOLVER_NFT_SYMBOL=LTST -L2_RESOLVER_NFT_BASE_URI=http://localhost:3000/metadata/ -L2_RESOLVER_ADDRESS= - -# Keys -PRIVATE_KEY= -ETHERSCAN_API_KEY= -LINEASCAN_API_KEY= - diff --git a/packages/contracts/.eslintignore b/packages/contracts/.eslintignore deleted file mode 100644 index 4e1bfd2d8..000000000 --- a/packages/contracts/.eslintignore +++ /dev/null @@ -1,23 +0,0 @@ -# directories -**/.coverage_artifacts -**/.coverage_cache -**/.coverage_contracts -**/artifacts -**/build -**/cache -**/coverage -**/dist -**/node_modules -**/types - -# files -*.env -*.log -.pnp.* -coverage.json -npm-debug.log* -yarn-debug.log* -yarn-error.log* -gasReporterOutput.json -package.json -.eslintrc.js \ No newline at end of file diff --git a/packages/contracts/.eslintrc.js b/packages/contracts/.eslintrc.js deleted file mode 100644 index 99c934070..000000000 --- a/packages/contracts/.eslintrc.js +++ /dev/null @@ -1,38 +0,0 @@ -module.exports = { - root: true, - extends: "eslint:recommended", - env: { - node: true, - jest: true, - }, - // One configuration for TS files and their rules, a second configuration to json files (package.json) to enforce - // usage of explicit package dependency - overrides: [ - { - files: ["*.ts", "*.js"], - extends: ["plugin:@typescript-eslint/recommended", "plugin:prettier/recommended"], - parserOptions: { - project: "tsconfig.json", - tsconfigRootDir: __dirname, - sourceType: "module", - }, - rules: { - "@typescript-eslint/no-inferrable-types": "off", - }, - }, - // - { - files: ["package.json"], - plugins: ["json-files"], - extends: [ - // Enables eslint-plugin-prettier and eslint-config-prettier. - // This will display Prettier errors as ESLint errors. - // This should always be the last configuration in the extends array. - "plugin:prettier/recommended", - ], - rules: { - "json-files/restrict-ranges": ["error", { versionHint: "pin" }], - }, - }, - ], -}; diff --git a/packages/contracts/.gitignore b/packages/contracts/.gitignore deleted file mode 100644 index 061a94fb5..000000000 --- a/packages/contracts/.gitignore +++ /dev/null @@ -1,26 +0,0 @@ -node_modules -.env -coverage -coverage.json -typechain -typechain-types - -# Hardhat files -cache -artifacts - - -node_modules -.env -coverage -coverage.json -typechain -typechain-types - -# Hardhat files -cache -artifacts - - -# OpenZeppelin -.openzeppelin \ No newline at end of file diff --git a/packages/contracts/.prettierignore b/packages/contracts/.prettierignore deleted file mode 100644 index f97c67360..000000000 --- a/packages/contracts/.prettierignore +++ /dev/null @@ -1,22 +0,0 @@ -# directories -**/.coverage_artifacts -**/.coverage_cache -**/.coverage_contracts -**/artifacts -**/build -**/cache -**/coverage -**/dist -**/node_modules -**/types -**/typechain-types - -# files -*.env -*.log -.pnp.* -coverage.json -npm-debug.log* -yarn-debug.log* -yarn-error.log* -gasReporterOutput.json \ No newline at end of file diff --git a/packages/contracts/.prettierrc.yaml b/packages/contracts/.prettierrc.yaml deleted file mode 100644 index e620912da..000000000 --- a/packages/contracts/.prettierrc.yaml +++ /dev/null @@ -1,16 +0,0 @@ -bracketSpacing: true -endOfLine: auto -importOrder: ["", "^[./]"] -importOrderParserPlugins: ["typescript"] -importOrderSeparation: true -importOrderSortSpecifiers: true -printWidth: 160 -singleQuote: false -tabWidth: 2 -trailingComma: all - -overrides: - - files: "*.sol" - options: - tabWidth: 2 - printWidth: 80 diff --git a/packages/contracts/.solcover.js b/packages/contracts/.solcover.js deleted file mode 100644 index a4e31a1fd..000000000 --- a/packages/contracts/.solcover.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - skipFiles: [], -}; diff --git a/packages/contracts/.solhint.json b/packages/contracts/.solhint.json deleted file mode 100644 index 14055916f..000000000 --- a/packages/contracts/.solhint.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "extends": "solhint:recommended", - "plugins": ["prettier"], - "rules": { - "constructor-syntax": "error", - "func-visibility": ["error", { "ignoreConstructors": true }], - "no-empty-blocks": "off", - "not-rely-on-time": "off", - "prettier/prettier": [ - "error", - { - "endOfLine": "auto" - } - ], - "quotes": ["off", "double"], - "reason-string": ["warn", { "maxLength": 64 }], - "compiler-version": ["off", "0.8.19"] - } -} diff --git a/packages/contracts/README.md b/packages/contracts/README.md deleted file mode 100644 index 468e2b7d4..000000000 --- a/packages/contracts/README.md +++ /dev/null @@ -1,97 +0,0 @@ -# Linea ENS Resolver - -## Documentation - -Linea ENS Resolver allows to resolve ENS domains on Linea. - -Deployment documentation available in [README.md](./../../README.md) - -## Install - -### Packages - -To install packages, execute: - -```shell -yarn -``` - -## Development - -### Compile - -To compile smart contracts, execute: - -```shell -yarn hardhat compile -``` - -### Testing - -To run tests, execute: - -```shell -yarn test -``` - -or - -```shell -npx hardhat test -``` - -To run tests on only one file, execute: - -```shell -npx hardhat test test/L1USDCBridge.ts -``` - -### Test coverage - -This project uses the Hardhat plugin [solidity-coverage](https://github.com/sc-forks/solidity-coverage/blob/master/HARDHAT_README.md) to assess the overall coverage of the unit tests. -To generate a boilerplate report, use the following command: - -```shell -yarn coverage -``` - -or - -```shell -npx hardhat coverage --solcoverjs ./.solcover.js -``` - -The report will be generated in the `coverage` folder at the root of the repository. To visualize it in your web browser, you can use the `coverage/index.html` file. -Note: the second command line might not work if the folder `coverage` already exists. If you encounter an issue, please delete the whole `coverage` folder and let hardhat-coverage regenerate a new one. - -### Contract verification on Etherscan - -```shell - npx hardhat verify --network NETWORK DEPLOYED_CONTRACT_ADDRESS "Constructor argument 1" "Constructor argument 2" -``` - -### Lint Solidity - -```bash -yarn lint:sol -``` - -### Lint TypeScript - -```bash -yarn lint:ts -``` - -### Prettier - -Check format code: - -```bash -yarn prettier:check -``` - -Format code: - -```bash -yarn prettier -``` diff --git a/packages/contracts/abi/ENSRegistry.json b/packages/contracts/abi/ENSRegistry.json deleted file mode 100644 index f380ca8c2..000000000 --- a/packages/contracts/abi/ENSRegistry.json +++ /dev/null @@ -1,202 +0,0 @@ -[ - { - "inputs": [{ "internalType": "contract ENS", "name": "_old", "type": "address" }], - "payable": false, - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "anonymous": false, - "inputs": [ - { "indexed": true, "internalType": "address", "name": "owner", "type": "address" }, - { "indexed": true, "internalType": "address", "name": "operator", "type": "address" }, - { "indexed": false, "internalType": "bool", "name": "approved", "type": "bool" } - ], - "name": "ApprovalForAll", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { "indexed": true, "internalType": "bytes32", "name": "node", "type": "bytes32" }, - { "indexed": true, "internalType": "bytes32", "name": "label", "type": "bytes32" }, - { "indexed": false, "internalType": "address", "name": "owner", "type": "address" } - ], - "name": "NewOwner", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { "indexed": true, "internalType": "bytes32", "name": "node", "type": "bytes32" }, - { "indexed": false, "internalType": "address", "name": "resolver", "type": "address" } - ], - "name": "NewResolver", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { "indexed": true, "internalType": "bytes32", "name": "node", "type": "bytes32" }, - { "indexed": false, "internalType": "uint64", "name": "ttl", "type": "uint64" } - ], - "name": "NewTTL", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { "indexed": true, "internalType": "bytes32", "name": "node", "type": "bytes32" }, - { "indexed": false, "internalType": "address", "name": "owner", "type": "address" } - ], - "name": "Transfer", - "type": "event" - }, - { - "constant": true, - "inputs": [ - { "internalType": "address", "name": "owner", "type": "address" }, - { "internalType": "address", "name": "operator", "type": "address" } - ], - "name": "isApprovedForAll", - "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [], - "name": "old", - "outputs": [{ "internalType": "contract ENS", "name": "", "type": "address" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [{ "internalType": "bytes32", "name": "node", "type": "bytes32" }], - "name": "owner", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [{ "internalType": "bytes32", "name": "node", "type": "bytes32" }], - "name": "recordExists", - "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": true, - "inputs": [{ "internalType": "bytes32", "name": "node", "type": "bytes32" }], - "name": "resolver", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "payable": false, - "stateMutability": "view", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { "internalType": "address", "name": "operator", "type": "address" }, - { "internalType": "bool", "name": "approved", "type": "bool" } - ], - "name": "setApprovalForAll", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { "internalType": "bytes32", "name": "node", "type": "bytes32" }, - { "internalType": "address", "name": "owner", "type": "address" } - ], - "name": "setOwner", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { "internalType": "bytes32", "name": "node", "type": "bytes32" }, - { "internalType": "address", "name": "owner", "type": "address" }, - { "internalType": "address", "name": "resolver", "type": "address" }, - { "internalType": "uint64", "name": "ttl", "type": "uint64" } - ], - "name": "setRecord", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { "internalType": "bytes32", "name": "node", "type": "bytes32" }, - { "internalType": "address", "name": "resolver", "type": "address" } - ], - "name": "setResolver", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { "internalType": "bytes32", "name": "node", "type": "bytes32" }, - { "internalType": "bytes32", "name": "label", "type": "bytes32" }, - { "internalType": "address", "name": "owner", "type": "address" } - ], - "name": "setSubnodeOwner", - "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { "internalType": "bytes32", "name": "node", "type": "bytes32" }, - { "internalType": "bytes32", "name": "label", "type": "bytes32" }, - { "internalType": "address", "name": "owner", "type": "address" }, - { "internalType": "address", "name": "resolver", "type": "address" }, - { "internalType": "uint64", "name": "ttl", "type": "uint64" } - ], - "name": "setSubnodeRecord", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": false, - "inputs": [ - { "internalType": "bytes32", "name": "node", "type": "bytes32" }, - { "internalType": "uint64", "name": "ttl", "type": "uint64" } - ], - "name": "setTTL", - "outputs": [], - "payable": false, - "stateMutability": "nonpayable", - "type": "function" - }, - { - "constant": true, - "inputs": [{ "internalType": "bytes32", "name": "node", "type": "bytes32" }], - "name": "ttl", - "outputs": [{ "internalType": "uint64", "name": "", "type": "uint64" }], - "payable": false, - "stateMutability": "view", - "type": "function" - } -] diff --git a/packages/contracts/contracts/l1/LineaResolverStub.sol b/packages/contracts/contracts/l1/LineaResolverStub.sol deleted file mode 100644 index 1c0e47b08..000000000 --- a/packages/contracts/contracts/l1/LineaResolverStub.sol +++ /dev/null @@ -1,226 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.19; - -import { SparseMerkleProof } from "./lib/SparseMerkleProof.sol"; - -import "hardhat/console.sol"; - -uint256 constant LAST_LEAF_INDEX = 41; - -struct L2StateProof { - bytes[] accountProof; - bytes[] tokenIdProof; - bytes[] addressProof; - uint256 accountLeafIndex; - uint256 tokenIdLeafIndex; - uint256 addressLeafIndex; - bytes accountValue; - bytes32 tokenIdValue; - bytes32 addressValue; - uint256 l2blockNumber; -} - -interface IResolverService { - function resolve( - bytes calldata name, - bytes calldata data - ) external view returns (L2StateProof memory proof); -} - -interface IExtendedResolver { - function resolve( - bytes memory name, - bytes memory data - ) external view returns (bytes memory); -} - -interface ISupportsInterface { - function supportsInterface(bytes4 interfaceID) external pure returns (bool); -} - -interface IRollup { - function stateRootHashes( - uint256 l2blockNumber - ) external view returns (bytes32); -} - -abstract contract SupportsInterface is ISupportsInterface { - function supportsInterface( - bytes4 interfaceID - ) public pure virtual override returns (bool) { - return interfaceID == type(ISupportsInterface).interfaceId; - } -} - -contract LineaResolverStub is IExtendedResolver, SupportsInterface { - string[] public gateways; - address public l2resolver; - address public rollup; - - error OffchainLookup( - address sender, - string[] urls, - bytes callData, - bytes4 callbackFunction, - bytes extraData - ); - - /** - * @dev The Linea Resolver on L1 will use the gateway passed as parameter to resolve - * the node, it needs to the resolver address on L2 to verify the returned result - * as well as the linea rollup address - * @param _gateways the urls to call to get the address from the resolver on L2 - * @param _l2resolver the address of the resolver on L2 - * @param _rollup the address of the linea rollup contract - */ - constructor(string[] memory _gateways, address _l2resolver, address _rollup) { - gateways = _gateways; - l2resolver = _l2resolver; - rollup = _rollup; - } - - /** - * Resolves a name, as specified by ENSIP 10. - * @param name The DNS-encoded name to resolve. - * @param data The ABI encoded data for the underlying resolution function (Eg, addr(bytes32), text(bytes32,string), etc). - * @return The return data, ABI encoded identically to the underlying function. - */ - function resolve( - bytes calldata name, - bytes calldata data - ) external view override returns (bytes memory) { - bytes memory callData = abi.encodeWithSelector( - IResolverService.resolve.selector, - name, - data - ); - - revert OffchainLookup( - address(this), - gateways, - callData, - LineaResolverStub.resolveWithProof.selector, - data - ); - } - - /** - * Callback used by CCIP read compatible clients to verify and parse the response. - */ - function resolveWithProof( - bytes calldata response, - bytes calldata extraData - ) external view returns (bytes memory) { - // We only resolve if the addr(bytes32) is called otherwise we simply return an empty response - bytes4 signature = bytes4(extraData[0:4]); - - if (signature != bytes4(0x3b3b57de)) { - return ""; - } - - // This is the hash name of the domain name - bytes32 node = abi.decode(extraData[4:], (bytes32)); - - L2StateProof memory proof = abi.decode(response, (L2StateProof)); - - bytes32 stateRoot = IRollup(rollup).stateRootHashes(proof.l2blockNumber); - // step 1: check that the right state root was used to calculate the proof - require( - stateRoot != bytes32(0), - "LineaResolverStub: invalid state root" - ); - - // step 2: verify the account proof - // the index slot 251 is for 'mapping(bytes32 => uint256) public addresses' in the L2 resolver - // the index slot 103 is for 'mapping(uint256 => address) private _owners' in the L2 resolver - - bool accountProofVerified = SparseMerkleProof.verifyProof( - proof.accountProof, - proof.accountLeafIndex, - stateRoot - ); - - require(accountProofVerified, "LineaResolverStub: invalid account proof"); - - // Verify the account value - bytes32 hAccountValue = SparseMerkleProof.hashAccountValue( - proof.accountValue - ); - - SparseMerkleProof.Leaf memory accountLeaf = SparseMerkleProof.getLeaf( - proof.accountProof[41] - ); - - require( - accountLeaf.hValue == hAccountValue, - "LineaResolverStub: account value invalid" - ); - - // Get the account to verify the storage values - SparseMerkleProof.Account memory account = SparseMerkleProof.getAccount( - proof.accountValue - ); - - // Calculate the tokenId storage slot to use as key - bytes32 tokenIdSlot = keccak256(abi.encode(node,251)); - - // Verify the tokenId key and value - verifyKeyValue( - account, - proof.tokenIdLeafIndex, - proof.tokenIdProof, - proof.tokenIdValue, - tokenIdSlot - ); - - // Calculate the owner storage slot to use as key - bytes32 ownerSlot = keccak256(abi.encode(proof.tokenIdValue,103)); - - // Verify the address key and value - verifyKeyValue( - account, - proof.addressLeafIndex, - proof.addressProof, - proof.addressValue, - ownerSlot - ); - - return abi.encode(proof.addressValue); - } - - function verifyKeyValue( - SparseMerkleProof.Account memory account, - uint256 leafIndex, - bytes[] memory proof, - bytes32 value, - bytes32 key - ) private pure { - bool storageProofVerified = SparseMerkleProof.verifyProof( - proof, - leafIndex, - account.storageRoot - ); - - require(storageProofVerified, "LineaResolverStub: invalid storage proof"); - - SparseMerkleProof.Leaf memory storageLeaf = SparseMerkleProof.getLeaf( - proof[LAST_LEAF_INDEX] - ); - - // Verify the key - bytes32 hKey = SparseMerkleProof.hashStorageValue(key); - require(storageLeaf.hKey == hKey, "LineaResolverStub: key invalid"); - - // Verify the storage value - bytes32 hValue = SparseMerkleProof.hashStorageValue(value); - require(storageLeaf.hValue == hValue, "LineaResolverStub: value invalid"); - } - - function supportsInterface( - bytes4 interfaceID - ) public pure override returns (bool) { - return - interfaceID == type(IExtendedResolver).interfaceId || - super.supportsInterface(interfaceID); - } -} diff --git a/packages/contracts/contracts/l1/lib/Mimc.sol b/packages/contracts/contracts/l1/lib/Mimc.sol deleted file mode 100644 index 0cd651efc..000000000 --- a/packages/contracts/contracts/l1/lib/Mimc.sol +++ /dev/null @@ -1,679 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -// Copyright 2023 Consensys Software Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Code generated by gnark DO NOT EDIT -pragma solidity 0.8.19; - -library Mimc { - uint256 constant FR_FIELD = - 8444461749428370424248824938781546531375899335154063827935233455917409239041; - - function hash(bytes calldata _msg) external pure returns (bytes32 mimcHash) { - assembly { - let chunks := div(add(_msg.length, 0x1f), 0x20) - - for { - let i := 0 - } lt(i, sub(chunks, 1)) { - i := add(i, 1) - } { - let offset := add(_msg.offset, mul(i, 0x20)) - let chunk := calldataload(offset) - - let r := encrypt(mimcHash, chunk) - mimcHash := addmod(addmod(mimcHash, r, FR_FIELD), chunk, FR_FIELD) - } - - let offset := add(_msg.offset, mul(sub(chunks, 1), 0x20)) - let lastChunk := calldataload(offset) - - if iszero(eq(mod(_msg.length, 0x20), 0)) { - let remaining := mod(_msg.length, 0x20) - lastChunk := shr(mul(sub(0x20, remaining), 0x8), lastChunk) - } - - let r := encrypt(mimcHash, lastChunk) - mimcHash := addmod(addmod(mimcHash, r, FR_FIELD), lastChunk, FR_FIELD) - - function encrypt(h, chunk) -> output { - let frField := FR_FIELD - let tmpSum := 0 - - tmpSum := addmod( - addmod(chunk, h, frField), - 6780559962679281898511952483033644312910028090361101779689089025541625982996, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 2327326745520207001136649348523057964841679868424949608370212081331899020358, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 6201177823658417253260885485467023993767823924255470286063250782233002635405, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 3401276671970505639801802718275229999176446092725813928949571059366811327963, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 796636033841689627732941016044857384234234277501564259311815186813195010627, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 159507412325830262114089631199386481336725966652415909300570415682233424809, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 1669348614406363339435491723584591316524711695667693315027811919444714635748, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 2220664510675218580883672035712942523468288190837741520497926350441362544422, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 1294712289478715410717626660893541311126892630747701030449280341780183665665, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 6758843230175145783288330173723849603007070607311612566540600202723911987180, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 6271650829101108787041306415787253036818921034903891854433479166754956001513, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 8037654458661109859150348337922011363549131313762043865209663327750426111866, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 2450972517788523786981910980516860147992539249204314270739451472218657823669, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 2707650969937705465351357815756127556801434183777713569980595073268026256128, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 7874262417209200618473337039194351886630571503697269268624099887104149796259, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 3089899920017810079637556867207463807565125948241456751227734590626249857937, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 8231877132811199596376758288825197494440517476607659739835166243301765860904, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 4889925300033981791993403687473437637164964770774352761851347729331041993593, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 506118690894045980182310960875885680782486421163823930266542078948815948062, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 4773308728424659273056201947330432214661646691949138677097247858746575076542, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 6610301125072219342086627276930551094394509958433369744427479834611436778066, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 8062913614098409973923064402439991628739389434149534836396892159147794104642, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 2576406140423312875091927795739341819101209176346955562285186911769083519728, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 6247267546819369987508590432055536928557259658317014243676640822343115627202, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 2354620213005699835215298236574714075068230025566107498090395819138978823906, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 1012123997779098542887516673253442986051441272786218052382513879552027657616, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 220252773286234814215172180118321537145064642853938490221604200051823270477, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 2306037967476458159399202685728266972768173510335885477997450635969358782263, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 5906000615460106310157278190403974694555979202144571560620360962365001056276, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 8029952345415718287377564183334920026617762793749604843629313086537726648143, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 6806091261750378774545720021859645013630360296898036304733359077422908323188, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 3791365032107216523624488143755156784159183778414385385850652127088602339940, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 7713951866326004273632564650741019619975760271948208739458822610304231437565, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 2159153222189174173490067225063044363535871059524538695070191871847470955412, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 3459892854150586819083449948613048924207735017129514254460829121652786324530, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 8165919441562399076732808928206069494664474480220235797297111305840352207764, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 5067127638759272574597184239140007718698192996511162583428330546781376830321, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 7564926180046670501077982861476967417487855218354401587881011340975488196742, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 4793316512087044382791577380686883286681140325373390439122763061600650301139, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 12025027725022723723984202199185080936456585195449250668991990971241927925, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 5056480146405086811789505170440731715530475328844870175949109998024731067467, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 3850822128034659558863504800917443538100103152464488164345952697508772708155, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 5490569542353168488797150359760203713598401616662275350850844170956899716180, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 6809916892509991991280249336166027496157481609693382555884367500846199028644, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 6102228360565846712478499570512196976845845959851353003471378423251561935785, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 7957411254301481793006532646538815862020547208300835763521138686017052464640, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 7577948604138385646013244290592520699579040577712519004775644201729392063846, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 6025758357861563690691793181574484773095829890586160167641973490103511417496, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 2004214547184552249779883547311284063339374005887218065319674453115808726850, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 1316449090346410801845183915381769525990226349513436734911941391785200212382, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 4556285572033080226119128815763547597118327635770271287655822355222839175285, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 2369904002063218534853867482545647755243877244064168179905450676831047307618, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 7451702566176584025980909730992154118931318734166468698682947787653334803016, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 1329300832483899103910420486510886619321904846687482243968569167489052205690, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 3238521361072472828313630322811653086792441312858682853521070248794222258735, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 3475214489590830586915334473771293324307275731565327099797069845161869229357, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 4274287601159036159363576568654710230919275259553081321690187920135177947814, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 6938336600682072955973769075275160235517201022692151378695173193891386346405, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 3998198747256139339077883878547228988120873864712400941893285440315291004215, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 6699213631756936754252081929574788294275116402464654263316543921533804167968, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 6962236729635042756258761323749531146700535903704299930132981735734543600942, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - tmpSum := addmod( - addmod(output, h, frField), - 6961288456480688271133399693659146309378114560595485436408179085016705585674, - frField - ) - output := mulmod(tmpSum, tmpSum, frField) - output := mulmod(output, output, frField) - output := mulmod(output, output, frField) - output := mulmod(mulmod(output, output, frField), tmpSum, frField) - - output := addmod(output, h, frField) - } - } - } -} diff --git a/packages/contracts/contracts/l1/lib/SparseMerkleProof.sol b/packages/contracts/contracts/l1/lib/SparseMerkleProof.sol deleted file mode 100644 index 5dc80c118..000000000 --- a/packages/contracts/contracts/l1/lib/SparseMerkleProof.sol +++ /dev/null @@ -1,215 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.19; - -import { Mimc } from "./Mimc.sol"; - -library SparseMerkleProof { - using Mimc for *; - - struct Account { - uint64 nonce; - uint256 balance; - bytes32 storageRoot; - bytes32 mimcCodeHash; - bytes32 keccakCodeHash; - uint64 codeSize; - } - - struct Leaf { - uint256 prev; - uint256 next; - bytes32 hKey; - bytes32 hValue; - } - - error WrongBytesLength(uint256 expectedLength, uint256 bytesLength); - - uint256 internal constant TREE_DEPTH = 40; - - /** - * @notice Format input and verify sparse merkle proof - * @param _rawProof Raw sparse merkle tree proof - * @param _leafIndex Index of the leaf - * @param _root Sparse merkle root - */ - function verifyProof( - bytes[] calldata _rawProof, - uint256 _leafIndex, - bytes32 _root - ) external pure returns (bool) { - ( - bytes32 nextFreeNode, - bytes32 leafHash, - bytes32[] memory proof - ) = _formatProof(_rawProof); - return _verify(proof, leafHash, _leafIndex, _root, nextFreeNode); - } - - /** - * @notice Hash a value using MIMC hash - * @param _input Value to hash - * @return {bytes32} Mimc hash - */ - function mimcHash(bytes calldata _input) external pure returns (bytes32) { - return Mimc.hash(_input); - } - - /** - * @notice Get leaf - * @param _encodedLeaf Encoded leaf bytes (prev, next, hKey, hValue) - * @return Leaf Formatted leaf struct - */ - function getLeaf( - bytes calldata _encodedLeaf - ) external pure returns (Leaf memory) { - return _parseLeaf(_encodedLeaf); - } - - /** - * @notice Get account - * @param _encodedAccountValue Encoded account value bytes (nonce, balance, storageRoot, mimcCodeHash, keccakCodeHash, codeSize) - * @return Account Formatted account struct - */ - function getAccount( - bytes calldata _encodedAccountValue - ) external pure returns (Account memory) { - return _parseAccount(_encodedAccountValue); - } - - /** - * @notice Hash account value - * @param _value Encoded account value bytes (nonce, balance, storageRoot, mimcCodeHash, keccakCodeHash, codeSize) - * @return {bytes32} Account value hash - */ - function hashAccountValue( - bytes calldata _value - ) external pure returns (bytes32) { - Account memory account = _parseAccount(_value); - (bytes32 msb, bytes32 lsb) = _splitBytes32(account.keccakCodeHash); - return - Mimc.hash( - abi.encode( - account.nonce, - account.balance, - account.storageRoot, - account.mimcCodeHash, - lsb, - msb, - account.codeSize - ) - ); - } - - /** - * @notice Hash storage value - * @param _value Encoded storage value bytes - * @return {bytes32} Storage value hash - */ - function hashStorageValue(bytes32 _value) external pure returns (bytes32) { - (bytes32 msb, bytes32 lsb) = _splitBytes32(_value); - return Mimc.hash(abi.encodePacked(lsb, msb)); - } - - /** - * @notice Parse leaf value - * @param _encodedLeaf Encoded leaf bytes (prev, next, hKey, hValue) - * @return {Leaf} Formatted leaf struct - */ - function _parseLeaf( - bytes calldata _encodedLeaf - ) private pure returns (Leaf memory) { - if (_encodedLeaf.length < 128) { - revert WrongBytesLength(128, _encodedLeaf.length); - } - return abi.decode(_encodedLeaf, (Leaf)); - } - - /** - * @notice Parse account value - * @param _value Encoded account value bytes (nonce, balance, storageRoot, mimcCodeHash, keccakCodeHash, codeSize) - * @return {Account} Formatted account struct - */ - function _parseAccount( - bytes calldata _value - ) private pure returns (Account memory) { - if (_value.length < 192) { - revert WrongBytesLength(192, _value.length); - } - return abi.decode(_value, (Account)); - } - - /** - * @notice Split bytes32 into two bytes32 taking most significant bits and least significant bits - * @param _b bytes to split - * @return msb Most significant bits - * @return lsb Least significant bits - */ - function _splitBytes32( - bytes32 _b - ) private pure returns (bytes32 msb, bytes32 lsb) { - assembly { - msb := shr(128, _b) - lsb := and(_b, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) - } - } - - /** - * @notice Format proof - * @param _rawProof Non formatted proof array - * @return (bytes32, bytes32, bytes32[]) NextFreeNode, leafHash and formatted proof array - */ - function _formatProof( - bytes[] calldata _rawProof - ) private pure returns (bytes32, bytes32, bytes32[] memory) { - uint256 rawProofLength = _rawProof.length; - - bytes32[] memory proof = new bytes32[](rawProofLength - 2); - bytes32 nextFreeNode = bytes32(_rawProof[0][:32]); - bytes32 leafHash = Mimc.hash(_rawProof[rawProofLength - 1]); - - for (uint i = 1; i < rawProofLength - 1; ) { - proof[rawProofLength - 2 - i] = Mimc.hash(_rawProof[i]); - unchecked { - ++i; - } - } - - return (nextFreeNode, leafHash, proof); - } - - /** - * @notice Verify sparse merkle proof - * @param _proof Sparse merkle tree proof - * @param _leafHash Leaf hash - * @param _leafIndex Index of the leaf - * @param _root Sparse merkle root - * @param _nextFreeNode Next free node - */ - function _verify( - bytes32[] memory _proof, - bytes32 _leafHash, - uint256 _leafIndex, - bytes32 _root, - bytes32 _nextFreeNode - ) private pure returns (bool) { - bytes32 computedHash = _leafHash; - uint256 currentIndex = _leafIndex; - - for (uint256 height; height < TREE_DEPTH; ) { - if ((currentIndex >> height) & 1 == 1) - computedHash = Mimc.hash( - abi.encodePacked(_proof[height], computedHash) - ); - else - computedHash = Mimc.hash( - abi.encodePacked(computedHash, _proof[height]) - ); - - unchecked { - ++height; - } - } - - return Mimc.hash(abi.encodePacked(_nextFreeNode, computedHash)) == _root; - } -} diff --git a/packages/contracts/contracts/l2/LineaResolver.sol b/packages/contracts/contracts/l2/LineaResolver.sol deleted file mode 100644 index e7cae505a..000000000 --- a/packages/contracts/contracts/l2/LineaResolver.sol +++ /dev/null @@ -1,195 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.18; - -import { ERC721EnumerableUpgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol"; -import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; -import { Counters } from "@openzeppelin/contracts/utils/Counters.sol"; -import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; -import { NameEncoder } from "@ensdomains/ens-contracts/contracts/utils/NameEncoder.sol"; - -/** -@title LineaResolver -@dev A Solidity contract that implements an ERC721 token for resolving Ethereum domain names to addresses. -@author ConsenSys -*/ -contract LineaResolver is ERC721EnumerableUpgradeable, OwnableUpgradeable { - // Mapping to store Ethereum domain names (as bytes32) and their corresponding addresses (as uint256) - mapping(bytes32 => uint256) public addresses; - // Mapping to store token IDs (as uint256) and their corresponding domain name (as string) - mapping(uint256 => string) public tokenDomains; - // Counter to keep track of token IDs for minting new tokens - using Counters for Counters.Counter; - Counters.Counter private _tokenIds; - // Private string variable to store the base URI for the token URI generation - string private _baseTokenURI; - - // Fees to send to mint a sub domain, initial set to 0.001 ETH - uint256 public baseFee; - - uint256 private constant BASE_FEE = 1e15; - - /** - * @dev Emitted when the address associated with a specific node is changed. - * @param node The bytes32 value representing the node whose address is being changed. - * @param a The new address that is being associated with the node. - */ - event AddrChanged(bytes32 indexed node, address a); - - /// @dev Disable constructor for safety - /// @custom:oz-upgrades-unsafe-allow constructor - constructor() { - _disableInitializers(); - } - - /** - * @dev Function to initialize the ERC721 contract with the given name, symbol, and base URI. - * @notice This constructor function is used to initialize the ERC721 contract with the given name, symbol, and base URI. - * @param _name The name of the ERC721 token. - * @param _symbol The symbol of the ERC721 token. - * @param baseURI The base URI for the token URI. - */ - function initialize( - string memory _name, - string memory _symbol, - string memory baseURI - ) external initializer { - __ERC721_init(_name, _symbol); - __Ownable_init(); - _baseTokenURI = baseURI; - _tokenIds.increment(); - baseFee = BASE_FEE; - } - - /** - * @dev Mints a new subdomain token for the given name and address. - * @notice This function is used to mint a new subdomain token for the given name and address. - * @param name The name of the subdomain to mint. - * @param _addr The address associated with the subdomain. - */ - function mintSubdomain(string memory name, address _addr) external payable { - require(msg.value >= baseFee, "LineaResolver: insufficient fees"); - - (, bytes32 node) = NameEncoder.dnsEncodeName(name); - - string memory domain = _toLower(name); - uint256 newItemId = _tokenIds.current(); - - require(addresses[node] == 0, "Sub-domain has already been registered"); - require(bytes(domain).length != 0, "Sub-domain cannot be null"); - - addresses[node] = newItemId; - tokenDomains[newItemId] = domain; - - emit AddrChanged(node, _addr); - _mint(_addr, newItemId); // mint the new token with the current _tokenIds - - _tokenIds.increment(); // increment tokenIds - } - - /** - * @dev Resolves an Ethereum domain. - * @notice This function is used to resolve an Ethereum domain. - * @param node The ENS node to resolve. - * @return The address associated with the resolved ENS node, or address(0) if not found. - */ - function resolve(bytes32 node) external view returns (address) { - uint256 _tokenId = addresses[node]; - if (!_exists(_tokenId)) { - return address(0); - } - return ownerOf(_tokenId); - } - - function exists(uint256 _tokenId) external view returns (bool) { - return _exists(_tokenId); - } - - /** - * @dev Sets the base token URI. - * @notice This function is used to set the base URI for token metadata of an ERC721 contract. - * @param baseURI The new base URI for token metadata. - * @return The updated base token URI. - */ - function setBaseTokenURI( - string memory baseURI - ) external onlyOwner returns (string memory) { - require(bytes(baseURI).length != 0, "Base URI cannot be empty"); - _baseTokenURI = baseURI; - return _baseTokenURI; - } - - /** - * @dev Sets the base fee to mint a sub domain - * @param newBaseFee the new base fee used to send to mint a sub domain - */ - function setBaseFee(uint256 newBaseFee) external onlyOwner { - baseFee = newBaseFee; - } - - /** - * @dev Retrieves the token URI for a specific ERC721 token. - * @notice This function retrieves the token URI associated with the specified ERC721 token ID. - * @param tokenId The ID of the ERC721 token to retrieve the token URI for. - * @return The token URI associated with the specified ERC721 token ID. - */ - function tokenURI( - uint256 tokenId - ) public view override returns (string memory) { - _requireMinted(tokenId); - - string memory _tokenURI = Strings.toString(tokenId); - string memory base = _baseTokenURI; - - // If there is no base URI, return the token URI. - if (bytes(base).length == 0) { - return _tokenURI; - } - // Concatenate the baseURI and tokenURI (via abi.encodePacked). - return string(abi.encodePacked(base, _tokenURI)); - } - - /** - * @dev Retrieves the name associated with a specific ERC721 token. - * @notice This function retrieves the name associated with the specified ERC721 token ID. - * @param tokenId The ID of the ERC721 token to retrieve the name for. - * @return The name associated with the specified ERC721 token ID. - */ - function tokenName(uint256 tokenId) public view returns (string memory) { - return tokenDomains[tokenId]; - } - - /** - * @dev Burns a specific ERC721 token. - * @notice This function is used to burn a specific ERC721 token by its token ID. - * @param tokenId The ID of the ERC721 token to be burned. - */ - function burn(uint256 tokenId) external { - require( - _isApprovedOrOwner(_msgSender(), tokenId), - "Caller is not owner or approved" - ); - _burn(tokenId); - delete tokenDomains[tokenId]; - } - - /** - * @dev Converts a string to lowercase. - * @notice This function takes an input string and converts it to lowercase. - * @param str The input string to be converted to lowercase. - * @return The lowercase version of the input string. - */ - function _toLower(string memory str) internal pure returns (string memory) { - bytes memory bStr = bytes(str); - bytes memory bLower = new bytes(bStr.length); - for (uint i = 0; i < bStr.length; i++) { - // Uppercase character... - if ((uint8(bStr[i]) >= 65) && (uint8(bStr[i]) <= 90)) { - // So we add 32 to make it lowercase - bLower[i] = bytes1(uint8(bStr[i]) + 32); - } else { - bLower[i] = bStr[i]; - } - } - return string(bLower); - } -} diff --git a/packages/contracts/contracts/mocks/FakeRollup.sol b/packages/contracts/contracts/mocks/FakeRollup.sol deleted file mode 100644 index 05063c3c7..000000000 --- a/packages/contracts/contracts/mocks/FakeRollup.sol +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity 0.8.18; - -/** -@title FakeRollup -@dev A mock version of the Linea Rollup contract for the unit tests -@author ConsenSys -*/ -contract FakeRollup { - // root hash of the current rollup state - bytes32 public stateRootHash = - 0x06263c3a0a8795755e30ec09dea189b3bb8e6e93c0037c9cce5c14ac24b992ec; -} diff --git a/packages/contracts/hardhat.config.ts b/packages/contracts/hardhat.config.ts deleted file mode 100644 index b7c05bcb5..000000000 --- a/packages/contracts/hardhat.config.ts +++ /dev/null @@ -1,67 +0,0 @@ -import * as dotenv from "dotenv"; - -import { HardhatUserConfig } from "hardhat/config"; -import "@nomicfoundation/hardhat-toolbox"; -import "solidity-coverage"; -import "@openzeppelin/hardhat-upgrades"; -import "hardhat-storage-layout"; - -const hardhatPrivateKey = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"; - -dotenv.config(); - -const config: HardhatUserConfig = { - solidity: { - compilers: [ - { - version: "0.8.19", - settings: { - optimizer: { - enabled: true, - runs: 200, - }, - }, - }, - { - version: "0.8.18", - settings: { - optimizer: { - enabled: true, - runs: 200, - }, - }, - }, - ], - }, - networks: { - goerli: { - url: process.env.L1_PROVIDER_URL, - accounts: process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [], - }, - goerliLinea: { - url: process.env.L2_PROVIDER_URL, - accounts: process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [], - }, - localhost: { - accounts: process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY, hardhatPrivateKey] : [], - }, - }, - etherscan: { - apiKey: { - goerli: process.env.ETHERSCAN_API_KEY ?? "", - goerliLinea: process.env.LINEASCAN_API_KEY ?? "", - }, - customChains: [ - { - network: "goerliLinea", - chainId: 59140, - urls: { - apiURL: "https://api-goerli.lineascan.build/api", - browserURL: "https://goerli.lineascan.build/", - }, - }, - ], - }, -}; - -export default config; diff --git a/packages/contracts/package.json b/packages/contracts/package.json deleted file mode 100644 index d98a27873..000000000 --- a/packages/contracts/package.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "name": "linea-resolver", - "version": "0.0.1", - "description": "Linea Resolver for ENS", - "main": "index.js", - "author": "Consensys", - "license": "MIT", - "scripts": { - "test": "npx hardhat test", - "coverage": "npx hardhat coverage --solcoverjs ./.solcover.js", - "lint": "yarn lint:sol && yarn lint:ts && yarn prettier:check", - "lint:sol": "solhint --config ./.solhint.json --max-warnings 0 \"contracts/**/*.sol\"", - "lint:ts": "eslint ./ ", - "prettier": "prettier --config ./.prettierrc.yaml --write \"**/*.{js,json,md,sol,ts,yaml,yml}\"", - "prettier:check": "prettier --check --config ./.prettierrc.yaml \"**/*.{js,json,md,sol,ts,yaml,yml}\"", - "compile": "hardhat compile" - }, - "devDependencies": { - "@ethersproject/abi": "^5.4.7", - "@ethersproject/providers": "^5.4.7", - "@nomicfoundation/hardhat-chai-matchers": "^1.0.0", - "@nomicfoundation/hardhat-network-helpers": "^1.0.8", - "@nomicfoundation/hardhat-toolbox": "^2.0.0", - "@nomiclabs/hardhat-ethers": "^2.0.0", - "@nomiclabs/hardhat-etherscan": "^3.0.0", - "@typechain/ethers-v5": "^10.1.0", - "@typechain/hardhat": "^6.1.2", - "@types/chai": "^4.2.0", - "@types/mocha": ">=9.1.0", - "@types/node": ">=12.0.0", - "@typescript-eslint/eslint-plugin": "^5.57.0", - "@typescript-eslint/parser": "^5.57.0", - "chai": "^4.2.0", - "eslint": "^8.37.0", - "eslint-config-prettier": "^8.8.0", - "eslint-plugin-json-files": "^2.1.0", - "eslint-plugin-prettier": "^4.2.1", - "ethers": "^5.4.7", - "hardhat": "^2.12.7", - "hardhat-gas-reporter": "^1.0.9", - "prettier": "^2.8.4", - "prettier-plugin-solidity": "^1.1.3", - "solhint": "^3.4.1", - "solhint-plugin-prettier": "^0.0.5", - "solidity-coverage": "^0.8.3", - "ts-node": ">=8.0.0", - "typechain": "^8.1.0", - "typescript": ">=4.5.0" - }, - "dependencies": { - "@ensdomains/ens-contracts": "^0.0.22", - "@eth-optimism/contracts": "^0.5.40", - "@openzeppelin/contracts": "^4.9.6", - "@openzeppelin/contracts-upgradeable": "^4.9.6", - "@openzeppelin/hardhat-upgrades": "^1.26.0", - "dotenv": "^16.0.3", - "hardhat-storage-layout": "^0.1.7", - "linea-resolver-gateway": "^1.0.0" - } -} \ No newline at end of file diff --git a/packages/contracts/scripts/constants.ts b/packages/contracts/scripts/constants.ts deleted file mode 100644 index b2d22867d..000000000 --- a/packages/contracts/scripts/constants.ts +++ /dev/null @@ -1,11 +0,0 @@ -export const REGISTRY_ADDRESS = { - goerli: "0x114D4603199df73e7D157787f8778E21fCd13066", - hardhat: "0x114D4603199df73e7D157787f8778E21fCd13066", - localhost: "0x114D4603199df73e7D157787f8778E21fCd13066", -}; - -export const ROLLUP_ADDRESS = { - goerli: "0x70BaD09280FD342D02fe64119779BC1f0791BAC2", - hardhat: "0x70BaD09280FD342D02fe64119779BC1f0791BAC2", - localhost: "0x70BaD09280FD342D02fe64119779BC1f0791BAC2", -}; diff --git a/packages/contracts/scripts/copy.ts b/packages/contracts/scripts/copy.ts deleted file mode 100644 index 2ae74af98..000000000 --- a/packages/contracts/scripts/copy.ts +++ /dev/null @@ -1,13 +0,0 @@ -import * as fs from "fs"; -import * as path from "path"; - -export const copyAbiToGateway = () => { - const fromDir = path.join(__dirname, "../artifacts/contracts/l1/LineaResolverStub.sol"); - const toDir = path.join(__dirname, "../../gateway/abi"); - - const jsonFile = fs.readFileSync(path.join(fromDir, "IResolverService.json"), { - encoding: "utf8", - }); - - fs.writeFileSync(path.join(toDir, "IResolverService.json"), jsonFile); -}; diff --git a/packages/contracts/scripts/deployL1.ts b/packages/contracts/scripts/deployL1.ts deleted file mode 100644 index 059f843ce..000000000 --- a/packages/contracts/scripts/deployL1.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { ethers, network, run } from "hardhat"; -import { REGISTRY_ADDRESS, ROLLUP_ADDRESS } from "./constants"; -import ensRegistryAbi from "../abi/ENSRegistry.json"; -import { copyAbiToGateway } from "./copy"; - -const HARDHAT_NETWORK_CHAIN_ID = 31337; - -let L2_RESOLVER_ADDRESS: string; -async function main() { - const [owner, hardhatAccount] = await ethers.getSigners(); - const chainId = await owner.getChainId(); - - // If on localhost we can send ETH to the owner so that we make sure we have enough for deployment - if (chainId === HARDHAT_NETWORK_CHAIN_ID) { - await hardhatAccount.sendTransaction({ value: ethers.utils.parseEther("100"), to: owner.address }); - } - - if (process.env.L2_RESOLVER_ADDRESS) { - L2_RESOLVER_ADDRESS = process.env.L2_RESOLVER_ADDRESS; - } else { - throw "Set L2_RESOLVER_ADDRESS="; - } - - // Deploy Linea Resolver Stub to L1 - const gatewayUrl = process.env.GATEWAY_URL ? process.env.GATEWAY_URL : "http://localhost:8080/{sender}/{data}.json"; - const rollupAddr = ROLLUP_ADDRESS[network.name as keyof typeof ROLLUP_ADDRESS]; - - const Mimc = await ethers.getContractFactory("Mimc"); - const mimc = await Mimc.deploy(); - - const SparseMerkleProof = await ethers.getContractFactory("SparseMerkleProof", { - libraries: { - Mimc: mimc.address, - }, - }); - const sparseMerkleProof = await SparseMerkleProof.deploy(); - - const LineaResolverStub = await ethers.getContractFactory("LineaResolverStub", { - libraries: { - SparseMerkleProof: sparseMerkleProof.address, - }, - }); - const lineaResolverStub = await LineaResolverStub.deploy([gatewayUrl], L2_RESOLVER_ADDRESS, rollupAddr); - await lineaResolverStub.deployed(); - console.log(`LineaResolverStub deployed to ${lineaResolverStub.address}`); - const registryAddr = REGISTRY_ADDRESS[network.name as keyof typeof REGISTRY_ADDRESS]; - const registry = await new ethers.Contract(registryAddr, ensRegistryAbi, owner); - const name = process.env.L1_ENS_DOMAIN ? process.env.L1_ENS_DOMAIN : "lineatest.eth"; - const node = ethers.utils.namehash(name); - const tx = await registry.setResolver(node, lineaResolverStub.address); - await tx.wait(); - console.log("L1 ENS name:", name, ", set to LineaResolverStub: ", lineaResolverStub.address); - - // Copy the Abi to the gateway folder - copyAbiToGateway(); - - if (chainId !== HARDHAT_NETWORK_CHAIN_ID) { - // Only verify on "live" blockchain - setTimeout(async () => { - console.log("Verify on Etherscan"); - try { - await run("verify:verify", { - address: lineaResolverStub.address, - constructorArguments: [[gatewayUrl], L2_RESOLVER_ADDRESS, rollupAddr], - }); - } catch (error) { - console.error(error.message); - } - }, 20000); - } -} - -// We recommend this pattern to be able to use async/await everywhere -// and properly handle errors. -main().catch((error) => { - console.error(error); - process.exitCode = 1; -}); diff --git a/packages/contracts/scripts/deployL2.ts b/packages/contracts/scripts/deployL2.ts deleted file mode 100644 index 778f2957e..000000000 --- a/packages/contracts/scripts/deployL2.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { ethers, run, upgrades } from "hardhat"; - -async function main() { - const [owner] = await ethers.getSigners(); - const chainId = await owner.getChainId(); - - // Deploy Linea Resolver to L2 - const LineaResolver = await ethers.getContractFactory("LineaResolver"); - const nftName = process.env.L2_RESOLVER_NFT_NAME; - const symbol = process.env.L2_RESOLVER_NFT_SYMBOL; - const baseUri = process.env.L2_RESOLVER_NFT_BASE_URI; - const lineaResolver = await upgrades.deployProxy(LineaResolver, [nftName, symbol, baseUri]); - await lineaResolver.deployed(); - console.log(`LineaResolver deployed to, L2_RESOLVER_ADDRESS: ${lineaResolver.address}`); - // Test with subdomain with default "test.lineatest.eth", assuming we still control lineatest.eth on L1 - const name = process.env.L2_ENS_SUBDOMAIN_TEST; - const tx = await lineaResolver.mintSubdomain(name, owner.address, { value: ethers.utils.parseEther("0.001") }); - await tx.wait(); - console.log(`Subdomain minted: ${process.env.L2_ENS_SUBDOMAIN_TEST}`); - - if (chainId !== 31337) { - // Only verify on "live" blockchain - setTimeout(async () => { - console.log("Verify on Lineascan"); - try { - await run("verify:verify", { - address: lineaResolver.address, - }); - } catch (error) { - console.error(error.message); - } - }, 30000); - } -} - -// We recommend this pattern to be able to use async/await everywhere -// and properly handle errors. -main().catch((error) => { - console.error(error); - process.exitCode = 1; -}); diff --git a/packages/contracts/test/LineaResolver.ts b/packages/contracts/test/LineaResolver.ts deleted file mode 100644 index 090546694..000000000 --- a/packages/contracts/test/LineaResolver.ts +++ /dev/null @@ -1,217 +0,0 @@ -import { loadFixture } from "@nomicfoundation/hardhat-network-helpers"; -import { ethers, upgrades } from "hardhat"; -import { expect } from "chai"; -import { constants } from "ethers"; - -describe("LineaResolver", function () { - async function deployContractsFixture() { - const [owner, unknown] = await ethers.getSigners(); - - const baseFee = 1000000000000000; - const domain = "julink.lineatest.eth"; - const hash = ethers.utils.namehash(domain); - - const undefinedDomain = "undefined.lineatest.eth"; - const undefinedHash = ethers.utils.namehash(undefinedDomain); - - // Deploy Resolver - const LineaResolver = await ethers.getContractFactory("LineaResolver"); - const nftName = "Lineatest"; - const symbol = "LTST"; - const baseUri = "http://localhost:3000/metadata/"; - const lineaResolver = await upgrades.deployProxy(LineaResolver, [nftName, symbol, baseUri]); - await lineaResolver.deployed(); - - // Mint domain - await lineaResolver.mintSubdomain(domain, owner.address, { value: baseFee }); - - return { - owner, - unknown, - domain, - baseUri, - lineaResolver, - hash, - undefinedHash, - baseFee, - }; - } - - describe("mintSubdomain", async () => { - it("Should format the domain to lowercase", async function () { - const { lineaResolver, owner, baseFee } = await loadFixture(deployContractsFixture); - - const domain = "JULINK42.lineatest.eth"; - await lineaResolver.mintSubdomain(domain, owner.address, { value: baseFee }); - const name = await lineaResolver.tokenName(2); - - expect(name).to.be.equal(domain.toLowerCase()); - }); - - it("Should revert if the fees are too low", async function () { - const { lineaResolver, owner, baseFee } = await loadFixture(deployContractsFixture); - - const domain = "JULINK42.lineatest.eth"; - const tooLowFee = baseFee - 1; - - await expect(lineaResolver.mintSubdomain(domain, owner.address, { value: tooLowFee })).to.be.revertedWith("LineaResolver: insufficient fees"); - }); - - it("Should not be able to mint twice the same sub domain", async function () { - const { lineaResolver, owner, baseFee, domain } = await loadFixture(deployContractsFixture); - - await expect(lineaResolver.mintSubdomain(domain, owner.address, { value: baseFee })).to.be.revertedWith("Sub-domain has already been registered"); - }); - - it("Should not be able to mint an empty domain", async function () { - const { lineaResolver, owner, baseFee } = await loadFixture(deployContractsFixture); - - await expect(lineaResolver.mintSubdomain("", owner.address, { value: baseFee })).to.be.revertedWith("Sub-domain cannot be null"); - }); - }); - - describe("resolve", async () => { - it("Should be able to resolve an address given a hashname", async function () { - const { lineaResolver, hash, owner } = await loadFixture(deployContractsFixture); - - expect(await lineaResolver.resolve(hash)).to.be.equal(owner.address); - }); - - it("Resolve should send address(0) if the hash has not been minted", async function () { - const { lineaResolver, undefinedHash } = await loadFixture(deployContractsFixture); - - expect(await lineaResolver.resolve(undefinedHash)).to.be.equal(constants.AddressZero); - }); - }); - - describe("exists", async () => { - it("Should be able to check if an tokenId exists", async function () { - const { lineaResolver } = await loadFixture(deployContractsFixture); - - expect(await lineaResolver.exists(1)).to.be.equal(true); - expect(await lineaResolver.exists(10)).to.be.equal(false); - }); - }); - - describe("setBaseTokenURI", async () => { - it("Should be able to change the base URI for tokens", async function () { - const newBaseUri = "http://localhost:3001/metadata/"; - const tokenId = 1; - const { lineaResolver } = await loadFixture(deployContractsFixture); - - await lineaResolver.setBaseTokenURI(newBaseUri); - const tokenURI = await lineaResolver.tokenURI(tokenId); - - expect(tokenURI).to.be.equal(new URL(tokenId.toString(), newBaseUri).toString()); - }); - - it("Should revert if Base URI is empty", async function () { - const { lineaResolver } = await loadFixture(deployContractsFixture); - - await expect(lineaResolver.setBaseTokenURI("")).to.be.revertedWith("Base URI cannot be empty"); - }); - - it("Should not be able to be called by non-owner", async function () { - const { lineaResolver, unknown } = await loadFixture(deployContractsFixture); - const newBaseUri = "http://localhost:3001/metadata/"; - - await expect(lineaResolver.connect(unknown).setBaseTokenURI(newBaseUri)).to.be.revertedWith("Ownable: caller is not the owner"); - }); - }); - - describe("tokenURI", async () => { - it("Should return token uri", async function () { - const tokenId = 1; - const { lineaResolver, baseUri } = await loadFixture(deployContractsFixture); - - const expectedUri = new URL(tokenId.toString(), baseUri).toString(); - const tokenUri = await lineaResolver.tokenURI(tokenId); - - await expect(tokenUri).to.be.equal(expectedUri); - }); - - it("Should revert if token does not exists", async function () { - const tokenId = 0; - const { lineaResolver } = await loadFixture(deployContractsFixture); - - await expect(lineaResolver.tokenURI(tokenId)).to.be.revertedWith("ERC721: invalid token ID"); - }); - - it("Should return only tokenId when Base URI is empty", async function () { - const { domain, owner, baseFee } = await loadFixture(deployContractsFixture); - - // Deploy Resolver - const LineaResolver = await ethers.getContractFactory("LineaResolver"); - const nftName = "Lineatest"; - const symbol = "LTST"; - const baseUri = ""; - const lineaResolver = await upgrades.deployProxy(LineaResolver, [nftName, symbol, baseUri]); - await lineaResolver.deployed(); - - const tokenId = 1; - // Mint domain - await lineaResolver.mintSubdomain(domain, owner.address, { value: baseFee }); - - const tokenUri = await lineaResolver.tokenURI(tokenId); - - await expect(tokenUri).to.be.equal(tokenId.toString()); - }); - }); - - describe("tokenName", async () => { - it("Should return token name", async function () { - const tokenId = 1; - const { lineaResolver, domain } = await loadFixture(deployContractsFixture); - - const name = await lineaResolver.tokenName(tokenId); - - await expect(name).to.be.equal(domain); - }); - }); - - describe("setBaseFee", async () => { - it("Should change the base fee", async function () { - const newbaseFee = 2000000000000000; - const { lineaResolver, baseFee } = await loadFixture(deployContractsFixture); - - expect(await lineaResolver.baseFee()).to.equal(baseFee); - await lineaResolver.setBaseFee(newbaseFee); - const fee = await lineaResolver.baseFee(); - - await expect(fee).to.be.equal(newbaseFee); - }); - - it("Should revert if caller is not owner", async function () { - const newbaseFee = 2000000000000000; - const { lineaResolver, unknown } = await loadFixture(deployContractsFixture); - - await expect(lineaResolver.connect(unknown).setBaseFee(newbaseFee)).to.be.revertedWith("Ownable: caller is not the owner"); - }); - }); - - describe("burn", async () => { - it("Should burn a token", async function () { - const tokenId = 1; - const { lineaResolver } = await loadFixture(deployContractsFixture); - - await lineaResolver.burn(tokenId); - - await expect(lineaResolver.ownerOf(tokenId)).to.be.revertedWith("ERC721: invalid token ID"); - }); - - it("Should revert if not token owner", async function () { - const tokenId = 1; - const { lineaResolver, unknown } = await loadFixture(deployContractsFixture); - - await expect(lineaResolver.connect(unknown).burn(tokenId)).to.be.revertedWith("Caller is not owner or approved"); - }); - - it("Should not be able to burn a token twice", async function () { - const tokenId = 1; - const { lineaResolver } = await loadFixture(deployContractsFixture); - - await expect(lineaResolver.burn(tokenId)).to.not.be.reverted; - await expect(lineaResolver.burn(tokenId)).to.be.revertedWith("ERC721: invalid token ID"); - }); - }); -}); diff --git a/packages/contracts/test/LineaResolverStub.ts b/packages/contracts/test/LineaResolverStub.ts deleted file mode 100644 index 493f36423..000000000 --- a/packages/contracts/test/LineaResolverStub.ts +++ /dev/null @@ -1,146 +0,0 @@ -import { loadFixture } from "@nomicfoundation/hardhat-network-helpers"; -import { ethers } from "hardhat"; -import { expect } from "chai"; -import { defaultAbiCoder } from "@ethersproject/abi"; -// We use mocked results from the gateway and L2 resolver for the unit tests -import { DOMAIN_NAME, EXPECTED_RESOLVE_WITH_PROOF_RESULT, GATEWAY_URL, L2_RESOLVER_ADDRESS, MOCKED_PROOF, MOCKED_PROOF_UNDEFINED } from "./mocks/proof"; - -describe("LineaResolverStub", function () { - async function deployContractsFixture() { - const [owner] = await ethers.getSigners(); - - const gateways = [GATEWAY_URL]; - const hash = ethers.utils.namehash(DOMAIN_NAME); - - const undefinedDomain = "undefined.lineatest.eth"; - const undefinedHash = ethers.utils.namehash(undefinedDomain); - - // Deploy FakeRollup - const FakeRollup = await ethers.getContractFactory("FakeRollup"); - const fakeRollup = await FakeRollup.deploy(); - await fakeRollup.deployed(); - - // Deploy ResolverStub - const LineaResolverStub = await ethers.getContractFactory("LineaResolverStub"); - const lineaResolverStub = await LineaResolverStub.deploy(gateways, L2_RESOLVER_ADDRESS, fakeRollup.address); - await lineaResolverStub.deployed(); - - return { - owner, - lineaResolverStub, - hash, - undefinedHash, - gateways, - }; - } - - describe("initialization", async () => { - it("The contract should have been deployed correctly", async function () { - const { lineaResolverStub } = await loadFixture(deployContractsFixture); - - expect(await lineaResolverStub.gateways(0)).to.be.equal(GATEWAY_URL); - expect(await lineaResolverStub.l2resolver()).to.be.equal(L2_RESOLVER_ADDRESS); - }); - }); - - describe("resolveWithProof", async () => { - it("Should return the expected address", async function () { - const { lineaResolverStub, hash } = await loadFixture(deployContractsFixture); - // We prefix with the function signature 'addr(bytes32)' as bytes4 - const extraData = `0x3b3b57de${hash.slice(2)}`; - const result = await lineaResolverStub.resolveWithProof( - defaultAbiCoder.encode(["(bytes32,bytes,bytes,bytes32,bytes,bytes)"], [Object.values(MOCKED_PROOF)]), - extraData, - ); - expect(result).to.equal(EXPECTED_RESOLVE_WITH_PROOF_RESULT); - }); - - it("Should revert if hash does not match the proof", async function () { - const { lineaResolverStub, undefinedHash } = await loadFixture(deployContractsFixture); - const extraData = `0x3b3b57de${undefinedHash.slice(2)}`; - await expect( - lineaResolverStub.resolveWithProof(defaultAbiCoder.encode(["(bytes32,bytes,bytes,bytes32,bytes,bytes)"], [Object.values(MOCKED_PROOF)]), extraData), - ).to.be.revertedWith("Invalid large internal hash"); - }); - - it("Should return empty bytes if the function signature is not the one expected", async function () { - const { lineaResolverStub, undefinedHash } = await loadFixture(deployContractsFixture); - const extraData = `0x00000000${undefinedHash.slice(2)}`; - const result = await lineaResolverStub.resolveWithProof( - defaultAbiCoder.encode(["(bytes32,bytes,bytes,bytes32,bytes,bytes)"], [Object.values(MOCKED_PROOF)]), - extraData, - ); - expect(result).to.be.equal("0x"); - }); - - it("Should return empty bytes if the domain does not exists but the proof is correct", async function () { - const { lineaResolverStub, undefinedHash } = await loadFixture(deployContractsFixture); - const extraData = `0x3b3b57de${undefinedHash.slice(2)}`; - const result = await lineaResolverStub.resolveWithProof( - defaultAbiCoder.encode(["(bytes32,bytes,bytes,bytes32,bytes,bytes)"], [Object.values(MOCKED_PROOF_UNDEFINED)]), - extraData, - ); - expect(result).to.be.equal("0x"); - }); - - it("Should revert when blockHash is not valid", async function () { - const { lineaResolverStub, hash } = await loadFixture(deployContractsFixture); - const extraData = `0x3b3b57de${hash.slice(2)}`; - const proofWithInvalidBlockHash = { ...MOCKED_PROOF }; - proofWithInvalidBlockHash.blockHash = "0x94ea534b47baee0ba1b851ea15ffd0435de5389022baf665d5f59dac55c140b1"; - await expect( - lineaResolverStub.resolveWithProof( - defaultAbiCoder.encode(["(bytes32,bytes,bytes,bytes32,bytes,bytes)"], [Object.values(proofWithInvalidBlockHash)]), - extraData, - ), - ).to.revertedWith("LineaResolverStub: blockHash encodedBlockArray mismatch"); - }); - - // it("Should revert if the given state root is invalid", async function () { - // const { lineaResolverStub, hash } = await loadFixture(deployContractsFixture); - // const extraData = `0x3b3b57de${hash.slice(2)}`; - // await expect( - // lineaResolverStub.resolveWithProof( - // defaultAbiCoder.encode(["(bytes32,bytes,bytes,bytes32,bytes,bytes)"], [Object.values(MOCKED_PROOF_INVALID_STATE_ROOT)]), - // extraData, - // ), - // ).to.revertedWith("LineaResolverStub: invalid state root"); - // }); - }); - - describe("resolve", async () => { - it("Should revert with OffchainLookup when calling resolve", async function () { - const { lineaResolverStub, hash } = await loadFixture(deployContractsFixture); - const extraData = `0x3b3b57de${hash.slice(2)}`; - const encodedName = ethers.utils.dnsEncode(DOMAIN_NAME); - try { - await lineaResolverStub.resolve(encodedName, extraData); - } catch (error) { - expect(error.errorName).to.equal("OffchainLookup"); - } - }); - }); - - describe("supportsInterface", async () => { - it("should return true for valid interfaceId", async () => { - const { lineaResolverStub } = await loadFixture(deployContractsFixture); - const anotherInterfaceId = "0x9061b923"; - const result = await lineaResolverStub.supportsInterface(anotherInterfaceId); - expect(result).to.be.equal(true); - }); - - it("should return true for valid interfaceId for the abstract SupportsInterface contract", async () => { - const { lineaResolverStub } = await loadFixture(deployContractsFixture); - const anotherInterfaceId = "0x01ffc9a7"; - const result = await lineaResolverStub.supportsInterface(anotherInterfaceId); - expect(result).to.be.equal(true); - }); - - it("should return false for invalid interfaceId", async () => { - const { lineaResolverStub } = await loadFixture(deployContractsFixture); - const invalidInterfaceId = "0x89abcdef"; - const result = await lineaResolverStub.supportsInterface(invalidInterfaceId); - expect(result).to.be.equal(false); - }); - }); -}); diff --git a/packages/contracts/test/mocks/proof.ts b/packages/contracts/test/mocks/proof.ts deleted file mode 100644 index efd0602d4..000000000 --- a/packages/contracts/test/mocks/proof.ts +++ /dev/null @@ -1,44 +0,0 @@ -export const MOCKED_PROOF = { - blockHash: "0x62e34bf5241fcd5867d8636a2df3da85112418b000e1ee694f55adba2d2a61ef", - encodedBlockArray: - "0xf9025fa0ba9dd3c24267ac8c69dd8c6d04e81d0531219bdb64c965eb9477f796f1a97aa6a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a006263c3a0a8795755e30ec09dea189b3bb8e6e93c0037c9cce5c14ac24b992eca076b2e766f6f9d71208f0135294693bfbdfeafa306cffa8ab9dfeb0ff25b0d23da0abd6d4f2796c2d68f23ec70ef84dfc480557aa525c57d41cb0e7e2c350525a5bb901000411004c81008002000220818024009868001000001002108047302104300e001000000880219002021121040c0838450228002898810603000022080024194000210004218020019400000808202411800298204042004a000020021140000a0a04004082ca0e01000038061410484002008090ba800406df442030a1100040001000c106020c088511a8002260010090000880080080048246100bc8b809012201158b0001060204400400400408004022a0072008a0000030000c000404040000020300200d5304502408210420100413000020050391000001026708210280512c00c042240040001008068299006120b2000110000c801000822250020002830c69948403a2c94084014425f5846477179ab861d883010b04846765746888676f312e31392e38856c696e757800000000000000c6213a998bbf8c73ad42b9a2ffd41756079d7c757f5afc09f34106701545336f35ef0a70f22fee18424802dac8e37109cf692a5269791e01cad2bcb2ad05c80d00a0000000000000000000000000000000000000000000000000000000000000000088000000000000000008", - accountProof: - "0xf90b4eb90214f90211a074bf02cfc45b2fa921a057b8c3434824a3b75cc4a365a1461baf15d8a76a3b2ca00a4e4372a8a249a722f1bda70b40b09375ffacaaf99bc8dd6ae5b2de05e91449a0f8dbdb380b33b51b95666a6f1f41944ebf5041992a8655bacc781b50cbcecfd6a0b3e08f0eab1f0e020a67ed36678b42e2877c841f272193f45991b77162185de3a0d73defc3e7b7b6379d46129ae363ade7d2419d6e19342e53b8592e846953fbafa0cb1bc88dc451890d752054cf404fca48751cdfb0195f20c2dbae94c69b4931c6a0939c2f27c11e15ceec59009ae30db4f8bd9335f5af6014ca4c333451b3c3184aa049326916e81c8e00c09686392eb31823a3bd053c52731d0b712307574494bb5aa04206dd491423eb844ee41e22680653d6ac7efc288ca28cad5ea1977268cae8bca0cd7805123ac6248174b72d90192def2f80c86968e16a9e8e449995f2923df862a060eceaed5b0a254d29b720c72986873fd5aaa060ad248dc2498ca833fc65ef06a09b3b6afa5d8b2d29471c8fa621f75930bb60c608958ace806d7f336b9c60bd11a0aa521eb1ef710f456f2fabe3421432e7bda4bd47033a036a7ea0f147d6c52124a01e09ecce431eaff4e8be5d26854799bc074c5854ad939807cf51c791668748b0a0e26b24546343934f70de7cd57501052387eb23d6230c7281f33899b7e2db8bd0a0595a26b6eee03eaf8ee15db05240d4297394d702f1965e4b7a548699512b3e0680b90214f90211a0da701846e02dbc7ae1e07ecbe37f1cf0a6bb65988a52baa7758cbba1c1687751a004a532c19b76d259a297ad30270f9ff5bddc5ee76f311e360078dd37e13f714da05197c7441bb7b23c38d0e9aefce0795be3472071b63b5f77279d62903f60cbf9a0136d77bc3c8c84d3f5551336daa5080f23cd26a56278842d7d61dd09865f363ea09e2399041f300246dccd79fb18bf05e449b23916f33b0e76944195c7066d6a3aa087c19d545e63a4597461e45133924775a53b94fcec2ad4750f12e4270678ed48a03aa61407c254133b9af66b5f5558b3317e0ae897de20406c5fb557d677a1fb3ea033bf7018bd72d09bf1dd6499a428ad8a70dbba19f26e1f24c46e7e3f9acbb457a072161190358126a6dab3fe1c4dc3b1660ad24cf3f828efd66f400c201d3303c6a0bcf19035111cab89f6d4e5d4c4bccac37b82b6be83eb2a6a2ece61aa20e40b4aa08d53f07bdacd5e0ab26775ca2ed72c5544798faed03b337b5c8d557f030ccb3fa05f92a9fe916552504a07b8bbc4bbad06675cb0ced34798fe858dc8fbbe62a426a0d83cdcf61d14701261c670c97a9989fd450283370badd02c15ebfef22ffe92eea0dda13ef6594492f3ba14575e819e896c97d4a3c97065a3dff0756de4bea4d869a089c26746e5ca57177115a67dbe4d079c0859f5bdd9756cd9a1e5a661cd590fcfa0545da93adf29a516869e66039b068d7824d242c746e5c075394224b92752017480b90214f90211a0d02022a72eecff5229b94100c8d22f8316edd2d70ebc7a84f4f5c2ae47bdb856a091e2088548ad9e34e971b59fac908a7c784fc4e4cebe1e720bb792868e9d8f8ba0a63e4f5037e7736830e1f7311d479d81f6a874544c74f1859ca24390a51e4c00a014192908dffa9e5a14d2818b4155b14c23e63e72f3702ff19be7bec63323b543a0af16d035ac24f39f825c2b08b3943d1511108a88a5ec5d2845a8d0f85da9c1d1a0a52cc6ab95af39f1a71738b158127837508bbd647aa8757859e923baaa338609a0325e9831e88f9945941f57b3f2d0582d7322a70fa5a31ff18e70d3de66315722a04c0530420b15e20a83a6e268ac56e2a3b2f2314c6bdb681205f6317c07124b09a0690e81d6631b49847fb2baacca66a65224a53825bf7b07d1bd64367292b1ec91a028567ca443e727a33ec34cb1c54507d07fd610851012dca84036d97369651473a0724a5da0c9c3cc19df9d7ed1fcf9b18ecc6ab5d86724fbc65bebc459a8973867a046d8562aab8eced82bf559625d101f6ce67ada4db8f561650b2c39d03a860fd6a05c19f42b365e40a46e8cef116ec53f672a9c8ecd4d3ae111882c7a26682d6b62a0b0e05e4b6dac3e91842eb66a6db72b9821e16d335d9458218388d61320db8072a0c198d81e8ed9e80bac3f2d84dfe5d7d7e369e5ee28dfe13599a16474ddad937fa087ca915b4f854fba5d915e6b46a9b8ea92b37c9c341f98767b87b7b2a0425a5b80b90214f90211a0d4eae198c44064a436ead1c857455bc3b595165ca8c146399c67905d3d33eb98a06fad337ee856d93606fb470ed3c46766b4c0a59b9175e23a9bbe776a2db3eb96a07e69d9d50e99c1622899046cd9235b53afa783d657fa9aeda625b08a4997188ea0221b9c941ef62dccf476505a98bf356d8272920d9cb113b83cd04db315c87ce7a0498c3da72b517dc340db878e53c100b973366f6eb8a6c0e9c5e2ae807302b33ba0c554fb2d25d75d0bec915787736444cf3144aac8a8642f87776bb917c1b578fda034a9d010b3264a6503ceba74ebf3053e59ddc7c8c9b19f1a8e669babe2093ea1a0f6f5b7ca74865d8f026b80ab67e88ee8f163724916a87f721171f8f375b89b72a05031ce378d37742e1b86737ffc43a2012431db926c56d88bf31d54ed539d6269a012c8ef62d8de7a525da61afe9ab8bd948fcb9b484f4bfbac4c6cbda1334c9a1ea07cfbca561e5915824fe7b05458102227bd05f970cfa619549424c6dc9501b51ea0a9338395957f397ff450be9936727d8309180f40b196500ce68566e837e03b85a00e28a4c7f0914bb782c74dab80c5ca087f0e94b8a489006e3dd92d4826b8f905a04251c522d64b106fcf7128c21ade77ec59b0bc489d905c2f0759ec25a6397825a00f6478137a0d56493c2f97aa5446cf5dea2314b0a3e896031c3a9d56b35db127a045877afb494ec4ef70e01481e1286c2872ef79af26acc50b305f9557c2157c7780b90194f90191a0f6608ca635729f8a8fea7deb8db6b20680b3e3df8737962f7764089260605ec080a0e2297604db344d9f9d58c705754ce7e855954470c7190788c091ba5b1802095aa01e8a6173cf1cf5ba3ce28bb339c47db4958f31503ae357e1e2dc70edf6cc6736a00016d451997205bba7d8c5f3eed64d94ebbd0d0c0b3fb0e9cea70962c67d1b7e80a0e481236766f65a01130fbc6c01bc4ad18db894e2d7c3d954999d6211c60ce462a0fefcc869443b19280265136a4864bbc892fbbec93c69105ecc7c6304e86179e4a0721df254e3b160850e99408850436e9c4f9ed1ed1d4d469427ca473fbc679304a0aac307350a9815413d15315a7fd6f35ed8f5c652080b46307cfa25a8b2003db8a00519b72f3123f0ba4018e33a552788cb24eab9b9f07a84898c1bdcc35b8b679ea047d5589419c52b1d66c8a365c714d6ff76b1240f5ed6b832297e4969485ced4f80a0f300df3e0f16b62724b8397bd436b18d22d8c26fc1f5a8cdbb001972a567a3fa80a02c442ff97c3c16d7f245f4356c5b57240227cc06780d6301b12d45aadac3ce5a80b893f891a0702621860a8694557023ce1f9841f7267d3f83327131915e4ab59258c1532480a0646ba8f69363840a3e833adf0f11d997e0876df2b378fadd110a468c1df316d28080808080808080a0447c20f9174108b35b26e6ae5d379dcb59666e143f1b488a8aea8bbd67ba0f0180a0eb27ac68e04742b53b00d3455cdabaa02ea780434ce5976e5156f67ea1b143c780808080b853f851808080808080a074ae376c5bf9ca418e1b1d945a38c691b18aeb8b8249d10af0dbb45057d32d3080808080808080a0bf40a050bc213927e66c0ff6053d6938dc5e26358f0c5aca783e46fa4ab889188080b86ff86d9d327788b3596eb995f8670853aeb7b0f0e073efbc9b9a6b24a54882fce4b84df84b0187038d7ea4c68000a0160159008a07e44095baa225f58e4f838ada9d3f620bd21a68cc005256747b9fa04d9be648c5bf39973670d9f8b481d5d0b971e6a2db2deccc6b98cde21c5dd83e", - stateRoot: "0x06263c3a0a8795755e30ec09dea189b3bb8e6e93c0037c9cce5c14ac24b992ec", - tokenIdStorageProof: - "0xf9019bb90174f901718080a04fc5f13ab2f9ba0c2da88b0151ab0e7cf4d85d08cca45ccd923c6ab76323eb2880a055023796ff2dd458613b29e60f044a03f4a1aa024ff806a6a863e5bf4a87333ea048b38baaa54b803768cc7ded6093605c5c5b846147e6bafc1ea121c16842cda7a0dcc579620f2566f065ad1031bd8782115dffd44f86613913d74ba04ebb48dc50a07df8c660d04c72bfab868fd6662bfc520d0cc678bab02c4646c9e305da55565ea0cc28ed9e85e9f1963e3f59487889370164c0dc339b3677d00e205d663045e990a011c85c4b2e8006a79da0e1b01ce22b75b94761f65665c1aaf900d33f9dcbd3a1a0ac7adf259785bfb25862f1275da301bcf5a045fc0e957cbfac4fb4372dfdd11ea0b355f93b3fd6a9b7487a49615f440cb2ef08d8e69518da514115388e032c2c5880a03b14da15a8834e6eb99236c20b0af7c2975163c64353e2ed804d67e9a13ec37ca0d74b37da21a0412edc00332b5cd1079056c11db7c6a28e14ba66acabd8ea0d7f8080a3e2a03df95047d61a3fea1a1de07355967c1731facbb810f6ccde0e76e7d11613bf5901", - ownerStorageProof: - "0xf901b1b90174f901718080a04fc5f13ab2f9ba0c2da88b0151ab0e7cf4d85d08cca45ccd923c6ab76323eb2880a055023796ff2dd458613b29e60f044a03f4a1aa024ff806a6a863e5bf4a87333ea048b38baaa54b803768cc7ded6093605c5c5b846147e6bafc1ea121c16842cda7a0dcc579620f2566f065ad1031bd8782115dffd44f86613913d74ba04ebb48dc50a07df8c660d04c72bfab868fd6662bfc520d0cc678bab02c4646c9e305da55565ea0cc28ed9e85e9f1963e3f59487889370164c0dc339b3677d00e205d663045e990a011c85c4b2e8006a79da0e1b01ce22b75b94761f65665c1aaf900d33f9dcbd3a1a0ac7adf259785bfb25862f1275da301bcf5a045fc0e957cbfac4fb4372dfdd11ea0b355f93b3fd6a9b7487a49615f440cb2ef08d8e69518da514115388e032c2c5880a03b14da15a8834e6eb99236c20b0af7c2975163c64353e2ed804d67e9a13ec37ca0d74b37da21a0412edc00332b5cd1079056c11db7c6a28e14ba66acabd8ea0d7f8080b838f7a0359b37c07c33320381d4e4c96378d671e24d99280083cfb1f14934ad8f71343f9594f110a41f75edeb224227747b64be7f6a7f140abc", -}; - -export const MOCKED_PROOF_UNDEFINED = { - blockHash: "0x62e34bf5241fcd5867d8636a2df3da85112418b000e1ee694f55adba2d2a61ef", - encodedBlockArray: - "0xf9025fa0ba9dd3c24267ac8c69dd8c6d04e81d0531219bdb64c965eb9477f796f1a97aa6a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a006263c3a0a8795755e30ec09dea189b3bb8e6e93c0037c9cce5c14ac24b992eca076b2e766f6f9d71208f0135294693bfbdfeafa306cffa8ab9dfeb0ff25b0d23da0abd6d4f2796c2d68f23ec70ef84dfc480557aa525c57d41cb0e7e2c350525a5bb901000411004c81008002000220818024009868001000001002108047302104300e001000000880219002021121040c0838450228002898810603000022080024194000210004218020019400000808202411800298204042004a000020021140000a0a04004082ca0e01000038061410484002008090ba800406df442030a1100040001000c106020c088511a8002260010090000880080080048246100bc8b809012201158b0001060204400400400408004022a0072008a0000030000c000404040000020300200d5304502408210420100413000020050391000001026708210280512c00c042240040001008068299006120b2000110000c801000822250020002830c69948403a2c94084014425f5846477179ab861d883010b04846765746888676f312e31392e38856c696e757800000000000000c6213a998bbf8c73ad42b9a2ffd41756079d7c757f5afc09f34106701545336f35ef0a70f22fee18424802dac8e37109cf692a5269791e01cad2bcb2ad05c80d00a0000000000000000000000000000000000000000000000000000000000000000088000000000000000008", - accountProof: - "0xf90b4eb90214f90211a074bf02cfc45b2fa921a057b8c3434824a3b75cc4a365a1461baf15d8a76a3b2ca00a4e4372a8a249a722f1bda70b40b09375ffacaaf99bc8dd6ae5b2de05e91449a0f8dbdb380b33b51b95666a6f1f41944ebf5041992a8655bacc781b50cbcecfd6a0b3e08f0eab1f0e020a67ed36678b42e2877c841f272193f45991b77162185de3a0d73defc3e7b7b6379d46129ae363ade7d2419d6e19342e53b8592e846953fbafa0cb1bc88dc451890d752054cf404fca48751cdfb0195f20c2dbae94c69b4931c6a0939c2f27c11e15ceec59009ae30db4f8bd9335f5af6014ca4c333451b3c3184aa049326916e81c8e00c09686392eb31823a3bd053c52731d0b712307574494bb5aa04206dd491423eb844ee41e22680653d6ac7efc288ca28cad5ea1977268cae8bca0cd7805123ac6248174b72d90192def2f80c86968e16a9e8e449995f2923df862a060eceaed5b0a254d29b720c72986873fd5aaa060ad248dc2498ca833fc65ef06a09b3b6afa5d8b2d29471c8fa621f75930bb60c608958ace806d7f336b9c60bd11a0aa521eb1ef710f456f2fabe3421432e7bda4bd47033a036a7ea0f147d6c52124a01e09ecce431eaff4e8be5d26854799bc074c5854ad939807cf51c791668748b0a0e26b24546343934f70de7cd57501052387eb23d6230c7281f33899b7e2db8bd0a0595a26b6eee03eaf8ee15db05240d4297394d702f1965e4b7a548699512b3e0680b90214f90211a0da701846e02dbc7ae1e07ecbe37f1cf0a6bb65988a52baa7758cbba1c1687751a004a532c19b76d259a297ad30270f9ff5bddc5ee76f311e360078dd37e13f714da05197c7441bb7b23c38d0e9aefce0795be3472071b63b5f77279d62903f60cbf9a0136d77bc3c8c84d3f5551336daa5080f23cd26a56278842d7d61dd09865f363ea09e2399041f300246dccd79fb18bf05e449b23916f33b0e76944195c7066d6a3aa087c19d545e63a4597461e45133924775a53b94fcec2ad4750f12e4270678ed48a03aa61407c254133b9af66b5f5558b3317e0ae897de20406c5fb557d677a1fb3ea033bf7018bd72d09bf1dd6499a428ad8a70dbba19f26e1f24c46e7e3f9acbb457a072161190358126a6dab3fe1c4dc3b1660ad24cf3f828efd66f400c201d3303c6a0bcf19035111cab89f6d4e5d4c4bccac37b82b6be83eb2a6a2ece61aa20e40b4aa08d53f07bdacd5e0ab26775ca2ed72c5544798faed03b337b5c8d557f030ccb3fa05f92a9fe916552504a07b8bbc4bbad06675cb0ced34798fe858dc8fbbe62a426a0d83cdcf61d14701261c670c97a9989fd450283370badd02c15ebfef22ffe92eea0dda13ef6594492f3ba14575e819e896c97d4a3c97065a3dff0756de4bea4d869a089c26746e5ca57177115a67dbe4d079c0859f5bdd9756cd9a1e5a661cd590fcfa0545da93adf29a516869e66039b068d7824d242c746e5c075394224b92752017480b90214f90211a0d02022a72eecff5229b94100c8d22f8316edd2d70ebc7a84f4f5c2ae47bdb856a091e2088548ad9e34e971b59fac908a7c784fc4e4cebe1e720bb792868e9d8f8ba0a63e4f5037e7736830e1f7311d479d81f6a874544c74f1859ca24390a51e4c00a014192908dffa9e5a14d2818b4155b14c23e63e72f3702ff19be7bec63323b543a0af16d035ac24f39f825c2b08b3943d1511108a88a5ec5d2845a8d0f85da9c1d1a0a52cc6ab95af39f1a71738b158127837508bbd647aa8757859e923baaa338609a0325e9831e88f9945941f57b3f2d0582d7322a70fa5a31ff18e70d3de66315722a04c0530420b15e20a83a6e268ac56e2a3b2f2314c6bdb681205f6317c07124b09a0690e81d6631b49847fb2baacca66a65224a53825bf7b07d1bd64367292b1ec91a028567ca443e727a33ec34cb1c54507d07fd610851012dca84036d97369651473a0724a5da0c9c3cc19df9d7ed1fcf9b18ecc6ab5d86724fbc65bebc459a8973867a046d8562aab8eced82bf559625d101f6ce67ada4db8f561650b2c39d03a860fd6a05c19f42b365e40a46e8cef116ec53f672a9c8ecd4d3ae111882c7a26682d6b62a0b0e05e4b6dac3e91842eb66a6db72b9821e16d335d9458218388d61320db8072a0c198d81e8ed9e80bac3f2d84dfe5d7d7e369e5ee28dfe13599a16474ddad937fa087ca915b4f854fba5d915e6b46a9b8ea92b37c9c341f98767b87b7b2a0425a5b80b90214f90211a0d4eae198c44064a436ead1c857455bc3b595165ca8c146399c67905d3d33eb98a06fad337ee856d93606fb470ed3c46766b4c0a59b9175e23a9bbe776a2db3eb96a07e69d9d50e99c1622899046cd9235b53afa783d657fa9aeda625b08a4997188ea0221b9c941ef62dccf476505a98bf356d8272920d9cb113b83cd04db315c87ce7a0498c3da72b517dc340db878e53c100b973366f6eb8a6c0e9c5e2ae807302b33ba0c554fb2d25d75d0bec915787736444cf3144aac8a8642f87776bb917c1b578fda034a9d010b3264a6503ceba74ebf3053e59ddc7c8c9b19f1a8e669babe2093ea1a0f6f5b7ca74865d8f026b80ab67e88ee8f163724916a87f721171f8f375b89b72a05031ce378d37742e1b86737ffc43a2012431db926c56d88bf31d54ed539d6269a012c8ef62d8de7a525da61afe9ab8bd948fcb9b484f4bfbac4c6cbda1334c9a1ea07cfbca561e5915824fe7b05458102227bd05f970cfa619549424c6dc9501b51ea0a9338395957f397ff450be9936727d8309180f40b196500ce68566e837e03b85a00e28a4c7f0914bb782c74dab80c5ca087f0e94b8a489006e3dd92d4826b8f905a04251c522d64b106fcf7128c21ade77ec59b0bc489d905c2f0759ec25a6397825a00f6478137a0d56493c2f97aa5446cf5dea2314b0a3e896031c3a9d56b35db127a045877afb494ec4ef70e01481e1286c2872ef79af26acc50b305f9557c2157c7780b90194f90191a0f6608ca635729f8a8fea7deb8db6b20680b3e3df8737962f7764089260605ec080a0e2297604db344d9f9d58c705754ce7e855954470c7190788c091ba5b1802095aa01e8a6173cf1cf5ba3ce28bb339c47db4958f31503ae357e1e2dc70edf6cc6736a00016d451997205bba7d8c5f3eed64d94ebbd0d0c0b3fb0e9cea70962c67d1b7e80a0e481236766f65a01130fbc6c01bc4ad18db894e2d7c3d954999d6211c60ce462a0fefcc869443b19280265136a4864bbc892fbbec93c69105ecc7c6304e86179e4a0721df254e3b160850e99408850436e9c4f9ed1ed1d4d469427ca473fbc679304a0aac307350a9815413d15315a7fd6f35ed8f5c652080b46307cfa25a8b2003db8a00519b72f3123f0ba4018e33a552788cb24eab9b9f07a84898c1bdcc35b8b679ea047d5589419c52b1d66c8a365c714d6ff76b1240f5ed6b832297e4969485ced4f80a0f300df3e0f16b62724b8397bd436b18d22d8c26fc1f5a8cdbb001972a567a3fa80a02c442ff97c3c16d7f245f4356c5b57240227cc06780d6301b12d45aadac3ce5a80b893f891a0702621860a8694557023ce1f9841f7267d3f83327131915e4ab59258c1532480a0646ba8f69363840a3e833adf0f11d997e0876df2b378fadd110a468c1df316d28080808080808080a0447c20f9174108b35b26e6ae5d379dcb59666e143f1b488a8aea8bbd67ba0f0180a0eb27ac68e04742b53b00d3455cdabaa02ea780434ce5976e5156f67ea1b143c780808080b853f851808080808080a074ae376c5bf9ca418e1b1d945a38c691b18aeb8b8249d10af0dbb45057d32d3080808080808080a0bf40a050bc213927e66c0ff6053d6938dc5e26358f0c5aca783e46fa4ab889188080b86ff86d9d327788b3596eb995f8670853aeb7b0f0e073efbc9b9a6b24a54882fce4b84df84b0187038d7ea4c68000a0160159008a07e44095baa225f58e4f838ada9d3f620bd21a68cc005256747b9fa04d9be648c5bf39973670d9f8b481d5d0b971e6a2db2deccc6b98cde21c5dd83e", - stateRoot: "0x06263c3a0a8795755e30ec09dea189b3bb8e6e93c0037c9cce5c14ac24b992ec", - tokenIdStorageProof: - "0xf901ccb90174f901718080a04fc5f13ab2f9ba0c2da88b0151ab0e7cf4d85d08cca45ccd923c6ab76323eb2880a055023796ff2dd458613b29e60f044a03f4a1aa024ff806a6a863e5bf4a87333ea048b38baaa54b803768cc7ded6093605c5c5b846147e6bafc1ea121c16842cda7a0dcc579620f2566f065ad1031bd8782115dffd44f86613913d74ba04ebb48dc50a07df8c660d04c72bfab868fd6662bfc520d0cc678bab02c4646c9e305da55565ea0cc28ed9e85e9f1963e3f59487889370164c0dc339b3677d00e205d663045e990a011c85c4b2e8006a79da0e1b01ce22b75b94761f65665c1aaf900d33f9dcbd3a1a0ac7adf259785bfb25862f1275da301bcf5a045fc0e957cbfac4fb4372dfdd11ea0b355f93b3fd6a9b7487a49615f440cb2ef08d8e69518da514115388e032c2c5880a03b14da15a8834e6eb99236c20b0af7c2975163c64353e2ed804d67e9a13ec37ca0d74b37da21a0412edc00332b5cd1079056c11db7c6a28e14ba66acabd8ea0d7f8080b853f851a0fd6d905a2dbd6a3d736026ee592bc681a81c032f8b8d9600cce5c9044e9b28798080808080808080808080a000068b3c5299def5fa9becc34d1f0a41f46f4502cdb88f4b2aed35fadd12526780808080", - ownerStorageProof: - "0xf90177b90174f901718080a04fc5f13ab2f9ba0c2da88b0151ab0e7cf4d85d08cca45ccd923c6ab76323eb2880a055023796ff2dd458613b29e60f044a03f4a1aa024ff806a6a863e5bf4a87333ea048b38baaa54b803768cc7ded6093605c5c5b846147e6bafc1ea121c16842cda7a0dcc579620f2566f065ad1031bd8782115dffd44f86613913d74ba04ebb48dc50a07df8c660d04c72bfab868fd6662bfc520d0cc678bab02c4646c9e305da55565ea0cc28ed9e85e9f1963e3f59487889370164c0dc339b3677d00e205d663045e990a011c85c4b2e8006a79da0e1b01ce22b75b94761f65665c1aaf900d33f9dcbd3a1a0ac7adf259785bfb25862f1275da301bcf5a045fc0e957cbfac4fb4372dfdd11ea0b355f93b3fd6a9b7487a49615f440cb2ef08d8e69518da514115388e032c2c5880a03b14da15a8834e6eb99236c20b0af7c2975163c64353e2ed804d67e9a13ec37ca0d74b37da21a0412edc00332b5cd1079056c11db7c6a28e14ba66acabd8ea0d7f8080", -}; - -export const MOCKED_PROOF_INVALID_STATE_ROOT = { - blockHash: "0xf250d4956bbd7fcf0835619b1663080e52f8f1406edad5418c0c5eedbf2a4405", - encodedBlockArray: - "0xf90272a009d91c407f6a40d23374b4b012541deabd36694740f7ba70537686d15a8c92e3a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a0ab36c666794b65d5c1471284de085714d5e4c9bc53725b586d884d5f6019b251a072d66fd498058fa29ded928f81916a7228cf7f47cf53f6823633099d39bdc667a02f0203944e89072aba3f32117b503e804805436e6508f35885e60a9aaae579e5b901000000000000080000000000000000000001080000021000000080900000000100000000000000002000000000000000000000000000002000000010000020000000800000000000080000000d000000400001000000000000000000008000000000500000020080000000010000000800000000800000000000000090400800400000000000000000000008000400000000002001000000002000000000000000020a0001010040000001000002000000000000010000000000010000000000000000000200000000002004000000000000000000000028008000111000042000001020000000000000002050020000000110900000400040a00400020000000002830493e08401c9c380832ce2028464186a36b875d883010b00846765746888676f312e31392e35856c696e7578000000000000004d517aef039a48b3b6bf921e210b7551c8e37107b17ee6f950a75d04d5e1b3c784913cac825a913979db704f3f118cec894a1fc451958ca86b27f7f2165e46c504015d84cbeda065cedc1d162d2277787f14a33400a0000000000000000000000000000000000000000000000000000000000000000088000000000000000007", - accountProof: - "0xf90891b90214f90211a03015f1cdd20a6c93702876fa26b9bc1cc6d1b5deb1d8802b5e0ac2742b994e87a0bcb5b96251b5fa0c323ae06590b70bac47906d0fe7fceb8640cac319d07eb549a02c7b6d2bc77ab50c71fc1a9f19dc630692fd0b9be7cd849243a87107b3766ee9a0e8125879ee12e235c96b4b17d3eca4f42d44711de58ab2bc93925c0ca7e1ce9ba08e5e6dec344730dd923dedf4ef753f50105e88617d1d0ef5312e35eb610dba57a0077ef94fc4ab42bc74064b1a00bef68dbffee62bd06dd49b621ad10d3ca4e26ea0b57f5d17b3c1a35b4b54232e201b846126e4af05e71f5bd95c9bece331971a9ea0fcfa9ad3ed26b610ad67ddcc846f798269941f3583580b0525894e132c62a270a02bc82d8e8a79442d340f1d4eb0f674b08f7ce4b86a44476c64382f7e3ebb103ea0aba4d9019d345d8a096c4cf5e7384d6a678f0c7e4394706419e36cae39ce51dca0e4b905ee19e9449549068d1c6f6afc026232556531434853a8c35543ddd20dbca096124ebb0a40abbe8b059850a2f0131dbc00e04a3bc0d331000903c0fd696eaaa06b864428fa516756a2ce71222be0b2bec631d05b9f38fe811aa992827881bcdea0b7d0bd197f4f83fae5b9c07d47078b9554e0041d7da0fa738adc24f224ddfb27a032a7b98a4bcfe84d35bbc916a16db2d767cbed11de6d906d12f8df996e1a31e1a036ef2f5cb05510a2db3ec41371444c261473c13abd5fc73d12ada1089ca3432980b90214f90211a0041a4f5532f8ec5eea89525017014a7a3ba0ce54527030310578d07e83364f75a092a204ef3067026e92d28fb3b6db6b540cb784713ad2048a9d5495678a6cfdc8a03c848252530e8930c70a16bf7b8f12651a2ff503d29cb02e3b23122ca84c5666a0d2487682399a322f267aa41d2f72065fd870f9e3ce93c4ccb88395bd392c6ca0a08b2c68f81fa9e3ddb1f0e9ffd04cd8d7d54138d187b3b8777eb44d61beb7a72ca0864b1e6afd88b137d85768e9a52ed506e6030b1ceaf1305f4ab6bf169ae450bda0ab5a4ce5e1bf332a26417e68e1e5bd7701e8d9010e19f6a93bd82335a66b5403a0db0d3347c0883988f29f4947f17d2f36992be92a746eb125104c0dad31cdce9ba04d93773364d0baebe1efd0ae5a882158f9e3bc86d15b73f050115bb4aab6e0fba09e861aece63f9ccb332fdf745ed38f673224bc7a029f2a10f85dd9a8196029b1a07aa22d6e31dba3ba59c36e98a305468a0a76ed325cdadd91f1c49ad626793fc5a00790dfc36bd6509d7052e9bc2f89314ec06a0fa864748b973de7a23b04b1b978a0aef81b4c1147c222f64d0bbae012ea568d3bcb272c5ac3960a97fe996204aa4fa0f83d0e9c03831c35012a05f5c641fe7b557ae3ddcb543af724b2c55ae5911ea2a07d8d4b6410cc5adada66c15329e43fb02da424cb87b94e53f82877ae9469c727a0a06c293c119b61c0280945da786157724a5441abaec938b0a4fdaa7d0097f7ad80b90214f90211a006a60435c5e9967ef148e389bc1f93fc5e16d966a56705c8afec273322767996a0e94d386c214eb9f24a91d6fb1f38c58052356cead2d85622df96d59975c11bd1a098acd79259f5d6c73da60f7fd7859fd78685a493226f962d2721a244a275ab45a0c4dcec340ba872e1e3b9f335d7b88450afe5ebf591a274308154a9760c5e1788a052fd0e3b0c57cd525876cf82fa64a59badf319682f679ccf4932b41ef0cc86daa0bf53484765c331f2962638dd4bce75f8e8af291cbceed33ab5939267ad5d27cea0da294477a35634382809d776f87002cf82e5b8daac53e4404ba303dd44266ac7a012e3655b07befa15ea2e28f3fff7b946d7c22785bb7f29aad0ad8b9fc953b546a06459b4eda0e622270f33e8ba06953d3951b1541cb850aaaa35f26a1bc1e30b07a0cec13f7bafab88909356ec53e3e9b5591c907b9ac0a5756b7c4cbcee7c8ed540a085bbe0e979fec807e176322fdba092f07785650768ede56c8b86775ab721537ba08ee785286d931d84c3f8e3fccb8b42233c49e7fb749559a84c023606c942d194a0c664f21fb57a7a3d962446c8f7f20f2f27530035071b8845377342ae65343e7fa02b41af96c2d18b79a905a7a8714218cbb3e6bf3bd13a021a3621068acaf3ab2aa0155263a0593fb9e4c96cd230f2c0d67c65297b7248bba082a46cfc549e528751a07b0747f9c7df005bf36da55ede75f58133e817032910dc5c19268f3fcb7740c280b901d4f901d1a02cdba158b2b7c973b3a2dbe894c6bfe70444462473da23884d315b31eb497fb6a04746e6419323138556bfd0cb3b8257dd7b7db3b04a7fcf6fda0d3eff69ee2248a07b99a901b65ce87e3fb09554da0f0bee3af3d05d76285646cd15897bc358158ba02e07e2934f65264698f9746a6de331696e5904a6a1c0f4a984f7f54a87eacde0a0fdfea228343914af697fd12326c29b1602a1127c264a71b8b1473da909571293a0fe6f9e92f3f08e82ad5a8ffc37434217638d1572ee46956e78c576cf4ec54dc1a08dab9ed9fe083043e148878ade420ea724e678673634fc993edf1996580629a8a059a786a8608420d7138b8f920bb20ed146a8a13a5acfb9f7bcb4a3fc05badceea0c53469c9c5150cd8cf6bda65e967afbcb7606a70673a12f40f7e4f6754318384a0294f9f41d23b15c3f72e1269120d4b2235bcc3afcdb627a65b3be51e8cfaaa8f80a05602c6d7a2b559b102ec13317682ca366797ead1575ef7382a80c1dd3ab85e50a0276d59125c2e30e0ac6216e049f15272fbe8afadb65eff8c4f684f367ecf39ef80a0edba17f97d10f7012c71b80745a9400382b829d0447ba9c462321770fe181103a09b49b59b6b6e00a3be31f703f48dc04de674ffa2880a6de3c379176f8dbd376e80b873f87180a0de2be07b9b6bfd4a778ea4e34ae53fb0558fd2b5c3de91ec119e43ed37f7869f8080808080808080a0d96e240f4b8e298a6516bb57c331fc3c684969cea07731e3ed83c74467ec17388080a0a194bca99baa71dd2a815e54f850ca7cd9468352d465b9aabaeb59a89a1aa5eb808080", - stateRoot: "0xab36c666794b65d5c1471284de085714d5e4c9bc53725b586d884d5f6019b251", - tokenIdStorageProof: "0xc0", - ownerStorageProof: "0xc0", -}; - -export const L2_RESOLVER_ADDRESS = "0x2EcF0F417D534b99f64777bF0cabCC651739B314"; - -export const DOMAIN_NAME = "julink.lineatest.eth"; - -export const GATEWAY_URL = "http://localhost:8080"; - -export const EXPECTED_RESOLVE_WITH_PROOF_RESULT = "0x000000000000000000000000f110a41f75edeb224227747b64be7f6a7f140abc"; diff --git a/packages/contracts/tsconfig.json b/packages/contracts/tsconfig.json deleted file mode 100644 index 5327256e8..000000000 --- a/packages/contracts/tsconfig.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "compilerOptions": { - "target": "es2020", - "module": "commonjs", - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "strict": true, - "skipLibCheck": true, - "useUnknownInCatchVariables": false, - "resolveJsonModule": true - } -} diff --git a/packages/gateway/contracts/RollupMock.sol b/packages/gateway/contracts/RollupMock.sol index 95ed9c6fc..59a663bbb 100644 --- a/packages/gateway/contracts/RollupMock.sol +++ b/packages/gateway/contracts/RollupMock.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.19; +pragma solidity ^0.8.25; contract RollupMock { function currentL2BlockNumber() public pure returns (uint256) { diff --git a/packages/gateway/contracts/TestL1.sol b/packages/gateway/contracts/TestL1.sol index 305bdb386..781eb8331 100644 --- a/packages/gateway/contracts/TestL1.sol +++ b/packages/gateway/contracts/TestL1.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.19; +pragma solidity ^0.8.25; import {EVMFetcher} from "linea-verifier/contracts/EVMFetcher.sol"; import {EVMFetchTarget} from "linea-verifier/contracts/EVMFetchTarget.sol"; diff --git a/packages/gateway/contracts/TestL2.sol b/packages/gateway/contracts/TestL2.sol index db6ada399..6894e5b9a 100644 --- a/packages/gateway/contracts/TestL2.sol +++ b/packages/gateway/contracts/TestL2.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.19; +pragma solidity ^0.8.25; contract TestL2 { uint256 latest; // Slot 0 diff --git a/packages/gateway/contracts/TestLineaVerifier.sol b/packages/gateway/contracts/TestLineaVerifier.sol index 7d2b7fdc1..eacdab648 100644 --- a/packages/gateway/contracts/TestLineaVerifier.sol +++ b/packages/gateway/contracts/TestLineaVerifier.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.19; +pragma solidity ^0.8.25; import {LineaVerifier} from "linea-verifier/contracts/LineaVerifier.sol"; diff --git a/packages/gateway/hardhat.config.ts b/packages/gateway/hardhat.config.ts index 31082e96d..300f0e206 100644 --- a/packages/gateway/hardhat.config.ts +++ b/packages/gateway/hardhat.config.ts @@ -5,7 +5,19 @@ import * as dotenv from "dotenv"; dotenv.config(); const config: HardhatUserConfig = { - solidity: "0.8.19", + solidity: { + compilers: [ + { + version: "0.8.25", + settings: { + optimizer: { + enabled: true, + runs: 200, + }, + }, + }, + ], + }, }; export default config; diff --git a/packages/l1-contracts/.mocharc.json b/packages/l1-contracts/.mocharc.json new file mode 100644 index 000000000..48586d7d7 --- /dev/null +++ b/packages/l1-contracts/.mocharc.json @@ -0,0 +1,7 @@ +{ + "require": "ts-node/register", + "loader": "ts-node/esm", + "extensions": ["ts", "tsx"], + "spec": ["test/**/*.spec.*"], + "watch-files": ["src"] +} diff --git a/packages/l1-contracts/contracts/L1Resolver.sol b/packages/l1-contracts/contracts/L1Resolver.sol new file mode 100644 index 000000000..8d46f7d07 --- /dev/null +++ b/packages/l1-contracts/contracts/L1Resolver.sol @@ -0,0 +1,225 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.25; + +import {EVMFetcher} from "linea-verifier/contracts/EVMFetcher.sol"; +import {EVMFetchTarget} from "linea-verifier/contracts/EVMFetchTarget.sol"; +import {IEVMVerifier} from "linea-verifier/contracts/IEVMVerifier.sol"; +import "@ensdomains/ens-contracts/contracts/registry/ENS.sol"; +import {INameWrapper} from "@ensdomains/ens-contracts/contracts/wrapper/INameWrapper.sol"; +import {BytesUtils} from "@ensdomains/ens-contracts/contracts/dnssec-oracle/BytesUtils.sol"; +import {IAddrResolver} from "@ensdomains/ens-contracts/contracts/resolvers/profiles/IAddrResolver.sol"; +import {IAddressResolver} from "@ensdomains/ens-contracts/contracts/resolvers/profiles/IAddressResolver.sol"; +import {ITextResolver} from "@ensdomains/ens-contracts/contracts/resolvers/profiles/ITextResolver.sol"; +import {IContentHashResolver} from "@ensdomains/ens-contracts/contracts/resolvers/profiles/IContentHashResolver.sol"; + +contract L1Resolver is EVMFetchTarget { + using EVMFetcher for EVMFetcher.EVMFetchRequest; + using BytesUtils for bytes; + IEVMVerifier immutable verifier; + ENS immutable ens; + INameWrapper immutable nameWrapper; + mapping(bytes32 => address) targets; + uint256 constant COIN_TYPE_ETH = 60; + uint256 constant RECORD_VERSIONS_SLOT = 0; + uint256 constant VERSIONABLE_ABIS_SLOT = 1; + uint256 constant VERSIONABLE_ADDRESSES_SLOT = 2; + uint256 constant VERSIONABLE_HASHES_SLOT = 3; + uint256 constant VERSIONABLE_TEXTS_SLOT = 10; + + event TargetSet(bytes32 indexed node, address target); + + function isAuthorised(bytes32 node) internal view returns (bool) { + // TODO: Add support for + // trustedETHController + // trustedReverseRegistrar + // isApprovedForAll + // isApprovedFor + address owner = ens.owner(node); + if (owner == address(nameWrapper)) { + owner = nameWrapper.ownerOf(uint256(node)); + } + return owner == msg.sender; + } + + modifier authorised(bytes32 node) { + require(isAuthorised(node)); + _; + } + + constructor(IEVMVerifier _verifier, ENS _ens, INameWrapper _nameWrapper) { + require( + address(_nameWrapper) != address(0), + "Name Wrapper address must be set" + ); + require( + address(_verifier) != address(0), + "Verifier address must be set" + ); + require(address(_ens) != address(0), "Registry address must be set"); + verifier = _verifier; + ens = _ens; + nameWrapper = _nameWrapper; + } + + /** + * Set target address to verify aagainst + * @param node The ENS node to query. + * @param target The L2 resolver address to verify against. + */ + function setTarget(bytes32 node, address target) public authorised(node) { + targets[node] = target; + emit TargetSet(node, target); + } + + /** + * @dev Returns the L2 target address that can answer queries for `name`. + * @param name DNS encoded ENS name to query + * @param offset The offset of the label to query recursively. + * @return node The node of the name + * @return target The L2 resolver address to verify against. + */ + function getTarget( + bytes memory name, + uint256 offset + ) public view returns (bytes32 node, address target) { + uint256 len = name.readUint8(offset); + node = bytes32(0); + if (len > 0) { + bytes32 label = name.keccak(offset + 1, len); + (node, target) = getTarget(name, offset + len + 1); + node = keccak256(abi.encodePacked(node, label)); + if (targets[node] != address(0)) { + return (node, targets[node]); + } + } else { + return (bytes32(0), address(0)); + } + return (node, target); + } + + /** + * @dev Resolve and verify a record stored in l2 target address. It supports subname by fetching target recursively to the nearlest parent. + * @param name DNS encoded ENS name to query + * @param data The actual calldata + * @return result result of the call + */ + function resolve( + bytes calldata name, + bytes calldata data + ) external view returns (bytes memory result) { + (, address target) = getTarget(name, 0); + bytes4 selector = bytes4(data); + + if (selector == IAddrResolver.addr.selector) { + bytes32 node = abi.decode(data[4:], (bytes32)); + return _addr(node, target); + } + if (selector == IAddressResolver.addr.selector) { + (bytes32 node, uint256 cointype) = abi.decode( + data[4:], + (bytes32, uint256) + ); + return _addr(node, cointype, target); + } + if (selector == ITextResolver.text.selector) { + (bytes32 node, string memory key) = abi.decode( + data[4:], + (bytes32, string) + ); + return bytes(_text(node, key, target)); + } + if (selector == IContentHashResolver.contenthash.selector) { + bytes32 node = abi.decode(data[4:], (bytes32)); + return _contenthash(node, target); + } + } + + function _addr( + bytes32 node, + address target + ) private view returns (bytes memory) { + EVMFetcher + .newFetchRequest(verifier, target) + .getStatic(RECORD_VERSIONS_SLOT) + .element(node) + .getDynamic(VERSIONABLE_ADDRESSES_SLOT) + .ref(0) + .element(node) + .element(COIN_TYPE_ETH) + .fetch(this.addrCallback.selector, ""); // recordVersions + } + + function addrCallback( + bytes[] memory values, + bytes memory + ) public pure returns (bytes memory) { + return abi.encode(address(bytes20(values[1]))); + } + + function _addr( + bytes32 node, + uint256 coinType, + address target + ) private view returns (bytes memory) { + EVMFetcher + .newFetchRequest(verifier, target) + .getStatic(RECORD_VERSIONS_SLOT) + .element(node) + .getDynamic(VERSIONABLE_ADDRESSES_SLOT) + .ref(0) + .element(node) + .element(coinType) + .fetch(this.addrCoinTypeCallback.selector, ""); + } + + function addrCoinTypeCallback( + bytes[] memory values, + bytes memory + ) public pure returns (bytes memory) { + return abi.encode(values[1]); + } + + function _text( + bytes32 node, + string memory key, + address target + ) private view returns (bytes memory) { + EVMFetcher + .newFetchRequest(verifier, target) + .getStatic(RECORD_VERSIONS_SLOT) + .element(node) + .getDynamic(VERSIONABLE_TEXTS_SLOT) + .ref(0) + .element(node) + .element(key) + .fetch(this.textCallback.selector, ""); + } + + function textCallback( + bytes[] memory values, + bytes memory + ) public pure returns (bytes memory) { + return abi.encode(string(values[1])); + } + + function _contenthash( + bytes32 node, + address target + ) private view returns (bytes memory) { + EVMFetcher + .newFetchRequest(verifier, target) + .getStatic(RECORD_VERSIONS_SLOT) + .element(node) + .getDynamic(VERSIONABLE_HASHES_SLOT) + .ref(0) + .element(node) + .fetch(this.contenthashCallback.selector, ""); + } + + function contenthashCallback( + bytes[] memory values, + bytes memory + ) public pure returns (bytes memory) { + return abi.encode(values[1]); + } +} diff --git a/packages/l1-contracts/contracts/RollupMock.sol b/packages/l1-contracts/contracts/RollupMock.sol new file mode 100644 index 000000000..7499efb54 --- /dev/null +++ b/packages/l1-contracts/contracts/RollupMock.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.25; + +contract RollupMock { + function currentL2BlockNumber() public pure returns (uint256) { + return 96857; + } + + function stateRootHashes( + uint256 blockNumber + ) public pure returns (bytes32) { + return + 0x0bfb083c42510e3258119e3b27a7e84730b80f6c9009416dd6e532843af93a7e; + } +} diff --git a/packages/l1-contracts/contracts/Verifier.sol b/packages/l1-contracts/contracts/Verifier.sol new file mode 100644 index 000000000..1554e9825 --- /dev/null +++ b/packages/l1-contracts/contracts/Verifier.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.25; + +import {LineaVerifier} from "linea-verifier/contracts/LineaVerifier.sol"; + +contract Verifier is LineaVerifier { + constructor( + string[] memory urls, + address rollup + ) LineaVerifier(urls, rollup) {} +} diff --git a/packages/l1-contracts/contracts/deps.sol b/packages/l1-contracts/contracts/deps.sol new file mode 100644 index 000000000..a968a7a7f --- /dev/null +++ b/packages/l1-contracts/contracts/deps.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT + +import "@ensdomains/ens-contracts/contracts/registry/ENSRegistry.sol"; +import "@ensdomains/ens-contracts/contracts/wrapper/NameWrapper.sol"; +import "@ensdomains/ens-contracts/contracts/ethregistrar/BaseRegistrarImplementation.sol"; +import "@ensdomains/ens-contracts/contracts/wrapper/StaticMetadataService.sol"; +import {ReverseRegistrar} from "@ensdomains/ens-contracts/contracts/reverseRegistrar/ReverseRegistrar.sol"; +import {PublicResolver} from "@ensdomains/ens-contracts/contracts/resolvers/PublicResolver.sol"; diff --git a/packages/l1-contracts/hardhat.config.ts b/packages/l1-contracts/hardhat.config.ts new file mode 100644 index 000000000..7633670d8 --- /dev/null +++ b/packages/l1-contracts/hardhat.config.ts @@ -0,0 +1,24 @@ +import "@nomicfoundation/hardhat-toolbox"; +import { HardhatUserConfig } from "hardhat/config"; +import * as dotenv from "dotenv"; + +dotenv.config(); + +const config: HardhatUserConfig = { + solidity: { + compilers: [ + { + version: "0.8.25", + settings: { + optimizer: { + enabled: true, + runs: 200, + }, + viaIR: true, + }, + }, + ], + }, +}; + +export default config; diff --git a/packages/l1-contracts/package.json b/packages/l1-contracts/package.json new file mode 100644 index 000000000..22ffbba31 --- /dev/null +++ b/packages/l1-contracts/package.json @@ -0,0 +1,51 @@ +{ + "name": "l1-contracts", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "mocha test/testL1Resolver.spec.ts --timeout 10000 --exit", + "compile": "hardhat compile", + "clean": "rm -fr artifacts cache node_modules typechain-types" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "@chainlink/ccip-read-server": "^0.2.1", + "@ensdomains/buffer": "^0.1.1", + "@ensdomains/ens-contracts": "^1.1.4", + "@nomicfoundation/hardhat-chai-matchers": "^2.0.0", + "@nomicfoundation/hardhat-ethers": "^3.0.0", + "@nomicfoundation/hardhat-ignition": "^0.15.0", + "@nomicfoundation/hardhat-ignition-ethers": "^0.15.0", + "@nomicfoundation/hardhat-network-helpers": "^1.0.0", + "@nomicfoundation/hardhat-toolbox": "^5.0.0", + "@nomicfoundation/hardhat-verify": "^1.0.0", + "@nomicfoundation/ignition-core": "^0.15.0", + "@openzeppelin/contracts": "^4.1.0", + "@typechain/ethers-v6": "^0.4.0", + "@typechain/hardhat": "^8.0.0", + "@types/chai": "^4.2.0", + "chai": "^4.2.0", + "clones-with-immutable-args": "Arachnid/clones-with-immutable-args#feature/create2", + "dns-packet": "^5.6.1", + "dotenv": "^16.0.3", + "ethers": "^6.11.1", + "hardhat": "^2.22.1", + "hardhat-gas-reporter": "^1.0.8", + "linea-resolver-gateway": "^1.0.0", + "linea-verifier": "^1.0.0", + "mocha": "^10.3.0", + "solidity-coverage": "^0.8.1", + "supertest": "^6.3.3", + "ts-node": "^10.9.2", + "tslib": "^2.6.2", + "typechain": "^8.2.0", + "typescript": "^5.4.3" + }, + "devDependencies": { + "@types/mocha": ">=9.1.0", + "@types/node": "^20.11.30" + } +} \ No newline at end of file diff --git a/packages/l1-contracts/test/testL1Resolver.spec.ts b/packages/l1-contracts/test/testL1Resolver.spec.ts new file mode 100644 index 000000000..8b9e58b0e --- /dev/null +++ b/packages/l1-contracts/test/testL1Resolver.spec.ts @@ -0,0 +1,374 @@ +import { makeL2Gateway } from "linea-resolver-gateway"; +import { Server } from "@chainlink/ccip-read-server"; +import { HardhatEthersProvider } from "@nomicfoundation/hardhat-ethers/internal/hardhat-ethers-provider"; +import { HardhatEthersHelpers } from "@nomicfoundation/hardhat-ethers/types"; +import { expect } from "chai"; +import { + BrowserProvider, + Contract, + JsonRpcProvider, + Signer, + ethers as ethersT, +} from "ethers"; +import { FetchRequest } from "ethers"; +import { ethers } from "hardhat"; +import { EthereumProvider } from "hardhat/types"; +import request from "supertest"; +import packet from "dns-packet"; +const labelhash = (label) => ethers.keccak256(ethers.toUtf8Bytes(label)); +const encodeName = (name) => "0x" + packet.name.encode(name).toString("hex"); +const domainName = "linea.eth"; +const node = ethers.namehash(domainName); +const encodedname = encodeName(domainName); + +const EMPTY_ADDRESS = "0x0000000000000000000000000000000000000000"; +const EMPTY_BYTES32 = + "0x0000000000000000000000000000000000000000000000000000000000000000"; + +type ethersObj = typeof ethersT & + Omit & { + provider: Omit & { + _hardhatProvider: EthereumProvider; + }; + }; + +declare module "hardhat/types/runtime" { + const ethers: ethersObj; + interface HardhatRuntimeEnvironment { + ethers: ethersObj; + } +} + +describe("Crosschain Resolver", () => { + let l1Provider: BrowserProvider; + let l2Provider: JsonRpcProvider; + let signer: Signer; + let verifier: Contract; + let target: Contract; + let l2contract: Contract; + let ens: Contract; + let wrapper: Contract; + let baseRegistrar: Contract; + let signerAddress, l2ResolverAddress, wrapperAddress; + + before(async () => { + if (!process.env.L2_PROVIDER_URL) { + throw "No L2_PROVIDER_URL found in env file"; + } + if (!process.env.L2_RESOLVER_ADDRESS) { + throw "No L2_RESOLVER_ADDRESS found in env file"; + } + + // Hack to get a 'real' ethers provider from hardhat. The default `HardhatProvider` + // doesn't support CCIP-read. + l1Provider = new ethers.BrowserProvider(ethers.provider._hardhatProvider); + l2Provider = new ethers.JsonRpcProvider( + process.env.L2_PROVIDER_URL, + 59140, + { + staticNetwork: true, + } + ); + // provider.on("debug", (x: any) => console.log(JSON.stringify(x, undefined, 2))); + signer = await l1Provider.getSigner(0); + signerAddress = await signer.getAddress(); + + const Rollup = await ethers.getContractFactory("RollupMock", signer); + const rollup = await Rollup.deploy(); + + const gateway = makeL2Gateway( + (l1Provider as unknown) as JsonRpcProvider, + l2Provider, + await rollup.getAddress() + ); + const server = new Server(); + gateway.add(server); + const app = server.makeApp("/"); + const getUrl = FetchRequest.createGetUrlFunc(); + ethers.FetchRequest.registerGetUrl(async (req: FetchRequest) => { + if (req.url != "test:") return getUrl(req); + + const r = request(app).post("/"); + if (req.hasBody()) { + r.set("Content-Type", "application/json").send( + ethers.toUtf8String(req.body) + ); + } + const response = await r; + return { + statusCode: response.statusCode, + statusMessage: response.ok ? "OK" : response.statusCode.toString(), + body: ethers.toUtf8Bytes(JSON.stringify(response.body)), + headers: { + "Content-Type": "application/json", + }, + }; + }); + const ensFactory = await ethers.getContractFactory("ENSRegistry", signer); + ens = await ensFactory.deploy(); + const ensAddress = await ens.getAddress(); + const baseRegistrarFactory = await ethers.getContractFactory( + "BaseRegistrarImplementation", + signer + ); + baseRegistrar = await baseRegistrarFactory.deploy( + ensAddress, + ethers.namehash("eth") + ); + const baseRegistrarAddress = await baseRegistrar.getAddress(); + await baseRegistrar.addController(signerAddress); + const metaDataserviceFactory = await ethers.getContractFactory( + "StaticMetadataService", + signer + ); + const metaDataservice = await metaDataserviceFactory.deploy( + "https://ens.domains" + ); + const metaDataserviceAddress = await metaDataservice.getAddress(); + const reverseRegistrarFactory = await ethers.getContractFactory( + "ReverseRegistrar", + signer + ); + const reverseRegistrar = await reverseRegistrarFactory.deploy(ensAddress); + const reverseRegistrarAddress = await reverseRegistrar.getAddress(); + await ens.setSubnodeOwner( + EMPTY_BYTES32, + labelhash("reverse"), + signerAddress + ); + await ens.setSubnodeOwner( + ethers.namehash("reverse"), + labelhash("addr"), + reverseRegistrarAddress + ); + await ens.setSubnodeOwner( + EMPTY_BYTES32, + labelhash("eth"), + baseRegistrarAddress + ); + await baseRegistrar.register(labelhash("linea"), signerAddress, 100000000); + const publicResolverFactory = await ethers.getContractFactory( + "PublicResolver", + signer + ); + const publicResolver = await publicResolverFactory.deploy( + ensAddress, + "0x0000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000", + reverseRegistrarAddress + ); + const publicResolverAddress = await publicResolver.getAddress(); + await reverseRegistrar.setDefaultResolver(publicResolverAddress); + + const wrapperFactory = await ethers.getContractFactory( + "NameWrapper", + signer + ); + await l1Provider.send("evm_mine", []); + wrapper = await wrapperFactory.deploy( + ensAddress, + baseRegistrarAddress, + metaDataserviceAddress + ); + wrapperAddress = await wrapper.getAddress(); + const impl = await ethers.getContractFactory("PublicResolver", signer); + l2ResolverAddress = process.env.L2_RESOLVER_ADDRESS; + + const Mimc = await ethers.getContractFactory("Mimc", signer); + const mimc = await Mimc.deploy(); + + const SparseMerkleProof = await ethers.getContractFactory( + "SparseMerkleProof", + { libraries: { Mimc: await mimc.getAddress() }, signer } + ); + const sparseMerkleProof = await SparseMerkleProof.deploy(); + + const verifierFactory = await ethers.getContractFactory("Verifier", { + libraries: { + SparseMerkleProof: await sparseMerkleProof.getAddress(), + }, + signer, + }); + verifier = await verifierFactory.deploy( + ["test:"], + await rollup.getAddress() + ); + + const l1ResolverFactory = await ethers.getContractFactory( + "L1Resolver", + signer + ); + const verifierAddress = await verifier.getAddress(); + target = await l1ResolverFactory.deploy( + verifierAddress, + ensAddress, + wrapperAddress + ); + // Mine an empty block so we have something to prove against + await l1Provider.send("evm_mine", []); + l2contract = new ethers.Contract( + l2ResolverAddress, + impl.interface, + l2Provider + ); + }); + + it("should not allow non owner to set target", async () => { + const incorrectnode = ethers.namehash("notowned.eth"); + const incorrectname = encodeName("notowned.eth"); + // For some reason expect().to.be.reverted isn't working + // Throwing Error: missing revert data (action="estimateGas"... + try { + await target.setTarget(incorrectnode, l2ResolverAddress); + } catch (e) {} + + const result = await target.getTarget(incorrectname, 0); + expect(result[1]).to.equal(EMPTY_ADDRESS); + }); + + it("should allow owner to set target", async () => { + await target.setTarget(node, signerAddress); + const result = await target.getTarget(encodeName(domainName), 0); + expect(result[1]).to.equal(signerAddress); + }); + + it("subname should get target of its parent", async () => { + const subname = "d.linea.eth"; + const encodedsubname = encodeName(subname); + const subnode = ethers.namehash(subname); + await target.setTarget(node, signerAddress); + const result = await target.getTarget(encodedsubname, 0); + expect(result[0]).to.equal(subnode); + expect(result[1]).to.equal(signerAddress); + }); + + it("should allow wrapped owner to set target", async () => { + const label = "wrapped"; + const tokenId = labelhash(label); + await baseRegistrar.setApprovalForAll(wrapperAddress, true); + await baseRegistrar.register(tokenId, signerAddress, 100000000); + await wrapper.wrapETH2LD( + label, + signerAddress, + 0, // CAN_DO_EVERYTHING + EMPTY_ADDRESS + ); + const wrappedtnode = ethers.namehash(`${label}.eth`); + await target.setTarget(wrappedtnode, l2ResolverAddress); + const encodedname = encodeName(`${label}.eth`); + const result = await target.getTarget(encodedname, 0); + expect(result[1]).to.equal(l2ResolverAddress); + }); + + it.only("should resolve empty ETH Address", async () => { + await target.setTarget(node, l2ResolverAddress); + const addr = "0x0000000000000000000000000000000000000000"; + const result = await l2contract["addr(bytes32)"](node); + expect(ethers.getAddress(result)).to.equal(addr); + await l1Provider.send("evm_mine", []); + + const i = new ethers.Interface(["function addr(bytes32) returns(address)"]); + const calldata = i.encodeFunctionData("addr", [node]); + const result2 = await target.resolve(encodedname, calldata, { + enableCcipRead: true, + }); + const decoded = i.decodeFunctionResult("addr", result2); + expect(decoded[0]).to.equal(addr); + }); + + it("should resolve ETH Address", async () => { + await target.setTarget(node, l2ResolverAddress); + const addr = "0x5A384227B65FA093DEC03Ec34e111Db80A040615"; + await l2contract.clearRecords(node); + await l2contract["setAddr(bytes32,address)"](node, addr); + const result = await l2contract["addr(bytes32)"](node); + expect(ethers.getAddress(result)).to.equal(addr); + await l1Provider.send("evm_mine", []); + + const i = new ethers.Interface(["function addr(bytes32) returns(address)"]); + const calldata = i.encodeFunctionData("addr", [node]); + const result2 = await target.resolve(encodedname, calldata, { + enableCcipRead: true, + }); + const decoded = i.decodeFunctionResult("addr", result2); + expect(decoded[0]).to.equal(addr); + }); + + it("should resolve ETH Address for subname", async () => { + await target.setTarget(node, l2ResolverAddress); + const addr = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"; + await l2contract.clearRecords(node); + const subname = "d.foo.eth"; + const subnode = ethers.namehash(subname); + const encodedsubname = encodeName(subname); + await l2contract["setAddr(bytes32,address)"](subnode, addr); + const result = await l2contract["addr(bytes32)"](subnode); + expect(ethers.getAddress(result)).to.equal(addr); + await l1Provider.send("evm_mine", []); + const i = new ethers.Interface(["function addr(bytes32) returns(address)"]); + const calldata = i.encodeFunctionData("addr", [subnode]); + + const result2 = await target.resolve(encodedsubname, calldata, { + enableCcipRead: true, + }); + const decoded = i.decodeFunctionResult("addr", result2); + expect(decoded[0]).to.equal(addr); + }); + + it("should resolve non ETH Address", async () => { + await target.setTarget(node, l2ResolverAddress); + const addr = "0x76a91462e907b15cbf27d5425399ebf6f0fb50ebb88f1888ac"; + const coinType = 0; // BTC + await l2contract.clearRecords(node); + await l2contract["setAddr(bytes32,uint256,bytes)"](node, coinType, addr); + await l1Provider.send("evm_mine", []); + + const i = new ethers.Interface([ + "function addr(bytes32,uint256) returns(bytes)", + ]); + const calldata = i.encodeFunctionData("addr", [node, coinType]); + const result2 = await target.resolve(encodedname, calldata, { + enableCcipRead: true, + }); + const decoded = i.decodeFunctionResult("addr", result2); + expect(decoded[0]).to.equal(addr); + }); + + it("should resolve text record", async () => { + await target.setTarget(node, l2ResolverAddress); + const key = "name"; + const value = "nick.eth"; + await l2contract.clearRecords(node); + await l2contract.setText(node, key, value); + await l1Provider.send("evm_mine", []); + + const i = new ethers.Interface([ + "function text(bytes32,string) returns(string)", + ]); + const calldata = i.encodeFunctionData("text", [node, key]); + const result2 = await target.resolve(encodedname, calldata, { + enableCcipRead: true, + }); + const decoded = i.decodeFunctionResult("text", result2); + expect(decoded[0]).to.equal(value); + }); + + it("should test contenthash", async () => { + await target.setTarget(node, l2ResolverAddress); + const contenthash = + "0xe3010170122029f2d17be6139079dc48696d1f582a8530eb9805b561eda517e22a892c7e3f1f"; + await l2contract.clearRecords(node); + await l2contract.setContenthash(node, contenthash); + await l1Provider.send("evm_mine", []); + + const i = new ethers.Interface([ + "function contenthash(bytes32) returns(bytes)", + ]); + const calldata = i.encodeFunctionData("contenthash", [node]); + const result2 = await target.resolve(encodedname, calldata, { + enableCcipRead: true, + }); + const decoded = i.decodeFunctionResult("contenthash", result2); + expect(decoded[0]).to.equal(contenthash); + }); +}); diff --git a/packages/l1-contracts/tsconfig.json b/packages/l1-contracts/tsconfig.json new file mode 100644 index 000000000..a8bc0bfda --- /dev/null +++ b/packages/l1-contracts/tsconfig.json @@ -0,0 +1,24 @@ +{ + "include": ["test"], + "compilerOptions": { + "module": "esnext", + "lib": ["dom", "esnext"], + "importHelpers": true, + "declaration": true, + "sourceMap": true, + "rootDir": "./test", + "noUnusedParameters": true, + "moduleResolution": "node", + "jsx": "react", + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "resolveJsonModule": true + }, + "ts-node": { + "compilerOptions": { + "module": "commonjs" + } + } +} diff --git a/packages/linea-verifier/contracts/EVMFetchTarget.sol b/packages/linea-verifier/contracts/EVMFetchTarget.sol index 43750c551..a294860b9 100644 --- a/packages/linea-verifier/contracts/EVMFetchTarget.sol +++ b/packages/linea-verifier/contracts/EVMFetchTarget.sol @@ -1,5 +1,5 @@ //SPDX-License-Identifier: MIT -pragma solidity ^0.8.19; +pragma solidity ^0.8.25; import {IEVMVerifier} from "./IEVMVerifier.sol"; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; diff --git a/packages/linea-verifier/contracts/EVMFetcher.sol b/packages/linea-verifier/contracts/EVMFetcher.sol index 717731833..e58af761f 100644 --- a/packages/linea-verifier/contracts/EVMFetcher.sol +++ b/packages/linea-verifier/contracts/EVMFetcher.sol @@ -1,5 +1,5 @@ //SPDX-License-Identifier: MIT -pragma solidity ^0.8.19; +pragma solidity ^0.8.25; import {IEVMVerifier} from "./IEVMVerifier.sol"; import {EVMFetchTarget} from "./EVMFetchTarget.sol"; diff --git a/packages/linea-verifier/contracts/IEVMVerifier.sol b/packages/linea-verifier/contracts/IEVMVerifier.sol index fb516d85b..5a6fee372 100644 --- a/packages/linea-verifier/contracts/IEVMVerifier.sol +++ b/packages/linea-verifier/contracts/IEVMVerifier.sol @@ -1,5 +1,5 @@ //SPDX-License-Identifier: MIT -pragma solidity ^0.8.19; +pragma solidity ^0.8.25; interface IEVMVerifier { function gatewayURLs() external view returns (string[] memory); diff --git a/packages/linea-verifier/contracts/LineaProofHelper.sol b/packages/linea-verifier/contracts/LineaProofHelper.sol index d61e08456..e52148043 100644 --- a/packages/linea-verifier/contracts/LineaProofHelper.sol +++ b/packages/linea-verifier/contracts/LineaProofHelper.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.19; +pragma solidity ^0.8.25; import {SparseMerkleProof} from "./lib/SparseMerkleProof.sol"; uint256 constant LAST_LEAF_INDEX = 41; diff --git a/packages/linea-verifier/contracts/LineaVerifier.sol b/packages/linea-verifier/contracts/LineaVerifier.sol index bb6d81a6d..a7b8a309e 100644 --- a/packages/linea-verifier/contracts/LineaVerifier.sol +++ b/packages/linea-verifier/contracts/LineaVerifier.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.19; +pragma solidity ^0.8.25; import {IEVMVerifier} from "./IEVMVerifier.sol"; import {StorageProofStruct, AccountProofStruct, LineaProofHelper} from "./LineaProofHelper.sol"; diff --git a/packages/linea-verifier/contracts/lib/Mimc.sol b/packages/linea-verifier/contracts/lib/Mimc.sol index 702ea64ee..848e516b7 100644 --- a/packages/linea-verifier/contracts/lib/Mimc.sol +++ b/packages/linea-verifier/contracts/lib/Mimc.sol @@ -15,7 +15,7 @@ // limitations under the License. // Code generated by gnark DO NOT EDIT -pragma solidity 0.8.19; +pragma solidity 0.8.25; library Mimc { uint256 constant FR_FIELD = diff --git a/packages/linea-verifier/contracts/lib/SparseMerkleProof.sol b/packages/linea-verifier/contracts/lib/SparseMerkleProof.sol index 3dfdd00ae..232fad565 100644 --- a/packages/linea-verifier/contracts/lib/SparseMerkleProof.sol +++ b/packages/linea-verifier/contracts/lib/SparseMerkleProof.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0 -pragma solidity 0.8.19; +pragma solidity 0.8.25; import {Mimc} from "./Mimc.sol"; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0a12c2c73..cbc51eb1c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -392,6 +392,77 @@ importers: '@types/node': 12.0.0 '@types/supertest': 2.0.16 + packages/l1-contracts: + specifiers: + '@chainlink/ccip-read-server': ^0.2.1 + '@ensdomains/buffer': ^0.1.1 + '@ensdomains/ens-contracts': ^1.1.4 + '@nomicfoundation/hardhat-chai-matchers': ^2.0.0 + '@nomicfoundation/hardhat-ethers': ^3.0.0 + '@nomicfoundation/hardhat-ignition': ^0.15.0 + '@nomicfoundation/hardhat-ignition-ethers': ^0.15.0 + '@nomicfoundation/hardhat-network-helpers': ^1.0.0 + '@nomicfoundation/hardhat-toolbox': ^5.0.0 + '@nomicfoundation/hardhat-verify': ^1.0.0 + '@nomicfoundation/ignition-core': ^0.15.0 + '@openzeppelin/contracts': ^4.1.0 + '@typechain/ethers-v6': ^0.4.0 + '@typechain/hardhat': ^8.0.0 + '@types/chai': ^4.2.0 + '@types/mocha': '>=9.1.0' + '@types/node': ^20.11.30 + chai: ^4.2.0 + clones-with-immutable-args: Arachnid/clones-with-immutable-args#feature/create2 + dns-packet: ^5.6.1 + dotenv: ^16.0.3 + ethers: ^6.11.1 + hardhat: ^2.22.1 + hardhat-gas-reporter: ^1.0.8 + linea-resolver-gateway: ^1.0.0 + linea-verifier: ^1.0.0 + mocha: ^10.3.0 + solidity-coverage: ^0.8.1 + supertest: ^6.3.3 + ts-node: ^10.9.2 + tslib: ^2.6.2 + typechain: ^8.2.0 + typescript: ^5.4.3 + dependencies: + '@chainlink/ccip-read-server': 0.2.1 + '@ensdomains/buffer': 0.1.1 + '@ensdomains/ens-contracts': 1.1.4 + '@nomicfoundation/hardhat-chai-matchers': 2.0.6_jdbevpxkivs2napmflo3uukf4u + '@nomicfoundation/hardhat-ethers': 3.0.5_duzhf5skjnmsa2dbfyive6aidy + '@nomicfoundation/hardhat-ignition': 0.15.0_3s37mufyk3hhmzfnu6jyw334pm + '@nomicfoundation/hardhat-ignition-ethers': 0.15.0_ucfvlxawy2vxuswcwdkjpms6uq + '@nomicfoundation/hardhat-network-helpers': 1.0.10_hardhat@2.22.2 + '@nomicfoundation/hardhat-toolbox': 5.0.0_uov6domybxgvm6o5htzjlrdj44 + '@nomicfoundation/hardhat-verify': 1.1.1_hardhat@2.22.2 + '@nomicfoundation/ignition-core': 0.15.0 + '@openzeppelin/contracts': 4.9.6 + '@typechain/ethers-v6': 0.4.3_dow6yfvguwbajy4xkhnmxrzqny + '@typechain/hardhat': 8.0.3_rt25j3vwtqpasnlw2xf3pat2lq + '@types/chai': 4.3.14 + chai: 4.4.1 + clones-with-immutable-args: github.com/Arachnid/clones-with-immutable-args/23768824cdc037f361f7065538b8f949cae9d3d1 + dns-packet: 5.6.1 + dotenv: 16.4.5 + ethers: 6.11.1 + hardhat: 2.22.2_y7776bjnyobavfdli66kdlm45y + hardhat-gas-reporter: 1.0.10_hardhat@2.22.2 + linea-resolver-gateway: link:../gateway + linea-verifier: link:../linea-verifier + mocha: 10.4.0 + solidity-coverage: 0.8.11_hardhat@2.22.2 + supertest: 6.3.4 + ts-node: 10.9.2_3gszlplltwxq26q56hnekbvdpe + tslib: 2.6.2 + typechain: 8.3.2_typescript@5.4.3 + typescript: 5.4.3 + devDependencies: + '@types/mocha': 10.0.6 + '@types/node': 20.11.30 + packages/linea-verifier: specifiers: '@openzeppelin/contracts': ^4.9.3 @@ -2004,6 +2075,15 @@ packages: typescript-logging: 1.0.1 dev: false + /@ensdomains/ens-contracts/1.1.4: + resolution: {integrity: sha512-kjdcjaznMtE2lwjAVTX2irs8mgNgJCVuB5hnhFhiMaO8dR/tlHQ5UhtZjhSYRhkZd0hLXYrMkXp6thnwpG+ltg==} + dependencies: + '@ensdomains/buffer': 0.1.1 + '@ensdomains/solsha1': 0.0.3 + '@openzeppelin/contracts': 4.9.6 + dns-packet: 5.6.1 + dev: false + /@ensdomains/ens-contracts/1.2.0-beta.0: resolution: {integrity: sha512-mb/1cPtwhShyaP6fWqDix6GfrJwVWlKgCFxzDKmqNGeFQhBOD/ojYGsy96eJ9UlM/7Tsg7w4RAj7xWrOlHtYIA==} dependencies: @@ -2686,6 +2766,16 @@ packages: '@ethersproject/logger': 5.7.0 '@ethersproject/properties': 5.7.0 + /@ethersproject/address/5.6.1: + resolution: {integrity: sha512-uOgF0kS5MJv9ZvCz7x6T2EXJSzotiybApn4XlOgoTX0xdtyVIJ7pF+6cGPxiEq/dpBiTfMiw7Yc81JcwhSYA0Q==} + dependencies: + '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/keccak256': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/rlp': 5.7.0 + dev: false + /@ethersproject/address/5.7.0: resolution: {integrity: sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==} dependencies: @@ -3923,6 +4013,42 @@ packages: - supports-color dev: false + /@nomicfoundation/hardhat-ignition-ethers/0.15.0_ucfvlxawy2vxuswcwdkjpms6uq: + resolution: {integrity: sha512-KmMNUc/jptfwdPA9ukQf+Ajon+m2vLBjDL2ze7d/vQdrS+fDxmoVwmbbEk4GOjianZcwgQOWD9dEWaj04QiowA==} + peerDependencies: + '@nomicfoundation/hardhat-ethers': ^3.0.4 + '@nomicfoundation/hardhat-ignition': ^0.15.0 + '@nomicfoundation/ignition-core': ^0.15.0 + ethers: ^6.7.0 + hardhat: ^2.18.0 + dependencies: + '@nomicfoundation/hardhat-ethers': 3.0.5_duzhf5skjnmsa2dbfyive6aidy + '@nomicfoundation/hardhat-ignition': 0.15.0_3s37mufyk3hhmzfnu6jyw334pm + '@nomicfoundation/ignition-core': 0.15.0 + ethers: 6.11.1 + hardhat: 2.22.2_y7776bjnyobavfdli66kdlm45y + dev: false + + /@nomicfoundation/hardhat-ignition/0.15.0_3s37mufyk3hhmzfnu6jyw334pm: + resolution: {integrity: sha512-GbAe90O22uM67U/JnffXX+mBMn0HqCKSH+D98Tb5uWqR1N/M00cB3yY8OdqzVai7I6SuIKTc91mPdvtWt8R3MA==} + peerDependencies: + '@nomicfoundation/hardhat-verify': ^2.0.1 + hardhat: ^2.18.0 + dependencies: + '@nomicfoundation/hardhat-verify': 1.1.1_hardhat@2.22.2 + '@nomicfoundation/ignition-core': 0.15.0 + '@nomicfoundation/ignition-ui': 0.15.0 + chalk: 4.1.2 + debug: 4.3.4 + fs-extra: 10.1.0 + hardhat: 2.22.2_y7776bjnyobavfdli66kdlm45y + prompts: 2.4.2 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: false + /@nomicfoundation/hardhat-network-helpers/1.0.10_hardhat@2.22.2: resolution: {integrity: sha512-R35/BMBlx7tWN5V6d/8/19QCwEmIdbnA4ZrsuXgvs8i2qFx5i7h6mH5pBS4Pwi4WigLH+upl6faYusrNPuzMrQ==} peerDependencies: @@ -3972,6 +4098,48 @@ packages: typescript: 5.4.3 dev: false + /@nomicfoundation/hardhat-toolbox/5.0.0_uov6domybxgvm6o5htzjlrdj44: + resolution: {integrity: sha512-FnUtUC5PsakCbwiVNsqlXVIWG5JIb5CEZoSXbJUsEBun22Bivx2jhF1/q9iQbzuaGpJKFQyOhemPB2+XlEE6pQ==} + peerDependencies: + '@nomicfoundation/hardhat-chai-matchers': ^2.0.0 + '@nomicfoundation/hardhat-ethers': ^3.0.0 + '@nomicfoundation/hardhat-ignition-ethers': ^0.15.0 + '@nomicfoundation/hardhat-network-helpers': ^1.0.0 + '@nomicfoundation/hardhat-verify': ^2.0.0 + '@typechain/ethers-v6': ^0.5.0 + '@typechain/hardhat': ^9.0.0 + '@types/chai': ^4.2.0 + '@types/mocha': '>=9.1.0' + '@types/node': '>=18.0.0' + chai: ^4.2.0 + ethers: ^6.4.0 + hardhat: ^2.11.0 + hardhat-gas-reporter: ^1.0.8 + solidity-coverage: ^0.8.1 + ts-node: '>=8.0.0' + typechain: ^8.3.0 + typescript: '>=4.5.0' + dependencies: + '@nomicfoundation/hardhat-chai-matchers': 2.0.6_jdbevpxkivs2napmflo3uukf4u + '@nomicfoundation/hardhat-ethers': 3.0.5_duzhf5skjnmsa2dbfyive6aidy + '@nomicfoundation/hardhat-ignition-ethers': 0.15.0_ucfvlxawy2vxuswcwdkjpms6uq + '@nomicfoundation/hardhat-network-helpers': 1.0.10_hardhat@2.22.2 + '@nomicfoundation/hardhat-verify': 1.1.1_hardhat@2.22.2 + '@typechain/ethers-v6': 0.4.3_dow6yfvguwbajy4xkhnmxrzqny + '@typechain/hardhat': 8.0.3_rt25j3vwtqpasnlw2xf3pat2lq + '@types/chai': 4.3.14 + '@types/mocha': 10.0.6 + '@types/node': 20.11.30 + chai: 4.4.1 + ethers: 6.11.1 + hardhat: 2.22.2_y7776bjnyobavfdli66kdlm45y + hardhat-gas-reporter: 1.0.10_hardhat@2.22.2 + solidity-coverage: 0.8.11_hardhat@2.22.2 + ts-node: 10.9.2_3gszlplltwxq26q56hnekbvdpe + typechain: 8.3.2_typescript@5.4.3 + typescript: 5.4.3 + dev: false + /@nomicfoundation/hardhat-verify/1.1.1_hardhat@2.22.2: resolution: {integrity: sha512-9QsTYD7pcZaQFEA3tBb/D/oCStYDiEVDN7Dxeo/4SCyHRSm86APypxxdOMEPlGmXsAvd+p1j/dTODcpxb8aztA==} peerDependencies: @@ -3991,6 +4159,27 @@ packages: - supports-color dev: false + /@nomicfoundation/ignition-core/0.15.0: + resolution: {integrity: sha512-d/h8jgJHY4xIroHqdaGeTkTqjQeuzmU759AOn1Fg88cuxVhS7JM22ZI0bQWyLNSMsVstHBIo+lSMIsvm9jBF2w==} + dependencies: + '@ethersproject/address': 5.6.1 + cbor: 9.0.2 + debug: 4.3.4 + ethers: 6.11.1 + fs-extra: 10.1.0 + immer: 10.0.2 + lodash: 4.17.21 + ndjson: 2.0.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: false + + /@nomicfoundation/ignition-ui/0.15.0: + resolution: {integrity: sha512-RBvvQ0e8RcEc/LoSzNTPVKZZ5vEwlmxt7PXG278+6DqCrOqxqmh6W9PtK/4mwwvnTeBqds+8j81jDf6vJbOVBQ==} + dev: false + /@nomicfoundation/solidity-analyzer-darwin-arm64/0.1.1: resolution: {integrity: sha512-KcTodaQw8ivDZyF+D76FokN/HdpgGpfjc/gFCImdLUyqB6eSWVaZPazMbeAjmfhx3R0zm/NYVzxwAokFKgrc0w==} engines: {node: '>= 10'} @@ -8515,6 +8704,13 @@ packages: dependencies: nofilter: 3.1.0 + /cbor/9.0.2: + resolution: {integrity: sha512-JPypkxsB10s9QOWwa6zwPzqE1Md3vqpPc+cai4sAecuCsRyAtAl/pMyhPlMbT/xtPnm2dznJZYRLui57qiRhaQ==} + engines: {node: '>=16'} + dependencies: + nofilter: 3.1.0 + dev: false + /chai-as-promised/7.1.1_chai@4.4.1: resolution: {integrity: sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==} peerDependencies: @@ -12128,7 +12324,6 @@ packages: graceful-fs: 4.2.11 jsonfile: 6.1.0 universalify: 2.0.1 - dev: true /fs-extra/11.2.0: resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==} @@ -13267,6 +13462,10 @@ packages: resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} dev: false + /immer/10.0.2: + resolution: {integrity: sha512-Rx3CqeqQ19sxUtYV9CU911Vhy8/721wRFnJv3REVGWUmoAcIwzifTsdmJte/MV+0/XpM35LZdQMBGkRIoLPwQA==} + dev: false + /immer/9.0.21: resolution: {integrity: sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==} dev: false @@ -15625,6 +15824,18 @@ packages: /natural-compare/1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + /ndjson/2.0.0: + resolution: {integrity: sha512-nGl7LRGrzugTtaFcJMhLbpzJM6XdivmbkdlaGcrk/LXg2KL/YBC6z1g70xh0/al+oFuVFP8N8kiWRucmeEH/qQ==} + engines: {node: '>=10'} + hasBin: true + dependencies: + json-stringify-safe: 5.0.1 + minimist: 1.2.8 + readable-stream: 3.6.2 + split2: 3.2.2 + through2: 4.0.2 + dev: false + /negotiator/0.6.3: resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} engines: {node: '>= 0.6'} @@ -18568,6 +18779,12 @@ packages: dependencies: extend-shallow: 3.0.2 + /split2/3.2.2: + resolution: {integrity: sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==} + dependencies: + readable-stream: 3.6.2 + dev: false + /split2/4.2.0: resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} engines: {node: '>= 10.x'} @@ -19441,6 +19658,12 @@ packages: xtend: 4.0.2 dev: true + /through2/4.0.2: + resolution: {integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==} + dependencies: + readable-stream: 3.6.2 + dev: false + /timed-out/4.0.1: resolution: {integrity: sha512-G7r3AhovYtr5YKOWQkta8RKAPb+J9IsO4uVmzjl8AZwfhs8UcUwTiD6gcJYSgOtzyjvQKrKYn41syHbUWMkafA==} engines: {node: '>=0.10.0'} @@ -19638,6 +19861,37 @@ packages: typescript: 3.9.10 yargs-parser: 18.1.3 + /ts-node/10.9.2_3gszlplltwxq26q56hnekbvdpe: + resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 20.11.30 + acorn: 8.11.3 + acorn-walk: 8.3.2 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.4.3 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + dev: false + /ts-node/10.9.2_72qbqdwn3fghjusb3itdkyfobe: resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} hasBin: true @@ -22147,3 +22401,9 @@ packages: react: 18.2.0 use-sync-external-store: 1.2.0_react@18.2.0 dev: false + + github.com/Arachnid/clones-with-immutable-args/23768824cdc037f361f7065538b8f949cae9d3d1: + resolution: {tarball: https://codeload.github.com/Arachnid/clones-with-immutable-args/tar.gz/23768824cdc037f361f7065538b8f949cae9d3d1} + name: clones-with-immutable-args + version: 1.1.0 + dev: false