├── .env.example ├── .eslintignore ├── .eslintrc.js ├── .githooks └── pre-commit ├── .github └── workflows │ ├── build-docker.yml │ └── main.yml ├── .gitignore ├── .prettierrc ├── .solcover.js ├── .solhint.json ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── VERIFY.md ├── audits ├── Hexens_Polygon_zkEVM_PUBLIC_27.02.23.pdf └── zkEVM-bridge-Spearbit-27-March.pdf ├── compiled-contracts ├── ERC20PermitMock.json ├── FflonkVerifier.json ├── PolygonZkEVM.json ├── PolygonZkEVMBridge.json ├── PolygonZkEVMBridgeMock.json ├── PolygonZkEVMDeployer.json ├── PolygonZkEVMGlobalExitRoot.json ├── PolygonZkEVMGlobalExitRootL2.json ├── PolygonZkEVMGlobalExitRootL2Mock.json ├── PolygonZkEVMGlobalExitRootMock.json ├── PolygonZkEVMMock.json ├── PolygonZkEVMTimelock.json ├── ProxyAdmin.json ├── TokenWrapped.json ├── TransparentUpgradeableProxy.json └── VerifierRollupHelperMock.json ├── contracts ├── PolygonZkEVM.sol ├── PolygonZkEVMBridge.sol ├── PolygonZkEVMGlobalExitRoot.sol ├── PolygonZkEVMGlobalExitRootL2.sol ├── PolygonZkEVMTimelock.sol ├── deployment │ └── PolygonZkEVMDeployer.sol ├── interfaces │ ├── IBasePolygonZkEVMGlobalExitRoot.sol │ ├── IBridgeMessageReceiver.sol │ ├── IPolygonZkEVMBridge.sol │ ├── IPolygonZkEVMErrors.sol │ ├── IPolygonZkEVMGlobalExitRoot.sol │ └── IVerifierRollup.sol ├── lib │ ├── DepositContract.sol │ ├── EmergencyManager.sol │ ├── GlobalExitRootLib.sol │ └── TokenWrapped.sol ├── mainnetUpgraded │ └── PolygonZkEVMUpgraded.sol ├── mocks │ ├── DAI.sol │ ├── DepositContractMock.sol │ ├── ERC20PermitMock.sol │ ├── ERC20WeirdMetadata.sol │ ├── PolygonZkEVMBridgeMock.sol │ ├── PolygonZkEVMGlobalExitRootL2Mock.sol │ ├── PolygonZkEVMGlobalExitRootMock.sol │ ├── PolygonZkEVMMock.sol │ ├── SequenceBatchesMock.sol │ ├── Uni.sol │ └── VerifierRollupHelperMock.sol ├── testnet │ ├── PolygonZkEVMTestnetClearStorage.sol │ └── PolygonZkEVMTestnetV2.sol └── verifiers │ └── FflonkVerifier.sol ├── deployment ├── 0_createGenesisMainnet.js ├── 1_createGenesis.js ├── 2_deployPolygonZKEVMDeployer.js ├── 3_deployContracts.js ├── README.md ├── deploy_parameters.json.example ├── genesis.json ├── helpers │ └── deployment-helpers.js ├── testnet │ └── prepareTestnet.js ├── verifyContracts.js └── verifyzkEVMDeployer.js ├── docker ├── Dockerfile.geth ├── README.md ├── docker-compose.geth.yml └── scripts │ ├── deploy-docker.sh │ ├── deploy-dockerv2.sh │ ├── deploy_parameters_docker.json │ ├── fund-accounts.js │ └── genesis_docker.json ├── docs ├── PolygonZkEVM.md ├── PolygonZkEVMBridge.md ├── PolygonZkEVMGlobalExitRoot.md ├── PolygonZkEVMGlobalExitRootL2.md ├── PolygonZkEVMTimelock.md ├── deployment │ └── PolygonZkEVMDeployer.md ├── lib │ ├── DepositContract.md │ ├── EmergencyManager.md │ ├── GlobalExitRootLib.md │ └── TokenWrapped.md ├── mainnetUpgraded │ └── PolygonZkEVMUpgraded.md ├── templates │ └── contract.hbs └── testnet │ ├── PolygonZkEVMTestnet.md │ ├── PolygonZkEVMTestnetClearStorage.md │ └── PolygonZkEVMTestnetV2.md ├── gas_report.md ├── hardhat.config.js ├── index.js ├── package-lock.json ├── package.json ├── src ├── create-genesis.js └── permit-helper.js ├── test └── contracts │ ├── bridge.test.js │ ├── bridgeMock.test.js │ ├── bridge_metadata.test.js │ ├── bridge_permit.test.js │ ├── depositContractMock.test.js │ ├── emergencyManager.test.js │ ├── globalExitRootManager.test.js │ ├── globalExitRootManagerL2.test.js │ ├── helpers │ └── test-helpers.js │ ├── polygonZkEVM.test.js │ ├── polygonZkEVMDeployer.test.js │ ├── polygonZkEVMTestnetV2.test.js │ ├── polygonZkEVMUpgraded.test.js │ ├── real-prover │ ├── real-flow.test.js │ ├── real-prover-test-inputs.test.js │ └── test-inputs │ │ ├── input.json │ │ ├── proof.json │ │ └── public.json │ ├── snark_stark_input.test.js │ └── timelockUpgradeTest.js ├── upgrade ├── README.md ├── arguments.js ├── deployVerifier.js ├── simpleUpgrade.js ├── timeLockUpgrade.js └── upgrade_parameters.json.example └── verifyMainnetDeployment ├── mainnetDeployParameters.json ├── mainnetDeployment.json ├── verifyDeployment.md ├── verifyMainnetDeployment.js └── verifyMainnetProofVerifier.md /.env.example: -------------------------------------------------------------------------------- 1 | MNEMONIC="test test test test test test test test test test test junk" 2 | INFURA_PROJECT_ID="" 3 | ETHERSCAN_API_KEY="" -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | zkproverjs/ -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | 'mocha', 4 | ], 5 | env: { 6 | node: true, 7 | mocha: true, 8 | }, 9 | extends: 'airbnb-base', 10 | rules: { 11 | indent: ['error', 4], 12 | 'mocha/no-exclusive-tests': 'error', 13 | 'max-len': ['error', { 14 | code: 140, comments: 200, ignoreStrings: true, ignoreTemplateLiterals: true, 15 | }], 16 | 'no-unused-vars': [2, { varsIgnorePattern: 'export^' }], 17 | 'no-return-assign': [0], 18 | 'no-underscore-dangle': [0], 19 | 'no-plusplus': ['error', { allowForLoopAfterthoughts: true }], 20 | 'func-names': [0], 21 | 'class-methods-use-this': [0], 22 | 'no-bitwise': [0], 23 | 'no-param-reassign': 'off', 24 | 'no-console': [2, { allow: ['warn', 'error'] }], 25 | 'import/prefer-default-export': [0], 26 | 'lines-between-class-members': ['error', 'always', { exceptAfterSingleLine: true }], 27 | 'multiline-comment-style': 'error', 28 | 'import/no-extraneous-dependencies': 'off' 29 | }, 30 | }; 31 | -------------------------------------------------------------------------------- /.githooks/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ## To use this hook execute in the project root: 4 | ## git config --local core.hooksPath .githooks/ 5 | if npm run lint; then 6 | npx hardhat compile --force 7 | npm run docgen 8 | git add docs 9 | cp artifacts/contracts/PolygonZkEVMBridge.sol/PolygonZkEVMBridge.json compiled-contracts/ 10 | cp artifacts/contracts/PolygonZkEVMGlobalExitRoot.sol/PolygonZkEVMGlobalExitRoot.json compiled-contracts/ 11 | cp artifacts/contracts/PolygonZkEVMGlobalExitRootL2.sol/PolygonZkEVMGlobalExitRootL2.json compiled-contracts/ 12 | cp artifacts/contracts/lib/TokenWrapped.sol/TokenWrapped.json compiled-contracts/ 13 | cp artifacts/contracts/mocks/PolygonZkEVMBridgeMock.sol/PolygonZkEVMBridgeMock.json compiled-contracts/ 14 | cp artifacts/contracts/mocks/ERC20PermitMock.sol/ERC20PermitMock.json compiled-contracts/ 15 | cp artifacts/contracts/mocks/PolygonZkEVMGlobalExitRootL2Mock.sol/PolygonZkEVMGlobalExitRootL2Mock.json compiled-contracts/ 16 | cp artifacts/contracts/mocks/PolygonZkEVMGlobalExitRootMock.sol/PolygonZkEVMGlobalExitRootMock.json compiled-contracts/ 17 | cp artifacts/contracts/mocks/PolygonZkEVMMock.sol/PolygonZkEVMMock.json compiled-contracts/ 18 | cp artifacts/contracts/mocks/VerifierRollupHelperMock.sol/VerifierRollupHelperMock.json compiled-contracts/ 19 | cp artifacts/contracts/PolygonZkEVM.sol/PolygonZkEVM.json compiled-contracts/ 20 | cp artifacts/contracts/verifiers/FflonkVerifier.sol/FflonkVerifier.json compiled-contracts/ 21 | cp artifacts/@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol/ProxyAdmin.json compiled-contracts/ 22 | cp artifacts/@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol/TransparentUpgradeableProxy.json compiled-contracts/ 23 | cp artifacts/contracts/deployment/PolygonZkEVMDeployer.sol/PolygonZkEVMDeployer.json compiled-contracts/ 24 | cp artifacts/contracts/PolygonZkEVMTimelock.sol/PolygonZkEVMTimelock.json compiled-contracts/ 25 | git add compiled-contracts 26 | exit 0 27 | else 28 | exit 1 29 | fi 30 | 31 | -------------------------------------------------------------------------------- /.github/workflows/build-docker.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: Build-Docker image 5 | 6 | on: 7 | push: 8 | branches: [main] 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | 13 | strategy: 14 | matrix: 15 | node-version: [16.x] 16 | 17 | steps: 18 | - name: Use Node.js ${{ matrix.node-version }} 19 | uses: actions/setup-node@v1 20 | with: 21 | node-version: ${{ matrix.node-version }} 22 | - name: Set int-bot SSH key 23 | run: | 24 | touch /tmp/ssh-key 25 | echo "${{ secrets.INT_BOT_SSH_KEY }}" > /tmp/ssh-key 26 | chmod 400 /tmp/ssh-key 27 | eval "$(ssh-agent -s)" 28 | ssh-add /tmp/ssh-key 29 | - name: Checkout code 30 | uses: actions/checkout@v2 31 | - name: setup 32 | run: | 33 | eval "$(ssh-agent -s)" 34 | ssh-add /tmp/ssh-key 35 | npm i 36 | sudo curl -L "https://github.com/docker/compose/releases/download/1.26.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose 37 | sudo chmod +x /usr/local/bin/docker-compose 38 | - name: Login to DockerHub 39 | uses: docker/login-action@v1 40 | with: 41 | username: ${{ secrets.DOCKERHUB_USERNAME }} 42 | password: ${{ secrets.DOCKERHUB_TOKEN }} 43 | - name: Build docker 44 | run: npm run docker:contracts 45 | - name: Push docker image 46 | run: npm run push:docker:contracts 47 | # Steps to push multi-platform image, it relies on the previous step: 48 | # npm run docker:contracts 49 | - name: Set up QEMU 50 | uses: docker/setup-qemu-action@v1 51 | - name: Set up Docker Buildx 52 | uses: docker/setup-buildx-action@v1 53 | - name: Build and push 54 | uses: docker/build-push-action@v2 55 | with: 56 | platforms: linux/amd64,linux/arm64 57 | push: true 58 | tags: hermeznetwork/geth-zkevm-contracts:1.5-integration 59 | file: docker/Dockerfile.geth 60 | context: . 61 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: Main CI 5 | 6 | on: 7 | push: 8 | branches: [main, develop] 9 | pull_request: 10 | branches: [main, develop] 11 | 12 | jobs: 13 | lint-and-test: 14 | runs-on: ubuntu-latest 15 | 16 | strategy: 17 | matrix: 18 | node-version: [16.x] 19 | 20 | steps: 21 | - name: Use Node.js ${{ matrix.node-version }} 22 | uses: actions/setup-node@v1 23 | with: 24 | node-version: ${{ matrix.node-version }} 25 | - name: Checkout code 26 | uses: actions/checkout@v2 27 | - name: setup 28 | run: npm i 29 | - name: linter 30 | run: npm run lint 31 | - name: test 32 | run: npm run test 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | coverage.json 2 | .env 3 | cache 4 | build 5 | yarn.lock 6 | node_modules 7 | coverage.json 8 | coverage 9 | .coverage_* 10 | .openzeppelin 11 | artifacts/ 12 | docs/interfaces 13 | docs/mocks 14 | .vscode/launch.json 15 | deploy_output.json 16 | deploy_parameters.json 17 | deployments 18 | upgrade_parameters.json 19 | docker/gethData/ 20 | *.ignore/ -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "overrides": [ 3 | { 4 | "files": "*.sol", 5 | "options": { 6 | "printWidth": 80, 7 | "tabWidth": 4, 8 | "useTabs": false, 9 | "singleQuote": false, 10 | "bracketSpacing": false, 11 | "explicitTypes": "always" 12 | } 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /.solcover.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | skipFiles: ['mocks', 'interfaces'] 3 | }; -------------------------------------------------------------------------------- /.solhint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "solhint:recommended", 3 | "rules": { 4 | "mark-callable-contracts": "off", 5 | "no-empty-blocks": "off", 6 | "compiler-version": ["error", "0.8.20"], 7 | "private-vars-leading-underscore": "error", 8 | "bracket-align": "off", 9 | "reason-string": "off", 10 | "not-rely-on-time": "off", 11 | "no-inline-assembly": "off", 12 | "check-send-result": "off" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": false, 3 | "solidity.linter": "solhint", 4 | "solidity.compileUsingRemoteVersion": "v0.8.20+commit.e14f2714", 5 | "solidity.remappings": ["@openzeppelin/=node_modules/@openzeppelin"], 6 | } 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # zkevm-contracts 2 | 3 | Smart contract implementation which will be used by the polygon-hermez zkevm 4 | 5 | [![Main CI](https://github.com/0xPolygonHermez/zkevm-contracts/actions/workflows/main.yml/badge.svg)](https://github.com/0xPolygonHermez/zkevm-contracts/actions/workflows/main.yml) 6 | 7 | ## Note 8 | 9 | Private keys and mnemonics contained in this repository are used for internal test exclusively. Do not use them in production environments 10 | 11 | ## Requirements 12 | 13 | - node version: 16.x 14 | - npm version: 7.x 15 | 16 | ## Repository structure 17 | 18 | - `contracts`: zkevm contracts 19 | - `PolygonZkEVMBridge.sol`: transfer assets between chains 20 | - `PolygonZkEVMGlobalExitRoot.sol`: manage global exit root in L1 21 | - `PolygonZkEVMGlobalExitRootL2.sol`: manage global exit root in L2 22 | - `PolygonZkEVM.sol`: consensus algorithm used by polygon hermez zkevm 23 | - `docs`: specs and useful links 24 | - `test`: contracts tests 25 | 26 | ## Activate github hook 27 | 28 | ``` 29 | git config --local core.hooksPath .githooks/ 30 | ``` 31 | 32 | ## Install 33 | 34 | ``` 35 | npm i 36 | ``` 37 | 38 | ## Run tests 39 | 40 | ``` 41 | npm run test 42 | ``` 43 | 44 | ## Run Linter 45 | 46 | See errors: 47 | 48 | ``` 49 | npm run lint 50 | ``` 51 | 52 | Autofix errors: 53 | 54 | ``` 55 | npm run lint:fix 56 | ``` 57 | 58 | ## Deploy on hardhat 59 | 60 | ``` 61 | npm run deploy:ZkEVM:hardhat 62 | ``` 63 | 64 | ## Build dockers 65 | 66 | ``` 67 | npm run docker:contracts 68 | ``` 69 | 70 | A new docker `hermez-geth1.3:latest` will be created 71 | This docker will contain a geth node with the deployed contracts 72 | The deployment output can be found in: `docker/deploymentOutput/deploy_output.json` 73 | To run the docker you can use: `docker run -p 8545:8545 hermez-geth1.3:latest` 74 | 75 | ## Note 76 | 77 | In order to test, the following private keys are being used. These keys are not meant to be used in any production environment: 78 | 79 | - private key: `0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80` 80 | - address:`0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266` 81 | - private key: `0xdfd01798f92667dbf91df722434e8fbe96af0211d4d1b82bbbbc8f1def7a814f` 82 | - address:`0xc949254d682d8c9ad5682521675b8f43b102aec4` 83 | 84 | # Verify Deployed Smart Contracts 85 | 86 | To verify that the smartcontracts of this repository are the same deployed on mainnet, you could follow the instructions described [document](verifyMainnetDeployment/verifyDeployment.md) 87 | 88 | The smartcontract used to verify a proof, it's a generated contract from zkEVM Rom and Pil (constraints). To verify the deployment of this smartcontract you could follow the instructions described in this [document](verifyMainnetDeployment/verifyMainnetProofVerifier.md) 89 | -------------------------------------------------------------------------------- /VERIFY.md: -------------------------------------------------------------------------------- 1 | # Verify Deployed Smart Contracts 2 | 3 | To verify that the smartcontracts of this repository are the same deployed on mainnet, you could follow the instructions described [document](verifyMainnetDeployment/verifyDeployment.md) 4 | 5 | The smartcontract used to verify a proof, it's a generated contract from zkEVM Rom and Pil (constraints). To verify the deployment of this smartcontract you could follow the instructions described in this [document](verifyMainnetDeployment/verifyMainnetProofVerifier.md) 6 | -------------------------------------------------------------------------------- /audits/Hexens_Polygon_zkEVM_PUBLIC_27.02.23.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okx/xlayer-contracts/aa4608049f65ffb3b9ebc3672b52a5445ea00bde/audits/Hexens_Polygon_zkEVM_PUBLIC_27.02.23.pdf -------------------------------------------------------------------------------- /audits/zkEVM-bridge-Spearbit-27-March.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okx/xlayer-contracts/aa4608049f65ffb3b9ebc3672b52a5445ea00bde/audits/zkEVM-bridge-Spearbit-27-March.pdf -------------------------------------------------------------------------------- /compiled-contracts/PolygonZkEVMGlobalExitRoot.json: -------------------------------------------------------------------------------- 1 | { 2 | "_format": "hh-sol-artifact-1", 3 | "contractName": "PolygonZkEVMGlobalExitRoot", 4 | "sourceName": "contracts/PolygonZkEVMGlobalExitRoot.sol", 5 | "abi": [ 6 | { 7 | "inputs": [ 8 | { 9 | "internalType": "address", 10 | "name": "_rollupAddress", 11 | "type": "address" 12 | }, 13 | { 14 | "internalType": "address", 15 | "name": "_bridgeAddress", 16 | "type": "address" 17 | } 18 | ], 19 | "stateMutability": "nonpayable", 20 | "type": "constructor" 21 | }, 22 | { 23 | "inputs": [], 24 | "name": "OnlyAllowedContracts", 25 | "type": "error" 26 | }, 27 | { 28 | "anonymous": false, 29 | "inputs": [ 30 | { 31 | "indexed": true, 32 | "internalType": "bytes32", 33 | "name": "mainnetExitRoot", 34 | "type": "bytes32" 35 | }, 36 | { 37 | "indexed": true, 38 | "internalType": "bytes32", 39 | "name": "rollupExitRoot", 40 | "type": "bytes32" 41 | } 42 | ], 43 | "name": "UpdateGlobalExitRoot", 44 | "type": "event" 45 | }, 46 | { 47 | "inputs": [], 48 | "name": "bridgeAddress", 49 | "outputs": [ 50 | { 51 | "internalType": "address", 52 | "name": "", 53 | "type": "address" 54 | } 55 | ], 56 | "stateMutability": "view", 57 | "type": "function" 58 | }, 59 | { 60 | "inputs": [], 61 | "name": "getLastGlobalExitRoot", 62 | "outputs": [ 63 | { 64 | "internalType": "bytes32", 65 | "name": "", 66 | "type": "bytes32" 67 | } 68 | ], 69 | "stateMutability": "view", 70 | "type": "function" 71 | }, 72 | { 73 | "inputs": [ 74 | { 75 | "internalType": "bytes32", 76 | "name": "", 77 | "type": "bytes32" 78 | } 79 | ], 80 | "name": "globalExitRootMap", 81 | "outputs": [ 82 | { 83 | "internalType": "uint256", 84 | "name": "", 85 | "type": "uint256" 86 | } 87 | ], 88 | "stateMutability": "view", 89 | "type": "function" 90 | }, 91 | { 92 | "inputs": [], 93 | "name": "lastMainnetExitRoot", 94 | "outputs": [ 95 | { 96 | "internalType": "bytes32", 97 | "name": "", 98 | "type": "bytes32" 99 | } 100 | ], 101 | "stateMutability": "view", 102 | "type": "function" 103 | }, 104 | { 105 | "inputs": [], 106 | "name": "lastRollupExitRoot", 107 | "outputs": [ 108 | { 109 | "internalType": "bytes32", 110 | "name": "", 111 | "type": "bytes32" 112 | } 113 | ], 114 | "stateMutability": "view", 115 | "type": "function" 116 | }, 117 | { 118 | "inputs": [], 119 | "name": "rollupAddress", 120 | "outputs": [ 121 | { 122 | "internalType": "address", 123 | "name": "", 124 | "type": "address" 125 | } 126 | ], 127 | "stateMutability": "view", 128 | "type": "function" 129 | }, 130 | { 131 | "inputs": [ 132 | { 133 | "internalType": "bytes32", 134 | "name": "newRoot", 135 | "type": "bytes32" 136 | } 137 | ], 138 | "name": "updateExitRoot", 139 | "outputs": [], 140 | "stateMutability": "nonpayable", 141 | "type": "function" 142 | } 143 | ], 144 | "bytecode": "0x60c060405234801561000f575f80fd5b506040516103e13803806103e183398101604081905261002e91610060565b6001600160a01b0391821660a05216608052610091565b80516001600160a01b038116811461005b575f80fd5b919050565b5f8060408385031215610071575f80fd5b61007a83610045565b915061008860208401610045565b90509250929050565b60805160a0516103226100bf5f395f818160e301526101b601525f818161012f015261016d01526103225ff3fe608060405234801561000f575f80fd5b506004361061007a575f3560e01c806333d6247d1161005857806333d6247d146100c15780633ed691ef146100d65780635ec6a8df146100de578063a3c573eb1461012a575f80fd5b806301fd90441461007e578063257b363214610099578063319cf735146100b8575b5f80fd5b6100865f5481565b6040519081526020015b60405180910390f35b6100866100a73660046102d5565b60026020525f908152604090205481565b61008660015481565b6100d46100cf3660046102d5565b610151565b005b61008661029b565b6101057f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610090565b6101057f000000000000000000000000000000000000000000000000000000000000000081565b5f5460015473ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016330361019f575060018290558161021a565b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001633036101e8575f83905582915061021a565b6040517fb49365dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080516020808201849052818301859052825180830384018152606090920190925280519101205f905f8181526002602052604081205491925003610295575f8181526002602052604080822042905551849184917f61014378f82a0d809aefaf87a8ac9505b89c321808287a6e7810f29304c1fce39190a35b50505050565b5f6102d06001545f54604080516020808201949094528082019290925280518083038201815260609092019052805191012090565b905090565b5f602082840312156102e5575f80fd5b503591905056fea26469706673582212205b8fae68ff3c2dfc257497be9184a2e772688dbece1343c3dc2e8c1923291be864736f6c63430008140033", 145 | "deployedBytecode": "0x608060405234801561000f575f80fd5b506004361061007a575f3560e01c806333d6247d1161005857806333d6247d146100c15780633ed691ef146100d65780635ec6a8df146100de578063a3c573eb1461012a575f80fd5b806301fd90441461007e578063257b363214610099578063319cf735146100b8575b5f80fd5b6100865f5481565b6040519081526020015b60405180910390f35b6100866100a73660046102d5565b60026020525f908152604090205481565b61008660015481565b6100d46100cf3660046102d5565b610151565b005b61008661029b565b6101057f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610090565b6101057f000000000000000000000000000000000000000000000000000000000000000081565b5f5460015473ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016330361019f575060018290558161021a565b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001633036101e8575f83905582915061021a565b6040517fb49365dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080516020808201849052818301859052825180830384018152606090920190925280519101205f905f8181526002602052604081205491925003610295575f8181526002602052604080822042905551849184917f61014378f82a0d809aefaf87a8ac9505b89c321808287a6e7810f29304c1fce39190a35b50505050565b5f6102d06001545f54604080516020808201949094528082019290925280518083038201815260609092019052805191012090565b905090565b5f602082840312156102e5575f80fd5b503591905056fea26469706673582212205b8fae68ff3c2dfc257497be9184a2e772688dbece1343c3dc2e8c1923291be864736f6c63430008140033", 146 | "linkReferences": {}, 147 | "deployedLinkReferences": {} 148 | } 149 | -------------------------------------------------------------------------------- /compiled-contracts/PolygonZkEVMGlobalExitRootL2.json: -------------------------------------------------------------------------------- 1 | { 2 | "_format": "hh-sol-artifact-1", 3 | "contractName": "PolygonZkEVMGlobalExitRootL2", 4 | "sourceName": "contracts/PolygonZkEVMGlobalExitRootL2.sol", 5 | "abi": [ 6 | { 7 | "inputs": [ 8 | { 9 | "internalType": "address", 10 | "name": "_bridgeAddress", 11 | "type": "address" 12 | } 13 | ], 14 | "stateMutability": "nonpayable", 15 | "type": "constructor" 16 | }, 17 | { 18 | "inputs": [], 19 | "name": "OnlyAllowedContracts", 20 | "type": "error" 21 | }, 22 | { 23 | "inputs": [], 24 | "name": "bridgeAddress", 25 | "outputs": [ 26 | { 27 | "internalType": "address", 28 | "name": "", 29 | "type": "address" 30 | } 31 | ], 32 | "stateMutability": "view", 33 | "type": "function" 34 | }, 35 | { 36 | "inputs": [ 37 | { 38 | "internalType": "bytes32", 39 | "name": "", 40 | "type": "bytes32" 41 | } 42 | ], 43 | "name": "globalExitRootMap", 44 | "outputs": [ 45 | { 46 | "internalType": "uint256", 47 | "name": "", 48 | "type": "uint256" 49 | } 50 | ], 51 | "stateMutability": "view", 52 | "type": "function" 53 | }, 54 | { 55 | "inputs": [], 56 | "name": "lastRollupExitRoot", 57 | "outputs": [ 58 | { 59 | "internalType": "bytes32", 60 | "name": "", 61 | "type": "bytes32" 62 | } 63 | ], 64 | "stateMutability": "view", 65 | "type": "function" 66 | }, 67 | { 68 | "inputs": [ 69 | { 70 | "internalType": "bytes32", 71 | "name": "newRoot", 72 | "type": "bytes32" 73 | } 74 | ], 75 | "name": "updateExitRoot", 76 | "outputs": [], 77 | "stateMutability": "nonpayable", 78 | "type": "function" 79 | } 80 | ], 81 | "bytecode": "0x60a060405234801561000f575f80fd5b5060405161023538038061023583398101604081905261002e9161003f565b6001600160a01b031660805261006c565b5f6020828403121561004f575f80fd5b81516001600160a01b0381168114610065575f80fd5b9392505050565b6080516101ab61008a5f395f818160a3015261010201526101ab5ff3fe608060405234801561000f575f80fd5b506004361061004a575f3560e01c806301fd90441461004e578063257b36321461006a57806333d6247d14610089578063a3c573eb1461009e575b5f80fd5b61005760015481565b6040519081526020015b60405180910390f35b61005761007836600461015e565b5f6020819052908152604090205481565b61009c61009736600461015e565b6100ea565b005b6100c57f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610061565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610159576040517fb49365dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600155565b5f6020828403121561016e575f80fd5b503591905056fea26469706673582212205108c6c4f924146b736832a1bdf696e20d900450207b7452462368d150f2c71c64736f6c63430008140033", 82 | "deployedBytecode": "0x608060405234801561000f575f80fd5b506004361061004a575f3560e01c806301fd90441461004e578063257b36321461006a57806333d6247d14610089578063a3c573eb1461009e575b5f80fd5b61005760015481565b6040519081526020015b60405180910390f35b61005761007836600461015e565b5f6020819052908152604090205481565b61009c61009736600461015e565b6100ea565b005b6100c57f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610061565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610159576040517fb49365dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600155565b5f6020828403121561016e575f80fd5b503591905056fea26469706673582212205108c6c4f924146b736832a1bdf696e20d900450207b7452462368d150f2c71c64736f6c63430008140033", 83 | "linkReferences": {}, 84 | "deployedLinkReferences": {} 85 | } 86 | -------------------------------------------------------------------------------- /compiled-contracts/PolygonZkEVMGlobalExitRootL2Mock.json: -------------------------------------------------------------------------------- 1 | { 2 | "_format": "hh-sol-artifact-1", 3 | "contractName": "PolygonZkEVMGlobalExitRootL2Mock", 4 | "sourceName": "contracts/mocks/PolygonZkEVMGlobalExitRootL2Mock.sol", 5 | "abi": [ 6 | { 7 | "inputs": [ 8 | { 9 | "internalType": "address", 10 | "name": "_bridgeAddress", 11 | "type": "address" 12 | } 13 | ], 14 | "stateMutability": "nonpayable", 15 | "type": "constructor" 16 | }, 17 | { 18 | "inputs": [], 19 | "name": "OnlyAllowedContracts", 20 | "type": "error" 21 | }, 22 | { 23 | "inputs": [], 24 | "name": "bridgeAddress", 25 | "outputs": [ 26 | { 27 | "internalType": "address", 28 | "name": "", 29 | "type": "address" 30 | } 31 | ], 32 | "stateMutability": "view", 33 | "type": "function" 34 | }, 35 | { 36 | "inputs": [ 37 | { 38 | "internalType": "bytes32", 39 | "name": "", 40 | "type": "bytes32" 41 | } 42 | ], 43 | "name": "globalExitRootMap", 44 | "outputs": [ 45 | { 46 | "internalType": "uint256", 47 | "name": "", 48 | "type": "uint256" 49 | } 50 | ], 51 | "stateMutability": "view", 52 | "type": "function" 53 | }, 54 | { 55 | "inputs": [], 56 | "name": "lastRollupExitRoot", 57 | "outputs": [ 58 | { 59 | "internalType": "bytes32", 60 | "name": "", 61 | "type": "bytes32" 62 | } 63 | ], 64 | "stateMutability": "view", 65 | "type": "function" 66 | }, 67 | { 68 | "inputs": [ 69 | { 70 | "internalType": "bytes32", 71 | "name": "newRoot", 72 | "type": "bytes32" 73 | } 74 | ], 75 | "name": "setExitRoot", 76 | "outputs": [], 77 | "stateMutability": "nonpayable", 78 | "type": "function" 79 | }, 80 | { 81 | "inputs": [ 82 | { 83 | "internalType": "bytes32", 84 | "name": "globalExitRoot", 85 | "type": "bytes32" 86 | }, 87 | { 88 | "internalType": "uint256", 89 | "name": "blockNumber", 90 | "type": "uint256" 91 | } 92 | ], 93 | "name": "setLastGlobalExitRoot", 94 | "outputs": [], 95 | "stateMutability": "nonpayable", 96 | "type": "function" 97 | }, 98 | { 99 | "inputs": [ 100 | { 101 | "internalType": "bytes32", 102 | "name": "newRoot", 103 | "type": "bytes32" 104 | } 105 | ], 106 | "name": "updateExitRoot", 107 | "outputs": [], 108 | "stateMutability": "nonpayable", 109 | "type": "function" 110 | } 111 | ], 112 | "bytecode": "0x60a060405234801561000f575f80fd5b506040516102a73803806102a783398101604081905261002e9161003f565b6001600160a01b031660805261006c565b5f6020828403121561004f575f80fd5b81516001600160a01b0381168114610065575f80fd5b9392505050565b60805161021d61008a5f395f818160fa0152610159015261021d5ff3fe608060405234801561000f575f80fd5b506004361061006f575f3560e01c806333d6247d1161004d57806333d6247d146100c357806396e07459146100d6578063a3c573eb146100f5575f80fd5b806301fd904414610073578063116c40c31461008f578063257b3632146100a4575b5f80fd5b61007c60015481565b6040519081526020015b60405180910390f35b6100a261009d3660046101b0565b600155565b005b61007c6100b23660046101b0565b5f6020819052908152604090205481565b6100a26100d13660046101b0565b610141565b6100a26100e43660046101c7565b5f9182526020829052604090912055565b61011c7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610086565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461009d576040517fb49365dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f602082840312156101c0575f80fd5b5035919050565b5f80604083850312156101d8575f80fd5b5050803592602090910135915056fea26469706673582212200429aefffcbf7324bb1dde3a45be34c3a7310774300755b6ec66494ae7db89ec64736f6c63430008140033", 113 | "deployedBytecode": "0x608060405234801561000f575f80fd5b506004361061006f575f3560e01c806333d6247d1161004d57806333d6247d146100c357806396e07459146100d6578063a3c573eb146100f5575f80fd5b806301fd904414610073578063116c40c31461008f578063257b3632146100a4575b5f80fd5b61007c60015481565b6040519081526020015b60405180910390f35b6100a261009d3660046101b0565b600155565b005b61007c6100b23660046101b0565b5f6020819052908152604090205481565b6100a26100d13660046101b0565b610141565b6100a26100e43660046101c7565b5f9182526020829052604090912055565b61011c7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610086565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000161461009d576040517fb49365dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f602082840312156101c0575f80fd5b5035919050565b5f80604083850312156101d8575f80fd5b5050803592602090910135915056fea26469706673582212200429aefffcbf7324bb1dde3a45be34c3a7310774300755b6ec66494ae7db89ec64736f6c63430008140033", 114 | "linkReferences": {}, 115 | "deployedLinkReferences": {} 116 | } 117 | -------------------------------------------------------------------------------- /compiled-contracts/PolygonZkEVMGlobalExitRootMock.json: -------------------------------------------------------------------------------- 1 | { 2 | "_format": "hh-sol-artifact-1", 3 | "contractName": "PolygonZkEVMGlobalExitRootMock", 4 | "sourceName": "contracts/mocks/PolygonZkEVMGlobalExitRootMock.sol", 5 | "abi": [ 6 | { 7 | "inputs": [ 8 | { 9 | "internalType": "address", 10 | "name": "_rollupAddress", 11 | "type": "address" 12 | }, 13 | { 14 | "internalType": "address", 15 | "name": "_bridgeAddress", 16 | "type": "address" 17 | } 18 | ], 19 | "stateMutability": "nonpayable", 20 | "type": "constructor" 21 | }, 22 | { 23 | "inputs": [], 24 | "name": "OnlyAllowedContracts", 25 | "type": "error" 26 | }, 27 | { 28 | "anonymous": false, 29 | "inputs": [ 30 | { 31 | "indexed": true, 32 | "internalType": "bytes32", 33 | "name": "mainnetExitRoot", 34 | "type": "bytes32" 35 | }, 36 | { 37 | "indexed": true, 38 | "internalType": "bytes32", 39 | "name": "rollupExitRoot", 40 | "type": "bytes32" 41 | } 42 | ], 43 | "name": "UpdateGlobalExitRoot", 44 | "type": "event" 45 | }, 46 | { 47 | "inputs": [], 48 | "name": "bridgeAddress", 49 | "outputs": [ 50 | { 51 | "internalType": "address", 52 | "name": "", 53 | "type": "address" 54 | } 55 | ], 56 | "stateMutability": "view", 57 | "type": "function" 58 | }, 59 | { 60 | "inputs": [], 61 | "name": "getLastGlobalExitRoot", 62 | "outputs": [ 63 | { 64 | "internalType": "bytes32", 65 | "name": "", 66 | "type": "bytes32" 67 | } 68 | ], 69 | "stateMutability": "view", 70 | "type": "function" 71 | }, 72 | { 73 | "inputs": [ 74 | { 75 | "internalType": "bytes32", 76 | "name": "", 77 | "type": "bytes32" 78 | } 79 | ], 80 | "name": "globalExitRootMap", 81 | "outputs": [ 82 | { 83 | "internalType": "uint256", 84 | "name": "", 85 | "type": "uint256" 86 | } 87 | ], 88 | "stateMutability": "view", 89 | "type": "function" 90 | }, 91 | { 92 | "inputs": [], 93 | "name": "lastMainnetExitRoot", 94 | "outputs": [ 95 | { 96 | "internalType": "bytes32", 97 | "name": "", 98 | "type": "bytes32" 99 | } 100 | ], 101 | "stateMutability": "view", 102 | "type": "function" 103 | }, 104 | { 105 | "inputs": [], 106 | "name": "lastRollupExitRoot", 107 | "outputs": [ 108 | { 109 | "internalType": "bytes32", 110 | "name": "", 111 | "type": "bytes32" 112 | } 113 | ], 114 | "stateMutability": "view", 115 | "type": "function" 116 | }, 117 | { 118 | "inputs": [], 119 | "name": "rollupAddress", 120 | "outputs": [ 121 | { 122 | "internalType": "address", 123 | "name": "", 124 | "type": "address" 125 | } 126 | ], 127 | "stateMutability": "view", 128 | "type": "function" 129 | }, 130 | { 131 | "inputs": [ 132 | { 133 | "internalType": "bytes32", 134 | "name": "globalExitRoot", 135 | "type": "bytes32" 136 | }, 137 | { 138 | "internalType": "uint256", 139 | "name": "timestamp", 140 | "type": "uint256" 141 | } 142 | ], 143 | "name": "setGlobalExitRoot", 144 | "outputs": [], 145 | "stateMutability": "nonpayable", 146 | "type": "function" 147 | }, 148 | { 149 | "inputs": [ 150 | { 151 | "internalType": "uint256", 152 | "name": "timestamp", 153 | "type": "uint256" 154 | } 155 | ], 156 | "name": "setLastGlobalExitRoot", 157 | "outputs": [], 158 | "stateMutability": "nonpayable", 159 | "type": "function" 160 | }, 161 | { 162 | "inputs": [ 163 | { 164 | "internalType": "bytes32", 165 | "name": "newRoot", 166 | "type": "bytes32" 167 | } 168 | ], 169 | "name": "updateExitRoot", 170 | "outputs": [], 171 | "stateMutability": "nonpayable", 172 | "type": "function" 173 | } 174 | ], 175 | "bytecode": "0x60c060405234801561000f575f80fd5b5060405161047838038061047883398101604081905261002e91610060565b6001600160a01b0391821660a05216608052610091565b80516001600160a01b038116811461005b575f80fd5b919050565b5f8060408385031215610071575f80fd5b61007a83610045565b915061008860208401610045565b90509250929050565b60805160a0516103b86100c05f395f818161013a015261022c01525f818161018601526101e301526103b85ff3fe608060405234801561000f575f80fd5b506004361061009f575f3560e01c806333d6247d116100725780635bcef673116100585780635bcef673146101165780635ec6a8df14610135578063a3c573eb14610181575f80fd5b806333d6247d146100fb5780633ed691ef1461010e575f80fd5b806301fd9044146100a3578063051a9e28146100be578063257b3632146100d3578063319cf735146100f2575b5f80fd5b6100ab5f5481565b6040519081526020015b60405180910390f35b6100d16100cc36600461034b565b6101a8565b005b6100ab6100e136600461034b565b60026020525f908152604090205481565b6100ab60015481565b6100d161010936600461034b565b6101c7565b6100ab610311565b6100d1610124366004610362565b5f9182526002602052604090912055565b61015c7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100b5565b61015c7f000000000000000000000000000000000000000000000000000000000000000081565b8060025f6101b4610311565b815260208101919091526040015f205550565b5f5460015473ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001633036102155750600182905581610290565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016330361025e575f839055829150610290565b6040517fb49365dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080516020808201849052818301859052825180830384018152606090920190925280519101205f905f818152600260205260408120549192500361030b575f8181526002602052604080822042905551849184917f61014378f82a0d809aefaf87a8ac9505b89c321808287a6e7810f29304c1fce39190a35b50505050565b5f6103466001545f54604080516020808201949094528082019290925280518083038201815260609092019052805191012090565b905090565b5f6020828403121561035b575f80fd5b5035919050565b5f8060408385031215610373575f80fd5b5050803592602090910135915056fea26469706673582212200799b5f60aa8eaf6d49205025cc41bfba78ce4f6ad614164e5da3c0bdc94810464736f6c63430008140033", 176 | "deployedBytecode": "0x608060405234801561000f575f80fd5b506004361061009f575f3560e01c806333d6247d116100725780635bcef673116100585780635bcef673146101165780635ec6a8df14610135578063a3c573eb14610181575f80fd5b806333d6247d146100fb5780633ed691ef1461010e575f80fd5b806301fd9044146100a3578063051a9e28146100be578063257b3632146100d3578063319cf735146100f2575b5f80fd5b6100ab5f5481565b6040519081526020015b60405180910390f35b6100d16100cc36600461034b565b6101a8565b005b6100ab6100e136600461034b565b60026020525f908152604090205481565b6100ab60015481565b6100d161010936600461034b565b6101c7565b6100ab610311565b6100d1610124366004610362565b5f9182526002602052604090912055565b61015c7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100b5565b61015c7f000000000000000000000000000000000000000000000000000000000000000081565b8060025f6101b4610311565b815260208101919091526040015f205550565b5f5460015473ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001633036102155750600182905581610290565b73ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016330361025e575f839055829150610290565b6040517fb49365dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b604080516020808201849052818301859052825180830384018152606090920190925280519101205f905f818152600260205260408120549192500361030b575f8181526002602052604080822042905551849184917f61014378f82a0d809aefaf87a8ac9505b89c321808287a6e7810f29304c1fce39190a35b50505050565b5f6103466001545f54604080516020808201949094528082019290925280518083038201815260609092019052805191012090565b905090565b5f6020828403121561035b575f80fd5b5035919050565b5f8060408385031215610373575f80fd5b5050803592602090910135915056fea26469706673582212200799b5f60aa8eaf6d49205025cc41bfba78ce4f6ad614164e5da3c0bdc94810464736f6c63430008140033", 177 | "linkReferences": {}, 178 | "deployedLinkReferences": {} 179 | } 180 | -------------------------------------------------------------------------------- /compiled-contracts/VerifierRollupHelperMock.json: -------------------------------------------------------------------------------- 1 | { 2 | "_format": "hh-sol-artifact-1", 3 | "contractName": "VerifierRollupHelperMock", 4 | "sourceName": "contracts/mocks/VerifierRollupHelperMock.sol", 5 | "abi": [ 6 | { 7 | "inputs": [ 8 | { 9 | "internalType": "bytes32[24]", 10 | "name": "proof", 11 | "type": "bytes32[24]" 12 | }, 13 | { 14 | "internalType": "uint256[1]", 15 | "name": "pubSignals", 16 | "type": "uint256[1]" 17 | } 18 | ], 19 | "name": "verifyProof", 20 | "outputs": [ 21 | { 22 | "internalType": "bool", 23 | "name": "", 24 | "type": "bool" 25 | } 26 | ], 27 | "stateMutability": "view", 28 | "type": "function" 29 | } 30 | ], 31 | "bytecode": "0x608060405234801561000f575f80fd5b5061014e8061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c80639121da8a1461002d575b5f80fd5b61004361003b366004610084565b600192915050565b604051901515815260200160405180910390f35b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f80610320808486031215610097575f80fd5b6103008401858111156100a8575f80fd5b8493508561031f8601126100ba575f80fd5b604051602080820182811067ffffffffffffffff821117156100de576100de610057565b6040529286019281888511156100f2575f80fd5b5b8484101561010a57833581529281019281016100f3565b50949790965094505050505056fea2646970667358221220b573319b6682fcc2f0db0c066055eb5cedcf703eed96af2d16f8d3320abc1bb564736f6c63430008140033", 32 | "deployedBytecode": "0x608060405234801561000f575f80fd5b5060043610610029575f3560e01c80639121da8a1461002d575b5f80fd5b61004361003b366004610084565b600192915050565b604051901515815260200160405180910390f35b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f80610320808486031215610097575f80fd5b6103008401858111156100a8575f80fd5b8493508561031f8601126100ba575f80fd5b604051602080820182811067ffffffffffffffff821117156100de576100de610057565b6040529286019281888511156100f2575f80fd5b5b8484101561010a57833581529281019281016100f3565b50949790965094505050505056fea2646970667358221220b573319b6682fcc2f0db0c066055eb5cedcf703eed96af2d16f8d3320abc1bb564736f6c63430008140033", 33 | "linkReferences": {}, 34 | "deployedLinkReferences": {} 35 | } 36 | -------------------------------------------------------------------------------- /contracts/PolygonZkEVMGlobalExitRoot.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | 3 | pragma solidity 0.8.20; 4 | 5 | import "./interfaces/IPolygonZkEVMGlobalExitRoot.sol"; 6 | import "./lib/GlobalExitRootLib.sol"; 7 | 8 | /** 9 | * Contract responsible for managing the exit roots across multiple networks 10 | */ 11 | contract PolygonZkEVMGlobalExitRoot is IPolygonZkEVMGlobalExitRoot { 12 | // PolygonZkEVMBridge address 13 | address public immutable bridgeAddress; 14 | 15 | // Rollup contract address 16 | address public immutable rollupAddress; 17 | 18 | // Rollup exit root, this will be updated every time a batch is verified 19 | bytes32 public lastRollupExitRoot; 20 | 21 | // Mainnet exit root, this will be updated every time a deposit is made in mainnet 22 | bytes32 public lastMainnetExitRoot; 23 | 24 | // Store every global exit root: Root --> timestamp 25 | mapping(bytes32 => uint256) public globalExitRootMap; 26 | 27 | /** 28 | * @dev Emitted when the global exit root is updated 29 | */ 30 | event UpdateGlobalExitRoot( 31 | bytes32 indexed mainnetExitRoot, 32 | bytes32 indexed rollupExitRoot 33 | ); 34 | 35 | /** 36 | * @param _rollupAddress Rollup contract address 37 | * @param _bridgeAddress PolygonZkEVMBridge contract address 38 | */ 39 | constructor(address _rollupAddress, address _bridgeAddress) { 40 | rollupAddress = _rollupAddress; 41 | bridgeAddress = _bridgeAddress; 42 | } 43 | 44 | /** 45 | * @notice Update the exit root of one of the networks and the global exit root 46 | * @param newRoot new exit tree root 47 | */ 48 | function updateExitRoot(bytes32 newRoot) external { 49 | // Store storage variables into temporal variables since will be used multiple times 50 | bytes32 cacheLastRollupExitRoot = lastRollupExitRoot; 51 | bytes32 cacheLastMainnetExitRoot = lastMainnetExitRoot; 52 | 53 | if (msg.sender == bridgeAddress) { 54 | lastMainnetExitRoot = newRoot; 55 | cacheLastMainnetExitRoot = newRoot; 56 | } else if (msg.sender == rollupAddress) { 57 | lastRollupExitRoot = newRoot; 58 | cacheLastRollupExitRoot = newRoot; 59 | } else { 60 | revert OnlyAllowedContracts(); 61 | } 62 | 63 | bytes32 newGlobalExitRoot = GlobalExitRootLib.calculateGlobalExitRoot( 64 | cacheLastMainnetExitRoot, 65 | cacheLastRollupExitRoot 66 | ); 67 | 68 | // If it already exists, do not modify the timestamp 69 | if (globalExitRootMap[newGlobalExitRoot] == 0) { 70 | globalExitRootMap[newGlobalExitRoot] = block.timestamp; 71 | emit UpdateGlobalExitRoot( 72 | cacheLastMainnetExitRoot, 73 | cacheLastRollupExitRoot 74 | ); 75 | } 76 | } 77 | 78 | /** 79 | * @notice Return last global exit root 80 | */ 81 | function getLastGlobalExitRoot() public view returns (bytes32) { 82 | return 83 | GlobalExitRootLib.calculateGlobalExitRoot( 84 | lastMainnetExitRoot, 85 | lastRollupExitRoot 86 | ); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /contracts/PolygonZkEVMGlobalExitRootL2.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | 3 | pragma solidity 0.8.20; 4 | import "./interfaces/IBasePolygonZkEVMGlobalExitRoot.sol"; 5 | 6 | /** 7 | * Contract responsible for managing the exit roots for the L2 and global exit roots 8 | * The special zkRom variables will be accessed and updated directly by the zkRom 9 | */ 10 | contract PolygonZkEVMGlobalExitRootL2 is IBasePolygonZkEVMGlobalExitRoot { 11 | ///////////////////////////// 12 | // Special zkRom variables 13 | //////////////////////////// 14 | 15 | // Store every global exit root: Root --> timestamp 16 | // Note this variable is updated only by the zkRom 17 | mapping(bytes32 => uint256) public globalExitRootMap; 18 | 19 | // Rollup exit root will be updated for every PolygonZkEVMBridge call 20 | // Note this variable will be readed by the zkRom 21 | bytes32 public lastRollupExitRoot; 22 | 23 | //////////////////// 24 | // Regular variables 25 | /////////////////// 26 | 27 | // PolygonZkEVM Bridge address 28 | address public immutable bridgeAddress; 29 | 30 | /** 31 | * @param _bridgeAddress PolygonZkEVMBridge contract address 32 | */ 33 | constructor(address _bridgeAddress) { 34 | bridgeAddress = _bridgeAddress; 35 | } 36 | 37 | /** 38 | * @notice Update the exit root of one of the networks and the global exit root 39 | * @param newRoot new exit tree root 40 | */ 41 | function updateExitRoot(bytes32 newRoot) external { 42 | if (msg.sender != bridgeAddress) { 43 | revert OnlyAllowedContracts(); 44 | } 45 | 46 | lastRollupExitRoot = newRoot; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /contracts/PolygonZkEVMTimelock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity 0.8.20; 3 | 4 | import "@openzeppelin/contracts/governance/TimelockController.sol"; 5 | import "./PolygonZkEVM.sol"; 6 | 7 | /** 8 | * @dev Contract module which acts as a timelocked controller. 9 | * This gives time for users of the controlled contract to exit before a potentially dangerous maintenance operation is applied. 10 | * If emergency mode of the zkevm contract system is active, this timelock have no delay. 11 | */ 12 | contract PolygonZkEVMTimelock is TimelockController { 13 | // Polygon ZK-EVM address. Will be used to check if it's on emergency state. 14 | PolygonZkEVM public immutable polygonZkEVM; 15 | 16 | /** 17 | * @notice Constructor of timelock 18 | * @param minDelay initial minimum delay for operations 19 | * @param proposers accounts to be granted proposer and canceller roles 20 | * @param executors accounts to be granted executor role 21 | * @param admin optional account to be granted admin role; disable with zero address 22 | * @param _polygonZkEVM polygonZkEVM address 23 | **/ 24 | constructor( 25 | uint256 minDelay, 26 | address[] memory proposers, 27 | address[] memory executors, 28 | address admin, 29 | PolygonZkEVM _polygonZkEVM 30 | ) TimelockController(minDelay, proposers, executors, admin) { 31 | polygonZkEVM = _polygonZkEVM; 32 | } 33 | 34 | /** 35 | * @dev Returns the minimum delay for an operation to become valid. 36 | * 37 | * This value can be changed by executing an operation that calls `updateDelay`. 38 | * If Polygon ZK-EVM is on emergency state the minDelay will be 0 instead. 39 | */ 40 | function getMinDelay() public view override returns (uint256 duration) { 41 | if (address(polygonZkEVM) != address(0) && polygonZkEVM.isEmergencyState()) { 42 | return 0; 43 | } else { 44 | return super.getMinDelay(); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /contracts/deployment/PolygonZkEVMDeployer.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity 0.8.20; 3 | 4 | import "@openzeppelin/contracts/access/Ownable.sol"; 5 | import "@openzeppelin/contracts/utils/Create2.sol"; 6 | import "@openzeppelin/contracts/utils/Address.sol"; 7 | 8 | /** 9 | * Contract responsible for deploying deterministic address contracts related with the PolygonZkEVM 10 | */ 11 | contract PolygonZkEVMDeployer is Ownable { 12 | /** 13 | * @param _owner Owner 14 | */ 15 | constructor(address _owner) Ownable() { 16 | _transferOwnership(_owner); 17 | } 18 | 19 | /** 20 | * @dev Emitted when a contract is deployed 21 | */ 22 | event NewDeterministicDeployment(address newContractAddress); 23 | 24 | /** 25 | * @dev Emitted when a contract is called 26 | */ 27 | event FunctionCall(); 28 | 29 | /** 30 | * @notice Allows to deploy a contract using create2 31 | * @param amount Amount used in create2 32 | * @param salt Salt used in create2 33 | * @param initBytecode Init bytecode that will be use in create2 34 | */ 35 | function deployDeterministic( 36 | uint256 amount, 37 | bytes32 salt, 38 | bytes memory initBytecode 39 | ) public payable onlyOwner { 40 | address newContractAddress = Create2.deploy(amount, salt, initBytecode); 41 | emit NewDeterministicDeployment(newContractAddress); 42 | } 43 | 44 | /** 45 | * @notice Allows to deploy a contract using create2 and call it afterwards 46 | * @param amount Amount used in create2 47 | * @param salt Salt used in create2 48 | * @param initBytecode Init bytecode that will be use in create2 49 | * @param dataCall Data used in the call after deploying the smart contract 50 | */ 51 | function deployDeterministicAndCall( 52 | uint256 amount, 53 | bytes32 salt, 54 | bytes memory initBytecode, 55 | bytes memory dataCall 56 | ) public payable onlyOwner { 57 | address newContractAddress = Create2.deploy(amount, salt, initBytecode); 58 | Address.functionCall(newContractAddress, dataCall); 59 | 60 | emit NewDeterministicDeployment(newContractAddress); 61 | } 62 | 63 | /** 64 | * @param targetAddress Amount of contract deploy 65 | * @param dataCall Data used to call the target smart contract 66 | * @param amount Data used to call the target smart contract 67 | */ 68 | function functionCall( 69 | address targetAddress, 70 | bytes memory dataCall, 71 | uint256 amount 72 | ) public payable onlyOwner { 73 | Address.functionCallWithValue(targetAddress, dataCall, amount); 74 | 75 | emit FunctionCall(); 76 | } 77 | 78 | /** 79 | * @param salt Salt used in create2 80 | * @param bytecodeHash Init bytecode hashed, it contains the constructor parameters 81 | */ 82 | function predictDeterministicAddress( 83 | bytes32 salt, 84 | bytes32 bytecodeHash 85 | ) public view returns (address) { 86 | return Create2.computeAddress(salt, bytecodeHash); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /contracts/interfaces/IBasePolygonZkEVMGlobalExitRoot.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | 3 | pragma solidity ^0.8.20; 4 | 5 | interface IBasePolygonZkEVMGlobalExitRoot { 6 | /** 7 | * @dev Thrown when the caller is not the allowed contracts 8 | */ 9 | error OnlyAllowedContracts(); 10 | 11 | function updateExitRoot(bytes32 newRollupExitRoot) external; 12 | 13 | function globalExitRootMap( 14 | bytes32 globalExitRootNum 15 | ) external returns (uint256); 16 | } 17 | -------------------------------------------------------------------------------- /contracts/interfaces/IBridgeMessageReceiver.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | 3 | pragma solidity 0.8.20; 4 | 5 | /** 6 | * @dev Define interface for PolygonZkEVM Bridge message receiver 7 | */ 8 | interface IBridgeMessageReceiver { 9 | function onMessageReceived( 10 | address originAddress, 11 | uint32 originNetwork, 12 | bytes memory data 13 | ) external payable; 14 | } 15 | -------------------------------------------------------------------------------- /contracts/interfaces/IPolygonZkEVMBridge.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | 3 | pragma solidity ^0.8.20; 4 | 5 | interface IPolygonZkEVMBridge { 6 | /** 7 | * @dev Thrown when sender is not the PolygonZkEVM address 8 | */ 9 | error OnlyPolygonZkEVM(); 10 | 11 | /** 12 | * @dev Thrown when the destination network is invalid 13 | */ 14 | error DestinationNetworkInvalid(); 15 | 16 | /** 17 | * @dev Thrown when the amount does not match msg.value 18 | */ 19 | error AmountDoesNotMatchMsgValue(); 20 | 21 | /** 22 | * @dev Thrown when user is bridging tokens and is also sending a value 23 | */ 24 | error MsgValueNotZero(); 25 | 26 | /** 27 | * @dev Thrown when the Ether transfer on claimAsset fails 28 | */ 29 | error EtherTransferFailed(); 30 | 31 | /** 32 | * @dev Thrown when the message transaction on claimMessage fails 33 | */ 34 | error MessageFailed(); 35 | 36 | /** 37 | * @dev Thrown when the global exit root does not exist 38 | */ 39 | error GlobalExitRootInvalid(); 40 | 41 | /** 42 | * @dev Thrown when the smt proof does not match 43 | */ 44 | error InvalidSmtProof(); 45 | 46 | /** 47 | * @dev Thrown when an index is already claimed 48 | */ 49 | error AlreadyClaimed(); 50 | 51 | /** 52 | * @dev Thrown when the owner of permit does not match the sender 53 | */ 54 | error NotValidOwner(); 55 | 56 | /** 57 | * @dev Thrown when the spender of the permit does not match this contract address 58 | */ 59 | error NotValidSpender(); 60 | 61 | /** 62 | * @dev Thrown when the amount of the permit does not match 63 | */ 64 | error NotValidAmount(); 65 | 66 | /** 67 | * @dev Thrown when the permit data contains an invalid signature 68 | */ 69 | error NotValidSignature(); 70 | 71 | function bridgeAsset( 72 | uint32 destinationNetwork, 73 | address destinationAddress, 74 | uint256 amount, 75 | address token, 76 | bool forceUpdateGlobalExitRoot, 77 | bytes calldata permitData 78 | ) external payable; 79 | 80 | function bridgeMessage( 81 | uint32 destinationNetwork, 82 | address destinationAddress, 83 | bool forceUpdateGlobalExitRoot, 84 | bytes calldata metadata 85 | ) external payable; 86 | 87 | function claimAsset( 88 | bytes32[32] calldata smtProof, 89 | uint32 index, 90 | bytes32 mainnetExitRoot, 91 | bytes32 rollupExitRoot, 92 | uint32 originNetwork, 93 | address originTokenAddress, 94 | uint32 destinationNetwork, 95 | address destinationAddress, 96 | uint256 amount, 97 | bytes calldata metadata 98 | ) external; 99 | 100 | function claimMessage( 101 | bytes32[32] calldata smtProof, 102 | uint32 index, 103 | bytes32 mainnetExitRoot, 104 | bytes32 rollupExitRoot, 105 | uint32 originNetwork, 106 | address originAddress, 107 | uint32 destinationNetwork, 108 | address destinationAddress, 109 | uint256 amount, 110 | bytes calldata metadata 111 | ) external; 112 | 113 | function updateGlobalExitRoot() external; 114 | 115 | function activateEmergencyState() external; 116 | 117 | function deactivateEmergencyState() external; 118 | } 119 | -------------------------------------------------------------------------------- /contracts/interfaces/IPolygonZkEVMErrors.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | 3 | pragma solidity ^0.8.20; 4 | 5 | interface IPolygonZkEVMErrors { 6 | /** 7 | * @dev Thrown when the pending state timeout exceeds the _HALT_AGGREGATION_TIMEOUT 8 | */ 9 | error PendingStateTimeoutExceedHaltAggregationTimeout(); 10 | 11 | /** 12 | * @dev Thrown when the trusted aggregator timeout exceeds the _HALT_AGGREGATION_TIMEOUT 13 | */ 14 | error TrustedAggregatorTimeoutExceedHaltAggregationTimeout(); 15 | 16 | /** 17 | * @dev Thrown when the caller is not the admin 18 | */ 19 | error OnlyAdmin(); 20 | 21 | /** 22 | * @dev Thrown when the caller is not the trusted sequencer 23 | */ 24 | error OnlyTrustedSequencer(); 25 | 26 | /** 27 | * @dev Thrown when the caller is not the trusted aggregator 28 | */ 29 | error OnlyTrustedAggregator(); 30 | 31 | /** 32 | * @dev Thrown when attempting to sequence 0 batches 33 | */ 34 | error SequenceZeroBatches(); 35 | 36 | /** 37 | * @dev Thrown when attempting to sequence or verify more batches than _MAX_VERIFY_BATCHES 38 | */ 39 | error ExceedMaxVerifyBatches(); 40 | 41 | /** 42 | * @dev Thrown when the forced data does not match 43 | */ 44 | error ForcedDataDoesNotMatch(); 45 | 46 | /** 47 | * @dev Thrown when the sequenced timestamp is below the forced minimum timestamp 48 | */ 49 | error SequencedTimestampBelowForcedTimestamp(); 50 | 51 | /** 52 | * @dev Thrown when a global exit root is not zero and does not exist 53 | */ 54 | error GlobalExitRootNotExist(); 55 | 56 | /** 57 | * @dev Thrown when transactions array length is above _MAX_TRANSACTIONS_BYTE_LENGTH. 58 | */ 59 | error TransactionsLengthAboveMax(); 60 | 61 | /** 62 | * @dev Thrown when a sequenced timestamp is not inside a correct range. 63 | */ 64 | error SequencedTimestampInvalid(); 65 | 66 | /** 67 | * @dev Thrown when there are more sequenced force batches than were actually submitted, should be unreachable 68 | */ 69 | error ForceBatchesOverflow(); 70 | 71 | /** 72 | * @dev Thrown when there are more sequenced force batches than were actually submitted 73 | */ 74 | error TrustedAggregatorTimeoutNotExpired(); 75 | 76 | /** 77 | * @dev Thrown when attempting to access a pending state that does not exist 78 | */ 79 | error PendingStateDoesNotExist(); 80 | 81 | /** 82 | * @dev Thrown when the init num batch does not match with the one in the pending state 83 | */ 84 | error InitNumBatchDoesNotMatchPendingState(); 85 | 86 | /** 87 | * @dev Thrown when the old state root of a certain batch does not exist 88 | */ 89 | error OldStateRootDoesNotExist(); 90 | 91 | /** 92 | * @dev Thrown when the init verification batch is above the last verification batch 93 | */ 94 | error InitNumBatchAboveLastVerifiedBatch(); 95 | 96 | /** 97 | * @dev Thrown when the final verification batch is below or equal the last verification batch 98 | */ 99 | error FinalNumBatchBelowLastVerifiedBatch(); 100 | 101 | /** 102 | * @dev Thrown when the zkproof is not valid 103 | */ 104 | error InvalidProof(); 105 | 106 | /** 107 | * @dev Thrown when attempting to consolidate a pending state not yet consolidable 108 | */ 109 | error PendingStateNotConsolidable(); 110 | 111 | /** 112 | * @dev Thrown when attempting to consolidate a pending state that is already consolidated or does not exist 113 | */ 114 | error PendingStateInvalid(); 115 | 116 | /** 117 | * @dev Thrown when the matic amount is below the necessary matic fee 118 | */ 119 | error NotEnoughMaticAmount(); 120 | 121 | /** 122 | * @dev Thrown when attempting to sequence a force batch using sequenceForceBatches and the 123 | * force timeout did not expire 124 | */ 125 | error ForceBatchTimeoutNotExpired(); 126 | 127 | /** 128 | * @dev Thrown when attempting to set a new trusted aggregator timeout equal or bigger than current one 129 | */ 130 | error NewTrustedAggregatorTimeoutMustBeLower(); 131 | 132 | /** 133 | * @dev Thrown when attempting to set a new pending state timeout equal or bigger than current one 134 | */ 135 | error NewPendingStateTimeoutMustBeLower(); 136 | 137 | /** 138 | * @dev Thrown when attempting to set a new multiplier batch fee in a invalid range of values 139 | */ 140 | error InvalidRangeMultiplierBatchFee(); 141 | 142 | /** 143 | * @dev Thrown when attempting to set a batch time target in an invalid range of values 144 | */ 145 | error InvalidRangeBatchTimeTarget(); 146 | 147 | /** 148 | * @dev Thrown when attempting to set a force batch timeout in an invalid range of values 149 | */ 150 | error InvalidRangeForceBatchTimeout(); 151 | 152 | /** 153 | * @dev Thrown when the caller is not the pending admin 154 | */ 155 | error OnlyPendingAdmin(); 156 | 157 | /** 158 | * @dev Thrown when the final pending state num is not in a valid range 159 | */ 160 | error FinalPendingStateNumInvalid(); 161 | 162 | /** 163 | * @dev Thrown when the final num batch does not match with the one in the pending state 164 | */ 165 | error FinalNumBatchDoesNotMatchPendingState(); 166 | 167 | /** 168 | * @dev Thrown when the stored root matches the new root proving a different state 169 | */ 170 | error StoredRootMustBeDifferentThanNewRoot(); 171 | 172 | /** 173 | * @dev Thrown when the batch is already verified when attempting to activate the emergency state 174 | */ 175 | error BatchAlreadyVerified(); 176 | 177 | /** 178 | * @dev Thrown when the batch is not sequenced or not at the end of a sequence when attempting to activate the emergency state 179 | */ 180 | error BatchNotSequencedOrNotSequenceEnd(); 181 | 182 | /** 183 | * @dev Thrown when the halt timeout is not expired when attempting to activate the emergency state 184 | */ 185 | error HaltTimeoutNotExpired(); 186 | 187 | /** 188 | * @dev Thrown when the old accumulate input hash does not exist 189 | */ 190 | error OldAccInputHashDoesNotExist(); 191 | 192 | /** 193 | * @dev Thrown when the new accumulate input hash does not exist 194 | */ 195 | error NewAccInputHashDoesNotExist(); 196 | 197 | /** 198 | * @dev Thrown when the new state root is not inside prime 199 | */ 200 | error NewStateRootNotInsidePrime(); 201 | 202 | /** 203 | * @dev Thrown when force batch is not allowed 204 | */ 205 | error ForceBatchNotAllowed(); 206 | 207 | /** 208 | * @dev Thrown when try to activate force batches when they are already active 209 | */ 210 | error ForceBatchesAlreadyActive(); 211 | } 212 | -------------------------------------------------------------------------------- /contracts/interfaces/IPolygonZkEVMGlobalExitRoot.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | 3 | pragma solidity ^0.8.20; 4 | import "./IBasePolygonZkEVMGlobalExitRoot.sol"; 5 | 6 | interface IPolygonZkEVMGlobalExitRoot is IBasePolygonZkEVMGlobalExitRoot { 7 | function getLastGlobalExitRoot() external view returns (bytes32); 8 | } 9 | -------------------------------------------------------------------------------- /contracts/interfaces/IVerifierRollup.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | 3 | pragma solidity ^0.8.20; 4 | 5 | /** 6 | * @dev Define interface verifier 7 | */ 8 | interface IVerifierRollup { 9 | function verifyProof( 10 | bytes32[24] calldata proof, 11 | uint256[1] memory pubSignals 12 | ) external view returns (bool); 13 | } 14 | -------------------------------------------------------------------------------- /contracts/lib/DepositContract.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity 0.8.20; 3 | 4 | import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; 5 | 6 | /** 7 | * This contract will be used as a helper for all the sparse merkle tree related functions 8 | * Based on the implementation of the deposit eth2.0 contract https://github.com/ethereum/consensus-specs/blob/dev/solidity_deposit_contract/deposit_contract.sol 9 | */ 10 | contract DepositContract is ReentrancyGuardUpgradeable { 11 | /** 12 | * @dev Thrown when the merkle tree is full 13 | */ 14 | error MerkleTreeFull(); 15 | 16 | // Merkle tree levels 17 | uint256 internal constant _DEPOSIT_CONTRACT_TREE_DEPTH = 32; 18 | 19 | // This ensures `depositCount` will fit into 32-bits 20 | uint256 internal constant _MAX_DEPOSIT_COUNT = 21 | 2 ** _DEPOSIT_CONTRACT_TREE_DEPTH - 1; 22 | 23 | // Branch array which contains the necessary sibilings to compute the next root when a new 24 | // leaf is inserted 25 | bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH] internal _branch; 26 | 27 | // Counter of current deposits 28 | uint256 public depositCount; 29 | 30 | /** 31 | * @dev This empty reserved space is put in place to allow future versions to add new 32 | * variables without shifting down storage in the inheritance chain. 33 | */ 34 | uint256[10] private _gap; 35 | 36 | /** 37 | * @notice Computes and returns the merkle root 38 | */ 39 | function getDepositRoot() public view returns (bytes32) { 40 | bytes32 node; 41 | uint256 size = depositCount; 42 | bytes32 currentZeroHashHeight = 0; 43 | 44 | for ( 45 | uint256 height = 0; 46 | height < _DEPOSIT_CONTRACT_TREE_DEPTH; 47 | height++ 48 | ) { 49 | if (((size >> height) & 1) == 1) 50 | node = keccak256(abi.encodePacked(_branch[height], node)); 51 | else 52 | node = keccak256(abi.encodePacked(node, currentZeroHashHeight)); 53 | 54 | currentZeroHashHeight = keccak256( 55 | abi.encodePacked(currentZeroHashHeight, currentZeroHashHeight) 56 | ); 57 | } 58 | return node; 59 | } 60 | 61 | /** 62 | * @notice Add a new leaf to the merkle tree 63 | * @param leafHash Leaf hash 64 | */ 65 | function _deposit(bytes32 leafHash) internal { 66 | bytes32 node = leafHash; 67 | 68 | // Avoid overflowing the Merkle tree (and prevent edge case in computing `_branch`) 69 | if (depositCount >= _MAX_DEPOSIT_COUNT) { 70 | revert MerkleTreeFull(); 71 | } 72 | 73 | // Add deposit data root to Merkle tree (update a single `_branch` node) 74 | uint256 size = ++depositCount; 75 | for ( 76 | uint256 height = 0; 77 | height < _DEPOSIT_CONTRACT_TREE_DEPTH; 78 | height++ 79 | ) { 80 | if (((size >> height) & 1) == 1) { 81 | _branch[height] = node; 82 | return; 83 | } 84 | node = keccak256(abi.encodePacked(_branch[height], node)); 85 | } 86 | // As the loop should always end prematurely with the `return` statement, 87 | // this code should be unreachable. We assert `false` just to be safe. 88 | assert(false); 89 | } 90 | 91 | /** 92 | * @notice Verify merkle proof 93 | * @param leafHash Leaf hash 94 | * @param smtProof Smt proof 95 | * @param index Index of the leaf 96 | * @param root Merkle root 97 | */ 98 | function verifyMerkleProof( 99 | bytes32 leafHash, 100 | bytes32[_DEPOSIT_CONTRACT_TREE_DEPTH] calldata smtProof, 101 | uint32 index, 102 | bytes32 root 103 | ) public pure returns (bool) { 104 | bytes32 node = leafHash; 105 | 106 | // Check merkle proof 107 | for ( 108 | uint256 height = 0; 109 | height < _DEPOSIT_CONTRACT_TREE_DEPTH; 110 | height++ 111 | ) { 112 | if (((index >> height) & 1) == 1) 113 | node = keccak256(abi.encodePacked(smtProof[height], node)); 114 | else node = keccak256(abi.encodePacked(node, smtProof[height])); 115 | } 116 | 117 | return node == root; 118 | } 119 | 120 | /** 121 | * @notice Given the leaf data returns the leaf value 122 | * @param leafType Leaf type --> [0] transfer Ether / ERC20 tokens, [1] message 123 | * @param originNetwork Origin Network 124 | * @param originAddress [0] Origin token address, 0 address is reserved for ether, [1] msg.sender of the message 125 | * @param destinationNetwork Destination network 126 | * @param destinationAddress Destination address 127 | * @param amount [0] Amount of tokens/ether, [1] Amount of ether 128 | * @param metadataHash Hash of the metadata 129 | */ 130 | function getLeafValue( 131 | uint8 leafType, 132 | uint32 originNetwork, 133 | address originAddress, 134 | uint32 destinationNetwork, 135 | address destinationAddress, 136 | uint256 amount, 137 | bytes32 metadataHash 138 | ) public pure returns (bytes32) { 139 | return 140 | keccak256( 141 | abi.encodePacked( 142 | leafType, 143 | originNetwork, 144 | originAddress, 145 | destinationNetwork, 146 | destinationAddress, 147 | amount, 148 | metadataHash 149 | ) 150 | ); 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /contracts/lib/EmergencyManager.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | 3 | pragma solidity ^0.8.20; 4 | 5 | /** 6 | * @dev Contract helper responsible to manage the emergency state 7 | */ 8 | contract EmergencyManager { 9 | /** 10 | * @dev Thrown when emergency state is active, and the function requires otherwise 11 | */ 12 | error OnlyNotEmergencyState(); 13 | 14 | /** 15 | * @dev Thrown when emergency state is not active, and the function requires otherwise 16 | */ 17 | error OnlyEmergencyState(); 18 | 19 | /** 20 | * @dev This empty reserved space is put in place to allow future versions to add new 21 | * variables without shifting down storage in the inheritance chain. 22 | */ 23 | uint256[10] private _gap; 24 | 25 | // Indicates whether the emergency state is active or not 26 | bool public isEmergencyState; 27 | 28 | /** 29 | * @dev Emitted when emergency state is activated 30 | */ 31 | event EmergencyStateActivated(); 32 | 33 | /** 34 | * @dev Emitted when emergency state is deactivated 35 | */ 36 | event EmergencyStateDeactivated(); 37 | 38 | /** 39 | * @notice Only allows a function to be callable if emergency state is unactive 40 | */ 41 | modifier ifNotEmergencyState() { 42 | if (isEmergencyState) { 43 | revert OnlyNotEmergencyState(); 44 | } 45 | _; 46 | } 47 | 48 | /** 49 | * @notice Only allows a function to be callable if emergency state is active 50 | */ 51 | modifier ifEmergencyState() { 52 | if (!isEmergencyState) { 53 | revert OnlyEmergencyState(); 54 | } 55 | _; 56 | } 57 | 58 | /** 59 | * @notice Activate emergency state 60 | */ 61 | function _activateEmergencyState() internal virtual ifNotEmergencyState { 62 | isEmergencyState = true; 63 | emit EmergencyStateActivated(); 64 | } 65 | 66 | /** 67 | * @notice Deactivate emergency state 68 | */ 69 | function _deactivateEmergencyState() internal virtual ifEmergencyState { 70 | isEmergencyState = false; 71 | emit EmergencyStateDeactivated(); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /contracts/lib/GlobalExitRootLib.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | 3 | pragma solidity 0.8.20; 4 | 5 | /** 6 | * @dev A library that provides the necessary calculations to calculate the global exit root 7 | */ 8 | library GlobalExitRootLib { 9 | function calculateGlobalExitRoot( 10 | bytes32 mainnetExitRoot, 11 | bytes32 rollupExitRoot 12 | ) internal pure returns (bytes32) { 13 | return keccak256(abi.encodePacked(mainnetExitRoot, rollupExitRoot)); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /contracts/lib/TokenWrapped.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0 2 | // Implementation of permit based on https://github.com/WETH10/WETH10/blob/main/contracts/WETH10.sol 3 | pragma solidity 0.8.20; 4 | 5 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 6 | 7 | contract TokenWrapped is ERC20 { 8 | // Domain typehash 9 | bytes32 public constant DOMAIN_TYPEHASH = 10 | keccak256( 11 | "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" 12 | ); 13 | // Permit typehash 14 | bytes32 public constant PERMIT_TYPEHASH = 15 | keccak256( 16 | "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" 17 | ); 18 | 19 | // Version 20 | string public constant VERSION = "1"; 21 | 22 | // Chain id on deployment 23 | uint256 public immutable deploymentChainId; 24 | 25 | // Domain separator calculated on deployment 26 | bytes32 private immutable _DEPLOYMENT_DOMAIN_SEPARATOR; 27 | 28 | // PolygonZkEVM Bridge address 29 | address public immutable bridgeAddress; 30 | 31 | // Decimals 32 | uint8 private immutable _decimals; 33 | 34 | // Permit nonces 35 | mapping(address => uint256) public nonces; 36 | 37 | modifier onlyBridge() { 38 | require( 39 | msg.sender == bridgeAddress, 40 | "TokenWrapped::onlyBridge: Not PolygonZkEVMBridge" 41 | ); 42 | _; 43 | } 44 | 45 | constructor( 46 | string memory name, 47 | string memory symbol, 48 | uint8 __decimals 49 | ) ERC20(name, symbol) { 50 | bridgeAddress = msg.sender; 51 | _decimals = __decimals; 52 | deploymentChainId = block.chainid; 53 | _DEPLOYMENT_DOMAIN_SEPARATOR = _calculateDomainSeparator(block.chainid); 54 | } 55 | 56 | function mint(address to, uint256 value) external onlyBridge { 57 | _mint(to, value); 58 | } 59 | 60 | // Notice that is not require to approve wrapped tokens to use the bridge 61 | function burn(address account, uint256 value) external onlyBridge { 62 | _burn(account, value); 63 | } 64 | 65 | function decimals() public view virtual override returns (uint8) { 66 | return _decimals; 67 | } 68 | 69 | // Permit relative functions 70 | function permit( 71 | address owner, 72 | address spender, 73 | uint256 value, 74 | uint256 deadline, 75 | uint8 v, 76 | bytes32 r, 77 | bytes32 s 78 | ) external { 79 | require( 80 | block.timestamp <= deadline, 81 | "TokenWrapped::permit: Expired permit" 82 | ); 83 | 84 | bytes32 hashStruct = keccak256( 85 | abi.encode( 86 | PERMIT_TYPEHASH, 87 | owner, 88 | spender, 89 | value, 90 | nonces[owner]++, 91 | deadline 92 | ) 93 | ); 94 | 95 | bytes32 digest = keccak256( 96 | abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR(), hashStruct) 97 | ); 98 | 99 | address signer = ecrecover(digest, v, r, s); 100 | require( 101 | signer != address(0) && signer == owner, 102 | "TokenWrapped::permit: Invalid signature" 103 | ); 104 | 105 | _approve(owner, spender, value); 106 | } 107 | 108 | /** 109 | * @notice Calculate domain separator, given a chainID. 110 | * @param chainId Current chainID 111 | */ 112 | function _calculateDomainSeparator( 113 | uint256 chainId 114 | ) private view returns (bytes32) { 115 | return 116 | keccak256( 117 | abi.encode( 118 | DOMAIN_TYPEHASH, 119 | keccak256(bytes(name())), 120 | keccak256(bytes(VERSION)), 121 | chainId, 122 | address(this) 123 | ) 124 | ); 125 | } 126 | 127 | /// @dev Return the DOMAIN_SEPARATOR. 128 | function DOMAIN_SEPARATOR() public view returns (bytes32) { 129 | return 130 | block.chainid == deploymentChainId 131 | ? _DEPLOYMENT_DOMAIN_SEPARATOR 132 | : _calculateDomainSeparator(block.chainid); 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /contracts/mainnetUpgraded/PolygonZkEVMUpgraded.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity 0.8.20; 3 | 4 | import "../PolygonZkEVM.sol"; 5 | 6 | /** 7 | * Contract responsible for managing the state and the updates of the L2 network 8 | * This contract will NOT BE USED IN PRODUCTION, will be used only in testnet enviroment 9 | */ 10 | contract PolygonZkEVMUpgraded is PolygonZkEVM { 11 | // Indicates the last version before upgrade 12 | uint256 public immutable VERSION_BEFORE_UPGRADE; 13 | 14 | // Indicates the current version 15 | uint256 public version; 16 | 17 | // Last batch verified before the last upgrade 18 | uint256 public lastVerifiedBatchBeforeUpgrade; 19 | 20 | /** 21 | * @param _globalExitRootManager Global exit root manager address 22 | * @param _matic MATIC token address 23 | * @param _rollupVerifier Rollup verifier address 24 | * @param _bridgeAddress Bridge address 25 | * @param _chainID L2 chainID 26 | */ 27 | constructor( 28 | IPolygonZkEVMGlobalExitRoot _globalExitRootManager, 29 | IERC20Upgradeable _matic, 30 | IVerifierRollup _rollupVerifier, 31 | IPolygonZkEVMBridge _bridgeAddress, 32 | uint64 _chainID, 33 | uint64 _forkID, 34 | uint256 versionBeforeUpgrade 35 | ) 36 | PolygonZkEVM( 37 | _globalExitRootManager, 38 | _matic, 39 | _rollupVerifier, 40 | _bridgeAddress, 41 | _chainID, 42 | _forkID 43 | ) 44 | { 45 | VERSION_BEFORE_UPGRADE = versionBeforeUpgrade; 46 | } 47 | 48 | /** 49 | * @dev Thrown when try to update version when it's already updated 50 | */ 51 | error VersionAlreadyUpdated(); 52 | 53 | /** 54 | * @dev Thrown when try to proof a non deterministic state using a verified batch from previous forkIDs 55 | */ 56 | error InitBatchMustMatchCurrentForkID(); 57 | 58 | /** 59 | * @notice Update version of the zkEVM 60 | * @param _versionString New version string 61 | */ 62 | function updateVersion(string memory _versionString) public { 63 | if (version != VERSION_BEFORE_UPGRADE) { 64 | revert VersionAlreadyUpdated(); 65 | } 66 | version++; 67 | 68 | lastVerifiedBatchBeforeUpgrade = lastVerifiedBatch; 69 | emit UpdateZkEVMVersion(lastVerifiedBatch, forkID, _versionString); 70 | } 71 | 72 | /** 73 | * @notice Internal function that proves a different state root given the same batches to verify 74 | * @param initPendingStateNum Init pending state, 0 if consolidated state is used 75 | * @param finalPendingStateNum Final pending state, that will be used to compare with the newStateRoot 76 | * @param initNumBatch Batch which the aggregator starts the verification 77 | * @param finalNewBatch Last batch aggregator intends to verify 78 | * @param newLocalExitRoot New local exit root once the batch is processed 79 | * @param newStateRoot New State root once the batch is processed 80 | * @param proof fflonk proof 81 | */ 82 | function _proveDistinctPendingState( 83 | uint64 initPendingStateNum, 84 | uint64 finalPendingStateNum, 85 | uint64 initNumBatch, 86 | uint64 finalNewBatch, 87 | bytes32 newLocalExitRoot, 88 | bytes32 newStateRoot, 89 | bytes32[24] calldata proof 90 | ) internal view override { 91 | if (initNumBatch < lastVerifiedBatchBeforeUpgrade) { 92 | revert InitBatchMustMatchCurrentForkID(); 93 | } 94 | 95 | super._proveDistinctPendingState( 96 | initPendingStateNum, 97 | finalPendingStateNum, 98 | initNumBatch, 99 | finalNewBatch, 100 | newLocalExitRoot, 101 | newStateRoot, 102 | proof 103 | ); 104 | } 105 | 106 | /** 107 | * @notice Verify and reward batches internal function 108 | * @param pendingStateNum Init pending state, 0 if consolidated state is used 109 | * @param initNumBatch Batch which the aggregator starts the verification 110 | * @param finalNewBatch Last batch aggregator intends to verify 111 | * @param newLocalExitRoot New local exit root once the batch is processed 112 | * @param newStateRoot New State root once the batch is processed 113 | * @param proof fflonk proof 114 | */ 115 | function _verifyAndRewardBatches( 116 | uint64 pendingStateNum, 117 | uint64 initNumBatch, 118 | uint64 finalNewBatch, 119 | bytes32 newLocalExitRoot, 120 | bytes32 newStateRoot, 121 | bytes32[24] calldata proof 122 | ) internal override { 123 | if (initNumBatch < lastVerifiedBatchBeforeUpgrade) { 124 | revert InitBatchMustMatchCurrentForkID(); 125 | } 126 | 127 | super._verifyAndRewardBatches( 128 | pendingStateNum, 129 | initNumBatch, 130 | finalNewBatch, 131 | newLocalExitRoot, 132 | newStateRoot, 133 | proof 134 | ); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /contracts/mocks/DAI.sol: -------------------------------------------------------------------------------- 1 | /** 2 | *Submitted for verification at Etherscan.io on 2019-11-14 3 | */ 4 | 5 | // hevm: flattened sources of /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/dai.sol 6 | pragma solidity =0.5.12; 7 | 8 | ////// /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/lib.sol 9 | // This program is free software: you can redistribute it and/or modify 10 | // it under the terms of the GNU General Public License as published by 11 | // the Free Software Foundation, either version 3 of the License, or 12 | // (at your option) any later version. 13 | 14 | // This program is distributed in the hope that it will be useful, 15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | // GNU General Public License for more details. 18 | 19 | // You should have received a copy of the GNU General Public License 20 | // along with this program. If not, see . 21 | 22 | /* pragma solidity 0.5.12; */ 23 | 24 | contract LibNote { 25 | event LogNote( 26 | bytes4 indexed sig, 27 | address indexed usr, 28 | bytes32 indexed arg1, 29 | bytes32 indexed arg2, 30 | bytes data 31 | ) anonymous; 32 | 33 | modifier note() { 34 | _; 35 | assembly { 36 | // log an 'anonymous' event with a constant 6 words of calldata 37 | // and four indexed topics: selector, caller, arg1 and arg2 38 | let mark := msize // end of memory ensures zero 39 | mstore(0x40, add(mark, 288)) // update free memory pointer 40 | mstore(mark, 0x20) // bytes type data offset 41 | mstore(add(mark, 0x20), 224) // bytes size (padded) 42 | calldatacopy(add(mark, 0x40), 0, 224) // bytes payload 43 | log4( 44 | mark, 45 | 288, // calldata 46 | shl(224, shr(224, calldataload(0))), // msg.sig 47 | caller, // msg.sender 48 | calldataload(4), // arg1 49 | calldataload(36) // arg2 50 | ) 51 | } 52 | } 53 | } 54 | 55 | ////// /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/dai.sol 56 | // Copyright (C) 2017, 2018, 2019 dbrock, rain, mrchico 57 | 58 | // This program is free software: you can redistribute it and/or modify 59 | // it under the terms of the GNU Affero General Public License as published by 60 | // the Free Software Foundation, either version 3 of the License, or 61 | // (at your option) any later version. 62 | // 63 | // This program is distributed in the hope that it will be useful, 64 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 65 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 66 | // GNU Affero General Public License for more details. 67 | // 68 | // You should have received a copy of the GNU Affero General Public License 69 | // along with this program. If not, see . 70 | 71 | /* pragma solidity 0.5.12; */ 72 | 73 | /* import "./lib.sol"; */ 74 | 75 | contract Dai is LibNote { 76 | // --- Auth --- 77 | mapping(address => uint256) public wards; 78 | 79 | function rely(address guy) external note auth { 80 | wards[guy] = 1; 81 | } 82 | 83 | function deny(address guy) external note auth { 84 | wards[guy] = 0; 85 | } 86 | 87 | modifier auth() { 88 | require(wards[msg.sender] == 1, "Dai/not-authorized"); 89 | _; 90 | } 91 | 92 | // --- ERC20 Data --- 93 | string public constant name = "Dai Stablecoin"; 94 | string public constant symbol = "DAI"; 95 | string public constant version = "1"; 96 | uint8 public constant decimals = 18; 97 | uint256 public totalSupply; 98 | 99 | mapping(address => uint256) public balanceOf; 100 | mapping(address => mapping(address => uint256)) public allowance; 101 | mapping(address => uint256) public nonces; 102 | 103 | event Approval(address indexed src, address indexed guy, uint256 wad); 104 | event Transfer(address indexed src, address indexed dst, uint256 wad); 105 | 106 | // --- Math --- 107 | function add(uint256 x, uint256 y) internal pure returns (uint256 z) { 108 | require((z = x + y) >= x); 109 | } 110 | 111 | function sub(uint256 x, uint256 y) internal pure returns (uint256 z) { 112 | require((z = x - y) <= x); 113 | } 114 | 115 | // --- EIP712 niceties --- 116 | bytes32 public DOMAIN_SEPARATOR; 117 | // bytes32 public constant PERMIT_TYPEHASH = keccak256("Permit(address holder,address spender,uint256 nonce,uint256 expiry,bool allowed)"); 118 | bytes32 public constant PERMIT_TYPEHASH = 119 | 0xea2aa0a1be11a07ed86d755c93467f4f82362b452371d1ba94d1715123511acb; 120 | 121 | constructor(uint256 chainId_) public { 122 | wards[msg.sender] = 1; 123 | DOMAIN_SEPARATOR = keccak256( 124 | abi.encode( 125 | keccak256( 126 | "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" 127 | ), 128 | keccak256(bytes(name)), 129 | keccak256(bytes(version)), 130 | chainId_, 131 | address(this) 132 | ) 133 | ); 134 | } 135 | 136 | // --- Token --- 137 | function transfer(address dst, uint256 wad) external returns (bool) { 138 | return transferFrom(msg.sender, dst, wad); 139 | } 140 | 141 | function transferFrom( 142 | address src, 143 | address dst, 144 | uint256 wad 145 | ) public returns (bool) { 146 | require(balanceOf[src] >= wad, "Dai/insufficient-balance"); 147 | if (src != msg.sender && allowance[src][msg.sender] != uint256(-1)) { 148 | require( 149 | allowance[src][msg.sender] >= wad, 150 | "Dai/insufficient-allowance" 151 | ); 152 | allowance[src][msg.sender] = sub(allowance[src][msg.sender], wad); 153 | } 154 | balanceOf[src] = sub(balanceOf[src], wad); 155 | balanceOf[dst] = add(balanceOf[dst], wad); 156 | emit Transfer(src, dst, wad); 157 | return true; 158 | } 159 | 160 | function mint(address usr, uint256 wad) external auth { 161 | balanceOf[usr] = add(balanceOf[usr], wad); 162 | totalSupply = add(totalSupply, wad); 163 | emit Transfer(address(0), usr, wad); 164 | } 165 | 166 | function burn(address usr, uint256 wad) external { 167 | require(balanceOf[usr] >= wad, "Dai/insufficient-balance"); 168 | if (usr != msg.sender && allowance[usr][msg.sender] != uint256(-1)) { 169 | require( 170 | allowance[usr][msg.sender] >= wad, 171 | "Dai/insufficient-allowance" 172 | ); 173 | allowance[usr][msg.sender] = sub(allowance[usr][msg.sender], wad); 174 | } 175 | balanceOf[usr] = sub(balanceOf[usr], wad); 176 | totalSupply = sub(totalSupply, wad); 177 | emit Transfer(usr, address(0), wad); 178 | } 179 | 180 | function approve(address usr, uint256 wad) external returns (bool) { 181 | allowance[msg.sender][usr] = wad; 182 | emit Approval(msg.sender, usr, wad); 183 | return true; 184 | } 185 | 186 | // --- Alias --- 187 | function push(address usr, uint256 wad) external { 188 | transferFrom(msg.sender, usr, wad); 189 | } 190 | 191 | function pull(address usr, uint256 wad) external { 192 | transferFrom(usr, msg.sender, wad); 193 | } 194 | 195 | function move( 196 | address src, 197 | address dst, 198 | uint256 wad 199 | ) external { 200 | transferFrom(src, dst, wad); 201 | } 202 | 203 | // --- Approve by signature --- 204 | function permit( 205 | address holder, 206 | address spender, 207 | uint256 nonce, 208 | uint256 expiry, 209 | bool allowed, 210 | uint8 v, 211 | bytes32 r, 212 | bytes32 s 213 | ) external { 214 | bytes32 digest = keccak256( 215 | abi.encodePacked( 216 | "\x19\x01", 217 | DOMAIN_SEPARATOR, 218 | keccak256( 219 | abi.encode( 220 | PERMIT_TYPEHASH, 221 | holder, 222 | spender, 223 | nonce, 224 | expiry, 225 | allowed 226 | ) 227 | ) 228 | ) 229 | ); 230 | 231 | require(holder != address(0), "Dai/invalid-address-0"); 232 | require(holder == ecrecover(digest, v, r, s), "Dai/invalid-permit"); 233 | require(expiry == 0 || now <= expiry, "Dai/permit-expired"); 234 | require(nonce == nonces[holder]++, "Dai/invalid-nonce"); 235 | uint256 wad = allowed ? uint256(-1) : 0; 236 | allowance[holder][spender] = wad; 237 | emit Approval(holder, spender, wad); 238 | } 239 | } 240 | -------------------------------------------------------------------------------- /contracts/mocks/DepositContractMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity 0.8.20; 3 | import "../lib/DepositContract.sol"; 4 | import "hardhat/console.sol"; 5 | 6 | /** 7 | * This contract will be used as a herlper for all the sparse merkle tree related functions 8 | * Based on the implementation of the deposit eth2.0 contract https://github.com/ethereum/consensus-specs/blob/dev/solidity_deposit_contract/deposit_contract.sol 9 | */ 10 | contract DepositContractMock is DepositContract { 11 | constructor() { 12 | initialize(); 13 | } 14 | 15 | function initialize() public initializer {} 16 | 17 | /** 18 | * @notice Given the leaf data returns the leaf value 19 | * @param leafType Leaf type 20 | * @param originNetwork Origin Network 21 | * @param originTokenAddress Origin token address, 0 address is reserved for ether 22 | * @param destinationNetwork Destination network 23 | * @param destinationAddress Destination address 24 | * @param amount Amount of tokens 25 | * @param metadataHash Hash of the metadata 26 | */ 27 | function deposit( 28 | uint8 leafType, 29 | uint32 originNetwork, 30 | address originTokenAddress, 31 | uint32 destinationNetwork, 32 | address destinationAddress, 33 | uint256 amount, 34 | bytes32 metadataHash 35 | ) public { 36 | _deposit( 37 | getLeafValue( 38 | leafType, 39 | originNetwork, 40 | originTokenAddress, 41 | destinationNetwork, 42 | destinationAddress, 43 | amount, 44 | metadataHash 45 | ) 46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /contracts/mocks/ERC20PermitMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | 3 | pragma solidity 0.8.20; 4 | 5 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 6 | 7 | contract ERC20PermitMock is ERC20 { 8 | constructor( 9 | string memory name, 10 | string memory symbol, 11 | address initialAccount, 12 | uint256 initialBalance 13 | ) payable ERC20(name, symbol) { 14 | _mint(initialAccount, initialBalance); 15 | NAME_HASH = keccak256(bytes(name)); 16 | } 17 | 18 | function mint(address account, uint256 amount) public { 19 | _mint(account, amount); 20 | } 21 | 22 | function burn(uint256 amount) public { 23 | _burn(msg.sender, amount); 24 | } 25 | 26 | function transferInternal(address from, address to, uint256 value) public { 27 | _transfer(from, to, value); 28 | } 29 | 30 | function approveInternal( 31 | address owner, 32 | address spender, 33 | uint256 value 34 | ) public { 35 | _approve(owner, spender, value); 36 | } 37 | 38 | // erc20 permit 39 | mapping(address => uint256) public nonces; 40 | 41 | bytes32 public constant PERMIT_TYPEHASH = 42 | keccak256( 43 | "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" 44 | ); 45 | 46 | bytes32 public NAME_HASH; 47 | 48 | // bytes32 public constant VERSION_HASH = 49 | // keccak256("1") 50 | bytes32 public constant VERSION_HASH = 51 | 0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6; 52 | 53 | // bytes32 public constant EIP712DOMAIN_HASH = 54 | // keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)") 55 | bytes32 public constant EIP712DOMAIN_HASH = 56 | 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f; 57 | 58 | function _validateSignedData( 59 | address signer, 60 | bytes32 encodeData, 61 | uint8 v, 62 | bytes32 r, 63 | bytes32 s 64 | ) internal view { 65 | bytes32 domainSeparator = keccak256( 66 | abi.encode( 67 | EIP712DOMAIN_HASH, 68 | NAME_HASH, 69 | VERSION_HASH, 70 | getChainId(), 71 | address(this) 72 | ) 73 | ); 74 | 75 | bytes32 digest = keccak256( 76 | abi.encodePacked("\x19\x01", domainSeparator, encodeData) 77 | ); 78 | address recoveredAddress = ecrecover(digest, v, r, s); 79 | // Explicitly disallow authorizations for address(0) as ecrecover returns address(0) on malformed messages 80 | require( 81 | recoveredAddress != address(0) && recoveredAddress == signer, 82 | "HEZ::_validateSignedData: INVALID_SIGNATURE" 83 | ); 84 | } 85 | 86 | function getChainId() public view returns (uint256 chainId) { 87 | assembly { 88 | chainId := chainid() 89 | } 90 | } 91 | 92 | function permit( 93 | address owner, 94 | address spender, 95 | uint256 value, 96 | uint256 deadline, 97 | uint8 v, 98 | bytes32 r, 99 | bytes32 s 100 | ) external { 101 | require(deadline >= block.timestamp, "HEZ::permit: AUTH_EXPIRED"); 102 | bytes32 encodeData = keccak256( 103 | abi.encode( 104 | PERMIT_TYPEHASH, 105 | owner, 106 | spender, 107 | value, 108 | nonces[owner]++, 109 | deadline 110 | ) 111 | ); 112 | _validateSignedData(owner, encodeData, v, r, s); 113 | _approve(owner, spender, value); 114 | } 115 | 116 | function DOMAIN_SEPARATOR() external view returns (bytes32) { 117 | return 118 | keccak256( 119 | abi.encode( 120 | EIP712DOMAIN_HASH, 121 | NAME_HASH, 122 | VERSION_HASH, 123 | getChainId(), 124 | address(this) 125 | ) 126 | ); 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /contracts/mocks/PolygonZkEVMBridgeMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity 0.8.20; 3 | import "../PolygonZkEVMBridge.sol"; 4 | import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; 5 | 6 | /** 7 | * PolygonZkEVMBridge that will be deployed on both networks Ethereum and Polygon zkEVM 8 | * Contract responsible to manage the token interactions with other networks 9 | */ 10 | contract PolygonZkEVMBridgeMock is PolygonZkEVMBridge, OwnableUpgradeable { 11 | uint256 public maxEtherBridge; 12 | 13 | /** 14 | * @param _networkID networkID 15 | * @param _globalExitRootManager global exit root manager address 16 | */ 17 | function initialize( 18 | uint32 _networkID, 19 | IBasePolygonZkEVMGlobalExitRoot _globalExitRootManager, 20 | address _polygonZkEVMaddress 21 | ) public override initializer { 22 | networkID = _networkID; 23 | globalExitRootManager = _globalExitRootManager; 24 | polygonZkEVMaddress = _polygonZkEVMaddress; 25 | 26 | maxEtherBridge = 0.25 ether; 27 | 28 | // Initialize OZ contracts 29 | __Ownable_init_unchained(); 30 | } 31 | 32 | function setNetworkID(uint32 _networkID) public onlyOwner { 33 | networkID = _networkID; 34 | } 35 | 36 | function setMaxEtherBridge(uint256 _maxEtherBridge) public onlyOwner { 37 | maxEtherBridge = _maxEtherBridge; 38 | } 39 | 40 | /** 41 | * @notice Deposit add a new leaf to the merkle tree 42 | * @param destinationNetwork Network destination 43 | * @param destinationAddress Address destination 44 | * @param amount Amount of tokens 45 | * @param token Token address, 0 address is reserved for ether 46 | * @param permitData Raw data of the call `permit` of the token 47 | */ 48 | function bridgeAsset( 49 | uint32 destinationNetwork, 50 | address destinationAddress, 51 | uint256 amount, 52 | address token, 53 | bool forceUpdateGlobalExitRoot, 54 | bytes calldata permitData 55 | ) public payable override { 56 | require( 57 | msg.value <= maxEtherBridge, 58 | "PolygonZkEVMBridge::bridgeAsset: Cannot bridge more than maxEtherBridge" 59 | ); 60 | super.bridgeAsset( 61 | destinationNetwork, 62 | destinationAddress, 63 | amount, 64 | token, 65 | forceUpdateGlobalExitRoot, 66 | permitData 67 | ); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /contracts/mocks/PolygonZkEVMGlobalExitRootL2Mock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity 0.8.20; 3 | 4 | import "../PolygonZkEVMGlobalExitRootL2.sol"; 5 | 6 | /** 7 | * Contract responsible for managing the exit roots across multiple networks 8 | 9 | */ 10 | contract PolygonZkEVMGlobalExitRootL2Mock is PolygonZkEVMGlobalExitRootL2 { 11 | /** 12 | * @param _bridgeAddress PolygonZkEVM Bridge contract address 13 | */ 14 | constructor( 15 | address _bridgeAddress 16 | ) PolygonZkEVMGlobalExitRootL2(_bridgeAddress) {} 17 | 18 | /** 19 | * @notice Set globalExitRoot 20 | * @param globalExitRoot New global exit root 21 | * @param blockNumber block number 22 | */ 23 | function setLastGlobalExitRoot( 24 | bytes32 globalExitRoot, 25 | uint256 blockNumber 26 | ) public { 27 | globalExitRootMap[globalExitRoot] = blockNumber; 28 | } 29 | 30 | /** 31 | * @notice Set rollup exit root 32 | * @param newRoot New rollup exit root 33 | */ 34 | function setExitRoot(bytes32 newRoot) public { 35 | lastRollupExitRoot = newRoot; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /contracts/mocks/PolygonZkEVMGlobalExitRootMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity 0.8.20; 3 | 4 | import "../PolygonZkEVMGlobalExitRoot.sol"; 5 | 6 | /** 7 | * Contract responsible for managing the exit roots across multiple networks 8 | 9 | */ 10 | contract PolygonZkEVMGlobalExitRootMock is PolygonZkEVMGlobalExitRoot { 11 | /** 12 | * @param _rollupAddress Rollup contract address 13 | * @param _bridgeAddress PolygonZkEVM Bridge contract address 14 | */ 15 | constructor( 16 | address _rollupAddress, 17 | address _bridgeAddress 18 | ) PolygonZkEVMGlobalExitRoot(_rollupAddress, _bridgeAddress) {} 19 | 20 | /** 21 | * @notice Set last global exit root 22 | * @param timestamp timestamp 23 | */ 24 | function setLastGlobalExitRoot(uint256 timestamp) public { 25 | globalExitRootMap[getLastGlobalExitRoot()] = timestamp; 26 | } 27 | 28 | /** 29 | * @notice Set last global exit root 30 | * @param timestamp timestamp 31 | */ 32 | function setGlobalExitRoot( 33 | bytes32 globalExitRoot, 34 | uint256 timestamp 35 | ) public { 36 | globalExitRootMap[globalExitRoot] = timestamp; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /contracts/mocks/SequenceBatchesMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity 0.8.20; 3 | import "../lib/DepositContract.sol"; 4 | import "hardhat/console.sol"; 5 | 6 | /** 7 | * This contract will be used as a helper for PolygonZkEVM tests 8 | */ 9 | contract SendData { 10 | /** 11 | * @notice Send data to destination 12 | * @param destination Destination 13 | * @param data Data 14 | */ 15 | function sendData(address destination, bytes memory data) public { 16 | destination.call(data); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /contracts/mocks/VerifierRollupHelperMock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | 3 | pragma solidity 0.8.20; 4 | 5 | import "../interfaces/IVerifierRollup.sol"; 6 | 7 | contract VerifierRollupHelperMock is IVerifierRollup { 8 | function verifyProof( 9 | bytes32[24] calldata proof, 10 | uint256[1] memory pubSignals 11 | ) public view override returns (bool) { 12 | return true; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /contracts/testnet/PolygonZkEVMTestnetClearStorage.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity 0.8.20; 3 | 4 | import "../PolygonZkEVM.sol"; 5 | 6 | /** 7 | * Contract responsible for managing the state and the updates of the L2 network 8 | * This contract will NOT BE USED IN PRODUCTION, will be used only in testnet enviroment 9 | */ 10 | contract PolygonZkEVMTestnetClearStorage is PolygonZkEVM { 11 | // Indicates the current version 12 | uint256 public version; 13 | 14 | /** 15 | * @param _globalExitRootManager Global exit root manager address 16 | * @param _matic MATIC token address 17 | * @param _rollupVerifier Rollup verifier address 18 | * @param _bridgeAddress Bridge address 19 | * @param _chainID L2 chainID 20 | */ 21 | constructor( 22 | IPolygonZkEVMGlobalExitRoot _globalExitRootManager, 23 | IERC20Upgradeable _matic, 24 | IVerifierRollup _rollupVerifier, 25 | IPolygonZkEVMBridge _bridgeAddress, 26 | uint64 _chainID, 27 | uint64 _forkID 28 | ) 29 | PolygonZkEVM( 30 | _globalExitRootManager, 31 | _matic, 32 | _rollupVerifier, 33 | _bridgeAddress, 34 | _chainID, 35 | _forkID 36 | ) 37 | {} 38 | 39 | /** 40 | * @dev Thrown when try to update version when it's already updated 41 | */ 42 | error VersionAlreadyUpdated(); 43 | 44 | /** 45 | * @notice Clear previous storage 46 | */ 47 | function clearStorage() public { 48 | forceBatchTimeout = 5 days; 49 | isForcedBatchDisallowed = true; 50 | assembly { 51 | sstore(version.slot, 0) 52 | sstore(add(version.slot,1), 0) 53 | sstore(add(version.slot,2), 0) 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /contracts/testnet/PolygonZkEVMTestnetV2.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity 0.8.20; 3 | 4 | import "../PolygonZkEVM.sol"; 5 | 6 | /** 7 | * Contract responsible for managing the state and the updates of the L2 network 8 | * This contract will NOT BE USED IN PRODUCTION, will be used only in testnet enviroment 9 | */ 10 | contract PolygonZkEVMTestnetV2 is PolygonZkEVM { 11 | // Indicates the current version 12 | uint256 public version; 13 | 14 | /** 15 | * @param _globalExitRootManager Global exit root manager address 16 | * @param _matic MATIC token address 17 | * @param _rollupVerifier Rollup verifier address 18 | * @param _bridgeAddress Bridge address 19 | * @param _chainID L2 chainID 20 | */ 21 | constructor( 22 | IPolygonZkEVMGlobalExitRoot _globalExitRootManager, 23 | IERC20Upgradeable _matic, 24 | IVerifierRollup _rollupVerifier, 25 | IPolygonZkEVMBridge _bridgeAddress, 26 | uint64 _chainID, 27 | uint64 _forkID 28 | ) 29 | PolygonZkEVM( 30 | _globalExitRootManager, 31 | _matic, 32 | _rollupVerifier, 33 | _bridgeAddress, 34 | _chainID, 35 | _forkID 36 | ) 37 | {} 38 | 39 | /** 40 | * @dev Thrown when try to update version when it's already updated 41 | */ 42 | error VersionAlreadyUpdated(); 43 | 44 | /** 45 | * @notice Update version of the zkEVM 46 | * @param _versionString New version string 47 | */ 48 | function updateVersion(string memory _versionString) public { 49 | if (version != 1) { 50 | revert VersionAlreadyUpdated(); 51 | } 52 | version++; 53 | 54 | emit UpdateZkEVMVersion(lastVerifiedBatch, forkID, _versionString); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /deployment/2_deployPolygonZKEVMDeployer.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-await-in-loop, no-use-before-define, no-lonely-if */ 2 | /* eslint-disable no-console, no-inner-declarations, no-undef, import/no-unresolved */ 3 | const { ethers } = require('hardhat'); 4 | const path = require('path'); 5 | const fs = require('fs'); 6 | require('dotenv').config({ path: path.resolve(__dirname, '../.env') }); 7 | 8 | const { deployPolygonZkEVMDeployer } = require('./helpers/deployment-helpers'); 9 | 10 | const pathDeployParameters = path.join(__dirname, './deploy_parameters.json'); 11 | const deployParameters = require('./deploy_parameters.json'); 12 | 13 | async function main() { 14 | // Load provider 15 | let currentProvider = ethers.provider; 16 | if (deployParameters.multiplierGas || deployParameters.maxFeePerGas) { 17 | if (process.env.HARDHAT_NETWORK !== 'hardhat') { 18 | currentProvider = new ethers.providers.JsonRpcProvider(`https://${process.env.HARDHAT_NETWORK}.infura.io/v3/${process.env.INFURA_PROJECT_ID}`); 19 | if (deployParameters.maxPriorityFeePerGas && deployParameters.maxFeePerGas) { 20 | console.log(`Hardcoded gas used: MaxPriority${deployParameters.maxPriorityFeePerGas} gwei, MaxFee${deployParameters.maxFeePerGas} gwei`); 21 | const FEE_DATA = { 22 | maxFeePerGas: ethers.utils.parseUnits(deployParameters.maxFeePerGas, 'gwei'), 23 | maxPriorityFeePerGas: ethers.utils.parseUnits(deployParameters.maxPriorityFeePerGas, 'gwei'), 24 | }; 25 | currentProvider.getFeeData = async () => FEE_DATA; 26 | } else { 27 | console.log('Multiplier gas used: ', deployParameters.multiplierGas); 28 | async function overrideFeeData() { 29 | const feedata = await ethers.provider.getFeeData(); 30 | return { 31 | maxFeePerGas: feedata.maxFeePerGas.mul(deployParameters.multiplierGas).div(1000), 32 | maxPriorityFeePerGas: feedata.maxPriorityFeePerGas.mul(deployParameters.multiplierGas).div(1000), 33 | }; 34 | } 35 | currentProvider.getFeeData = overrideFeeData; 36 | } 37 | } 38 | } 39 | 40 | // Load deployer 41 | let deployer; 42 | if (deployParameters.deployerPvtKey) { 43 | deployer = new ethers.Wallet(deployParameters.deployerPvtKey, currentProvider); 44 | } else if (process.env.MNEMONIC) { 45 | deployer = ethers.Wallet.fromMnemonic(process.env.MNEMONIC, 'm/44\'/60\'/0\'/0/0').connect(currentProvider); 46 | } else { 47 | [deployer] = (await ethers.getSigners()); 48 | } 49 | 50 | // Load initialZkEVMDeployerOwner 51 | const { 52 | initialZkEVMDeployerOwner, 53 | } = deployParameters; 54 | 55 | if (initialZkEVMDeployerOwner === undefined || initialZkEVMDeployerOwner === '') { 56 | throw new Error('Missing parameter: initialZkEVMDeployerOwner'); 57 | } 58 | 59 | // Deploy PolygonZkEVMDeployer if is not deployed already using keyless deployment 60 | const [zkEVMDeployerContract, keylessDeployer] = await deployPolygonZkEVMDeployer(initialZkEVMDeployerOwner, deployer); 61 | if (keylessDeployer === ethers.constants.AddressZero) { 62 | console.log('#######################\n'); 63 | console.log('polygonZkEVMDeployer already deployed on: ', zkEVMDeployerContract.address); 64 | } else { 65 | console.log('#######################\n'); 66 | console.log('polygonZkEVMDeployer deployed on: ', zkEVMDeployerContract.address); 67 | } 68 | 69 | deployParameters.zkEVMDeployerAddress = zkEVMDeployerContract.address; 70 | fs.writeFileSync(pathDeployParameters, JSON.stringify(deployParameters, null, 1)); 71 | } 72 | 73 | main().catch((e) => { 74 | console.error(e); 75 | process.exit(1); 76 | }); 77 | -------------------------------------------------------------------------------- /deployment/README.md: -------------------------------------------------------------------------------- 1 | ## Requirements 2 | 3 | - node version: 14.x 4 | - npm version: 7.x 5 | 6 | ## Deployment 7 | 8 | In project root execute: 9 | 10 | ``` 11 | npm i 12 | cp .env.example .env 13 | ``` 14 | 15 | Fill `.env` with your `MNEMONIC` and `INFURA_PROJECT_ID` 16 | If you want to verify the contracts also fill the `ETHERSCAN_API_KEY` 17 | 18 | ``` 19 | cd deployment 20 | cp deploy_parameters.json.example deploy_parameters.json 21 | ``` 22 | 23 | Fill created `deploy_parameters.json` with appropiate parameters. 24 | See below for more information about the `deploy_parameters.json` 25 | 26 | The first step is deploying and verifying the `PolygonZkEVMDeployer`, this will be the factory for deterministic contracts, the address of the contracts will depend on the `salt` and the `initialZkEVMDeployerOwner` 27 | 28 | This contrat is deployed using a keyless deployment, therefore the gasPrice is hardcoded. 29 | The value is on `100 gweis`, if it's necessary to update it go to `helpers/deployment-helpers.js` and update the `gasPriceKeylessDeployment` constant. 30 | Note that this operation will change all the deterministic address deployed. 31 | 32 | ``` 33 | npm run deploy:deployer:ZkEVM:goerli 34 | npm run verify:deployer:ZkEVM:goerli 35 | ``` 36 | 37 | To deploy on testnet is necessary a token MATIC contract, therefore, there's another script that previously to the actual deployment, deploys a matic contracts and adds it automatically to the `deploy_parameters.json` 38 | 39 | To deploy on testnet use:`deploy:testnet:ZkEVM:${network}` 40 | 41 | In other cases use fullfill `maticTokenAddress` in the `deploy_parameters.json` and run `deploy:ZkEVM:${network}` 42 | 43 | ``` 44 | npm run deploy:testnet:ZkEVM:goerli 45 | 46 | ``` 47 | 48 | To verify contracts use `npm run verify:ZkEVM:${network}` 49 | 50 | ``` 51 | npm run verify:ZkEVM:goerli 52 | ``` 53 | 54 | A new folder will be created witth the following name `deployments/${network}_$(date +%s)` with all the output information and the OZ proxy information. 55 | 56 | ## deploy-parameters.json 57 | 58 | - `realVerifier`: bool, Indicates whether deploy a real verifier or not 59 | - `trustedSequencerURL`: string, trustedSequencer URL 60 | - `networkName`: string, networkName 61 | - `version`:string, will just be emitted at initialization of the contract, usefull just for synchronizer 62 | - `trustedSequencer`: address, trusted sequencer addresss 63 | - `chainID`: uint64, chainID of the zkEVM 64 | - `trustedAggregator`:address, Trusted aggregator address 65 | - `trustedAggregatorTimeout`: uint64, If a sequence is not verified in this timeout everyone can verify it 66 | - `pendingStateTimeout`: uint64, Once a pending state exceeds this timeout it can be consolidated 67 | - `forkID`: uint64, Fork ID of the zkEVM, indicates the prover (zkROM/executor) version 68 | - `admin`:address, Admin address, can adjust PolygonZkEVM parameters or stop the emergency state 69 | - `zkEVMOwner`: address, Able to put the PolygonZkEVM into emergency state (kill switch) 70 | - `timelockAddress`: address, Timelock owner address, able to send start an upgradability process via timelock 71 | - `minDelayTimelock`: number, Minimum timelock delay, 72 | - `salt`: bytes32, Salt used in `PolygonZkEVMDeployer` to deploy deterministic contracts, such as the PolygonZkEVMBridge 73 | - `initialZkEVMDeployerOwner`: address, Initial owner of the `PolygonZkEVMDeployer` 74 | - `maticTokenAddress`: address, Matic token address, only if deploy on testnet can be left blank and will fullfilled by the scripts. 75 | - `zkEVMDeployerAddress`: address, Address of the `PolygonZkEVMDeployer`. Can be left blank, will be fullfilled automatically with the `deploy:deployer:ZkEVM:goerli` script. 76 | 77 | ### Optional Parameters 78 | 79 | - `deployerPvtKey`: string, pvtKey of the deployer, overrides the address in `MNEMONIC` of `.env` if exist 80 | - `maxFeePerGas`:string, Set `maxFeePerGas`, must define aswell `maxPriorityFeePerGas` to use it 81 | - `maxPriorityFeePerGas`:string, Set `maxPriorityFeePerGas`, must define aswell `maxFeePerGas` to use it 82 | - `multiplierGas`: number, Gas multiplier with 3 decimals. If `maxFeePerGas` and `maxPriorityFeePerGas` are set, this will not take effect 83 | 84 | ## Notes 85 | 86 | - Since there are deterministic address you cannot deploy twice on the same network using the same `salt` and `initialZkEVMDeployerOwner`. Changing one of them is enough to make a new deployment. 87 | - It's mandatory to delete the `.openzeppelin` upgradebility information in order to make a new deployment 88 | - `genesis.json` has been generated using the tool: `1_createGenesis`, this script depends on the `deploy_parameters` aswell. 89 | -------------------------------------------------------------------------------- /deployment/deploy_parameters.json.example: -------------------------------------------------------------------------------- 1 | { 2 | "realVerifier": false, 3 | "trustedSequencerURL": "http://zkevm-json-rpc:8123", 4 | "networkName": "zkevm", 5 | "version":"0.0.1", 6 | "trustedSequencer":"0x617b3a3528F9cDd6630fd3301B9c8911F7Bf063D", 7 | "chainID": 1001, 8 | "trustedAggregator":"0x617b3a3528F9cDd6630fd3301B9c8911F7Bf063D", 9 | "trustedAggregatorTimeout": 604799, 10 | "pendingStateTimeout": 604799, 11 | "forkID": 1, 12 | "admin":"0x617b3a3528F9cDd6630fd3301B9c8911F7Bf063D", 13 | "zkEVMOwner": "0x617b3a3528F9cDd6630fd3301B9c8911F7Bf063D", 14 | "timelockAddress": "0x617b3a3528F9cDd6630fd3301B9c8911F7Bf063D", 15 | "minDelayTimelock": 3600, 16 | "salt": "0x0000000000000000000000000000000000000000000000000000000000000000", 17 | "initialZkEVMDeployerOwner" :"0xaddress", 18 | "maticTokenAddress":"0x617b3a3528F9cDd6630fd3301B9c8911F7Bf063D", 19 | "zkEVMDeployerAddress":"", 20 | "deployerPvtKey": "", 21 | "maxFeePerGas":"", 22 | "maxPriorityFeePerGas":"", 23 | "multiplierGas": "" 24 | } -------------------------------------------------------------------------------- /deployment/helpers/deployment-helpers.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-await-in-loop, no-use-before-define, no-lonely-if, import/no-dynamic-require */ 2 | /* eslint-disable no-console, no-inner-declarations, no-undef, import/no-unresolved */ 3 | const { expect } = require('chai'); 4 | const { ethers } = require('hardhat'); 5 | 6 | const gasPriceKeylessDeployment = '100'; // 100 gweis 7 | 8 | async function deployPolygonZkEVMDeployer(deployerAddress, signer) { 9 | const PolgonZKEVMDeployerFactory = await ethers.getContractFactory('PolygonZkEVMDeployer', signer); 10 | 11 | const deployTxZKEVMDeployer = (PolgonZKEVMDeployerFactory.getDeployTransaction( 12 | deployerAddress, 13 | )).data; 14 | 15 | const gasLimit = ethers.BigNumber.from(1000000); // Put 1 Million, aprox 650k are necessary 16 | const gasPrice = ethers.BigNumber.from(ethers.utils.parseUnits(gasPriceKeylessDeployment, 'gwei')); 17 | const to = '0x'; // bc deployment transaction, "to" is "0x" 18 | const tx = { 19 | to, 20 | nonce: 0, 21 | value: 0, 22 | gasLimit: gasLimit.toHexString(), 23 | gasPrice: gasPrice.toHexString(), 24 | data: deployTxZKEVMDeployer, 25 | }; 26 | 27 | const signature = { 28 | v: 27, 29 | r: '0x5ca1ab1e0', // Equals 0x00000000000000000000000000000000000000000000000000000005ca1ab1e0 30 | s: '0x5ca1ab1e', // Equals 0x000000000000000000000000000000000000000000000000000000005ca1ab1e 31 | }; 32 | const serializedTransaction = ethers.utils.serializeTransaction(tx, signature); 33 | const resultTransaction = ethers.utils.parseTransaction(serializedTransaction); 34 | const totalEther = gasLimit.mul(gasPrice); // 0.1 ether 35 | 36 | // Check if it's already deployed 37 | const zkEVMDeployerAddress = ethers.utils.getContractAddress(resultTransaction); 38 | if (await signer.provider.getCode(zkEVMDeployerAddress) !== '0x') { 39 | const zkEVMDeployerContract = PolgonZKEVMDeployerFactory.attach(zkEVMDeployerAddress); 40 | expect(await zkEVMDeployerContract.owner()).to.be.equal(signer.address); 41 | return [zkEVMDeployerContract, ethers.constants.AddressZero]; 42 | } 43 | 44 | // Fund keyless deployment 45 | const params = { 46 | to: resultTransaction.from, 47 | value: totalEther.toHexString(), 48 | }; 49 | await (await signer.sendTransaction(params)).wait(); 50 | 51 | // Deploy zkEVMDeployer 52 | await (await signer.provider.sendTransaction(serializedTransaction)).wait(); 53 | 54 | const zkEVMDeployerContract = await PolgonZKEVMDeployerFactory.attach(zkEVMDeployerAddress); 55 | expect(await zkEVMDeployerContract.owner()).to.be.equal(deployerAddress); 56 | return [zkEVMDeployerContract, resultTransaction.from]; 57 | } 58 | 59 | async function create2Deployment(polgonZKEVMDeployerContract, salt, deployTransaction, dataCall, deployer, hardcodedGasLimit) { 60 | // Encode deploy transaction 61 | const hashInitCode = ethers.utils.solidityKeccak256(['bytes'], [deployTransaction]); 62 | 63 | // Precalculate create2 address 64 | const precalculatedAddressDeployed = ethers.utils.getCreate2Address(polgonZKEVMDeployerContract.address, salt, hashInitCode); 65 | const amount = 0; 66 | 67 | if (await deployer.provider.getCode(precalculatedAddressDeployed) !== '0x') { 68 | return [precalculatedAddressDeployed, false]; 69 | } 70 | 71 | if (dataCall) { 72 | // Deploy using create2 and call 73 | if (hardcodedGasLimit) { 74 | const populatedTransaction = await polgonZKEVMDeployerContract.populateTransaction.deployDeterministicAndCall( 75 | amount, 76 | salt, 77 | deployTransaction, 78 | dataCall, 79 | ); 80 | populatedTransaction.gasLimit = ethers.BigNumber.from(hardcodedGasLimit); 81 | await (await deployer.sendTransaction(populatedTransaction)).wait(); 82 | } else { 83 | await (await polgonZKEVMDeployerContract.deployDeterministicAndCall(amount, salt, deployTransaction, dataCall)).wait(); 84 | } 85 | } else { 86 | // Deploy using create2 87 | if (hardcodedGasLimit) { 88 | const populatedTransaction = await polgonZKEVMDeployerContract.populateTransaction.deployDeterministic( 89 | amount, 90 | salt, 91 | deployTransaction, 92 | ); 93 | populatedTransaction.gasLimit = ethers.BigNumber.from(hardcodedGasLimit); 94 | await (await deployer.sendTransaction(populatedTransaction)).wait(); 95 | } else { 96 | await (await polgonZKEVMDeployerContract.deployDeterministic(amount, salt, deployTransaction)).wait(); 97 | } 98 | } 99 | return [precalculatedAddressDeployed, true]; 100 | } 101 | 102 | module.exports = { 103 | deployPolygonZkEVMDeployer, 104 | create2Deployment, 105 | }; 106 | -------------------------------------------------------------------------------- /deployment/testnet/prepareTestnet.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-await-in-loop, no-use-before-define, no-lonely-if, no-restricted-syntax */ 2 | /* eslint-disable no-console, no-inner-declarations, no-undef, import/no-unresolved */ 3 | const { ethers } = require('hardhat'); 4 | const path = require('path'); 5 | const fs = require('fs'); 6 | require('dotenv').config({ path: path.resolve(__dirname, '../../.env') }); 7 | 8 | const pathDeployParameters = path.join(__dirname, '../deploy_parameters.json'); 9 | const deployParameters = require('../deploy_parameters.json'); 10 | 11 | async function main() { 12 | // Load provider 13 | let currentProvider = ethers.provider; 14 | if (deployParameters.multiplierGas || deployParameters.maxFeePerGas) { 15 | if (process.env.HARDHAT_NETWORK !== 'hardhat') { 16 | currentProvider = new ethers.providers.JsonRpcProvider(`https://${process.env.HARDHAT_NETWORK}.infura.io/v3/${process.env.INFURA_PROJECT_ID}`); 17 | if (deployParameters.maxPriorityFeePerGas && deployParameters.maxFeePerGas) { 18 | console.log(`Hardcoded gas used: MaxPriority${deployParameters.maxPriorityFeePerGas} gwei, MaxFee${deployParameters.maxFeePerGas} gwei`); 19 | const FEE_DATA = { 20 | maxFeePerGas: ethers.utils.parseUnits(deployParameters.maxFeePerGas, 'gwei'), 21 | maxPriorityFeePerGas: ethers.utils.parseUnits(deployParameters.maxPriorityFeePerGas, 'gwei'), 22 | }; 23 | currentProvider.getFeeData = async () => FEE_DATA; 24 | } else { 25 | console.log('Multiplier gas used: ', deployParameters.multiplierGas); 26 | async function overrideFeeData() { 27 | const feedata = await ethers.provider.getFeeData(); 28 | return { 29 | maxFeePerGas: feedata.maxFeePerGas.mul(deployParameters.multiplierGas), 30 | maxPriorityFeePerGas: feedata.maxPriorityFeePerGas.mul(deployParameters.multiplierGas), 31 | }; 32 | } 33 | currentProvider.getFeeData = overrideFeeData; 34 | } 35 | } 36 | } 37 | 38 | // Load deployer 39 | let deployer; 40 | if (deployParameters.deployerPvtKey) { 41 | deployer = new ethers.Wallet(deployParameters.deployerPvtKey, currentProvider); 42 | console.log('Using pvtKey deployer with address: ', deployer.address); 43 | } else if (process.env.MNEMONIC) { 44 | deployer = ethers.Wallet.fromMnemonic(process.env.MNEMONIC, 'm/44\'/60\'/0\'/0/0').connect(currentProvider); 45 | console.log('Using MNEMONIC deployer with address: ', deployer.address); 46 | } else { 47 | [deployer] = (await ethers.getSigners()); 48 | } 49 | 50 | // Check trusted address from deploy parameters 51 | const mandatoryDeploymentParameters = [ 52 | 'trustedAggregator', 53 | 'trustedSequencer', 54 | ]; 55 | 56 | for (const parameterName of mandatoryDeploymentParameters) { 57 | if (deployParameters[parameterName] === undefined || deployParameters[parameterName] === '') { 58 | throw new Error(`Missing parameter: ${parameterName}`); 59 | } 60 | } 61 | 62 | const { 63 | trustedAggregator, 64 | trustedSequencer, 65 | } = deployParameters; 66 | 67 | /* 68 | *Deployment MATIC 69 | */ 70 | const maticTokenName = 'Matic Token'; 71 | const maticTokenSymbol = 'MATIC'; 72 | const maticTokenInitialBalance = ethers.utils.parseEther('20000000'); 73 | 74 | const maticTokenFactory = await ethers.getContractFactory('ERC20PermitMock', deployer); 75 | const maticTokenContract = await maticTokenFactory.deploy( 76 | maticTokenName, 77 | maticTokenSymbol, 78 | deployer.address, 79 | maticTokenInitialBalance, 80 | ); 81 | await maticTokenContract.deployed(); 82 | 83 | console.log('#######################\n'); 84 | console.log('Matic deployed to:', maticTokenContract.address); 85 | 86 | // fund sequencer account with tokens and ether if it have less than 0.1 ether. 87 | const balanceEther = await ethers.provider.getBalance(trustedSequencer); 88 | const minEtherBalance = ethers.utils.parseEther('0.1'); 89 | if (balanceEther < minEtherBalance) { 90 | const params = { 91 | to: trustedSequencer, 92 | value: minEtherBalance, 93 | }; 94 | await deployer.sendTransaction(params); 95 | } 96 | const tokensBalance = ethers.utils.parseEther('100000'); 97 | await (await maticTokenContract.transfer(trustedSequencer, tokensBalance)).wait(); 98 | 99 | // fund aggregator account with ether if it have less than 0.1 ether. 100 | const balanceEtherAggr = await ethers.provider.getBalance(trustedAggregator); 101 | if (balanceEtherAggr < minEtherBalance) { 102 | const params = { 103 | to: trustedAggregator, 104 | value: minEtherBalance, 105 | }; 106 | await deployer.sendTransaction(params); 107 | } 108 | 109 | deployParameters.maticTokenAddress = maticTokenContract.address; 110 | fs.writeFileSync(pathDeployParameters, JSON.stringify(deployParameters, null, 1)); 111 | } 112 | 113 | main().catch((e) => { 114 | console.error(e); 115 | process.exit(1); 116 | }); 117 | -------------------------------------------------------------------------------- /deployment/verifyContracts.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-dynamic-require, no-await-in-loop, no-restricted-syntax, guard-for-in */ 2 | require('dotenv').config(); 3 | const path = require('path'); 4 | const hre = require('hardhat'); 5 | const { expect } = require('chai'); 6 | const { ethers } = require('hardhat'); 7 | 8 | const pathDeployOutputParameters = path.join(__dirname, './deploy_output.json'); 9 | const pathDeployParameters = path.join(__dirname, './deploy_parameters.json'); 10 | const deployOutputParameters = require(pathDeployOutputParameters); 11 | const deployParameters = require(pathDeployParameters); 12 | 13 | async function main() { 14 | // load deployer account 15 | if (typeof process.env.ETHERSCAN_API_KEY === 'undefined') { 16 | throw new Error('Etherscan API KEY has not been defined'); 17 | } 18 | 19 | // verify maticToken 20 | const maticTokenName = 'Matic Token'; 21 | const maticTokenSymbol = 'MATIC'; 22 | const maticTokenInitialBalance = ethers.utils.parseEther('20000000'); 23 | try { 24 | // verify governance 25 | await hre.run( 26 | 'verify:verify', 27 | { 28 | address: deployOutputParameters.maticTokenAddress, 29 | constructorArguments: [ 30 | maticTokenName, 31 | maticTokenSymbol, 32 | deployOutputParameters.deployerAddress, 33 | maticTokenInitialBalance, 34 | ], 35 | }, 36 | ); 37 | } catch (error) { 38 | // expect(error.message.toLowerCase().includes('already verified')).to.be.equal(true); 39 | } 40 | 41 | // verify verifier 42 | try { 43 | await hre.run( 44 | 'verify:verify', 45 | { 46 | address: deployOutputParameters.verifierAddress, 47 | }, 48 | ); 49 | } catch (error) { 50 | expect(error.message.toLowerCase().includes('already verified')).to.be.equal(true); 51 | } 52 | 53 | const { minDelayTimelock } = deployParameters; 54 | const { timelockAddress } = deployParameters; 55 | try { 56 | await hre.run( 57 | 'verify:verify', 58 | { 59 | address: deployOutputParameters.timelockContractAddress, 60 | constructorArguments: [ 61 | minDelayTimelock, 62 | [timelockAddress], 63 | [timelockAddress], 64 | timelockAddress, 65 | deployOutputParameters.polygonZkEVMAddress, 66 | ], 67 | }, 68 | ); 69 | } catch (error) { 70 | expect(error.message.toLowerCase().includes('already verified')).to.be.equal(true); 71 | } 72 | 73 | // verify proxy admin 74 | try { 75 | await hre.run( 76 | 'verify:verify', 77 | { 78 | address: deployOutputParameters.proxyAdminAddress, 79 | }, 80 | ); 81 | } catch (error) { 82 | expect(error.message.toLowerCase().includes('already verified')).to.be.equal(true); 83 | } 84 | 85 | // verify zkEVM address 86 | try { 87 | await hre.run( 88 | 'verify:verify', 89 | { 90 | address: deployOutputParameters.polygonZkEVMAddress, 91 | constructorArguments: [ 92 | deployOutputParameters.polygonZkEVMGlobalExitRootAddress, 93 | deployOutputParameters.maticTokenAddress, 94 | deployOutputParameters.verifierAddress, 95 | deployOutputParameters.polygonZkEVMBridgeAddress, 96 | deployOutputParameters.chainID, 97 | deployOutputParameters.forkID, 98 | ], 99 | }, 100 | ); 101 | } catch (error) { 102 | expect(error.message.toLowerCase().includes('proxyadmin')).to.be.equal(true); 103 | } 104 | 105 | // verify global exit root address 106 | try { 107 | await hre.run( 108 | 'verify:verify', 109 | { 110 | address: deployOutputParameters.polygonZkEVMGlobalExitRootAddress, 111 | constructorArguments: [ 112 | deployOutputParameters.polygonZkEVMAddress, 113 | deployOutputParameters.polygonZkEVMBridgeAddress, 114 | ], 115 | }, 116 | ); 117 | } catch (error) { 118 | expect(error.message.toLowerCase().includes('proxyadmin')).to.be.equal(true); 119 | } 120 | 121 | try { 122 | await hre.run( 123 | 'verify:verify', 124 | { 125 | address: deployOutputParameters.polygonZkEVMBridgeAddress, 126 | }, 127 | ); 128 | } catch (error) { 129 | expect(error.message.toLowerCase().includes('proxyadmin')).to.be.equal(true); 130 | } 131 | } 132 | 133 | main() 134 | .then(() => process.exit(0)) 135 | .catch((error) => { 136 | console.error(error); 137 | process.exit(1); 138 | }); 139 | -------------------------------------------------------------------------------- /deployment/verifyzkEVMDeployer.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-dynamic-require, no-await-in-loop, no-restricted-syntax, guard-for-in */ 2 | require('dotenv').config(); 3 | const path = require('path'); 4 | const hre = require('hardhat'); 5 | const { expect } = require('chai'); 6 | 7 | const pathDeployParameters = path.join(__dirname, './deploy_parameters.json'); 8 | const deployParameters = require(pathDeployParameters); 9 | 10 | async function main() { 11 | // load deployer account 12 | if (typeof process.env.ETHERSCAN_API_KEY === 'undefined') { 13 | throw new Error('Etherscan API KEY has not been defined'); 14 | } 15 | 16 | // verify zkEVM deployer 17 | try { 18 | await hre.run( 19 | 'verify:verify', 20 | { 21 | address: deployParameters.zkEVMDeployerAddress, 22 | constructorArguments: [ 23 | deployParameters.initialZkEVMDeployerOwner, 24 | ], 25 | }, 26 | ); 27 | } catch (error) { 28 | expect(error.message.toLowerCase().includes('already verified')).to.be.equal(true); 29 | } 30 | } 31 | 32 | main() 33 | .then(() => process.exit(0)) 34 | .catch((error) => { 35 | console.error(error); 36 | process.exit(1); 37 | }); 38 | -------------------------------------------------------------------------------- /docker/Dockerfile.geth: -------------------------------------------------------------------------------- 1 | FROM ethereum/client-go 2 | 3 | EXPOSE 8545 4 | 5 | COPY docker/gethData / 6 | 7 | ENTRYPOINT ["geth"] 8 | CMD ["--rpc.allow-unprotected-txs", "--http", "--http.addr", "0.0.0.0","--http.corsdomain", "*", "--http.vhosts" ,"*", "--ws", "--ws.origins", "*", "--ws.addr", "0.0.0.0", "--dev", "--datadir", "/geth_data"] -------------------------------------------------------------------------------- /docker/README.md: -------------------------------------------------------------------------------- 1 | # Docker deployment 2 | 3 | By default the following mnemonic will be used to deploy the smart contracts `MNEMONIC="test test test test test test test test test test test junk"`. 4 | Also the first 20 accounts of this mnemonic will be funded with ether. 5 | The first account of the mnemonic will be the deployer of the smart contracts and therefore the holder of all the MATIC test tokens, which are necessary to pay the `sendBatch` transactions. 6 | You can change the deployment `mnemonic` creating a `.env` file in the project root with the following variable: 7 | `MNEMONIC=` 8 | 9 | ## Requirements 10 | 11 | - node version: 14.x 12 | - npm version: 7.x 13 | - docker 14 | - docker-compose 15 | 16 | ## Build dockers 17 | 18 | In project root execute: 19 | 20 | ``` 21 | npm i 22 | npm run docker:contracts 23 | ``` 24 | 25 | A new docker `geth-zkevm-contracts:latest` will be created 26 | This docker will contain a geth node with the deployed contracts 27 | The deployment output can be found in: `docker/deploymentOutput/deploy_output.json` 28 | To run the docker you can use: `docker run -p 8545:8545 geth-zkevm-contracts:latest` 29 | -------------------------------------------------------------------------------- /docker/docker-compose.geth.yml: -------------------------------------------------------------------------------- 1 | version: "3.3" 2 | services: 3 | geth: 4 | image: ethereum/client-go 5 | environment: 6 | - DEV_PERIOD 7 | ports: 8 | - "8545:8545" 9 | volumes: 10 | - ./gethData/geth_data:/geth_data 11 | entrypoint: 12 | - geth 13 | - --rpc.allow-unprotected-txs 14 | - --http 15 | - --http.addr 16 | - "0.0.0.0" 17 | - --dev 18 | - --dev.period 19 | - $DEV_PERIOD 20 | - --datadir 21 | - /geth_data 22 | -------------------------------------------------------------------------------- /docker/scripts/deploy-docker.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | sudo rm -rf docker/gethData/geth_data 3 | rm deployment/deploy_ongoing.json 4 | DEV_PERIOD=1 docker-compose -f docker/docker-compose.geth.yml up -d geth 5 | sleep 5 6 | node docker/scripts/fund-accounts.js 7 | cp docker/scripts/deploy_parameters_docker.json deployment/deploy_parameters.json 8 | cp docker/scripts/genesis_docker.json deployment/genesis.json 9 | npx hardhat run deployment/testnet/prepareTestnet.js --network localhost 10 | npx hardhat run deployment/2_deployPolygonZKEVMDeployer.js --network localhost 11 | npx hardhat run deployment/3_deployContracts.js --network localhost 12 | mkdir docker/deploymentOutput 13 | mv deployment/deploy_output.json docker/deploymentOutput 14 | docker-compose -f docker/docker-compose.geth.yml down 15 | sudo docker build -t hermeznetwork/geth-zkevm-contracts -f docker/Dockerfile.geth . 16 | # Let it readable for the multiplatform build coming later! 17 | sudo chmod -R go+rxw docker/gethData 18 | -------------------------------------------------------------------------------- /docker/scripts/deploy-dockerv2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | sudo rm -rf docker/gethData/geth_data 3 | DEV_PERIOD=1 docker compose -f docker/docker-compose.geth.yml up -d geth 4 | sleep 5 5 | node docker/scripts/fund-accounts.js 6 | cp docker/scripts/deploy_parameters_docker.json deployment/deploy_parameters.json 7 | cp docker/scripts/genesis_docker.json deployment/genesis.json 8 | npx hardhat run deployment/testnet/prepareTestnet.js --network localhost 9 | npx hardhat run deployment/2_deployPolygonZKEVMDeployer.js --network localhost 10 | npx hardhat run deployment/3_deployContracts.js --network localhost 11 | mkdir docker/deploymentOutput 12 | mv deployment/deploy_output.json docker/deploymentOutput 13 | docker compose -f docker/docker-compose.geth.yml down 14 | sudo docker build -t hermeznetwork/geth-zkevm-contracts -f docker/Dockerfile.geth . 15 | # Let it readable for the multiplatform build coming later! 16 | sudo chmod -R go+rxw docker/gethData -------------------------------------------------------------------------------- /docker/scripts/deploy_parameters_docker.json: -------------------------------------------------------------------------------- 1 | { 2 | "realVerifier": false, 3 | "trustedSequencerURL": "http://zkevm-json-rpc:8123", 4 | "networkName": "zkevm", 5 | "version":"0.0.1", 6 | "trustedSequencer":"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", 7 | "chainID": 1001, 8 | "trustedAggregator":"0x70997970C51812dc3A010C7d01b50e0d17dc79C8", 9 | "trustedAggregatorTimeout": 604799, 10 | "pendingStateTimeout": 604799, 11 | "forkID": 1, 12 | "admin":"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", 13 | "zkEVMOwner": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", 14 | "timelockAddress": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", 15 | "minDelayTimelock": 10, 16 | "salt": "0x0000000000000000000000000000000000000000000000000000000000000000", 17 | "zkEVMDeployerAddress":"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", 18 | "initialZkEVMDeployerOwner" :"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", 19 | "maticTokenAddress":"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266" 20 | } -------------------------------------------------------------------------------- /docker/scripts/fund-accounts.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-await-in-loop */ 2 | 3 | const ethers = require('ethers'); 4 | require('dotenv').config(); 5 | 6 | const DEFAULT_MNEMONIC = 'test test test test test test test test test test test junk'; 7 | const DEFAULT_NUM_ACCOUNTS = 20; 8 | 9 | async function main() { 10 | const MNEMONIC = process.env.MNEMONIC || DEFAULT_MNEMONIC; 11 | const currentProvider = new ethers.providers.JsonRpcProvider('http://localhost:8545'); 12 | const signerNode = await currentProvider.getSigner(); 13 | const numAccountsToFund = process.env.NUM_ACCOUNTS || DEFAULT_NUM_ACCOUNTS; 14 | 15 | for (let i = 0; i < numAccountsToFund; i++) { 16 | const pathWallet = `m/44'/60'/0'/0/${i}`; 17 | const accountWallet = ethers.Wallet.fromMnemonic(MNEMONIC, pathWallet); 18 | const params = [{ 19 | from: await signerNode.getAddress(), 20 | to: accountWallet.address, 21 | value: '0x3635C9ADC5DEA00000', 22 | }]; 23 | const tx = await currentProvider.send('eth_sendTransaction', params); 24 | if (i === numAccountsToFund - 1) { 25 | await currentProvider.waitForTransaction(tx); 26 | } 27 | } 28 | } 29 | 30 | main() 31 | .then(() => process.exit(0)) 32 | .catch((error) => { 33 | console.error(error); 34 | process.exit(1); 35 | }); 36 | -------------------------------------------------------------------------------- /docs/PolygonZkEVMGlobalExitRoot.md: -------------------------------------------------------------------------------- 1 | Contract responsible for managing the exit roots across multiple networks 2 | 3 | 4 | ## Functions 5 | ### constructor 6 | ```solidity 7 | function constructor( 8 | address _rollupAddress, 9 | address _bridgeAddress 10 | ) public 11 | ``` 12 | 13 | 14 | #### Parameters: 15 | | Name | Type | Description | 16 | | :--- | :--- | :------------------------------------------------------------------- | 17 | |`_rollupAddress` | address | Rollup contract address 18 | |`_bridgeAddress` | address | PolygonZkEVMBridge contract address 19 | 20 | ### updateExitRoot 21 | ```solidity 22 | function updateExitRoot( 23 | bytes32 newRoot 24 | ) external 25 | ``` 26 | Update the exit root of one of the networks and the global exit root 27 | 28 | 29 | #### Parameters: 30 | | Name | Type | Description | 31 | | :--- | :--- | :------------------------------------------------------------------- | 32 | |`newRoot` | bytes32 | new exit tree root 33 | 34 | ### getLastGlobalExitRoot 35 | ```solidity 36 | function getLastGlobalExitRoot( 37 | ) public returns (bytes32) 38 | ``` 39 | Return last global exit root 40 | 41 | 42 | 43 | ## Events 44 | ### UpdateGlobalExitRoot 45 | ```solidity 46 | event UpdateGlobalExitRoot( 47 | ) 48 | ``` 49 | 50 | Emitted when the global exit root is updated 51 | 52 | -------------------------------------------------------------------------------- /docs/PolygonZkEVMGlobalExitRootL2.md: -------------------------------------------------------------------------------- 1 | Contract responsible for managing the exit roots for the L2 and global exit roots 2 | The special zkRom variables will be accessed and updated directly by the zkRom 3 | 4 | 5 | ## Functions 6 | ### constructor 7 | ```solidity 8 | function constructor( 9 | address _bridgeAddress 10 | ) public 11 | ``` 12 | 13 | 14 | #### Parameters: 15 | | Name | Type | Description | 16 | | :--- | :--- | :------------------------------------------------------------------- | 17 | |`_bridgeAddress` | address | PolygonZkEVMBridge contract address 18 | 19 | ### updateExitRoot 20 | ```solidity 21 | function updateExitRoot( 22 | bytes32 newRoot 23 | ) external 24 | ``` 25 | Update the exit root of one of the networks and the global exit root 26 | 27 | 28 | #### Parameters: 29 | | Name | Type | Description | 30 | | :--- | :--- | :------------------------------------------------------------------- | 31 | |`newRoot` | bytes32 | new exit tree root 32 | 33 | -------------------------------------------------------------------------------- /docs/PolygonZkEVMTimelock.md: -------------------------------------------------------------------------------- 1 | 2 | Contract module which acts as a timelocked controller. 3 | This gives time for users of the controlled contract to exit before a potentially dangerous maintenance operation is applied. 4 | If emergency mode of the zkevm contract system is active, this timelock have no delay. 5 | 6 | ## Functions 7 | ### constructor 8 | ```solidity 9 | function constructor( 10 | uint256 minDelay, 11 | address[] proposers, 12 | address[] executors, 13 | address admin, 14 | contract PolygonZkEVM _polygonZkEVM 15 | ) public 16 | ``` 17 | Constructor of timelock 18 | 19 | 20 | #### Parameters: 21 | | Name | Type | Description | 22 | | :--- | :--- | :------------------------------------------------------------------- | 23 | |`minDelay` | uint256 | initial minimum delay for operations 24 | |`proposers` | address[] | accounts to be granted proposer and canceller roles 25 | |`executors` | address[] | accounts to be granted executor role 26 | |`admin` | address | optional account to be granted admin role; disable with zero address 27 | |`_polygonZkEVM` | contract PolygonZkEVM | polygonZkEVM address 28 | 29 | 30 | ### getMinDelay 31 | ```solidity 32 | function getMinDelay( 33 | ) public returns (uint256 duration) 34 | ``` 35 | 36 | Returns the minimum delay for an operation to become valid. 37 | 38 | This value can be changed by executing an operation that calls `updateDelay`. 39 | If Polygon ZK-EVM is on emergency state the minDelay will be 0 instead. 40 | 41 | 42 | -------------------------------------------------------------------------------- /docs/deployment/PolygonZkEVMDeployer.md: -------------------------------------------------------------------------------- 1 | Contract responsible for deploying deterministic address contracts related with the PolygonZkEVM 2 | 3 | 4 | ## Functions 5 | ### constructor 6 | ```solidity 7 | function constructor( 8 | address _owner 9 | ) public 10 | ``` 11 | 12 | 13 | #### Parameters: 14 | | Name | Type | Description | 15 | | :--- | :--- | :------------------------------------------------------------------- | 16 | |`_owner` | address | Owner 17 | 18 | ### deployDeterministic 19 | ```solidity 20 | function deployDeterministic( 21 | uint256 amount, 22 | bytes32 salt, 23 | bytes initBytecode 24 | ) public 25 | ``` 26 | Allows to deploy a contract using create2 27 | 28 | 29 | #### Parameters: 30 | | Name | Type | Description | 31 | | :--- | :--- | :------------------------------------------------------------------- | 32 | |`amount` | uint256 | Amount used in create2 33 | |`salt` | bytes32 | Salt used in create2 34 | |`initBytecode` | bytes | Init bytecode that will be use in create2 35 | 36 | ### deployDeterministicAndCall 37 | ```solidity 38 | function deployDeterministicAndCall( 39 | uint256 amount, 40 | bytes32 salt, 41 | bytes initBytecode, 42 | bytes dataCall 43 | ) public 44 | ``` 45 | Allows to deploy a contract using create2 and call it afterwards 46 | 47 | 48 | #### Parameters: 49 | | Name | Type | Description | 50 | | :--- | :--- | :------------------------------------------------------------------- | 51 | |`amount` | uint256 | Amount used in create2 52 | |`salt` | bytes32 | Salt used in create2 53 | |`initBytecode` | bytes | Init bytecode that will be use in create2 54 | |`dataCall` | bytes | Data used in the call after deploying the smart contract 55 | 56 | ### functionCall 57 | ```solidity 58 | function functionCall( 59 | address targetAddress, 60 | bytes dataCall, 61 | uint256 amount 62 | ) public 63 | ``` 64 | 65 | 66 | #### Parameters: 67 | | Name | Type | Description | 68 | | :--- | :--- | :------------------------------------------------------------------- | 69 | |`targetAddress` | address | Amount of contract deploy 70 | |`dataCall` | bytes | Data used to call the target smart contract 71 | |`amount` | uint256 | Data used to call the target smart contract 72 | 73 | ### predictDeterministicAddress 74 | ```solidity 75 | function predictDeterministicAddress( 76 | bytes32 salt, 77 | bytes32 bytecodeHash 78 | ) public returns (address) 79 | ``` 80 | 81 | 82 | #### Parameters: 83 | | Name | Type | Description | 84 | | :--- | :--- | :------------------------------------------------------------------- | 85 | |`salt` | bytes32 | Salt used in create2 86 | |`bytecodeHash` | bytes32 | Init bytecode hashed, it contains the constructor parameters 87 | 88 | ## Events 89 | ### NewDeterministicDeployment 90 | ```solidity 91 | event NewDeterministicDeployment( 92 | ) 93 | ``` 94 | 95 | Emitted when a contract is deployed 96 | 97 | ### FunctionCall 98 | ```solidity 99 | event FunctionCall( 100 | ) 101 | ``` 102 | 103 | Emitted when a contract is called 104 | 105 | -------------------------------------------------------------------------------- /docs/lib/DepositContract.md: -------------------------------------------------------------------------------- 1 | This contract will be used as a helper for all the sparse merkle tree related functions 2 | Based on the implementation of the deposit eth2.0 contract https://github.com/ethereum/consensus-specs/blob/dev/solidity_deposit_contract/deposit_contract.sol 3 | 4 | 5 | ## Functions 6 | ### getDepositRoot 7 | ```solidity 8 | function getDepositRoot( 9 | ) public returns (bytes32) 10 | ``` 11 | Computes and returns the merkle root 12 | 13 | 14 | 15 | ### _deposit 16 | ```solidity 17 | function _deposit( 18 | bytes32 leafHash 19 | ) internal 20 | ``` 21 | Add a new leaf to the merkle tree 22 | 23 | 24 | #### Parameters: 25 | | Name | Type | Description | 26 | | :--- | :--- | :------------------------------------------------------------------- | 27 | |`leafHash` | bytes32 | Leaf hash 28 | 29 | ### verifyMerkleProof 30 | ```solidity 31 | function verifyMerkleProof( 32 | bytes32 leafHash, 33 | bytes32[32] smtProof, 34 | uint32 index, 35 | bytes32 root 36 | ) public returns (bool) 37 | ``` 38 | Verify merkle proof 39 | 40 | 41 | #### Parameters: 42 | | Name | Type | Description | 43 | | :--- | :--- | :------------------------------------------------------------------- | 44 | |`leafHash` | bytes32 | Leaf hash 45 | |`smtProof` | bytes32[32] | Smt proof 46 | |`index` | uint32 | Index of the leaf 47 | |`root` | bytes32 | Merkle root 48 | 49 | ### getLeafValue 50 | ```solidity 51 | function getLeafValue( 52 | uint8 leafType, 53 | uint32 originNetwork, 54 | address originAddress, 55 | uint32 destinationNetwork, 56 | address destinationAddress, 57 | uint256 amount, 58 | bytes32 metadataHash 59 | ) public returns (bytes32) 60 | ``` 61 | Given the leaf data returns the leaf value 62 | 63 | 64 | #### Parameters: 65 | | Name | Type | Description | 66 | | :--- | :--- | :------------------------------------------------------------------- | 67 | |`leafType` | uint8 | Leaf type --> [0] transfer Ether / ERC20 tokens, [1] message 68 | |`originNetwork` | uint32 | Origin Network 69 | |`originAddress` | address | [0] Origin token address, 0 address is reserved for ether, [1] msg.sender of the message 70 | |`destinationNetwork` | uint32 | Destination network 71 | |`destinationAddress` | address | Destination address 72 | |`amount` | uint256 | [0] Amount of tokens/ether, [1] Amount of ether 73 | |`metadataHash` | bytes32 | Hash of the metadata 74 | 75 | -------------------------------------------------------------------------------- /docs/lib/EmergencyManager.md: -------------------------------------------------------------------------------- 1 | 2 | Contract helper responsible to manage the emergency state 3 | 4 | ## Functions 5 | ### _activateEmergencyState 6 | ```solidity 7 | function _activateEmergencyState( 8 | ) internal 9 | ``` 10 | Activate emergency state 11 | 12 | 13 | 14 | ### _deactivateEmergencyState 15 | ```solidity 16 | function _deactivateEmergencyState( 17 | ) internal 18 | ``` 19 | Deactivate emergency state 20 | 21 | 22 | 23 | ## Events 24 | ### EmergencyStateActivated 25 | ```solidity 26 | event EmergencyStateActivated( 27 | ) 28 | ``` 29 | 30 | Emitted when emergency state is activated 31 | 32 | ### EmergencyStateDeactivated 33 | ```solidity 34 | event EmergencyStateDeactivated( 35 | ) 36 | ``` 37 | 38 | Emitted when emergency state is deactivated 39 | 40 | -------------------------------------------------------------------------------- /docs/lib/GlobalExitRootLib.md: -------------------------------------------------------------------------------- 1 | 2 | A library that provides the necessary calculations to calculate the global exit root 3 | 4 | ## Functions 5 | ### calculateGlobalExitRoot 6 | ```solidity 7 | function calculateGlobalExitRoot( 8 | ) internal returns (bytes32) 9 | ``` 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /docs/lib/TokenWrapped.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ## Functions 5 | ### constructor 6 | ```solidity 7 | function constructor( 8 | ) public 9 | ``` 10 | 11 | 12 | 13 | 14 | ### mint 15 | ```solidity 16 | function mint( 17 | ) external 18 | ``` 19 | 20 | 21 | 22 | 23 | ### burn 24 | ```solidity 25 | function burn( 26 | ) external 27 | ``` 28 | 29 | 30 | 31 | 32 | ### decimals 33 | ```solidity 34 | function decimals( 35 | ) public returns (uint8) 36 | ``` 37 | 38 | 39 | 40 | 41 | ### permit 42 | ```solidity 43 | function permit( 44 | ) external 45 | ``` 46 | 47 | 48 | 49 | 50 | ### DOMAIN_SEPARATOR 51 | ```solidity 52 | function DOMAIN_SEPARATOR( 53 | ) public returns (bytes32) 54 | ``` 55 | 56 | Return the DOMAIN_SEPARATOR. 57 | 58 | 59 | -------------------------------------------------------------------------------- /docs/mainnetUpgraded/PolygonZkEVMUpgraded.md: -------------------------------------------------------------------------------- 1 | Contract responsible for managing the state and the updates of the L2 network 2 | This contract will NOT BE USED IN PRODUCTION, will be used only in testnet enviroment 3 | 4 | 5 | ## Functions 6 | ### constructor 7 | ```solidity 8 | function constructor( 9 | contract IPolygonZkEVMGlobalExitRoot _globalExitRootManager, 10 | contract IERC20Upgradeable _matic, 11 | contract IVerifierRollup _rollupVerifier, 12 | contract IPolygonZkEVMBridge _bridgeAddress, 13 | uint64 _chainID 14 | ) public 15 | ``` 16 | 17 | 18 | #### Parameters: 19 | | Name | Type | Description | 20 | | :--- | :--- | :------------------------------------------------------------------- | 21 | |`_globalExitRootManager` | contract IPolygonZkEVMGlobalExitRoot | Global exit root manager address 22 | |`_matic` | contract IERC20Upgradeable | MATIC token address 23 | |`_rollupVerifier` | contract IVerifierRollup | Rollup verifier address 24 | |`_bridgeAddress` | contract IPolygonZkEVMBridge | Bridge address 25 | |`_chainID` | uint64 | L2 chainID 26 | 27 | ### updateVersion 28 | ```solidity 29 | function updateVersion( 30 | string _versionString 31 | ) public 32 | ``` 33 | Update version of the zkEVM 34 | 35 | 36 | #### Parameters: 37 | | Name | Type | Description | 38 | | :--- | :--- | :------------------------------------------------------------------- | 39 | |`_versionString` | string | New version string 40 | 41 | ### _proveDistinctPendingState 42 | ```solidity 43 | function _proveDistinctPendingState( 44 | uint64 initPendingStateNum, 45 | uint64 finalPendingStateNum, 46 | uint64 initNumBatch, 47 | uint64 finalNewBatch, 48 | bytes32 newLocalExitRoot, 49 | bytes32 newStateRoot, 50 | bytes32[24] proof 51 | ) internal 52 | ``` 53 | Internal function that proves a different state root given the same batches to verify 54 | 55 | 56 | #### Parameters: 57 | | Name | Type | Description | 58 | | :--- | :--- | :------------------------------------------------------------------- | 59 | |`initPendingStateNum` | uint64 | Init pending state, 0 if consolidated state is used 60 | |`finalPendingStateNum` | uint64 | Final pending state, that will be used to compare with the newStateRoot 61 | |`initNumBatch` | uint64 | Batch which the aggregator starts the verification 62 | |`finalNewBatch` | uint64 | Last batch aggregator intends to verify 63 | |`newLocalExitRoot` | bytes32 | New local exit root once the batch is processed 64 | |`newStateRoot` | bytes32 | New State root once the batch is processed 65 | |`proof` | bytes32[24] | fflonk proof 66 | 67 | ### _verifyAndRewardBatches 68 | ```solidity 69 | function _verifyAndRewardBatches( 70 | uint64 pendingStateNum, 71 | uint64 initNumBatch, 72 | uint64 finalNewBatch, 73 | bytes32 newLocalExitRoot, 74 | bytes32 newStateRoot, 75 | bytes32[24] proof 76 | ) internal 77 | ``` 78 | Verify and reward batches internal function 79 | 80 | 81 | #### Parameters: 82 | | Name | Type | Description | 83 | | :--- | :--- | :------------------------------------------------------------------- | 84 | |`pendingStateNum` | uint64 | Init pending state, 0 if consolidated state is used 85 | |`initNumBatch` | uint64 | Batch which the aggregator starts the verification 86 | |`finalNewBatch` | uint64 | Last batch aggregator intends to verify 87 | |`newLocalExitRoot` | bytes32 | New local exit root once the batch is processed 88 | |`newStateRoot` | bytes32 | New State root once the batch is processed 89 | |`proof` | bytes32[24] | fflonk proof 90 | 91 | -------------------------------------------------------------------------------- /docs/templates/contract.hbs: -------------------------------------------------------------------------------- 1 | {{{natspec.userdoc}}} 2 | {{{natspec.devdoc}}} 3 | 4 | {{#if ownFunctions}} 5 | ## Functions 6 | {{/if}} 7 | {{#ownFunctions}} 8 | ### {{name}} 9 | ```solidity 10 | function {{name}}( 11 | {{#natspec.params}} 12 | {{#lookup ../args.types @index}}{{/lookup}} {{param}}{{#if @last}}{{else}},{{/if}} 13 | {{/natspec.params}} 14 | ) {{visibility}}{{#if outputs}} returns ({{outputs}}){{/if}} 15 | ``` 16 | {{#if natspec.userdoc}}{{natspec.userdoc}}{{/if}} 17 | {{#if natspec.devdoc}}{{natspec.devdoc}}{{/if}} 18 | {{#if natspec.params}} 19 | #### Parameters: 20 | | Name | Type | Description | 21 | | :--- | :--- | :------------------------------------------------------------------- | 22 | {{#natspec.params}} 23 | |`{{param}}` | {{#lookup ../args.types @index}}{{/lookup}} | {{ description }}{{/natspec.params}}{{/if}} 24 | {{#if natspec.returns}} 25 | #### Return Values: 26 | | Name | Type | Description | 27 | | :----------------------------- | :------------ | :--------------------------------------------------------------------------- | 28 | {{#natspec.returns}} 29 | |`{{param}}`| {{#lookup ../args.types @index}}{{/lookup}} | {{{description}}}{{/natspec.returns}}{{/if}} 30 | {{/ownFunctions}} 31 | {{#if ownEvents}} 32 | ## Events 33 | {{/if}} 34 | {{#ownEvents}} 35 | ### {{name}} 36 | ```solidity 37 | event {{name}}( 38 | {{#natspec.params}} 39 | {{#lookup ../args.types @index}}{{/lookup}} {{param}}{{#if @last}}{{else}},{{/if}} 40 | {{/natspec.params}} 41 | ) 42 | ``` 43 | {{#if natspec.userdoc}}{{natspec.userdoc}}{{/if}} 44 | {{#if natspec.devdoc}}{{natspec.devdoc}}{{/if}} 45 | {{#if natspec.params}} 46 | #### Parameters: 47 | | Name | Type | Description | 48 | | :----------------------------- | :------------ | :--------------------------------------------- | 49 | {{#natspec.params}} 50 | |`{{param}}`| {{#lookup ../args.types @index}}{{/lookup}} | {{{description}}}{{/natspec.params}}{{/if}} 51 | {{/ownEvents}} -------------------------------------------------------------------------------- /docs/testnet/PolygonZkEVMTestnet.md: -------------------------------------------------------------------------------- 1 | Contract responsible for managing the state and the updates of the L2 network 2 | This contract will NOT BE USED IN PRODUCTION, will be used only in testnet enviroment 3 | 4 | 5 | ## Functions 6 | ### constructor 7 | ```solidity 8 | function constructor( 9 | contract IPolygonZkEVMGlobalExitRoot _globalExitRootManager, 10 | contract IERC20Upgradeable _matic, 11 | contract IVerifierRollup _rollupVerifier, 12 | contract IPolygonZkEVMBridge _bridgeAddress, 13 | uint64 _chainID 14 | ) public 15 | ``` 16 | 17 | 18 | #### Parameters: 19 | | Name | Type | Description | 20 | | :--- | :--- | :------------------------------------------------------------------- | 21 | |`_globalExitRootManager` | contract IPolygonZkEVMGlobalExitRoot | Global exit root manager address 22 | |`_matic` | contract IERC20Upgradeable | MATIC token address 23 | |`_rollupVerifier` | contract IVerifierRollup | Rollup verifier address 24 | |`_bridgeAddress` | contract IPolygonZkEVMBridge | Bridge address 25 | |`_chainID` | uint64 | L2 chainID 26 | 27 | ### forceBatch 28 | ```solidity 29 | function forceBatch( 30 | ) public 31 | ``` 32 | 33 | 34 | 35 | 36 | ### sequenceForceBatches 37 | ```solidity 38 | function sequenceForceBatches( 39 | ) external 40 | ``` 41 | 42 | 43 | 44 | 45 | ### getForceBatchTimeout 46 | ```solidity 47 | function getForceBatchTimeout( 48 | ) public returns (uint64) 49 | ``` 50 | 51 | 52 | 53 | 54 | ### setForceBatchTimeout 55 | ```solidity 56 | function setForceBatchTimeout( 57 | uint64 newforceBatchTimeout 58 | ) public 59 | ``` 60 | Set new forcedBatchTimeout 61 | 62 | 63 | #### Parameters: 64 | | Name | Type | Description | 65 | | :--- | :--- | :------------------------------------------------------------------- | 66 | |`newforceBatchTimeout` | uint64 | new forced batches timeout 67 | 68 | ### setForcedBatchesAllowed 69 | ```solidity 70 | function setForcedBatchesAllowed( 71 | uint256 newForcedBatchesAllowed 72 | ) public 73 | ``` 74 | Set new forced batches allowed 75 | Defined as a uint256 because it will be easy to updgrade afterwards 76 | 77 | 78 | #### Parameters: 79 | | Name | Type | Description | 80 | | :--- | :--- | :------------------------------------------------------------------- | 81 | |`newForcedBatchesAllowed` | uint256 | new forced batches allowed 82 | 83 | -------------------------------------------------------------------------------- /docs/testnet/PolygonZkEVMTestnetClearStorage.md: -------------------------------------------------------------------------------- 1 | Contract responsible for managing the state and the updates of the L2 network 2 | This contract will NOT BE USED IN PRODUCTION, will be used only in testnet enviroment 3 | 4 | 5 | ## Functions 6 | ### constructor 7 | ```solidity 8 | function constructor( 9 | contract IPolygonZkEVMGlobalExitRoot _globalExitRootManager, 10 | contract IERC20Upgradeable _matic, 11 | contract IVerifierRollup _rollupVerifier, 12 | contract IPolygonZkEVMBridge _bridgeAddress, 13 | uint64 _chainID 14 | ) public 15 | ``` 16 | 17 | 18 | #### Parameters: 19 | | Name | Type | Description | 20 | | :--- | :--- | :------------------------------------------------------------------- | 21 | |`_globalExitRootManager` | contract IPolygonZkEVMGlobalExitRoot | Global exit root manager address 22 | |`_matic` | contract IERC20Upgradeable | MATIC token address 23 | |`_rollupVerifier` | contract IVerifierRollup | Rollup verifier address 24 | |`_bridgeAddress` | contract IPolygonZkEVMBridge | Bridge address 25 | |`_chainID` | uint64 | L2 chainID 26 | 27 | ### clearStorage 28 | ```solidity 29 | function clearStorage( 30 | ) public 31 | ``` 32 | Clear previous storage 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /docs/testnet/PolygonZkEVMTestnetV2.md: -------------------------------------------------------------------------------- 1 | Contract responsible for managing the state and the updates of the L2 network 2 | This contract will NOT BE USED IN PRODUCTION, will be used only in testnet enviroment 3 | 4 | 5 | ## Functions 6 | ### constructor 7 | ```solidity 8 | function constructor( 9 | contract IPolygonZkEVMGlobalExitRoot _globalExitRootManager, 10 | contract IERC20Upgradeable _matic, 11 | contract IVerifierRollup _rollupVerifier, 12 | contract IPolygonZkEVMBridge _bridgeAddress, 13 | uint64 _chainID 14 | ) public 15 | ``` 16 | 17 | 18 | #### Parameters: 19 | | Name | Type | Description | 20 | | :--- | :--- | :------------------------------------------------------------------- | 21 | |`_globalExitRootManager` | contract IPolygonZkEVMGlobalExitRoot | Global exit root manager address 22 | |`_matic` | contract IERC20Upgradeable | MATIC token address 23 | |`_rollupVerifier` | contract IVerifierRollup | Rollup verifier address 24 | |`_bridgeAddress` | contract IPolygonZkEVMBridge | Bridge address 25 | |`_chainID` | uint64 | L2 chainID 26 | 27 | ### updateVersion 28 | ```solidity 29 | function updateVersion( 30 | string _versionString 31 | ) public 32 | ``` 33 | Update version of the zkEVM 34 | 35 | 36 | #### Parameters: 37 | | Name | Type | Description | 38 | | :--- | :--- | :------------------------------------------------------------------- | 39 | |`_versionString` | string | New version string 40 | 41 | -------------------------------------------------------------------------------- /hardhat.config.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config(); 2 | require('@nomiclabs/hardhat-waffle'); 3 | require('hardhat-gas-reporter'); 4 | require('solidity-coverage'); 5 | require('@nomiclabs/hardhat-etherscan'); 6 | require('@openzeppelin/hardhat-upgrades'); 7 | require('hardhat-dependency-compiler'); 8 | 9 | const DEFAULT_MNEMONIC = 'test test test test test test test test test test test junk'; 10 | 11 | /* 12 | * You need to export an object to set up your config 13 | * Go to https://hardhat.org/config/ to learn more 14 | */ 15 | 16 | /** 17 | * @type import('hardhat/config').HardhatUserConfig 18 | */ 19 | module.exports = { 20 | dependencyCompiler: { 21 | paths: [ 22 | '@openzeppelin/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol', 23 | '@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol', 24 | '@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol', 25 | ], // , 26 | // keep: true 27 | }, 28 | solidity: { 29 | compilers: [ 30 | { 31 | version: '0.8.20', 32 | settings: { 33 | optimizer: { 34 | enabled: true, 35 | runs: 999999, 36 | }, 37 | }, 38 | }, 39 | { 40 | version: '0.6.11', 41 | settings: { 42 | optimizer: { 43 | enabled: true, 44 | runs: 999999, 45 | }, 46 | }, 47 | }, 48 | { 49 | version: '0.5.12', 50 | settings: { 51 | optimizer: { 52 | enabled: true, 53 | runs: 999999, 54 | }, 55 | }, 56 | }, 57 | { 58 | version: '0.5.16', 59 | settings: { 60 | optimizer: { 61 | enabled: true, 62 | runs: 999999, 63 | }, 64 | }, 65 | }, 66 | ], 67 | }, 68 | networks: { 69 | mainnet: { 70 | url: process.env.MAINNET_PROVIDER ? process.env.MAINNET_PROVIDER : `https://mainnet.infura.io/v3/${process.env.INFURA_PROJECT_ID}`, 71 | accounts: { 72 | mnemonic: process.env.MNEMONIC || DEFAULT_MNEMONIC, 73 | path: "m/44'/60'/0'/0", 74 | initialIndex: 0, 75 | count: 20, 76 | }, 77 | }, 78 | ropsten: { 79 | url: process.env.ROPSTEN_PROVIDER ? process.env.ROPSTEN_PROVIDER : `https://ropsten.infura.io/v3/${process.env.INFURA_PROJECT_ID}`, 80 | accounts: { 81 | mnemonic: process.env.MNEMONIC || DEFAULT_MNEMONIC, 82 | path: "m/44'/60'/0'/0", 83 | initialIndex: 0, 84 | count: 20, 85 | }, 86 | }, 87 | goerli: { 88 | url: process.env.GOERLI_PROVIDER ? process.env.GOERLI_PROVIDER : `https://goerli.infura.io/v3/${process.env.INFURA_PROJECT_ID}`, 89 | accounts: { 90 | mnemonic: process.env.MNEMONIC || DEFAULT_MNEMONIC, 91 | path: "m/44'/60'/0'/0", 92 | initialIndex: 0, 93 | count: 20, 94 | }, 95 | }, 96 | rinkeby: { 97 | url: process.env.RINKEBY_PROVIDER ? process.env.RINKEBY_PROVIDER : `https://rinkeby.infura.io/v3/${process.env.INFURA_PROJECT_ID}`, 98 | accounts: { 99 | mnemonic: process.env.MNEMONIC || DEFAULT_MNEMONIC, 100 | path: "m/44'/60'/0'/0", 101 | initialIndex: 0, 102 | count: 20, 103 | }, 104 | }, 105 | localhost: { 106 | url: 'http://127.0.0.1:8545', 107 | accounts: { 108 | mnemonic: process.env.MNEMONIC || DEFAULT_MNEMONIC, 109 | path: "m/44'/60'/0'/0", 110 | initialIndex: 0, 111 | count: 20, 112 | }, 113 | }, 114 | hardhat: { 115 | initialDate: '0', 116 | allowUnlimitedContractSize: true, 117 | initialBaseFeePerGas: '0', 118 | accounts: { 119 | mnemonic: process.env.MNEMONIC || DEFAULT_MNEMONIC, 120 | path: "m/44'/60'/0'/0", 121 | initialIndex: 0, 122 | count: 20, 123 | }, 124 | }, 125 | polygonZKEVMTestnet: { 126 | url: 'https://rpc.public.zkevm-test.net', 127 | accounts: { 128 | mnemonic: process.env.MNEMONIC || DEFAULT_MNEMONIC, 129 | path: "m/44'/60'/0'/0", 130 | initialIndex: 0, 131 | count: 20, 132 | }, 133 | }, 134 | polygonZKEVMMainnet: { 135 | url: 'https://zkevm-rpc.com', 136 | accounts: { 137 | mnemonic: process.env.MNEMONIC || DEFAULT_MNEMONIC, 138 | path: "m/44'/60'/0'/0", 139 | initialIndex: 0, 140 | count: 20, 141 | }, 142 | }, 143 | }, 144 | gasReporter: { 145 | enabled: !!process.env.REPORT_GAS, 146 | outputFile: process.env.REPORT_GAS_FILE ? './gas_report.md' : null, 147 | noColors: !!process.env.REPORT_GAS_FILE, 148 | }, 149 | etherscan: { 150 | apiKey: { 151 | polygonZKEVMTestnet: `${process.env.ETHERSCAN_ZKEVM_API_KEY}`, 152 | polygonZKEVMMainnet: `${process.env.ETHERSCAN_ZKEVM_API_KEY}`, 153 | goerli: `${process.env.ETHERSCAN_API_KEY}`, 154 | mainnet: `${process.env.ETHERSCAN_API_KEY}`, 155 | }, 156 | customChains: [ 157 | { 158 | network: 'polygonZKEVMMainnet', 159 | chainId: 1101, 160 | urls: { 161 | apiURL: 'https://api-zkevm.polygonscan.com/api', 162 | browserURL: 'https://zkevm.polygonscan.com/', 163 | }, 164 | }, 165 | { 166 | network: 'polygonZKEVMTestnet', 167 | chainId: 1442, 168 | urls: { 169 | apiURL: 'https://api-testnet-zkevm.polygonscan.com/api', 170 | browserURL: 'https://testnet-zkevm.polygonscan.com/', 171 | }, 172 | }, 173 | ], 174 | }, 175 | }; 176 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports.PolygonZkEVMBridge = require('./compiled-contracts/PolygonZkEVMBridge.json'); 2 | module.exports.PolygonZkEVMGlobalExitRoot = require('./compiled-contracts/PolygonZkEVMGlobalExitRoot.json'); 3 | module.exports.PolygonZkEVMGlobalExitRootL2 = require('./compiled-contracts/PolygonZkEVMGlobalExitRootL2.json'); 4 | module.exports.PolygonZkEVM = require('./compiled-contracts/PolygonZkEVM.json'); 5 | module.exports.TokenWrapped = require('./compiled-contracts/TokenWrapped.json'); 6 | module.exports.FflonkVerifier = require('./compiled-contracts/FflonkVerifier.json'); 7 | module.exports.PolygonZkEVMBridgeMock = require('./compiled-contracts/PolygonZkEVMBridgeMock.json'); 8 | module.exports.ERC20PermitMock = require('./compiled-contracts/ERC20PermitMock.json'); 9 | module.exports.PolygonZkEVMGlobalExitRootL2Mock = require('./compiled-contracts/PolygonZkEVMGlobalExitRootL2Mock.json'); 10 | module.exports.PolygonZkEVMGlobalExitRootMock = require('./compiled-contracts/PolygonZkEVMGlobalExitRootMock.json'); 11 | module.exports.PolygonZkEVMMock = require('./compiled-contracts/PolygonZkEVMMock.json'); 12 | module.exports.VerifierRollupHelperMock = require('./compiled-contracts/VerifierRollupHelperMock.json'); 13 | module.exports.PermitHelper = require('./src/permit-helper'); 14 | module.exports.ProxyAdmin = require('./compiled-contracts/ProxyAdmin.json'); 15 | module.exports.TransparentUpgradeableProxy = require('./compiled-contracts/TransparentUpgradeableProxy.json'); 16 | module.exports.PolygonZkEVMDeployer = require('./compiled-contracts/PolygonZkEVMDeployer.json'); 17 | module.exports.PolygonZkEVMTimelock = require('./compiled-contracts/PolygonZkEVMTimelock.json'); 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@0xpolygonhermez/zkevm-contracts", 3 | "description": "Core contracts for the Polygon Hermez zkEVM", 4 | "version": "2.0.0", 5 | "repository": { 6 | "type": "git", 7 | "url": "git+https://github.com/0xPolygonHermez/contracts-zkEVM.git" 8 | }, 9 | "main": "index.js", 10 | "keywords": [ 11 | "zkevm", 12 | "snark", 13 | "polygon", 14 | "hermez", 15 | "stark", 16 | "EVM", 17 | "ethereum", 18 | "blockchain" 19 | ], 20 | "author": "0xPolygonHermez", 21 | "files": [ 22 | "contracts", 23 | "index.js", 24 | "compiled-contracts", 25 | "src" 26 | ], 27 | "bugs": { 28 | "url": "https://github.com/0xPolygonHermez/contracts-zkEVM/issues" 29 | }, 30 | "homepage": "https://github.com/0xPolygonHermez/contracts-zkEVM#readme", 31 | "license": "pending", 32 | "dependencies": { 33 | "chai": "^4.3.7", 34 | "ethers": "^5.7.2" 35 | }, 36 | "devDependencies": { 37 | "@0xpolygonhermez/zkevm-commonjs": "github:0xPolygonHermez/zkevm-commonjs#v2.0.0-fork.5", 38 | "@nomiclabs/hardhat-ethers": "^2.2.2", 39 | "@nomiclabs/hardhat-etherscan": "^3.1.7", 40 | "@nomiclabs/hardhat-waffle": "^2.0.5", 41 | "@openzeppelin/contracts": "4.8.2", 42 | "@openzeppelin/contracts-upgradeable": "4.8.2", 43 | "@openzeppelin/hardhat-upgrades": "1.22.1", 44 | "@openzeppelin/test-helpers": "0.5.16", 45 | "circomlibjs": "0.1.1", 46 | "dotenv": "^8.6.0", 47 | "eslint": "^8.36.0", 48 | "eslint-config-airbnb-base": "^15.0.0", 49 | "eslint-plugin-mocha": "^9.0.0", 50 | "ethereum-waffle": "^3.4.4", 51 | "ffjavascript": "^0.2.57", 52 | "hardhat": "^2.16.1", 53 | "hardhat-dependency-compiler": "^1.1.3", 54 | "hardhat-gas-reporter": "^1.0.9", 55 | "prettier": "^2.8.4", 56 | "prettier-plugin-solidity": "^1.1.3", 57 | "solc-0.8": "npm:solc@0.8.20", 58 | "solidity-coverage": "^0.7.22", 59 | "solidity-docgen": "^0.5.17" 60 | }, 61 | "scripts": { 62 | "saveDeployment:goerli": "mkdir -p deployments/goerli_$(date +%s) && cp -r deployment/deploy_*.json deployments/goerli_$(date +%s) && cp .openzeppelin/goerli.json deployments/goerli_$(date +%s) && cp deployment/genesis.json deployments/goerli_$(date +%s)", 63 | "saveDeployment:mainnet": "mkdir -p deployments/mainnet_$(date +%s) && cp -r deployment/deploy_*.json deployments/mainnet_$(date +%s) && cp .openzeppelin/mainnet.json deployments/mainnet_$(date +%s) && cp deployment/genesis.json deployments/mainnet_$(date +%s)", 64 | "test": "npx hardhat test test/contracts/**.test.js", 65 | "docgen": "npx solidity-docgen --solc-module solc-0.8 -t ./docs/templates -e ./contracts/verifiers,./contracts/mocks", 66 | "prepare:testnet:ZkEVM:localhost": "npx hardhat run deployment/testnet/prepareTestnet.js --network localhost", 67 | "deploy:ZkEVM:localhost": "rm -f .openzeppelin/unknown-31337.json && node deployment/1_createGenesis.js && npx hardhat run deployment/2_deployPolygonZKEVMDeployer.js --network localhost && npx hardhat run deployment/3_deployContracts.js --network localhost", 68 | "deploy:testnet:ZkEVM:localhost": "npm run prepare:testnet:ZkEVM:localhost && npm run deploy:ZkEVM:localhost", 69 | "prepare:testnet:ZkEVM:goerli": "npx hardhat run deployment/testnet/prepareTestnet.js --network goerli", 70 | "deploy:ZkEVM:goerli": "node deployment/1_createGenesis.js && npx hardhat run deployment/3_deployContracts.js --network goerli && npm run saveDeployment:goerli", 71 | "deploy:deployer:ZkEVM:goerli": "npx hardhat run deployment/2_deployPolygonZKEVMDeployer.js --network goerli", 72 | "verify:deployer:ZkEVM:goerli": "npx hardhat run deployment/verifyzkEVMDeployer.js --network goerli", 73 | "deploy:testnet:ZkEVM:goerli": "npm run prepare:testnet:ZkEVM:goerli && npm run deploy:ZkEVM:goerli", 74 | "upgrade:timelock:goerli": "npx hardhat run upgrade/timeLockUpgrade.js --network goerli", 75 | "verify:ZkEVM:goerli": "npx hardhat run deployment/verifyContracts.js --network goerli", 76 | "deploy:deployer:ZkEVM:mainnet": "npx hardhat run deployment/2_deployPolygonZKEVMDeployer.js --network mainnet", 77 | "verify:deployer:ZkEVM:mainnet": "npx hardhat run deployment/verifyzkEVMDeployer.js --network mainnet", 78 | "deploy:ZkEVM:mainnet": "node deployment/1_createGenesis.js && npx hardhat run deployment/3_deployContracts.js --network mainnet && npm run saveDeployment:mainnet", 79 | "upgrade:timelock:mainnet": "npx hardhat run upgrade/timeLockUpgrade.js --network mainnet", 80 | "verify:ZkEVM:mainnet": "npx hardhat run deployment/verifyContracts.js --network mainnet", 81 | "lint": "npx eslint ./test && npx eslint ./docker/scripts && npx eslint ./deployment && npx eslint ./src", 82 | "lint:fix": "npx eslint ./test --fix && npx eslint ./docker/scripts --fix && npx eslint ./deployment --fix && npx eslint ./src --fix", 83 | "compile": "npx hardhat compile", 84 | "docker:contracts": "./docker/scripts/deploy-docker.sh", 85 | "dockerv2:contracts": "./docker/scripts/deploy-dockerv2.sh", 86 | "push:docker:contracts": "docker push hermeznetwork/geth-zkevm-contracts", 87 | "update:genesis": "node deployment/1_createGenesis.js && node deployment/1_createGenesis.js --test --input ../docker/scripts/deploy_parameters_docker.json --out ../docker/scripts/genesis_docker.json", 88 | "coverage": "npx hardhat coverage", 89 | "gas:report": "REPORT_GAS=true npx hardhat test", 90 | "gas:report:file": "rm -f .openzeppelin/unknown-31337.json && REPORT_GAS=true REPORT_GAS_FILE=true npx hardhat test", 91 | "deploy:testnet:ZkEVM:test:goerli": "npm run prepare:testnet:ZkEVM:goerli && npm run deploy:ZkEVM:test:goerli", 92 | "deploy:ZkEVM:test:goerli": "node deployment/1_createGenesis.js --test && npx hardhat run deployment/3_deployContracts.js --network goerli && npm run saveDeployment:goerli" 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/permit-helper.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require('ethers'); 2 | const { expect } = require('chai'); 3 | 4 | /** 5 | * Create a permit signature with the EIP-2612 standard 6 | * @param {Object} tokenContractInstance - EthersJS contract instance of the token 7 | * @param {Object} wallet - EthersJs wallet instance that will sign the permit 8 | * @param {String} spenderAddress - Spender address, usually the contract that the permit will interact with 9 | * @param {String} value - Value of the permit 10 | * @param {String} nonce - Nonce of the permit 11 | * @param {String} deadline - Deadline of the permit 12 | * @returns {Object} - Signature obejct, { v, r, s} 13 | */ 14 | async function createPermitSignature(tokenContractInstance, wallet, spenderAddress, value, nonce, deadline, chainId) { 15 | const name = await tokenContractInstance.name(); 16 | 17 | // The domain 18 | const domain = { 19 | name, 20 | version: '1', 21 | chainId, 22 | verifyingContract: tokenContractInstance.address, 23 | }; 24 | 25 | // The named list of all type definitions 26 | const types = { 27 | Permit: [ 28 | { name: 'owner', type: 'address' }, 29 | { name: 'spender', type: 'address' }, 30 | { name: 'value', type: 'uint256' }, 31 | { name: 'nonce', type: 'uint256' }, 32 | { name: 'deadline', type: 'uint256' }, 33 | ], 34 | }; 35 | 36 | // The data to sign 37 | const values = { 38 | owner: wallet.address, 39 | spender: spenderAddress, 40 | value, 41 | nonce, 42 | deadline, 43 | }; 44 | 45 | const rawSignature = await wallet._signTypedData(domain, types, values); 46 | const signature = ethers.utils.splitSignature(rawSignature); 47 | const recoveredAddressTyped = ethers.utils.verifyTypedData(domain, types, values, rawSignature); 48 | expect(recoveredAddressTyped).to.be.equal(wallet.address); 49 | 50 | return signature; 51 | } 52 | 53 | /** 54 | * Create a permit signature with the DAi approach 55 | * @param {Object} tokenContractInstance - EthersJS contract instance of the token 56 | * @param {Object} wallet - EthersJs wallet instance that will sign the permit 57 | * @param {String} spenderAddress - Spender address, usually the contract that the permit will interact with 58 | * @param {String} value - Value of the permit 59 | * @param {String} nonce - Nonce of the permit 60 | * @param {String} expiry - expiry of the permit 61 | * @param {Number} chainId - expiry of the permit 62 | * @returns {Object} - Signature obejct, { v, r, s} 63 | */ 64 | async function createPermitSignatureDaiType(tokenContractInstance, wallet, spenderAddress, nonce, expiry, chainId) { 65 | const name = await tokenContractInstance.name(); 66 | const version = await tokenContractInstance.version(); 67 | 68 | // The domain 69 | const domain = { 70 | name, 71 | version, 72 | chainId, 73 | verifyingContract: tokenContractInstance.address, 74 | }; 75 | 76 | // The named list of all type definitions 77 | const types = { 78 | Permit: [ 79 | { name: 'holder', type: 'address' }, 80 | { name: 'spender', type: 'address' }, 81 | { name: 'nonce', type: 'uint256' }, 82 | { name: 'expiry', type: 'uint256' }, 83 | { name: 'allowed', type: 'bool' }, 84 | ], 85 | }; 86 | 87 | // The data to sign 88 | const values = { 89 | holder: wallet.address, 90 | spender: spenderAddress, 91 | nonce, 92 | expiry, 93 | allowed: true, 94 | }; 95 | 96 | const rawSignature = await wallet._signTypedData(domain, types, values); 97 | const signature = ethers.utils.splitSignature(rawSignature); 98 | const recoveredAddressTyped = ethers.utils.verifyTypedData(domain, types, values, rawSignature); 99 | 100 | expect(recoveredAddressTyped).to.be.equal(wallet.address); 101 | 102 | return signature; 103 | } 104 | 105 | /** 106 | * Create a permit signature with the UNI approach 107 | * @param {Object} tokenContractInstance - EthersJS contract instance of the token 108 | * @param {Object} wallet - EthersJs wallet instance that will sign the permit 109 | * @param {String} spenderAddress - Spender address, usually the contract that the permit will interact with 110 | * @param {String} value - Value of the permit 111 | * @param {String} nonce - Nonce of the permit 112 | * @param {String} deadline - Deadline of the permit 113 | * @param {Number} chainId - expiry of the permit 114 | * @returns {Object} - Signature obejct, { v, r, s} 115 | */ 116 | async function createPermitSignatureUniType(tokenContractInstance, wallet, spenderAddress, value, nonce, deadline, chainId) { 117 | const name = await tokenContractInstance.name(); 118 | 119 | // The domain 120 | const domain = { 121 | name, 122 | chainId, 123 | verifyingContract: tokenContractInstance.address, 124 | }; 125 | 126 | // The named list of all type definitions 127 | const types = { 128 | Permit: [ 129 | { name: 'owner', type: 'address' }, 130 | { name: 'spender', type: 'address' }, 131 | { name: 'value', type: 'uint256' }, 132 | { name: 'nonce', type: 'uint256' }, 133 | { name: 'deadline', type: 'uint256' }, 134 | ], 135 | }; 136 | 137 | // The data to sign 138 | const values = { 139 | owner: wallet.address, 140 | spender: spenderAddress, 141 | value, 142 | nonce, 143 | deadline, 144 | }; 145 | 146 | const rawSignature = await wallet._signTypedData(domain, types, values); 147 | const signature = ethers.utils.splitSignature(rawSignature); 148 | const recoveredAddressTyped = ethers.utils.verifyTypedData(domain, types, values, rawSignature); 149 | expect(recoveredAddressTyped).to.be.equal(wallet.address); 150 | 151 | return signature; 152 | } 153 | 154 | /** 155 | * Permit interface 156 | */ 157 | const ifacePermit = new ethers.utils.Interface(['function permit(address,address,uint256,uint256,uint8,bytes32,bytes32)']); 158 | 159 | /** 160 | * Permit interface DAI 161 | */ 162 | const ifacePermitDAI = new ethers.utils.Interface(['function permit(address,address,uint256,uint256,bool,uint8,bytes32,bytes32)']); 163 | 164 | module.exports = { 165 | createPermitSignature, 166 | createPermitSignatureDaiType, 167 | ifacePermit, 168 | ifacePermitDAI, 169 | createPermitSignatureUniType, 170 | }; 171 | -------------------------------------------------------------------------------- /test/contracts/globalExitRootManager.test.js: -------------------------------------------------------------------------------- 1 | const { expect } = require('chai'); 2 | const { ethers } = require('hardhat'); 3 | 4 | function calculateGlobalExitRoot(mainnetExitRoot, rollupExitRoot) { 5 | return ethers.utils.solidityKeccak256(['bytes32', 'bytes32'], [mainnetExitRoot, rollupExitRoot]); 6 | } 7 | const zero32bytes = '0x0000000000000000000000000000000000000000000000000000000000000000'; 8 | 9 | describe('Global Exit Root', () => { 10 | let rollup; 11 | let PolygonZkEVMBridge; 12 | 13 | let polygonZkEVMGlobalExitRoot; 14 | beforeEach('Deploy contracts', async () => { 15 | // load signers 16 | [, rollup, PolygonZkEVMBridge] = await ethers.getSigners(); 17 | 18 | // deploy global exit root manager 19 | const PolygonZkEVMGlobalExitRootFactory = await ethers.getContractFactory('PolygonZkEVMGlobalExitRoot'); 20 | 21 | polygonZkEVMGlobalExitRoot = await PolygonZkEVMGlobalExitRootFactory.deploy( 22 | rollup.address, 23 | PolygonZkEVMBridge.address, 24 | ); 25 | await polygonZkEVMGlobalExitRoot.deployed(); 26 | }); 27 | 28 | it('should check the constructor parameters', async () => { 29 | expect(await polygonZkEVMGlobalExitRoot.rollupAddress()).to.be.equal(rollup.address); 30 | expect(await polygonZkEVMGlobalExitRoot.bridgeAddress()).to.be.equal(PolygonZkEVMBridge.address); 31 | expect(await polygonZkEVMGlobalExitRoot.lastRollupExitRoot()).to.be.equal(zero32bytes); 32 | expect(await polygonZkEVMGlobalExitRoot.lastMainnetExitRoot()).to.be.equal(zero32bytes); 33 | }); 34 | 35 | it('should update root and check global exit root', async () => { 36 | const newRootRollup = ethers.utils.hexlify(ethers.utils.randomBytes(32)); 37 | 38 | await expect(polygonZkEVMGlobalExitRoot.updateExitRoot(newRootRollup)) 39 | .to.be.revertedWith('OnlyAllowedContracts'); 40 | 41 | // Update root from the rollup 42 | await expect(polygonZkEVMGlobalExitRoot.connect(rollup).updateExitRoot(newRootRollup)) 43 | .to.emit(polygonZkEVMGlobalExitRoot, 'UpdateGlobalExitRoot') 44 | .withArgs(zero32bytes, newRootRollup); 45 | 46 | expect(await polygonZkEVMGlobalExitRoot.getLastGlobalExitRoot()) 47 | .to.be.equal(calculateGlobalExitRoot(zero32bytes, newRootRollup)); 48 | 49 | // Update root from the PolygonZkEVMBridge 50 | const newRootBridge = ethers.utils.hexlify(ethers.utils.randomBytes(32)); 51 | await expect(polygonZkEVMGlobalExitRoot.connect(PolygonZkEVMBridge).updateExitRoot(newRootBridge)) 52 | .to.emit(polygonZkEVMGlobalExitRoot, 'UpdateGlobalExitRoot') 53 | .withArgs(newRootBridge, newRootRollup); 54 | 55 | expect(await polygonZkEVMGlobalExitRoot.lastMainnetExitRoot()).to.be.equal(newRootBridge); 56 | expect(await polygonZkEVMGlobalExitRoot.getLastGlobalExitRoot()) 57 | .to.be.equal(calculateGlobalExitRoot(newRootBridge, newRootRollup)); 58 | }); 59 | }); 60 | -------------------------------------------------------------------------------- /test/contracts/globalExitRootManagerL2.test.js: -------------------------------------------------------------------------------- 1 | const { expect } = require('chai'); 2 | const { ethers } = require('hardhat'); 3 | 4 | const zero32bytes = '0x0000000000000000000000000000000000000000000000000000000000000000'; 5 | 6 | describe('Global Exit Root L2', () => { 7 | let PolygonZkEVMBridge; 8 | let polygonZkEVMGlobalExitRoot; 9 | let deployer; 10 | 11 | beforeEach('Deploy contracts', async () => { 12 | // load signers 13 | [deployer, PolygonZkEVMBridge] = await ethers.getSigners(); 14 | 15 | // deploy global exit root manager 16 | const PolygonZkEVMGlobalExitRootFactory = await ethers.getContractFactory('PolygonZkEVMGlobalExitRootL2Mock', deployer); 17 | polygonZkEVMGlobalExitRoot = await PolygonZkEVMGlobalExitRootFactory.deploy(PolygonZkEVMBridge.address); 18 | }); 19 | 20 | it('should check the constructor parameters', async () => { 21 | expect(await polygonZkEVMGlobalExitRoot.bridgeAddress()).to.be.equal(PolygonZkEVMBridge.address); 22 | expect(await polygonZkEVMGlobalExitRoot.lastRollupExitRoot()).to.be.equal(zero32bytes); 23 | }); 24 | 25 | it('should update root and check global exit root', async () => { 26 | const newRootRollup = ethers.utils.hexlify(ethers.utils.randomBytes(32)); 27 | 28 | await expect(polygonZkEVMGlobalExitRoot.updateExitRoot(newRootRollup)) 29 | .to.be.revertedWith('OnlyAllowedContracts'); 30 | 31 | // Update root from the rollup 32 | await polygonZkEVMGlobalExitRoot.connect(PolygonZkEVMBridge).updateExitRoot(newRootRollup); 33 | 34 | expect(await polygonZkEVMGlobalExitRoot.lastRollupExitRoot()).to.be.equal(newRootRollup); 35 | }); 36 | 37 | it('should update root and check the storage position matches', async () => { 38 | // Check global exit root 39 | const newRoot = ethers.utils.hexlify(ethers.utils.randomBytes(32)); 40 | const blockNumber = 1; 41 | await polygonZkEVMGlobalExitRoot.setLastGlobalExitRoot(newRoot, blockNumber); 42 | expect(await polygonZkEVMGlobalExitRoot.globalExitRootMap(newRoot)).to.be.equal(blockNumber); 43 | const mapStoragePosition = 0; 44 | const key = newRoot; 45 | const storagePosition = ethers.utils.solidityKeccak256(['uint256', 'uint256'], [key, mapStoragePosition]); 46 | const storageValue = await ethers.provider.getStorageAt(polygonZkEVMGlobalExitRoot.address, storagePosition); 47 | expect(blockNumber).to.be.equal(ethers.BigNumber.from(storageValue).toNumber()); 48 | 49 | // Check rollup exit root 50 | const newRootRollupExitRoot = ethers.utils.hexlify(ethers.utils.randomBytes(32)); 51 | await polygonZkEVMGlobalExitRoot.setExitRoot(newRootRollupExitRoot); 52 | expect(await polygonZkEVMGlobalExitRoot.lastRollupExitRoot()).to.be.equal(newRootRollupExitRoot); 53 | 54 | const storagePositionExitRoot = 1; 55 | const storageValueExitRoot = await ethers.provider.getStorageAt(polygonZkEVMGlobalExitRoot.address, storagePositionExitRoot); 56 | expect(newRootRollupExitRoot, storageValueExitRoot); 57 | }); 58 | }); 59 | -------------------------------------------------------------------------------- /test/contracts/helpers/test-helpers.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-await-in-loop */ 2 | const { stateUtils } = require('@0xpolygonhermez/zkevm-commonjs'); 3 | 4 | async function setGenesisBlock(addressArray, amountArray, nonceArray, smt) { 5 | let currentRoot = smt.empty; 6 | for (let i = 0; i < addressArray.length; i++) { 7 | currentRoot = await stateUtils.setAccountState(addressArray[i], smt, currentRoot, amountArray[i], nonceArray[i]); 8 | } 9 | 10 | return currentRoot; 11 | } 12 | 13 | module.exports = { 14 | setGenesisBlock, 15 | }; 16 | -------------------------------------------------------------------------------- /test/contracts/polygonZkEVMTestnetV2.test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-plusplus, no-await-in-loop */ 2 | const { expect } = require('chai'); 3 | const { ethers, upgrades } = require('hardhat'); 4 | 5 | describe('Polygon ZK-EVM TestnetV2', () => { 6 | let deployer; 7 | let trustedAggregator; 8 | let trustedSequencer; 9 | let admin; 10 | 11 | let verifierContract; 12 | let polygonZkEVMBridgeContract; 13 | let polygonZkEVMContract; 14 | let maticTokenContract; 15 | let polygonZkEVMGlobalExitRoot; 16 | 17 | const maticTokenName = 'Matic Token'; 18 | const maticTokenSymbol = 'MATIC'; 19 | const maticTokenInitialBalance = ethers.utils.parseEther('20000000'); 20 | 21 | const genesisRoot = '0x0000000000000000000000000000000000000000000000000000000000000001'; 22 | 23 | const networkIDMainnet = 0; 24 | const urlSequencer = 'http://zkevm-json-rpc:8123'; 25 | const chainID = 1000; 26 | const networkName = 'zkevm'; 27 | const version = '0.0.1'; 28 | const forkID = 0; 29 | const pendingStateTimeoutDefault = 100; 30 | const trustedAggregatorTimeoutDefault = 10; 31 | let firstDeployment = true; 32 | 33 | beforeEach('Deploy contract', async () => { 34 | upgrades.silenceWarnings(); 35 | 36 | // load signers 37 | [deployer, trustedAggregator, trustedSequencer, admin] = await ethers.getSigners(); 38 | 39 | // deploy mock verifier 40 | const VerifierRollupHelperFactory = await ethers.getContractFactory( 41 | 'VerifierRollupHelperMock', 42 | ); 43 | verifierContract = await VerifierRollupHelperFactory.deploy(); 44 | 45 | // deploy MATIC 46 | const maticTokenFactory = await ethers.getContractFactory('ERC20PermitMock'); 47 | maticTokenContract = await maticTokenFactory.deploy( 48 | maticTokenName, 49 | maticTokenSymbol, 50 | deployer.address, 51 | maticTokenInitialBalance, 52 | ); 53 | await maticTokenContract.deployed(); 54 | 55 | /* 56 | * deploy global exit root manager 57 | * In order to not have trouble with nonce deploy first proxy admin 58 | */ 59 | await upgrades.deployProxyAdmin(); 60 | if ((await upgrades.admin.getInstance()).address !== '0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0') { 61 | firstDeployment = false; 62 | } 63 | const nonceProxyBridge = Number((await ethers.provider.getTransactionCount(deployer.address))) + (firstDeployment ? 3 : 2); 64 | const nonceProxyZkevm = nonceProxyBridge + 2; // Always have to redeploy impl since the polygonZkEVMGlobalExitRoot address changes 65 | 66 | const precalculateBridgeAddress = ethers.utils.getContractAddress({ from: deployer.address, nonce: nonceProxyBridge }); 67 | const precalculateZkevmAddress = ethers.utils.getContractAddress({ from: deployer.address, nonce: nonceProxyZkevm }); 68 | firstDeployment = false; 69 | 70 | const PolygonZkEVMGlobalExitRootFactory = await ethers.getContractFactory('PolygonZkEVMGlobalExitRoot'); 71 | polygonZkEVMGlobalExitRoot = await upgrades.deployProxy(PolygonZkEVMGlobalExitRootFactory, [], { 72 | initializer: false, 73 | constructorArgs: [precalculateZkevmAddress, precalculateBridgeAddress], 74 | unsafeAllow: ['constructor', 'state-variable-immutable'], 75 | }); 76 | 77 | // deploy PolygonZkEVMBridge 78 | const polygonZkEVMBridgeFactory = await ethers.getContractFactory('PolygonZkEVMBridge'); 79 | polygonZkEVMBridgeContract = await upgrades.deployProxy(polygonZkEVMBridgeFactory, [], { initializer: false }); 80 | 81 | // deploy PolygonZkEVMTestnet 82 | const PolygonZkEVMFactory = await ethers.getContractFactory('PolygonZkEVMTestnetV2'); 83 | polygonZkEVMContract = await upgrades.deployProxy(PolygonZkEVMFactory, [], { 84 | initializer: false, 85 | constructorArgs: [ 86 | polygonZkEVMGlobalExitRoot.address, 87 | maticTokenContract.address, 88 | verifierContract.address, 89 | polygonZkEVMBridgeContract.address, 90 | chainID, 91 | forkID, 92 | ], 93 | unsafeAllow: ['constructor', 'state-variable-immutable'], 94 | }); 95 | 96 | expect(precalculateBridgeAddress).to.be.equal(polygonZkEVMBridgeContract.address); 97 | expect(precalculateZkevmAddress).to.be.equal(polygonZkEVMContract.address); 98 | 99 | await polygonZkEVMBridgeContract.initialize(networkIDMainnet, polygonZkEVMGlobalExitRoot.address, polygonZkEVMContract.address); 100 | await polygonZkEVMContract.initialize( 101 | { 102 | admin: admin.address, 103 | trustedSequencer: trustedSequencer.address, 104 | pendingStateTimeout: pendingStateTimeoutDefault, 105 | trustedAggregator: trustedAggregator.address, 106 | trustedAggregatorTimeout: trustedAggregatorTimeoutDefault, 107 | }, 108 | genesisRoot, 109 | urlSequencer, 110 | networkName, 111 | version, 112 | ); 113 | 114 | // fund sequencer address with Matic tokens 115 | await maticTokenContract.transfer(trustedSequencer.address, ethers.utils.parseEther('1000')); 116 | }); 117 | 118 | it('should check the constructor parameters', async () => { 119 | expect(await polygonZkEVMContract.version()).to.be.equal(0); 120 | }); 121 | 122 | it('should check updateVersion', async () => { 123 | const newVersionString = '0.0.2'; 124 | 125 | /* 126 | * const lastVerifiedBatch = 0; 127 | * await expect(polygonZkEVMContract.updateVersion(newVersionString)) 128 | * .to.emit(polygonZkEVMContract, 'UpdateZkEVMVersion').withArgs(lastVerifiedBatch, forkID, newVersionString); 129 | */ 130 | 131 | await expect(polygonZkEVMContract.updateVersion(newVersionString)) 132 | .to.be.revertedWith('VersionAlreadyUpdated'); 133 | 134 | // expect(await polygonZkEVMContract.version()).to.be.equal(1); 135 | }); 136 | }); 137 | -------------------------------------------------------------------------------- /test/contracts/real-prover/real-prover-test-inputs.test.js: -------------------------------------------------------------------------------- 1 | const { expect } = require('chai'); 2 | const { ethers } = require('hardhat'); 3 | 4 | const { contractUtils } = require('@0xpolygonhermez/zkevm-commonjs'); 5 | 6 | const { generateSolidityInputs } = contractUtils; 7 | 8 | const proofJson = require('./test-inputs/proof.json'); 9 | const input = require('./test-inputs/public.json'); 10 | 11 | describe('Real prover inputs test', () => { 12 | let verifierContract; 13 | 14 | beforeEach('Deploy contract', async () => { 15 | // deploy mock verifier 16 | const VerifierFactory = await ethers.getContractFactory( 17 | 'FflonkVerifier', 18 | ); 19 | verifierContract = await VerifierFactory.deploy(); 20 | }); 21 | 22 | it('Test real prover', async () => { 23 | const proof = generateSolidityInputs(proofJson); 24 | 25 | expect(await verifierContract.verifyProof( 26 | proof, 27 | input, 28 | )).to.be.equal(true); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /test/contracts/real-prover/test-inputs/proof.json: -------------------------------------------------------------------------------- 1 | { 2 | "curve": "bn128", 3 | "evaluations": { 4 | "a": "9702969745918705481839805950921709589337567271136858610573534676949744842267", 5 | "b": "341902451305098325588274536638232982500645316303847667311699639028281007546", 6 | "c": "10089136329707562787095186991940399671235868281107556829251231305232728679682", 7 | "inv": "1955317095964997532096759377382751305143448868916056378222243512469054113842", 8 | "qc": "10782279106031138244634232032817369339714783360582741873805912278948357157586", 9 | "ql": "21251808300522045537904185777972611020866727049420529442210109963857906214889", 10 | "qm": "17471054534374682175982394929866179474101758026949454352441573981958345011791", 11 | "qo": "593458529869580986585382253403246015645108630200332957766491007433366200564", 12 | "qr": "14857681067819006905475333449198913926111918296903865133508595828620835725428", 13 | "s1": "3807827801268525577391775311558443473982829962972149818537946317394078789278", 14 | "s2": "4397320204995723396306594522728505487798639077199002369395380144177013324052", 15 | "s3": "18332001246779002778528499238127440740157760469206669940377231761041608865451", 16 | "t1w": "3783166700504360214709754445949688701744393960851118042830956743923382253816", 17 | "t2w": "13996969915734692472195789214718626509129048070536208858437857877922069792469", 18 | "z": "8541406622232730765144154114534482432327357919465646008346907097038763678566", 19 | "zw": "1832633582965391321323432315063604337854235240731281923564364630154302008895" 20 | }, 21 | "polynomials": { 22 | "C1": [ 23 | "5320383136707118150961589735727057893618792443592325268991891786568049186597", 24 | "3429053040128136166640053209131079617911025054412502995806068449238317388495", 25 | "1" 26 | ], 27 | "C2": [ 28 | "13110027018027162687869061215276171550037210425611115274025292428135814498280", 29 | "19744765739594594951498703331610475091676541995387229955171858316234990841770", 30 | "1" 31 | ], 32 | "W1": [ 33 | "19953864813013383811791292897136363698413701896013021750839490990469478344731", 34 | "12225282668357773750977460317101465492913810465324122457193920924888880034763", 35 | "1" 36 | ], 37 | "W2": [ 38 | "9044609927797983462416846529925883781292057530242351839556328732192193714074", 39 | "11917256847008706478816281118166319202875650041166749915284162189072588726279", 40 | "1" 41 | ] 42 | }, 43 | "protocol": "fflonk" 44 | } -------------------------------------------------------------------------------- /test/contracts/real-prover/test-inputs/public.json: -------------------------------------------------------------------------------- 1 | [ 2 | "5105835634000876263592828603732612898759495378504810447268373845312293495935" 3 | ] -------------------------------------------------------------------------------- /test/contracts/snark_stark_input.test.js: -------------------------------------------------------------------------------- 1 | const { expect } = require('chai'); 2 | const { ethers, upgrades } = require('hardhat'); 3 | 4 | const { contractUtils } = require('@0xpolygonhermez/zkevm-commonjs'); 5 | 6 | describe('Polygon ZK-EVM snark stark input test', () => { 7 | let polygonZkEVMContract; 8 | const genesisRoot = '0x0000000000000000000000000000000000000000000000000000000000000001'; 9 | let randomSigner; 10 | 11 | const urlSequencer = 'http://zkevm-json-rpc:8123'; 12 | const chainID = 1000; 13 | const networkName = 'zkevm'; 14 | const version = '0.0.1'; 15 | const forkID = 0; 16 | const batchL2Data = '0xee80843b9aca00830186a0944d5cf5032b2a844602278b01199ed191a86c93ff88016345785d8a0000808203e880801cee7e01dc62f69a12c3510c6d64de04ee6346d84b6a017f3e786c7d87f963e75d8cc91fa983cd6d9cf55fff80d73bd26cd333b0f098acc1e58edb1fd484ad731b'; 17 | beforeEach('Deploy contract', async () => { 18 | upgrades.silenceWarnings(); 19 | // load signers 20 | [randomSigner] = await ethers.getSigners(); 21 | 22 | // deploy PolygonZkEVMMock 23 | const PolygonZkEVMFactory = await ethers.getContractFactory('PolygonZkEVMMock'); 24 | polygonZkEVMContract = await upgrades.deployProxy(PolygonZkEVMFactory, [], { 25 | initializer: false, 26 | constructorArgs: [ 27 | randomSigner.address, 28 | randomSigner.address, 29 | randomSigner.address, 30 | randomSigner.address, 31 | chainID, 32 | 0, 33 | ], 34 | unsafeAllow: ['constructor', 'state-variable-immutable'], 35 | }); 36 | 37 | await polygonZkEVMContract.initialize( 38 | { 39 | admin: randomSigner.address, 40 | trustedSequencer: randomSigner.address, 41 | pendingStateTimeout: 0, 42 | trustedAggregator: randomSigner.address, 43 | trustedAggregatorTimeout: 0, 44 | }, 45 | genesisRoot, 46 | urlSequencer, 47 | networkName, 48 | version, 49 | ); 50 | 51 | await polygonZkEVMContract.deployed(); 52 | }); 53 | 54 | it('Check Accumualte input Hash', async () => { 55 | const oldAccInputHash = '0x0000000000000000000000000000000000000000000000000000000000000000'; 56 | const globalExitRoot = '0x090bcaf734c4f06c93954a827b45a6e8c67b8e0fd1e0a35a1c5982d6961828f9'; 57 | const timestamp = 1944498031; 58 | const sequencerAddr = '0x617b3a3528F9cDd6630fd3301B9c8911F7Bf063D'; 59 | const expectedStarkHashExecutor = '0x704d5cfd3e44b82028f7f8cae31168267a7422c5a447b90a65134116da5a8432'; 60 | 61 | const batchL2DataHash = contractUtils.calculateBatchHashData(batchL2Data); 62 | const accumulateInputHashJs = await contractUtils.calculateAccInputHash( 63 | oldAccInputHash, 64 | batchL2DataHash, 65 | globalExitRoot, 66 | timestamp, 67 | sequencerAddr, 68 | ); 69 | const accumulateInputHashSC = await polygonZkEVMContract.calculateAccInputHash( 70 | oldAccInputHash, 71 | batchL2Data, 72 | globalExitRoot, 73 | timestamp, 74 | sequencerAddr, 75 | ); 76 | expect(accumulateInputHashJs).to.be.equal(accumulateInputHashSC); 77 | expect(accumulateInputHashSC).to.be.equal(expectedStarkHashExecutor); 78 | }); 79 | it('Check commonjs unit test', async () => { 80 | // Unit test taken from https://github.com/0xPolygonHermez/zkevm-commonjs/blob/main/test/contract-utils.test.js#L16 81 | const oldStateRoot = '0x2dc4db4293af236cb329700be43f08ace740a05088f8c7654736871709687e90'; 82 | const newStateRoot = '0xbff23fc2c168c033aaac77503ce18f958e9689d5cdaebb88c5524ce5c0319de3'; 83 | const newLocalExitRoot = '0x0000000000000000000000000000000000000000000000000000000000000000'; 84 | const oldAccInputHash = '0x0000000000000000000000000000000000000000000000000000000000000000'; 85 | const newAccInputHash = '0x2c9d2c1b2ed8e4be0719f443235c3483f8d6288c6d057859e7210fe39acce682'; 86 | const oldNumBatch = 0; 87 | const newNumBatch = 1; 88 | const aggregatorAddress = '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266'; 89 | const expectedSnarkInputHash = '14018390222040434090025131340942647213193155362626068451264286945439322107665'; 90 | 91 | const lastPendingStateConsolidated = 0; 92 | const sequencedTimestamp = 999; 93 | // set smart contract with correct parameters 94 | await polygonZkEVMContract.setStateRoot(oldStateRoot, oldNumBatch); 95 | await polygonZkEVMContract.setSequencedBatches(newNumBatch, newAccInputHash, sequencedTimestamp, lastPendingStateConsolidated); 96 | await polygonZkEVMContract.setSequencedBatch(1); 97 | 98 | await ethers.provider.send('hardhat_impersonateAccount', [aggregatorAddress]); 99 | const aggregator = await ethers.getSigner(aggregatorAddress); 100 | await randomSigner.sendTransaction({ 101 | to: aggregatorAddress, 102 | value: ethers.utils.parseEther('4'), 103 | }); 104 | 105 | // Compute SC input 106 | const pendingStateNum = 0; 107 | const inputSnarkSC = await polygonZkEVMContract.connect(aggregator).getNextSnarkInput( 108 | pendingStateNum, 109 | oldNumBatch, 110 | newNumBatch, 111 | newLocalExitRoot, 112 | newStateRoot, 113 | ); 114 | 115 | // Compute Js input 116 | const inputSnarkJS = await contractUtils.calculateSnarkInput( 117 | oldStateRoot, 118 | newStateRoot, 119 | newLocalExitRoot, 120 | oldAccInputHash, 121 | newAccInputHash, 122 | oldNumBatch, 123 | newNumBatch, 124 | chainID, 125 | aggregatorAddress, 126 | forkID, 127 | ); 128 | 129 | expect(inputSnarkSC).to.be.equal(inputSnarkJS); 130 | expect(inputSnarkSC).to.be.equal(expectedSnarkInputHash); 131 | }); 132 | }); 133 | -------------------------------------------------------------------------------- /upgrade/README.md: -------------------------------------------------------------------------------- 1 | ## Requirements 2 | 3 | - node version: 14.x 4 | - npm version: 7.x 5 | 6 | ## Upgrade 7 | 8 | ``` 9 | npm i 10 | cp .env.example .env 11 | ``` 12 | 13 | Fill `.env` with your `MNEMONIC` and `INFURA_PROJECT_ID` 14 | 15 | In order to upgrade the contracts we will need the information on `deployments/${network}_$(date +%s)` 16 | 17 | In project root, copy the `${network}.json` of the deployment that you want to upgrade and copy it on the `./.openzeppelin` 18 | e.g. `cp deployments/${network}_$(date +%s)/${network}.json ./.openzeppelin` 19 | 20 | Then fill the upgrade parameters: 21 | 22 | ``` 23 | cd deployment 24 | cp upgrade_parameters.json.example upgrade_parameters.json 25 | ``` 26 | 27 | Fill created `upgrade_parameters.json` with appropiate parameters. 28 | You should fullfill the upgrades array, with all the updates that you intend to do ( more information in `upgrade-parameters.json` section) 29 | 30 | if the deployment was deployed without a timelock you can use the `simpleUpgradeScript.js`: 31 | 32 | - Run the script 33 | 34 | Otherwise, in case of timelock use `timeLockUpgrade.js` 35 | 36 | - Run the script 37 | - Now the necessary transactions to interact with the timelock are printed in the screen `schedule` and `execute`, also will be saved in 38 | `./upgrade_output_${new Date().getTime() / 1000}.json` file 39 | - With the owner of the timelock (multisig or account), send the data printed by `schedule` to the `Timelock` contract. 40 | - Once the necessary `timelockMinDelay` has expired, with the same account you can now send the data printed by `execute` to the `Timelock` contract and the contracts will be upgraded. 41 | 42 | ## upgrade-parameters.json 43 | 44 | - `timelockMinDelay`: number, timelock delay between the schedule and execution, must be bigger than current min delay 45 | - `upgrades`: Object, Indicates which address and to which implementation must upgrade 46 | - address: address of the current proxy 47 | - contractName: string, contract name that the proxy will be updated to 48 | - constructorArgs: Array, optional, constructor arguments of the new implementation deployed 49 | 50 | ### Optional Parameters 51 | 52 | - `multiplierGas`: number, Gas multiplier. If maxFeePerGas and maxPriorityFeePerGas are set, will not take effect 53 | - `deployerPvtKey`: string, deployerPvtKey of the deployer 54 | - `timelockSalt`: string, Optional salt for the timelock 55 | -------------------------------------------------------------------------------- /upgrade/arguments.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | '0x6407cf296a27B38fd29c401518504D388F1DFB3d', 3 | '0xF1b13757bcF3EF902a7847f409A6068BA43a89D4', 4 | '0x4ceB990D2E2ee6d0e163fa80d12bac72C0F28D52', 5 | '0xcFA773Cc48FBde3CA4D24eeCb19D224d697026b2', 6 | 1440, 7 | 2 8 | ] -------------------------------------------------------------------------------- /upgrade/deployVerifier.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-await-in-loop */ 2 | /* eslint-disable no-console, no-inner-declarations, no-undef, import/no-unresolved */ 3 | 4 | const { ethers } = require('hardhat'); 5 | const path = require('path'); 6 | require('dotenv').config({ path: path.resolve(__dirname, '../.env') }); 7 | async function main() { 8 | let currentProvider = ethers.provider; 9 | let deployer; 10 | if (process.env.MNEMONIC) { 11 | deployer = ethers.Wallet.fromMnemonic(process.env.MNEMONIC, 'm/44\'/60\'/0\'/0/0').connect(currentProvider); 12 | console.log("using mnemonic", deployer.address) 13 | } else { 14 | [deployer] = (await ethers.getSigners()); 15 | } 16 | 17 | /* 18 | * Deploy verifier 19 | */ 20 | const VerifierRollup = await ethers.getContractFactory('FflonkVerifier', deployer); 21 | const verifierContract = await VerifierRollup.deploy(); 22 | await verifierContract.deployed(); 23 | 24 | console.log('#######################\n'); 25 | console.log('Verifier deployed to:', verifierContract.address); 26 | 27 | console.log("you can verify the new verifier address with:") 28 | console.log(`npx hardhat verify ${verifierContract.address} --network ${process.env.HARDHAT_NETWORK}`); 29 | } 30 | 31 | main().catch((e) => { 32 | console.error(e); 33 | process.exit(1); 34 | }); 35 | -------------------------------------------------------------------------------- /upgrade/simpleUpgrade.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console, no-unused-vars */ 2 | const hre = require('hardhat'); 3 | const { ethers, upgrades } = require('hardhat'); 4 | const path = require('path'); 5 | require('dotenv').config({ path: path.resolve(__dirname, '../.env') }); 6 | const upgradeParameters = require('./upgrade_parameters.json'); 7 | 8 | async function main() { 9 | // Set multiplier Gas 10 | let currentProvider = ethers.provider; 11 | if (upgradeParameters.multiplierGas) { 12 | if (process.env.HARDHAT_NETWORK !== 'hardhat') { 13 | const multiplierGas = upgradeParameters.multiplierGas; 14 | currentProvider = new ethers.providers.JsonRpcProvider(`https://${process.env.HARDHAT_NETWORK}.infura.io/v3/${process.env.INFURA_PROJECT_ID}`); 15 | async function overrideFeeData() { 16 | const feedata = await ethers.provider.getFeeData(); 17 | return { 18 | maxFeePerGas: feedata.maxFeePerGas.mul(multiplierGas), 19 | maxPriorityFeePerGas: feedata.maxPriorityFeePerGas.mul(multiplierGas), 20 | }; 21 | } 22 | currentProvider.getFeeData = overrideFeeData; 23 | } 24 | } 25 | let deployer; 26 | if (upgradeParameters.deployerPvtKey) { 27 | deployer = new ethers.Wallet(upgradeParameters.deployerPvtKey, currentProvider); 28 | } else if (process.env.MNEMONIC) { 29 | deployer = ethers.Wallet.fromMnemonic(process.env.MNEMONIC, 'm/44\'/60\'/0\'/0/0').connect(currentProvider); 30 | } else { 31 | [deployer] = (await ethers.getSigners()); 32 | } 33 | 34 | // compìle contracts 35 | await hre.run('compile'); 36 | 37 | for (const upgrade of upgradeParameters.upgrades) { 38 | const proxyPolygonAddress = upgrade.address; 39 | const polygonZkEVMFactory = await ethers.getContractFactory(upgrade.contractName, deployer); 40 | 41 | if (upgrade.constructorArgs) { 42 | const txZKEVM = await upgrades.upgradeProxy(proxyPolygonAddress, polygonZkEVMFactory, 43 | { 44 | constructorArgs: upgrade.constructorArgs, 45 | unsafeAllow: ['constructor', 'state-variable-immutable'], 46 | call: {fn: upgrade.callAfterUpgrade.functionName, args: upgrade.callAfterUpgrade.arguments} 47 | }); 48 | 49 | console.log(txZKEVM.deployTransaction); 50 | console.log(await txZKEVM.deployTransaction.wait()); 51 | console.log('upgrade succesfull', upgrade.contractName); 52 | 53 | console.log(txZKEVM.address); 54 | console.log("you can verify the new impl address with:") 55 | console.log(`npx hardhat verify --constructor-args upgrade/arguments.js ${txZKEVM.address} --network ${process.env.HARDHAT_NETWORK}\n`); 56 | console.log("Copy the following constructor arguments on: upgrade/arguments.js \n", upgrade.constructorArgs) 57 | } else { 58 | const txZKEVM = await upgrades.upgradeProxy(proxyPolygonAddress, polygonZkEVMFactory) 59 | 60 | console.log(txZKEVM.address); 61 | console.log("you can verify the new impl address with:") 62 | console.log(`npx hardhat verify ${txZKEVM.address} --network ${process.env.HARDHAT_NETWORK}`); 63 | } 64 | } 65 | } 66 | main() 67 | .then(() => process.exit(0)) 68 | .catch((error) => { 69 | console.error(error); 70 | process.exit(1); 71 | }); 72 | -------------------------------------------------------------------------------- /upgrade/timeLockUpgrade.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console, no-unused-vars, no-use-before-define */ 2 | const hre = require('hardhat'); 3 | const { ethers, upgrades } = require('hardhat'); 4 | const path = require('path'); 5 | require('dotenv').config({ path: path.resolve(__dirname, '../.env') }); 6 | const fs = require('fs'); 7 | 8 | const upgradeParameters = require('./upgrade_parameters.json'); 9 | 10 | const pathOutputJson = path.join(__dirname, `./upgrade_output_${new Date().getTime() / 1000}.json`); 11 | 12 | async function main() { 13 | // Set multiplier Gas 14 | let currentProvider = ethers.provider; 15 | if (upgradeParameters.multiplierGas) { 16 | if (process.env.HARDHAT_NETWORK !== 'hardhat') { 17 | const { multiplierGas } = upgradeParameters; 18 | currentProvider = new ethers.providers.JsonRpcProvider(`https://${process.env.HARDHAT_NETWORK}.infura.io/v3/${process.env.INFURA_PROJECT_ID}`); 19 | async function overrideFeeData() { 20 | const feedata = await ethers.provider.getFeeData(); 21 | return { 22 | maxFeePerGas: feedata.maxFeePerGas.mul(multiplierGas), 23 | maxPriorityFeePerGas: feedata.maxPriorityFeePerGas.mul(multiplierGas), 24 | }; 25 | } 26 | currentProvider.getFeeData = overrideFeeData; 27 | } 28 | } 29 | 30 | // Check contract name existence 31 | for (const upgrade of upgradeParameters.upgrades) { 32 | await ethers.getContractFactory(upgrade.contractName); 33 | } 34 | 35 | let deployer; 36 | if (upgradeParameters.deployerPvtKey) { 37 | deployer = new ethers.Wallet(upgradeParameters.deployerPvtKey, currentProvider); 38 | } else if (process.env.MNEMONIC) { 39 | deployer = ethers.Wallet.fromMnemonic(process.env.MNEMONIC, 'm/44\'/60\'/0\'/0/0').connect(currentProvider); 40 | console.log('using mnemonic', deployer.address); 41 | } else { 42 | [deployer] = (await ethers.getSigners()); 43 | } 44 | // compìle contracts 45 | await hre.run('compile'); 46 | 47 | const proxyAdmin = await upgrades.admin.getInstance(); 48 | const output = []; 49 | 50 | // Upgrade zkevm 51 | for (const upgrade of upgradeParameters.upgrades) { 52 | const proxyPolygonAddress = upgrade.address; 53 | const polygonZkEVMFactory = await ethers.getContractFactory(upgrade.contractName, deployer); 54 | 55 | let newImplPolygonAddress; 56 | 57 | if (upgrade.constructorArgs) { 58 | newImplPolygonAddress = await upgrades.prepareUpgrade( 59 | proxyPolygonAddress, 60 | polygonZkEVMFactory, 61 | { 62 | constructorArgs: upgrade.constructorArgs, 63 | unsafeAllow: ['constructor', 'state-variable-immutable'], 64 | }, 65 | ); 66 | 67 | console.log({ newImplPolygonAddress }); 68 | console.log('you can verify the new impl address with:'); 69 | console.log(`npx hardhat verify --constructor-args upgrade/arguments.js ${newImplPolygonAddress} --network ${process.env.HARDHAT_NETWORK}\n`); 70 | console.log('Copy the following constructor arguments on: upgrade/arguments.js \n', upgrade.constructorArgs); 71 | } else { 72 | newImplPolygonAddress = await upgrades.prepareUpgrade(proxyPolygonAddress, polygonZkEVMFactory); 73 | 74 | console.log({ newImplPolygonAddress }); 75 | console.log('you can verify the new impl address with:'); 76 | console.log(`npx hardhat verify ${newImplPolygonAddress} --network ${process.env.HARDHAT_NETWORK}`); 77 | } 78 | 79 | // Use timelock 80 | const salt = upgradeParameters.timelockSalt || ethers.constants.HashZero; 81 | 82 | let operation; 83 | if (upgrade.callAfterUpgrade) { 84 | operation = genOperation( 85 | proxyAdmin.address, 86 | 0, // value 87 | proxyAdmin.interface.encodeFunctionData( 88 | 'upgradeAndCall', 89 | [ 90 | proxyPolygonAddress, 91 | newImplPolygonAddress, 92 | polygonZkEVMFactory.interface.encodeFunctionData( 93 | upgrade.callAfterUpgrade.functionName, 94 | upgrade.callAfterUpgrade.arguments, 95 | ), 96 | ], 97 | ), 98 | ethers.constants.HashZero, // predecesoor 99 | salt, // salt 100 | ); 101 | } else { 102 | operation = genOperation( 103 | proxyAdmin.address, 104 | 0, // value 105 | proxyAdmin.interface.encodeFunctionData( 106 | 'upgrade', 107 | [proxyPolygonAddress, 108 | newImplPolygonAddress], 109 | ), 110 | ethers.constants.HashZero, // predecesoor 111 | salt, // salt 112 | ); 113 | } 114 | 115 | // Timelock operations 116 | const TimelockFactory = await ethers.getContractFactory('PolygonZkEVMTimelock', deployer); 117 | const minDelay = upgradeParameters.timelockMinDelay || 0; 118 | 119 | // Schedule operation 120 | const scheduleData = TimelockFactory.interface.encodeFunctionData( 121 | 'schedule', 122 | [ 123 | operation.target, 124 | operation.value, 125 | operation.data, 126 | operation.predecessor, 127 | operation.salt, 128 | minDelay, 129 | ], 130 | ); 131 | // Execute operation 132 | const executeData = TimelockFactory.interface.encodeFunctionData( 133 | 'execute', 134 | [ 135 | operation.target, 136 | operation.value, 137 | operation.data, 138 | operation.predecessor, 139 | operation.salt, 140 | ], 141 | ); 142 | 143 | console.log({ scheduleData }); 144 | console.log({ executeData }); 145 | output.push({ 146 | contractName: upgrade.contractName, 147 | scheduleData, 148 | executeData, 149 | }); 150 | } 151 | 152 | fs.writeFileSync(pathOutputJson, JSON.stringify(output, null, 1)); 153 | } 154 | main() 155 | .then(() => process.exit(0)) 156 | .catch((error) => { 157 | console.error(error); 158 | process.exit(1); 159 | }); 160 | 161 | // OZ test functions 162 | function genOperation(target, value, data, predecessor, salt) { 163 | const id = ethers.utils.solidityKeccak256([ 164 | 'address', 165 | 'uint256', 166 | 'bytes', 167 | 'uint256', 168 | 'bytes32', 169 | ], [ 170 | target, 171 | value, 172 | data, 173 | predecessor, 174 | salt, 175 | ]); 176 | return { 177 | id, target, value, data, predecessor, salt, 178 | }; 179 | } 180 | -------------------------------------------------------------------------------- /upgrade/upgrade_parameters.json.example: -------------------------------------------------------------------------------- 1 | { 2 | "timelockMinDelay":10, 3 | "upgrades": [ 4 | { 5 | "address": "0xEfF10DB3c6445FB06411c6fc74fDCC8D1019aC7d", 6 | "contractName": "PolygonZkEVMTestnetV2", 7 | "constructorArgs": [ 8 | "0x6407cf296a27B38fd29c401518504D388F1DFB3d", 9 | "0xF1b13757bcF3EF902a7847f409A6068BA43a89D4", 10 | "0x4ceB990D2E2ee6d0e163fa80d12bac72C0F28D52", 11 | "0xcFA773Cc48FBde3CA4D24eeCb19D224d697026b2", 12 | 1440, 13 | 2 14 | ], 15 | "callAfterUpgrade": 16 | { 17 | "functionName": "updateVersion", 18 | "arguments": [ 19 | "v0.8.0.0-rc.2-forkid.2" 20 | ] 21 | } 22 | } 23 | ], 24 | "multiplierGas": 0, 25 | "deployerPvtKey": "", 26 | "timelockSalt": "" 27 | } -------------------------------------------------------------------------------- /verifyMainnetDeployment/mainnetDeployParameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "realVerifier": true, 3 | "trustedSequencerURL": "https://zkevm-rpc.com/", 4 | "networkName": "polygon zkEVM", 5 | "version": "v1.1.0-fork.4", 6 | "trustedSequencer": "0x148Ee7dAF16574cD020aFa34CC658f8F3fbd2800", 7 | "chainID": 1101, 8 | "trustedAggregator": "0xdA87c4a76922598Ac0272F4D9503a35071D686eA", 9 | "trustedAggregatorTimeout": 432000, 10 | "pendingStateTimeout": 432000, 11 | "forkID": 4, 12 | "admin": "0x242daE44F5d8fb54B198D03a94dA45B5a4413e21", 13 | "zkEVMOwner": "0x242daE44F5d8fb54B198D03a94dA45B5a4413e21", 14 | "timelockAddress": "0x4c1665d6651ecEfa59B9B3041951608468b18891", 15 | "minDelayTimelock": 864000, 16 | "salt": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa", 17 | "zkEVMDeployerAddress": "0xCB19eDdE626906eB1EE52357a27F62dd519608C2", 18 | "initialZkEVMDeployerOwner": "0x4c1665d6651ecEfa59B9B3041951608468b18891", 19 | "maticTokenAddress": "0x7D1AfA7B718fb893dB30A3aBc0Cfc608AaCfeBB0" 20 | } -------------------------------------------------------------------------------- /verifyMainnetDeployment/mainnetDeployment.json: -------------------------------------------------------------------------------- 1 | { 2 | "polygonZkEVMAddress": "0x5132A183E9F3CB7C848b0AAC5Ae0c4f0491B7aB2", 3 | "polygonZkEVMBridgeAddress": "0x2a3DD3EB832aF982ec71669E178424b10Dca2EDe", 4 | "polygonZkEVMGlobalExitRootAddress": "0x580bda1e7A0CFAe92Fa7F6c20A3794F169CE3CFb", 5 | "fflonkVerifierAddress": "0x4F9A0e7FD2Bf6067db6994CF12E4495Df938E6e9", 6 | "polygonZkEVMDeployerAddress": "0xCB19eDdE626906eB1EE52357a27F62dd519608C2", 7 | "polygonZkEVMTimelockAddress": "0xEf1462451C30Ea7aD8555386226059Fe837CA4EF", 8 | "genesisRoot": "0x3f86b09b43e3e49a41fc20a07579b79eba044253367817d5c241d23c0e2bc5c9" 9 | } -------------------------------------------------------------------------------- /verifyMainnetDeployment/verifyDeployment.md: -------------------------------------------------------------------------------- 1 | # Verify Deployment mainnet 2 | 3 | This document ins a guide in order to verify the mainnet smart contract deploymet of the zkEVM 4 | 5 | ## Basic OS preparation 6 | 7 | You should have a version of node: >16 (e.g. 18.14.0 ) 8 | If not you can execute the following commands: 9 | 10 | ```bash 11 | curl -sL https://deb.nodesource.com/setup_18.x -o nodesource_setup.sh 12 | sudo bash nodesource_setup.sh 13 | sudo apt install -y nodejs 14 | node -v 15 | ``` 16 | 17 | ## Download zkevm contracts repository 18 | 19 | DOwnload and install the zkevm-contracts repository and go to the specific commit 20 | 21 | ```bash 22 | git clone https://github.com/0xPolygonHermez/zkevm-contracts 23 | npm i 24 | git checkout 7a8d0c1950cf267fb7b10be8a47506754399cd4a 25 | ``` 26 | 27 | ## Verify deployment 28 | 29 | In order to verify the deployment, we will compare the deployed bytecode with the compiled locally. Some of the contracts use [`immutables`](https://docs.soliditylang.org/en/v0.8.19/contracts.html#immutable), in that case it's not enough to just compile the code and compare withthe deployed bytecode. 30 | The easiest way is to verify this contracts is to deploy them on a local enviroment and then compare the bytecodes of this contracts and the mainnet ones. 31 | 32 | In order to launch the script, you need a mainnet provider. 33 | In root of the project create a `.env` file you Infura api key information: 34 | 35 | ``` 36 | mkdir .env 37 | ``` 38 | 39 | `.env` file should contain something like: 40 | 41 | ``` 42 | INFURA_PROJECT_ID="s" 43 | ``` 44 | 45 | Now you can compile the contracts and run the script: 46 | 47 | ```bash 48 | npx hardhat compile 49 | node verifyMainnetDeployment/verifyMainnetDeployment.js 50 | ``` 51 | 52 | This script verifies the deployed bytecode of the address provided in `deploymentMainnet.json` 53 | 54 | ## Verify genesis root 55 | 56 | At the end of the previous script we also verify that the genesis provided in the`deploymentMainnet.json` matches hte one in the `polygonZkEVM` 57 | 58 | In order to verify the genesis, you can the script to generate it. The script in a very similar behaviour of the last script, deploy localy the contracts and then copy the deployed btyecode into the corresponding address. 59 | 60 | ```bash= 61 | node deployment/1_createGenesis.js --input ../verifyMainnetDeployment/mainnetDeployParameters.json --out ../verifyMainnetDeployment/genesis.json 62 | ``` 63 | 64 | Now a new file will be created in `verifyMainnetDeployment/genesis.json` 65 | Here you can check all the genesis information, and you can assert that the `root` generated matches the one on `mainnetDeployment.json` 66 | --------------------------------------------------------------------------------