├── .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 | [](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 |
--------------------------------------------------------------------------------