├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .prettierignore ├── .prettierrc.js ├── .solcover.js ├── .solhint.json ├── .solhintignore ├── README.md ├── common.ts ├── contracts ├── LineaRollup.sol ├── LineaRollupInit.sol ├── ProxyAdminReplica.sol ├── ZkEvmV2.sol ├── interfaces │ ├── IGenericErrors.sol │ ├── IMessageService.sol │ ├── IPauseManager.sol │ ├── IRateLimiter.sol │ ├── l1 │ │ ├── IL1MessageManager.sol │ │ ├── IL1MessageManagerV1.sol │ │ ├── IL1MessageService.sol │ │ ├── ILineaRollup.sol │ │ ├── IPlonkVerifier.sol │ │ └── IZkEvmV2.sol │ └── l2 │ │ ├── IL2MessageManager.sol │ │ └── IL2MessageManagerV1.sol ├── lib │ ├── Mimc.sol │ ├── SparseMerkleProof.sol │ └── Utils.sol ├── messageService │ ├── MessageServiceBase.sol │ ├── l1 │ │ ├── L1MessageManager.sol │ │ ├── L1MessageService.sol │ │ ├── TransientStorageReentrancyGuardUpgradeable.sol │ │ └── v1 │ │ │ ├── L1MessageManagerV1.sol │ │ │ └── L1MessageServiceV1.sol │ ├── l2 │ │ ├── L2MessageManager.sol │ │ ├── L2MessageService.sol │ │ └── v1 │ │ │ ├── L2MessageManagerV1.sol │ │ │ └── L2MessageServiceV1.sol │ └── lib │ │ ├── PauseManager.sol │ │ ├── RateLimiter.sol │ │ ├── SparseMerkleTreeVerifier.sol │ │ ├── TimeLock.sol │ │ └── TransientStorageHelpers.sol ├── proxies │ ├── ProxyAdmin.sol │ └── TransparentUpgradeableProxy.sol ├── test-contracts │ ├── L2MessageServiceLineaMainnet.sol │ ├── LineaRollupAlphaV3.sol │ ├── TestEIP4844.sol │ ├── TestL1MessageManager.sol │ ├── TestL1MessageService.sol │ ├── TestL1MessageServiceMerkleProof.sol │ ├── TestL1RevertContract.sol │ ├── TestL2MessageManager.sol │ ├── TestL2MessageService.sol │ ├── TestLineaRollup.sol │ ├── TestLineaSurgeXP.sol │ ├── TestMessageServiceBase.sol │ ├── TestPauseManager.sol │ ├── TestPublicInputVerifier.sol │ ├── TestRateLimiter.sol │ ├── TestReceivingContract.sol │ ├── TestSparseMerkleTreeVerifier.sol │ └── TestUtils.sol ├── token │ ├── ITokenMinter.sol │ ├── ITokenMintingRateLimiter.sol │ ├── LineaSurgeXP.sol │ ├── LineaVoyageXP.sol │ ├── MyToken.sol │ └── TokenMintingRateLimiter.sol ├── tokenBridge │ ├── BridgedToken.sol │ ├── CustomBridgedToken.sol │ ├── TokenBridge.sol │ ├── interfaces │ │ └── ITokenBridge.sol │ └── mocks │ │ ├── ERC20MintBurn.sol │ │ ├── ERC20NoNameMintBurn.sol │ │ ├── ERC20UnknownDecimals.sol │ │ ├── ERC20WeirdNameSymbol.sol │ │ ├── ERCFees.sol │ │ ├── MessageBridgeV2 │ │ └── MockMessageServiceV2.sol │ │ ├── MockMessageService.sol │ │ ├── MockTokenBridge.sol │ │ ├── Reentrancy │ │ ├── MaliciousERC777.sol │ │ └── ReentrancyContract.sol │ │ └── UpgradedBridgedToken.sol └── verifiers │ ├── PlonkVerifier.sol │ ├── PlonkVerifierDev.sol │ ├── PlonkVerifierForDataAggregation.sol │ ├── PlonkVerifierForMultiTypeDataAggregation.sol │ ├── PlonkVerifierFull.sol │ ├── PlonkVerifierFullLarge.sol │ ├── Utils.sol │ └── test │ ├── TestPlonkVerifier.sol │ ├── TestPlonkVerifierForDataAggregation.sol │ ├── TestPlonkVerifierFull.sol │ └── TestPlonkVerifierFullLarge.sol ├── deploy ├── 01_deploy_IntegrationTestTrueVerifier.ts ├── 02_deploy_PlonkVerifierDev.ts ├── 03_deploy_PlonkVerifierFull.ts ├── 04_deploy_PlonkVerifierForDataAggregation.ts ├── 04_deploy_PlonkVerifierForMultiTypeDataAggregation.ts ├── 04_deploy_PlonkVerifierFullLarge.ts ├── 05_deploy_Timelock.ts ├── 06_deploy_LineaRollup.ts ├── 06_deploy_LineaRollupAlphaV3.ts ├── 06_deploy_LineaRollupImplementation.ts ├── 06_deploy_LineaRollupWithReinitialization.ts ├── 07_deploy_L2MessageService.ts ├── 07_deploy_L2MessageServiceImplementation.ts ├── 07_deploy_L2MessageServiceV1Deployed.ts ├── 08_deploy_BridgedToken.ts ├── 09_deploy_TokenBridge.ts ├── 10_deploy_LXPToken.ts ├── 10_deploy_SurgeXPToken.ts ├── 11_deploy_CustomBridgedToken.ts ├── 11_deploy_MYToken.ts ├── 13_deploy_TestEIP4844.ts └── V1 │ ├── L2MessageServiceV1Cache │ └── validations.json │ ├── L2MessageServiceV1Deployed.json │ ├── ZkEvmV2Cache │ └── validations.json │ └── ZkEvmV2Deployed.json ├── deployments.json ├── docs ├── deployment.md ├── linea-token-bridge.md └── operational.md ├── gnosisZodiac.d.ts ├── hardhat.config.ts ├── package.json ├── pnpm-lock.yaml ├── scripts ├── cli.ts ├── gnosis │ ├── CreateSafeTransaction.ts │ ├── CreateSafeTransactionSetVerifier.ts │ ├── SafeABI.json │ ├── create4-8SafeL1.ts │ ├── create4-8SafeL2.ts │ ├── create5-8SafeL1.ts │ ├── create5-8SafeL2.ts │ ├── createSecurityCouncilSafeL1.ts │ ├── createSecurityCouncilSafeL2.ts │ ├── createZodiacL1.ts │ ├── createZodiacL2.ts │ ├── encodeProoflessOutput.ts │ ├── encodingTX.ts │ ├── encodingTx2.ts │ ├── increaseSafeThresholdL1.ts │ ├── increaseSafeThresholdL2.ts │ ├── prooflessExample.json │ └── queryContract.ts ├── hardhat │ ├── postCompile.ts │ └── utils.ts ├── testEIP4844 │ ├── MixAndMatch │ │ ├── aggregatedProof-1-114.json │ │ ├── blocks-1-46.json │ │ ├── blocks-47-81.json │ │ ├── blocks-82-114.json │ │ └── sendBlobTransaction.ts │ ├── SixInOne │ │ ├── aggregatedProof-1-206.json │ │ ├── blocks-1-46.json │ │ ├── blocks-115-155.json │ │ ├── blocks-156-175.json │ │ ├── blocks-176-206.json │ │ ├── blocks-47-81.json │ │ ├── blocks-82-114.json │ │ └── sendBlobTransaction.ts │ ├── ThreeByTwo │ │ ├── aggregatedProof-1-206.json │ │ ├── blocks-1-46.json │ │ ├── blocks-115-155.json │ │ ├── blocks-156-175.json │ │ ├── blocks-176-206.json │ │ ├── blocks-47-81.json │ │ ├── blocks-82-114.json │ │ └── sendBlobTransaction.ts │ ├── aggregatedProof-1-81.json │ ├── aggregatedProof-82-153.json │ ├── blocks-1-46.json │ ├── blocks-120-153.json │ ├── blocks-47-81.json │ ├── blocks-82-119.json │ ├── sendBlobTransaction.ts │ └── trusted_setup.txt ├── tokenBridge │ ├── gasEstimation │ │ └── gasEstimation.ts │ └── test │ │ ├── deployBridgedTokenBeacon.ts │ │ ├── deployMock.ts │ │ ├── deployTokenBridges.ts │ │ └── deployTokens.ts ├── upgrades │ ├── upgradeL2MessageService.ts │ ├── upgradeLineaRollup.ts │ ├── upgradeLineaRollupAlphaV3ToV4.ts │ ├── upgradeLineaRollup_no_reinitialisation.ts │ └── upgradeLineaRollup_with_reinitialisation.ts └── utils.ts ├── test ├── L1MessageService.ts ├── L2MessageManager.ts ├── L2MessageService.ts ├── LineaRollup.ts ├── LineaRollupInit.ts ├── LineaRollupNew.ts ├── LineaSurgeXP.ts ├── LineaVoyageXP.ts ├── MessageServiceBase.ts ├── PauseManager.ts ├── RateLimiter.ts ├── SparseMerkleProof.ts ├── Timelock.ts ├── TokenMintingRateLimiter.ts ├── Utils.ts ├── messageService │ ├── l1 │ │ └── L1MessageManager.ts │ └── lib │ │ └── SparseMerkleTreeVerifier.ts ├── mimc.ts ├── testData │ ├── .DS_Store │ ├── compressedData │ │ ├── aggregatedProof-1-155.json │ │ ├── blocks-1-46.json │ │ ├── blocks-115-155.json │ │ ├── blocks-47-81.json │ │ ├── blocks-82-114.json │ │ ├── multipleProofs │ │ │ ├── aggregatedProof-1-81.json │ │ │ ├── aggregatedProof-82-153.json │ │ │ ├── blocks-1-46.json │ │ │ ├── blocks-120-153.json │ │ │ ├── blocks-47-81.json │ │ │ └── blocks-82-119.json │ │ └── test │ │ │ ├── aggregatedProof-1-46.json │ │ │ └── blocks-1-46.json │ ├── compressedDataEip4844 │ │ ├── aggregatedProof-1-155.json │ │ ├── blocks-1-46.json │ │ ├── blocks-115-155.json │ │ ├── blocks-47-81.json │ │ ├── blocks-82-114.json │ │ ├── multipleProofs │ │ │ ├── aggregatedProof-1-81.json │ │ │ ├── aggregatedProof-82-153.json │ │ │ ├── blocks-1-46.json │ │ │ ├── blocks-120-153.json │ │ │ ├── blocks-47-81.json │ │ │ └── blocks-82-119.json │ │ └── test │ │ │ ├── aggregatedProof-1-46.json │ │ │ └── blocks-1-46.json │ ├── integrationWithProver │ │ ├── blobSubmissions │ │ │ ├── 1000501-1000503-bcv0.0.0-ccv0.0.0-getZkBlobCompressionProof.json │ │ │ ├── 1000504-1000505-bcv0.0.0-ccv0.0.0-getZkBlobCompressionProof.json │ │ │ ├── 1000506-1000507-bcv0.0.0-ccv0.0.0-getZkBlobCompressionProof.json │ │ │ ├── 1000508-1000512-bcv0.0.0-ccv0.0.0-getZkBlobCompressionProof.json │ │ │ ├── 1000513-1000518-bcv0.0.0-ccv0.0.0-getZkBlobCompressionProof.json │ │ │ ├── 1000519-1000522-bcv0.0.0-ccv0.0.0-getZkBlobCompressionProof.json │ │ │ ├── 1000523-1000528-bcv0.0.0-ccv0.0.0-getZkBlobCompressionProof.json │ │ │ ├── 1000529-1000530-bcv0.0.0-ccv0.0.0-getZkBlobCompressionProof.json │ │ │ ├── 1000531-1000536-bcv0.0.0-ccv0.0.0-getZkBlobCompressionProof.json │ │ │ ├── 1000537-1000538-bcv0.0.0-ccv0.0.0-getZkBlobCompressionProof.json │ │ │ ├── 1000539-1000544-bcv0.0.0-ccv0.0.0-getZkBlobCompressionProof.json │ │ │ ├── 1000545-1000548-bcv0.0.0-ccv0.0.0-getZkBlobCompressionProof.json │ │ │ ├── 1000549-1000550-bcv0.0.0-ccv0.0.0-getZkBlobCompressionProof.json │ │ │ ├── 1000551-1000554-bcv0.0.0-ccv0.0.0-getZkBlobCompressionProof.json │ │ │ ├── 1000555-1000560-bcv0.0.0-ccv0.0.0-getZkBlobCompressionProof.json │ │ │ ├── 1000561-1000563-bcv0.0.0-ccv0.0.0-getZkBlobCompressionProof.json │ │ │ ├── 1000564-1000565-bcv0.0.0-ccv0.0.0-getZkBlobCompressionProof.json │ │ │ ├── 1000566-1000571-bcv0.0.0-ccv0.0.0-getZkBlobCompressionProof.json │ │ │ ├── 1000572-1000576-bcv0.0.0-ccv0.0.0-getZkBlobCompressionProof.json │ │ │ ├── 1000577-1000580-bcv0.0.0-ccv0.0.0-getZkBlobCompressionProof.json │ │ │ ├── 1000581-1000586-bcv0.0.0-ccv0.0.0-getZkBlobCompressionProof.json │ │ │ ├── 1000587-1000588-bcv0.0.0-ccv0.0.0-getZkBlobCompressionProof.json │ │ │ ├── 1000589-1000592-bcv0.0.0-ccv0.0.0-getZkBlobCompressionProof.json │ │ │ ├── 1000593-1000594-bcv0.0.0-ccv0.0.0-getZkBlobCompressionProof.json │ │ │ └── 1000595-1000599-bcv0.0.0-ccv0.0.0-getZkBlobCompressionProof.json │ │ └── rolling-hash-history.json │ ├── merkle-proof-data.json │ ├── mimc-test-data.json │ └── test-transactions.json ├── tokenBridge │ ├── BridgedToken.ts │ ├── E2E.ts │ ├── TokenBridge.ts │ └── utils │ │ └── permitHelper.ts ├── upgrades │ ├── verify_L2MessageService_Upgrade.ts │ └── verify_LineaRollup_Upgrade.ts └── utils │ ├── constants.ts │ ├── deployment.ts │ ├── helpers.ts │ └── types.ts ├── tsconfig.json └── utils ├── auditedDeployVerifier.ts ├── deployments.ts ├── environmentHelper.ts ├── readAddress.ts ├── storeAddress.ts ├── supportedNetworks.ts └── verifyContract.ts /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build 3 | cache 4 | coverage 5 | typechain-types -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true, 5 | browser: false, 6 | es2022: true, 7 | }, 8 | ignorePatterns: ["dist", "coverage"], 9 | extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended", "plugin:prettier/recommended"], 10 | parser: "@typescript-eslint/parser", 11 | plugins: ["@typescript-eslint", "prettier"], 12 | parserOptions: { 13 | ecmaVersion: 12, 14 | sourceType: "module", 15 | }, 16 | }; 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | coverage 4 | coverage.json 5 | typechain 6 | typechain-types 7 | cache 8 | build 9 | .openzeppelin 10 | 11 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build 3 | cache 4 | coverage* 5 | gasReporterOutput.json 6 | typechain-types 7 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | /** @type {import("prettier").Config} */ 2 | module.exports = { 3 | trailingComma: "all", 4 | tabWidth: 2, 5 | semi: true, 6 | singleQuote: false, 7 | printWidth: 120, 8 | bracketSpacing: true, 9 | plugins: ["prettier-plugin-solidity"], 10 | overrides: [ 11 | { 12 | files: "*.sol", 13 | options: { 14 | parser: "solidity-parse", 15 | bracketSpacing: true, 16 | printWidth: 120, 17 | singleQuote: false, 18 | tabWidth: 2, 19 | useTabs: false, 20 | }, 21 | }, 22 | ], 23 | }; 24 | -------------------------------------------------------------------------------- /.solcover.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | skipFiles: ["test-contracts", "verifiers/test"], 3 | }; 4 | -------------------------------------------------------------------------------- /.solhint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "solhint:recommended", 3 | "rules": { 4 | "compiler-version": ["error", "^0.8.0"], 5 | "func-visibility": ["warn", { "ignoreConstructors": true }], 6 | "no-inline-assembly": "off", 7 | "var-name-mixedcase": "off", 8 | "const-name-snakecase": "off", 9 | "func-name-mixedcase": "off", 10 | "state-visibility": "off", 11 | "no-empty-blocks": "off", 12 | "avoid-low-level-calls": "off", 13 | "reason-string": "off", 14 | "check-send-result": "off", 15 | "no-unused-import": ["error"], 16 | "gas-custom-errors": "off" 17 | } 18 | } -------------------------------------------------------------------------------- /.solhintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | contracts/test-contracts -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # linea-contracts 2 | 3 | ## Audits 4 | ### Fourth Audit Round (Latest) 5 | 6 | **Open Zeppelin** 7 | - Gas optimization audit: https://blog.openzeppelin.com/linea-gas-optimizations-audit 8 | 9 | 10 | ### Third Audit Round 11 | **Open Zeppelin** 12 | 13 | - Blob submission audit: https://blog.openzeppelin.com/linea-blob-submission-audit 14 | 15 | ### Second Audit Round 16 | 17 | **Diligence** 18 | - Proof aggregation, data compression and message service updates Audit: https://consensys.io/diligence/audits/2024/01/linea-contracts-update/ 19 | 20 | **Open Zeppelin** 21 | 22 | - Proof aggregation, data compression and message service updates Audit: https://blog.openzeppelin.com/linea-v2-audit 23 | 24 | ### First Audit Round 25 | 26 | **Diligence** 27 | 28 | - Plonk Verifier: https://consensys.io/diligence/audits/2023/06/linea-plonk-verifier/ 29 | - Message Service & Rollup: https://consensys.io/diligence/audits/2023/06/linea-message-service/ 30 | - Canonical Token Bridge: https://consensys.io/diligence/audits/2023/06/linea-canonical-token-bridge/ 31 | 32 | **Open Zeppelin** 33 | 34 | - Linea Bridge Audit: https://blog.openzeppelin.com/linea-bridge-audit-1 35 | - Linea Verifier Audit: https://blog.openzeppelin.com/linea-verifier-audit-1 36 | 37 | 38 | 39 | --- 40 | 41 | ## Installation and testing 42 | 43 | To run the solution's tests, coverage and gas reporting, be sure to install pnpm and then 44 | ``` 45 | # Install all the dependencies 46 | 47 | pnpm install 48 | 49 | pnpm run test 50 | 51 | pnpm run test:reportgas 52 | 53 | pnpm run coverage 54 | ``` -------------------------------------------------------------------------------- /common.ts: -------------------------------------------------------------------------------- 1 | const MAX_GAS_LIMIT = process.env.TX_GAS_LIMIT ? parseInt(process.env.TX_GAS_LIMIT) : 500000000; 2 | 3 | function getBlockchainNode(): string { 4 | return process.env.BLOCKCHAIN_NODE || "http://127.0.0.1:8545"; 5 | } 6 | 7 | function getL2BlockchainNode(): string | undefined { 8 | return process.env.L2_BLOCKCHAIN_NODE; 9 | } 10 | 11 | export { MAX_GAS_LIMIT, getBlockchainNode, getL2BlockchainNode }; 12 | -------------------------------------------------------------------------------- /contracts/LineaRollupInit.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity 0.8.24; 3 | 4 | import { LineaRollup } from "./LineaRollup.sol"; 5 | 6 | /** 7 | * @title Contract to reinitialize cross-chain messaging on L1 and rollup proving. 8 | * @author ConsenSys Software Inc. 9 | * @dev Init indicates it is an initializer contract 10 | * @custom:security-contact security-report@linea.build 11 | */ 12 | contract LineaRollupInit is LineaRollup { 13 | /** 14 | * @notice Reinitializes LineaRollup and underlying service dependencies. 15 | * @param _initialStateRootHash The initial hash at migration used for proof verification. 16 | * @param _initialL2BlockNumber The initial block number at migration. 17 | */ 18 | function initializeV2(uint256 _initialL2BlockNumber, bytes32 _initialStateRootHash) external reinitializer(3) { 19 | currentL2BlockNumber = _initialL2BlockNumber; 20 | stateRootHashes[_initialL2BlockNumber] = _initialStateRootHash; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /contracts/ProxyAdminReplica.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // OpenZeppelin Contracts (last updated v4.8.3) (proxy/transparent/ProxyAdmin.sol) 3 | 4 | pragma solidity ^0.8.0; 5 | 6 | /** 7 | * @dev This is only for operational scripts. Do not use for anything else. 8 | @dev This generates an artefact and contract types in order to use when transferring ownership. 9 | */ 10 | contract ProxyAdminReplica { 11 | function transferOwnership(address newOwner) public {} 12 | } 13 | -------------------------------------------------------------------------------- /contracts/ZkEvmV2.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity 0.8.24; 3 | 4 | import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; 5 | import { AccessControlUpgradeable } from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; 6 | import { L1MessageServiceV1 } from "./messageService/l1/v1/L1MessageServiceV1.sol"; 7 | import { IZkEvmV2 } from "./interfaces/l1/IZkEvmV2.sol"; 8 | import { IPlonkVerifier } from "./interfaces/l1/IPlonkVerifier.sol"; 9 | 10 | /** 11 | * @title Contract to manage cross-chain messaging on L1 and rollup proving. 12 | * @author ConsenSys Software Inc. 13 | * @custom:security-contact security-report@linea.build 14 | */ 15 | abstract contract ZkEvmV2 is Initializable, AccessControlUpgradeable, L1MessageServiceV1, IZkEvmV2 { 16 | uint256 internal constant MODULO_R = 21888242871839275222246405745257275088548364400416034343698204186575808495617; 17 | bytes32 public constant OPERATOR_ROLE = keccak256("OPERATOR_ROLE"); 18 | 19 | /// @dev DEPRECATED in favor of currentFinalizedState hash. 20 | uint256 public currentTimestamp; 21 | 22 | uint256 public currentL2BlockNumber; 23 | 24 | mapping(uint256 blockNumber => bytes32 stateRootHash) public stateRootHashes; 25 | mapping(uint256 proofType => address verifierAddress) public verifiers; 26 | 27 | /// @dev Total contract storage is 54 slots with the gap below. 28 | /// @dev Keep 50 free storage slots for future implementation updates to avoid storage collision. 29 | uint256[50] private __gap; 30 | 31 | /** 32 | * @notice Verifies the proof with locally computed public inputs. 33 | * @dev If the verifier based on proof type is not found, it reverts with InvalidProofType. 34 | * @param _publicInputHash The full BlockData collection - block, transaction and log data. 35 | * @param _proofType The proof type to determine which verifier contract to use. 36 | * @param _proof The proof to be verified with the proof type verifier contract. 37 | * @param _parentStateRootHash The beginning roothash to start with. 38 | * @param _finalizedL2BlockNumber The final L2 block number being finalized. 39 | * @param _finalStateRootHash The state root finalized up until. 40 | */ 41 | function _verifyProof( 42 | uint256 _publicInputHash, 43 | uint256 _proofType, 44 | bytes calldata _proof, 45 | bytes32 _parentStateRootHash, 46 | uint256 _finalizedL2BlockNumber, 47 | bytes32 _finalStateRootHash 48 | ) internal { 49 | uint256[] memory input = new uint256[](1); 50 | input[0] = _publicInputHash; 51 | 52 | address verifierToUse = verifiers[_proofType]; 53 | 54 | if (verifierToUse == address(0)) { 55 | revert InvalidProofType(); 56 | } 57 | 58 | bool success = IPlonkVerifier(verifierToUse).Verify(_proof, input); 59 | if (!success) { 60 | revert InvalidProof(); 61 | } 62 | 63 | emit BlocksVerificationDone(_finalizedL2BlockNumber, _parentStateRootHash, _finalStateRootHash); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /contracts/interfaces/IGenericErrors.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | pragma solidity >=0.8.19 <=0.8.24; 3 | 4 | /** 5 | * @title Interface declaring generic errors. 6 | * @author ConsenSys Software Inc. 7 | * @custom:security-contact security-report@linea.build 8 | */ 9 | interface IGenericErrors { 10 | /** 11 | * @dev Thrown when a parameter is the zero address. 12 | */ 13 | error ZeroAddressNotAllowed(); 14 | } 15 | -------------------------------------------------------------------------------- /contracts/interfaces/IPauseManager.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | pragma solidity >=0.8.19 <=0.8.24; 3 | 4 | /** 5 | * @title Interface declaring pre-existing pausing functions, events and errors. 6 | * @author ConsenSys Software Inc. 7 | * @custom:security-contact security-report@linea.build 8 | */ 9 | interface IPauseManager { 10 | /** 11 | * @notice Emitted when a pause type is paused. 12 | * @param messageSender The address performing the pause. 13 | * @param pauseType The indexed pause type that was paused. 14 | */ 15 | event Paused(address messageSender, uint256 indexed pauseType); 16 | 17 | /** 18 | * @notice Emitted when a pause type is unpaused. 19 | * @param messageSender The address performing the unpause. 20 | * @param pauseType The indexed pause type that was unpaused. 21 | */ 22 | event UnPaused(address messageSender, uint256 indexed pauseType); 23 | 24 | /** 25 | * @dev Thrown when a specific pause type is paused. 26 | */ 27 | error IsPaused(uint256 pauseType); 28 | 29 | /** 30 | * @dev Thrown when a specific pause type is not paused and expected to be. 31 | */ 32 | error IsNotPaused(uint256 pauseType); 33 | } 34 | -------------------------------------------------------------------------------- /contracts/interfaces/IRateLimiter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | pragma solidity >=0.8.19 <=0.8.24; 3 | 4 | /** 5 | * @title Interface declaring rate limiting messaging functions, events and errors. 6 | * @author ConsenSys Software Inc. 7 | * @custom:security-contact security-report@linea.build 8 | */ 9 | interface IRateLimiter { 10 | /** 11 | * @notice Emitted when the Rate Limit is initialized. 12 | * @param periodInSeconds The time period in seconds the rate limiter has been initialized to. 13 | * @param limitInWei The limit in Wei the rate limiter has been initialized to. 14 | * @param currentPeriodEnd The time the current rate limit period will end. 15 | */ 16 | event RateLimitInitialized(uint256 periodInSeconds, uint256 limitInWei, uint256 currentPeriodEnd); 17 | 18 | /** 19 | * @notice Emitted when the amount in the period is reset to zero. 20 | * @param resettingAddress The indexed address of who reset the used amount back to zero. 21 | */ 22 | event AmountUsedInPeriodReset(address indexed resettingAddress); 23 | 24 | /** 25 | * @notice Emitted when the limit is changed. 26 | * @param amountChangeBy The indexed address of who changed the rate limit. 27 | * @param amount The rate limited amount in Wei that was set. 28 | * @param amountUsedLoweredToLimit Indicates if the amount used was lowered to the limit to avoid confusion. 29 | * @param usedAmountResetToZero Indicates if the amount used was set to zero because of the current period expiring. 30 | * @dev If the current used amount is higher than the new limit, the used amount is lowered to the limit. 31 | * @dev amountUsedLoweredToLimit and usedAmountResetToZero cannot be true at the same time. 32 | */ 33 | event LimitAmountChanged( 34 | address indexed amountChangeBy, 35 | uint256 amount, 36 | bool amountUsedLoweredToLimit, 37 | bool usedAmountResetToZero 38 | ); 39 | 40 | /** 41 | * @dev Thrown when an amount breaches the limit in the period. 42 | */ 43 | error RateLimitExceeded(); 44 | 45 | /** 46 | * @dev Thrown when the period is initialised to zero. 47 | */ 48 | error PeriodIsZero(); 49 | 50 | /** 51 | * @dev Thrown when the limit is initialised to zero. 52 | */ 53 | error LimitIsZero(); 54 | 55 | /** 56 | * @notice Resets the rate limit amount to the amount specified. 57 | * @param _amount sets the new limit amount. 58 | */ 59 | function resetRateLimitAmount(uint256 _amount) external; 60 | 61 | /** 62 | * @notice Resets the amount used in the period to zero. 63 | */ 64 | function resetAmountUsedInPeriod() external; 65 | } 66 | -------------------------------------------------------------------------------- /contracts/interfaces/l1/IL1MessageManager.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity 0.8.24; 3 | 4 | /** 5 | * @title L1 Message manager interface for current functions, events and errors. 6 | * @author ConsenSys Software Inc. 7 | * @custom:security-contact security-report@linea.build 8 | */ 9 | interface IL1MessageManager { 10 | /** 11 | * @notice Emitted when a new message is sent and the rolling hash updated. 12 | * @param messageNumber The unique indexed message number for the message. 13 | * @param rollingHash The indexed rolling hash computed for the current message number. 14 | * @param messageHash The indexed hash of the message parameters. 15 | */ 16 | event RollingHashUpdated(uint256 indexed messageNumber, bytes32 indexed rollingHash, bytes32 indexed messageHash); 17 | 18 | /** 19 | * @notice Emitted when the L2 merkle root has been anchored on L1. 20 | * @param l2MerkleRoot The indexed L2 Merkle root that has been anchored on L1 Ethereum. 21 | * @param treeDepth The indexed tree depth of the Merkle root. 22 | * @dev There may be more than one of these in a finalization depending on the amount of L2->L1 messages in the finalization. 23 | */ 24 | event L2MerkleRootAdded(bytes32 indexed l2MerkleRoot, uint256 indexed treeDepth); 25 | 26 | /** 27 | * @notice Emitted when the l2 block contains L2 messages during finalization. 28 | * @param l2Block The indexed L2 block containing L2 to L1 messages. 29 | * @dev This is used externally in the logic for determining which messages belong to which Merkle root when claiming. 30 | */ 31 | event L2MessagingBlockAnchored(uint256 indexed l2Block); 32 | 33 | /** 34 | * @dev Thrown when the message has already been claimed. 35 | */ 36 | error MessageAlreadyClaimed(uint256 messageIndex); 37 | 38 | /** 39 | * @dev Thrown when the L2 merkle root has already been anchored on L1. 40 | */ 41 | error L2MerkleRootAlreadyAnchored(bytes32 merkleRoot); 42 | 43 | /** 44 | * @dev Thrown when the L2 messaging blocks offsets bytes length is not a multiple of 2. 45 | */ 46 | error BytesLengthNotMultipleOfTwo(uint256 bytesLength); 47 | 48 | /** 49 | * @notice Check if the L2->L1 message is claimed or not. 50 | * @param _messageNumber The message number on L2. 51 | */ 52 | function isMessageClaimed(uint256 _messageNumber) external view returns (bool); 53 | } 54 | -------------------------------------------------------------------------------- /contracts/interfaces/l1/IL1MessageManagerV1.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | pragma solidity 0.8.24; 3 | 4 | /** 5 | * @title L1 Message manager V1 interface for pre-existing functions, events and errors. 6 | * @author ConsenSys Software Inc. 7 | * @custom:security-contact security-report@linea.build 8 | */ 9 | interface IL1MessageManagerV1 { 10 | /** 11 | * @notice Emitted when L2->L1 message hashes have been added to L1 storage. 12 | * @param messageHash The indexed hash of the message parameters. 13 | * @dev DEPRECATED - This is kept for backwards compatability for external consumers. 14 | */ 15 | event L2L1MessageHashAddedToInbox(bytes32 indexed messageHash); 16 | 17 | /** 18 | * @notice Emitted when L1->L2 messages have been anchored on L2 and updated on L1. 19 | * @param messageHashes The collection of hashes indicating which messages were added on L2. of the message parameters. 20 | * @dev DEPRECATED - This is kept for backwards compatability for external consumers. 21 | */ 22 | event L1L2MessagesReceivedOnL2(bytes32[] messageHashes); 23 | 24 | /** 25 | * @dev Thrown when the message has already been claimed. 26 | */ 27 | error MessageDoesNotExistOrHasAlreadyBeenClaimed(bytes32 messageHash); 28 | } 29 | -------------------------------------------------------------------------------- /contracts/interfaces/l1/IL1MessageService.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | pragma solidity 0.8.24; 3 | 4 | /** 5 | * @title L1 Message Service interface for pre-existing functions, events and errors. 6 | * @author ConsenSys Software Inc. 7 | * @custom:security-contact security-report@linea.build 8 | */ 9 | 10 | interface IL1MessageService { 11 | /** 12 | * @param proof The proof array related to the claimed message. 13 | * @param messageNumber The message number of the claimed message. 14 | * @param leafIndex The leaf index related to the merkle proof of the message. 15 | * @param from The address of the original sender. 16 | * @param to The address the message is intended for. 17 | * @param fee The fee being paid for the message delivery. 18 | * @param value The value to be transferred to the destination address. 19 | * @param feeRecipient The recipient for the fee. 20 | * @param merkleRoot The merkle root of the claimed message. 21 | * @param data The calldata to pass to the recipient. 22 | */ 23 | struct ClaimMessageWithProofParams { 24 | bytes32[] proof; 25 | uint256 messageNumber; 26 | uint32 leafIndex; 27 | address from; 28 | address to; 29 | uint256 fee; 30 | uint256 value; 31 | address payable feeRecipient; 32 | bytes32 merkleRoot; 33 | bytes data; 34 | } 35 | 36 | /** 37 | * @notice Emitted when initializing Linea Rollup contract with a system migration block. 38 | */ 39 | event SystemMigrationBlockInitialized(uint256 systemMigrationBlock); 40 | /** 41 | * @dev Thrown when L2 merkle root does not exist. 42 | */ 43 | error L2MerkleRootDoesNotExist(); 44 | 45 | /** 46 | * @dev Thrown when the merkle proof is invalid. 47 | */ 48 | error InvalidMerkleProof(); 49 | 50 | /** 51 | * @dev Thrown when merkle depth doesn't match proof length. 52 | */ 53 | error ProofLengthDifferentThanMerkleDepth(uint256 actual, uint256 expected); 54 | } 55 | -------------------------------------------------------------------------------- /contracts/interfaces/l1/IPlonkVerifier.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | pragma solidity 0.8.24; 3 | 4 | /** 5 | * @title Interface declaring verifier functions. 6 | * @author ConsenSys Software Inc. 7 | * @custom:security-contact security-report@linea.build 8 | */ 9 | interface IPlonkVerifier { 10 | /** 11 | * @notice Interface for verifier contracts. 12 | * @param _proof The proof used to verify. 13 | * @param _public_inputs The computed public inputs for the proof verification. 14 | */ 15 | function Verify(bytes calldata _proof, uint256[] calldata _public_inputs) external returns (bool); 16 | } 17 | -------------------------------------------------------------------------------- /contracts/interfaces/l1/IZkEvmV2.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | pragma solidity 0.8.24; 3 | 4 | /** 5 | * @title ZkEvm rollup interface for pre-existing functions, events and errors. 6 | * @author ConsenSys Software Inc. 7 | * @custom:security-contact security-report@linea.build 8 | */ 9 | interface IZkEvmV2 { 10 | /** 11 | * @notice Emitted when a L2 block has been finalized on L1. 12 | * @param blockNumber The indexed L2 block number that is finalized in the finalization. 13 | * @param stateRootHash The indexed state root hash for the L2 block. 14 | * @param finalizedWithProof Indicates if the L2 block in the finalization is proven or not. 15 | * @dev DEPRECATED. This has been left for existing consumers. 16 | */ 17 | event BlockFinalized(uint256 indexed blockNumber, bytes32 indexed stateRootHash, bool indexed finalizedWithProof); 18 | 19 | /** 20 | * @notice Emitted when a L2 blocks have been finalized on L1. 21 | * @param lastBlockFinalized The indexed L2 block number the finalization is up until. 22 | * @param startingRootHash The state root hash the finalization started from. This is the last finalized block's state root. 23 | * @param finalRootHash The L2 block state root hash the finalization ended on. 24 | */ 25 | event BlocksVerificationDone(uint256 indexed lastBlockFinalized, bytes32 startingRootHash, bytes32 finalRootHash); 26 | 27 | /** 28 | * @dev Thrown when the starting rootHash does not match the existing state 29 | */ 30 | error StartingRootHashDoesNotMatch(); 31 | 32 | /** 33 | * @dev Thrown when zk proof is empty bytes 34 | */ 35 | error ProofIsEmpty(); 36 | 37 | /** 38 | * @dev Thrown when zk proof type is invalid 39 | */ 40 | error InvalidProofType(); 41 | 42 | /** 43 | * @dev Thrown when zk proof is invalid 44 | */ 45 | error InvalidProof(); 46 | } 47 | -------------------------------------------------------------------------------- /contracts/interfaces/l2/IL2MessageManager.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | pragma solidity 0.8.19; 3 | 4 | /** 5 | * @title Interface declaring cross-chain messaging on L2 functions, events and errors. 6 | * @author ConsenSys Software Inc. 7 | * @custom:security-contact security-report@linea.build 8 | */ 9 | interface IL2MessageManager { 10 | /** 11 | * @notice Emitted after all messages are anchored on L2 and the latest message index rolling hash stored. 12 | * @param messageNumber The unique L1 computed indexed message number for the message. 13 | * @param rollingHash The indexed L1 rolling hash computed for the current message number. 14 | * @dev NB: This event is used to provide data to the rollup. The last messageNumber and rollingHash, 15 | * emitted in a rollup will be used in the public input for validating the L1->L2 messaging state transition. 16 | */ 17 | event RollingHashUpdated(uint256 indexed messageNumber, bytes32 indexed rollingHash); 18 | 19 | /** 20 | * @dev Reverts when message number synchronization is mismatched. 21 | */ 22 | error L1MessageNumberSynchronizationWrong(uint256 expected, uint256 found); 23 | 24 | /** 25 | * @dev Reverts when rolling hash synchronization is mismatched. 26 | */ 27 | error L1RollingHashSynchronizationWrong(bytes32 expected, bytes32 found); 28 | 29 | /** 30 | * @dev Reverts when final rolling hash is zero hash. 31 | */ 32 | error FinalRollingHashIsZero(); 33 | 34 | /** 35 | * @dev Emitted when the service switches over to a new version. 36 | * @dev This is currently not in use, but left for future migrations and for existing consumers. 37 | */ 38 | event ServiceVersionMigrated(uint256 indexed version); 39 | 40 | /** 41 | * @notice Anchor L1-> L2 message hashes with expected message number and rolling hash. 42 | * @dev Reverts if computed rolling hash and ending message number don't match. 43 | * @param _messageHashes New message hashes to anchor on L2. 44 | * @param _startingMessageNumber The expected L1 message number to start when anchoring. 45 | * @param _finalMessageNumber The expected L1 message number to end on when anchoring. 46 | * @param _finalRollingHash The expected L1 rolling hash to end on when anchoring. 47 | */ 48 | function anchorL1L2MessageHashes( 49 | bytes32[] calldata _messageHashes, 50 | uint256 _startingMessageNumber, 51 | uint256 _finalMessageNumber, 52 | bytes32 _finalRollingHash 53 | ) external; 54 | } 55 | -------------------------------------------------------------------------------- /contracts/interfaces/l2/IL2MessageManagerV1.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | pragma solidity 0.8.19; 3 | 4 | /** 5 | * @title Interface declaring pre-existing cross-chain messaging on L2 functions, events and errors. 6 | * @author ConsenSys Software Inc. 7 | * @custom:security-contact security-report@linea.build 8 | */ 9 | interface IL2MessageManagerV1 { 10 | /** 11 | * @notice Emitted when L2 minimum fee is changed. 12 | * @param previousMinimumFee The previous minimum fee in Wei. 13 | * @param newMinimumFee The new minimum fee in Wei. 14 | * @param calledBy The indexed address who changed the minimum fee. 15 | */ 16 | event MinimumFeeChanged(uint256 previousMinimumFee, uint256 newMinimumFee, address indexed calledBy); 17 | 18 | /** 19 | * @notice Emitted when L1->L2 message hashes have been added to L2 storage. 20 | * @param messageHashes The message hashes that were added to L2 for claiming. 21 | */ 22 | event L1L2MessageHashesAddedToInbox(bytes32[] messageHashes); 23 | 24 | /** 25 | * @dev Thrown when the message hashes list length is higher than one hundred. 26 | */ 27 | error MessageHashesListLengthHigherThanOneHundred(uint256 length); 28 | 29 | /** 30 | * @dev Thrown when the message does not exist or has already been claimed. 31 | */ 32 | error MessageDoesNotExistOrHasAlreadyBeenClaimed(bytes32 messageHash); 33 | } 34 | -------------------------------------------------------------------------------- /contracts/lib/Utils.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity >=0.8.19 <=0.8.24; 3 | 4 | library Utils { 5 | /** 6 | * @notice Performs a gas optimized keccak hash. 7 | * @param _left Left value. 8 | * @param _right Right value. 9 | */ 10 | function _efficientKeccak(bytes32 _left, bytes32 _right) internal pure returns (bytes32 value) { 11 | /// @solidity memory-safe-assembly 12 | assembly { 13 | mstore(0x00, _left) 14 | mstore(0x20, _right) 15 | value := keccak256(0x00, 0x40) 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /contracts/messageService/MessageServiceBase.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | pragma solidity >=0.8.19 <=0.8.24; 3 | 4 | import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; 5 | import { IMessageService } from "../interfaces/IMessageService.sol"; 6 | import { IGenericErrors } from "../interfaces/IGenericErrors.sol"; 7 | 8 | /** 9 | * @title Base contract to manage cross-chain messaging. 10 | * @author ConsenSys Software Inc. 11 | * @custom:security-contact security-report@linea.build 12 | */ 13 | abstract contract MessageServiceBase is Initializable, IGenericErrors { 14 | IMessageService public messageService; 15 | address public remoteSender; 16 | 17 | /// @dev Total contract storage is 12 slots with the gap below. 18 | /// @dev Keep 10 free storage slots for future implementation updates to avoid storage collision. 19 | uint256[10] private __base_gap; 20 | 21 | /** 22 | * @dev Thrown when the caller address is not the message service address 23 | */ 24 | error CallerIsNotMessageService(); 25 | 26 | /** 27 | * @dev Thrown when remote sender address is not authorized. 28 | */ 29 | error SenderNotAuthorized(); 30 | 31 | /** 32 | * @dev Modifier to make sure the caller is the known message service. 33 | * 34 | * Requirements: 35 | * 36 | * - The msg.sender must be the message service. 37 | */ 38 | modifier onlyMessagingService() { 39 | if (msg.sender != address(messageService)) { 40 | revert CallerIsNotMessageService(); 41 | } 42 | _; 43 | } 44 | 45 | /** 46 | * @dev Modifier to make sure the original sender is allowed. 47 | * 48 | * Requirements: 49 | * 50 | * - The original message sender via the message service must be a known sender. 51 | */ 52 | modifier onlyAuthorizedRemoteSender() { 53 | if (messageService.sender() != remoteSender) { 54 | revert SenderNotAuthorized(); 55 | } 56 | _; 57 | } 58 | 59 | /** 60 | * @notice Initializes the message service 61 | * @dev Must be initialized in the initialize function of the main contract or constructor 62 | * @param _messageService The message service address, cannot be empty. 63 | */ 64 | function __MessageServiceBase_init(address _messageService) internal onlyInitializing { 65 | if (_messageService == address(0)) { 66 | revert ZeroAddressNotAllowed(); 67 | } 68 | 69 | messageService = IMessageService(_messageService); 70 | } 71 | 72 | /** 73 | * @notice Sets the remote sender 74 | * @param _remoteSender The authorized remote sender address, cannot be empty. 75 | */ 76 | function _setRemoteSender(address _remoteSender) internal { 77 | if (_remoteSender == address(0)) { 78 | revert ZeroAddressNotAllowed(); 79 | } 80 | 81 | remoteSender = _remoteSender; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /contracts/messageService/l1/TransientStorageReentrancyGuardUpgradeable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity 0.8.24; 3 | 4 | import { TransientStorageHelpers } from "../lib/TransientStorageHelpers.sol"; 5 | 6 | /** 7 | * @title Contract that helps prevent reentrant calls. 8 | * @author ConsenSys Software Inc. 9 | * @custom:security-contact security-report@linea.build 10 | */ 11 | abstract contract TransientStorageReentrancyGuardUpgradeable { 12 | using TransientStorageHelpers for *; 13 | 14 | bytes32 private constant REENTRANCY_GUARD_TRANSIENT_KEY = 15 | bytes32(uint256(keccak256("eip1967.reentrancy.guard.transient.key")) - 1); 16 | 17 | uint256 private constant NOT_ENTERED = 0; 18 | uint256 private constant ENTERED = 1; 19 | 20 | error ReentrantCall(); 21 | 22 | /// @dev This gap is used to not shift down the storage layout after removing the OpenZeppelin ReentrancyGuardUpgradeable contract. 23 | uint256[50] private __gap_ReentrancyGuardUpgradeable; 24 | 25 | modifier nonReentrant() { 26 | _nonReentrantBefore(); 27 | _; 28 | _nonReentrantAfter(); 29 | } 30 | 31 | /** 32 | * @notice Checks reentrancy and if not reentrant sets the transient reentry flag. 33 | * @dev This uses the TransientStorageHelpers library and REENTRANCY_GUARD_TRANSIENT_KEY. 34 | */ 35 | function _nonReentrantBefore() private { 36 | if (TransientStorageHelpers.tloadUint256(REENTRANCY_GUARD_TRANSIENT_KEY) != NOT_ENTERED) { 37 | revert ReentrantCall(); 38 | } 39 | 40 | TransientStorageHelpers.tstoreUint256(REENTRANCY_GUARD_TRANSIENT_KEY, ENTERED); 41 | } 42 | 43 | /** 44 | * @notice Clears reentry transient storage flag. 45 | * @dev This uses the TransientStorageHelpers library and REENTRANCY_GUARD_TRANSIENT_KEY. 46 | */ 47 | function _nonReentrantAfter() private { 48 | TransientStorageHelpers.tstoreUint256(REENTRANCY_GUARD_TRANSIENT_KEY, NOT_ENTERED); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /contracts/messageService/l1/v1/L1MessageManagerV1.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity 0.8.24; 3 | 4 | import { IL1MessageManagerV1 } from "../../../interfaces/l1/IL1MessageManagerV1.sol"; 5 | 6 | /** 7 | * @title Contract to manage cross-chain message hashes storage and status on L1. 8 | * @author ConsenSys Software Inc. 9 | * @custom:security-contact security-report@linea.build 10 | */ 11 | abstract contract L1MessageManagerV1 is IL1MessageManagerV1 { 12 | uint8 public constant INBOX_STATUS_UNKNOWN = 0; 13 | uint8 public constant INBOX_STATUS_RECEIVED = 1; 14 | 15 | uint8 public constant OUTBOX_STATUS_UNKNOWN = 0; 16 | uint8 public constant OUTBOX_STATUS_SENT = 1; 17 | uint8 public constant OUTBOX_STATUS_RECEIVED = 2; 18 | 19 | /// @dev Mapping to store L1->L2 message hashes status. 20 | /// @dev messageHash => messageStatus (0: unknown, 1: sent, 2: received). 21 | mapping(bytes32 messageHash => uint256 messageStatus) public outboxL1L2MessageStatus; 22 | 23 | /// @dev Mapping to store L2->L1 message hashes status. 24 | /// @dev messageHash => messageStatus (0: unknown, 1: received). 25 | mapping(bytes32 messageHash => uint256 messageStatus) public inboxL2L1MessageStatus; 26 | 27 | /// @dev Keep free storage slots for future implementation updates to avoid storage collision. 28 | // ******************************************************************************************* 29 | // NB: THIS GAP HAS BEEN PUSHED OUT IN FAVOUR OF THE GAP INSIDE THE REENTRANCY CODE 30 | //uint256[50] private __gap; 31 | // NB: DO NOT USE THIS GAP 32 | // ******************************************************************************************* 33 | 34 | /// @dev Total contract storage is 2 slots. 35 | 36 | /** 37 | * @notice Update the status of L2->L1 message when a user claims a message on L1. 38 | * @dev The L2->L1 message is removed from storage. 39 | * @dev Due to the nature of the rollup, we should not get a second entry of this. 40 | * @param _messageHash Hash of the message. 41 | */ 42 | function _updateL2L1MessageStatusToClaimed(bytes32 _messageHash) internal { 43 | if (inboxL2L1MessageStatus[_messageHash] != INBOX_STATUS_RECEIVED) { 44 | revert MessageDoesNotExistOrHasAlreadyBeenClaimed(_messageHash); 45 | } 46 | 47 | delete inboxL2L1MessageStatus[_messageHash]; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /contracts/messageService/l2/L2MessageService.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity 0.8.19; 3 | 4 | import { AccessControlUpgradeable } from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; 5 | import { L2MessageServiceV1 } from "./v1/L2MessageServiceV1.sol"; 6 | import { L2MessageManager } from "./L2MessageManager.sol"; 7 | 8 | /** 9 | * @title Contract to manage cross-chain messaging on L2. 10 | * @author ConsenSys Software Inc. 11 | * @custom:security-contact security-report@linea.build 12 | */ 13 | contract L2MessageService is AccessControlUpgradeable, L2MessageServiceV1, L2MessageManager { 14 | /// @dev Total contract storage is 50 slots with the gap below. 15 | /// @dev Keep 50 free storage slots for future implementation updates to avoid storage collision. 16 | uint256[50] private __gap_L2MessageService; 17 | } 18 | -------------------------------------------------------------------------------- /contracts/messageService/l2/v1/L2MessageManagerV1.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity 0.8.19; 3 | 4 | import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; 5 | import { IL2MessageManagerV1 } from "../../../interfaces/l2/IL2MessageManagerV1.sol"; 6 | import { PauseManager } from "../../lib/PauseManager.sol"; 7 | 8 | /** 9 | * @title Contract to manage cross-chain message hashes storage and statuses on L2. 10 | * @author ConsenSys Software Inc. 11 | * @custom:security-contact security-report@linea.build 12 | */ 13 | abstract contract L2MessageManagerV1 is Initializable, PauseManager, IL2MessageManagerV1 { 14 | uint8 public constant INBOX_STATUS_UNKNOWN = 0; 15 | uint8 public constant INBOX_STATUS_RECEIVED = 1; 16 | uint8 public constant INBOX_STATUS_CLAIMED = 2; 17 | 18 | bytes32 public constant L1_L2_MESSAGE_SETTER_ROLE = keccak256("L1_L2_MESSAGE_SETTER_ROLE"); 19 | 20 | /** 21 | * @dev Mapping to store L1->L2 message hashes status. 22 | * @dev messageHash => messageStatus (0: unknown, 1: received, 2: claimed). 23 | */ 24 | mapping(bytes32 messageHash => uint256 messageStatus) public inboxL1L2MessageStatus; 25 | 26 | /// @dev Keep free storage slots for future implementation updates to avoid storage collision. 27 | // ******************************************************************************************* 28 | // NB: THIS GAP HAS BEEN PUSHED OUT IN FAVOUR OF THE GAP INSIDE THE REENTRANCY CODE 29 | //uint256[50] private __gap; 30 | // NB: DO NOT USE THIS GAP 31 | // ******************************************************************************************* 32 | 33 | /// @dev Total contract storage is 1 slot. 34 | 35 | /** 36 | * @notice Initialises L2 message manager contract. 37 | * @param _l1l2MessageSetter The address owning the L1_L2_MESSAGE_SETTER_ROLE role. 38 | */ 39 | function __L2MessageManager_init(address _l1l2MessageSetter) internal onlyInitializing { 40 | _grantRole(L1_L2_MESSAGE_SETTER_ROLE, _l1l2MessageSetter); 41 | } 42 | 43 | /** 44 | * @notice Update the status of L1->L2 message when a user claims a message on L2. 45 | * @param _messageHash Hash of the message. 46 | */ 47 | function _updateL1L2MessageStatusToClaimed(bytes32 _messageHash) internal { 48 | if (inboxL1L2MessageStatus[_messageHash] != INBOX_STATUS_RECEIVED) { 49 | revert MessageDoesNotExistOrHasAlreadyBeenClaimed(_messageHash); 50 | } 51 | 52 | inboxL1L2MessageStatus[_messageHash] = INBOX_STATUS_CLAIMED; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /contracts/messageService/lib/SparseMerkleTreeVerifier.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity 0.8.24; 3 | 4 | /** 5 | * @title Library to verify sparse merkle proofs and to get the leaf hash value 6 | * @author ConsenSys Software Inc. 7 | * @custom:security-contact security-report@linea.build 8 | */ 9 | library SparseMerkleTreeVerifier { 10 | /** 11 | * @notice Verify merkle proof 12 | * @param _leafHash Leaf hash. 13 | * @param _proof Sparse merkle tree proof. 14 | * @param _leafIndex Index of the leaf. 15 | * @param _root Merkle root. 16 | */ 17 | function _verifyMerkleProof( 18 | bytes32 _leafHash, 19 | bytes32[] calldata _proof, 20 | uint32 _leafIndex, 21 | bytes32 _root 22 | ) internal pure returns (bool) { 23 | bytes32 node = _leafHash; 24 | 25 | for (uint256 height; height < _proof.length; ++height) { 26 | if (((_leafIndex >> height) & 1) == 1) { 27 | node = _efficientKeccak(_proof[height], node); 28 | } else { 29 | node = _efficientKeccak(node, _proof[height]); 30 | } 31 | } 32 | return node == _root; 33 | } 34 | 35 | /** 36 | * @notice Performs a gas optimized keccak hash 37 | * @param _left Left value. 38 | * @param _right Right value. 39 | */ 40 | function _efficientKeccak(bytes32 _left, bytes32 _right) internal pure returns (bytes32 value) { 41 | assembly { 42 | mstore(0x00, _left) 43 | mstore(0x20, _right) 44 | value := keccak256(0x00, 0x40) 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /contracts/messageService/lib/TimeLock.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity >=0.8.19 <=0.8.24; 3 | 4 | import { TimelockController } from "@openzeppelin/contracts/governance/TimelockController.sol"; 5 | 6 | /** 7 | * @title TimeLock contract used to manage contract upgrades 8 | * @author ConsenSys Software Inc. 9 | * @notice This timelock contract will be the owner of all upgrades that gives users confidence and an ability to exit should they want to before an upgrade takes place 10 | * @custom:security-contact security-report@linea.build 11 | */ 12 | contract TimeLock is TimelockController { 13 | constructor( 14 | uint256 minDelay, 15 | address[] memory proposers, 16 | address[] memory executors, 17 | address admin 18 | ) TimelockController(minDelay, proposers, executors, admin) {} 19 | } 20 | -------------------------------------------------------------------------------- /contracts/messageService/lib/TransientStorageHelpers.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity 0.8.24; 3 | 4 | /** 5 | * @title Library that provides helper functions to interact with transient storage. 6 | * @author ConsenSys Software Inc. 7 | * @custom:security-contact security-report@linea.build 8 | */ 9 | library TransientStorageHelpers { 10 | /** 11 | * @notice Internal function that stores a uint256 value at a given key in the EVM's transient storage using the `tstore` opcode. 12 | * @param _key The key in the EVM transient storage where the value should be stored. 13 | * @param _value The uint256 value to be stored at the specified key in the EVM transient storage. 14 | */ 15 | function tstoreUint256(bytes32 _key, uint256 _value) internal { 16 | assembly { 17 | tstore(_key, _value) 18 | } 19 | } 20 | 21 | /** 22 | * @notice Internal function that retrieves a uint256 value from the EVM's transient storage using the `tload` opcode. 23 | * @param _key The key in the EVM transient storage from which the value should be retrieved. 24 | * @return value The uint256 value retrieved from the specified key in the EVM transient storage. 25 | */ 26 | function tloadUint256(bytes32 _key) internal view returns (uint256 value) { 27 | assembly { 28 | value := tload(_key) 29 | } 30 | } 31 | 32 | /** 33 | * @notice Internal function that stores an address at a given key in the EVM's transient storage using the `tstore` opcode. 34 | * @param _key The key in the EVM transient storage where the value should be stored. 35 | * @param _addr The address to be stored at the specified key in the EVM transient storage. 36 | */ 37 | function tstoreAddress(bytes32 _key, address _addr) internal { 38 | assembly { 39 | tstore(_key, _addr) 40 | } 41 | } 42 | 43 | /** 44 | * @notice Internal function that retrieves an address from the EVM's transient storage using the `tload` opcode. 45 | * @param _key The key in the EVM transient storage from which the value should be retrieved. 46 | * @return addr The address retrieved from the specified key in the EVM transient storage. 47 | */ 48 | function tloadAddress(bytes32 _key) internal view returns (address addr) { 49 | assembly { 50 | addr := tload(_key) 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /contracts/test-contracts/TestEIP4844.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity 0.8.24; 3 | 4 | contract TestEIP4844 { 5 | event BlobHashEvent(bytes32 blobHash); 6 | 7 | function submitData( 8 | bytes32 _snarkHash, 9 | uint256 _y, 10 | bytes1[48] memory _kzgCommitment, 11 | bytes1[48] memory _kzgProof 12 | ) external { 13 | bytes32 h = blobhash(0); 14 | 15 | bytes32 compressedDataComputedX = keccak256(abi.encode(_snarkHash, h)); 16 | 17 | (bool success, ) = address(0x0a).staticcall( 18 | abi.encodePacked(h, compressedDataComputedX, _y, _kzgCommitment, _kzgProof) 19 | ); 20 | if (!success) { 21 | revert("PointEvaluationFailed"); 22 | } 23 | 24 | emit BlobHashEvent(h); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /contracts/test-contracts/TestL1MessageManager.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity 0.8.24; 3 | 4 | import { L1MessageManager } from "../messageService/l1/L1MessageManager.sol"; 5 | 6 | contract TestL1MessageManager is L1MessageManager { 7 | /** 8 | * @dev Thrown when the L1->L2 message has not been sent. 9 | */ 10 | error L1L2MessageNotSent(bytes32 messageHash); 11 | 12 | /** 13 | * @dev Thrown when the message has already been received. 14 | */ 15 | error MessageAlreadyReceived(bytes32 messageHash); 16 | 17 | ///@dev V1 18 | function addL2L1MessageHash(bytes32 _messageHash) external { 19 | if (inboxL2L1MessageStatus[_messageHash] != INBOX_STATUS_UNKNOWN) { 20 | revert MessageAlreadyReceived(_messageHash); 21 | } 22 | 23 | inboxL2L1MessageStatus[_messageHash] = INBOX_STATUS_RECEIVED; 24 | } 25 | 26 | function updateL2L1MessageStatusToClaimed(bytes32 _messageHash) external { 27 | _updateL2L1MessageStatusToClaimed(_messageHash); 28 | } 29 | 30 | function addL1L2MessageHash(bytes32 _messageHash) external { 31 | outboxL1L2MessageStatus[_messageHash] = OUTBOX_STATUS_SENT; 32 | } 33 | 34 | function updateL1L2MessageStatusToReceived(bytes32[] calldata _messageHashes) external { 35 | uint256 messageHashArrayLength = _messageHashes.length; 36 | 37 | for (uint256 i; i < messageHashArrayLength; ++i) { 38 | bytes32 messageHash = _messageHashes[i]; 39 | uint256 existingStatus = outboxL1L2MessageStatus[messageHash]; 40 | 41 | if (existingStatus == OUTBOX_STATUS_UNKNOWN) { 42 | revert L1L2MessageNotSent(messageHash); 43 | } 44 | 45 | if (existingStatus != OUTBOX_STATUS_RECEIVED) { 46 | outboxL1L2MessageStatus[messageHash] = OUTBOX_STATUS_RECEIVED; 47 | } 48 | } 49 | } 50 | 51 | ///@dev V2 52 | function setL2L1MessageToClaimed(uint256 _messageNumber) external { 53 | _setL2L1MessageToClaimed(_messageNumber); 54 | } 55 | 56 | function addL2MerkleRoots(bytes32[] calldata _newRoot, uint256 _treeDepth) external { 57 | _addL2MerkleRoots(_newRoot, _treeDepth); 58 | } 59 | 60 | function anchorL2MessagingBlocks(bytes calldata _l2MessagingBlocksOffsets, uint256 _currentL2BlockNumber) external { 61 | _anchorL2MessagingBlocks(_l2MessagingBlocksOffsets, _currentL2BlockNumber); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /contracts/test-contracts/TestL1MessageService.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity 0.8.24; 3 | 4 | import { L1MessageService } from "../messageService/l1/L1MessageService.sol"; 5 | 6 | contract TestL1MessageService is L1MessageService { 7 | /** 8 | * @dev Thrown when the message has already been received. 9 | */ 10 | error MessageAlreadyReceived(bytes32 messageHash); 11 | 12 | address public originalSender; 13 | bool private reentryDone; 14 | 15 | function initialize( 16 | address _limitManagerAddress, 17 | address _pauserManagerAddress, 18 | uint256 _rateLimitPeriod, 19 | uint256 _rateLimitAmount 20 | ) public initializer { 21 | _grantRole(DEFAULT_ADMIN_ROLE, msg.sender); 22 | __MessageService_init(_limitManagerAddress, _pauserManagerAddress, _rateLimitPeriod, _rateLimitAmount); 23 | } 24 | 25 | function tryInitialize( 26 | address _limitManagerAddress, 27 | address _pauserManagerAddress, 28 | uint256 _rateLimitPeriod, 29 | uint256 _rateLimitAmount 30 | ) external { 31 | __MessageService_init(_limitManagerAddress, _pauserManagerAddress, _rateLimitPeriod, _rateLimitAmount); 32 | } 33 | 34 | // @dev - the this. sendMessage is because the function is an "external" call and not wrapped 35 | function canSendMessage(address _to, uint256 _fee, bytes calldata _calldata) external payable { 36 | this.sendMessage{ value: msg.value }(_to, _fee, _calldata); 37 | } 38 | 39 | function addL2L1MessageHash(bytes32 _messageHash) external { 40 | if (inboxL2L1MessageStatus[_messageHash] != INBOX_STATUS_UNKNOWN) { 41 | revert MessageAlreadyReceived(_messageHash); 42 | } 43 | 44 | inboxL2L1MessageStatus[_messageHash] = INBOX_STATUS_RECEIVED; 45 | } 46 | 47 | function setSender() external payable { 48 | (bool success, bytes memory data) = msg.sender.call(abi.encodeWithSignature("sender()")); 49 | if (success) { 50 | originalSender = abi.decode(data, (address)); 51 | } 52 | } 53 | 54 | function sendNewMessage() external payable { 55 | this.sendMessage{ value: 1 wei }(address(this), 1, "0x"); 56 | } 57 | 58 | function doReentry() external payable { 59 | address originalAddress; 60 | 61 | (bool success, bytes memory data) = msg.sender.call(abi.encodeWithSignature("sender()")); 62 | if (success) { 63 | originalAddress = abi.decode(data, (address)); 64 | } 65 | 66 | if (!reentryDone) { 67 | (bool succeeded, bytes memory dataInner) = msg.sender.call( 68 | abi.encodeWithSignature( 69 | "claimMessage(address,address,uint256,uint256,address,bytes,uint256)", 70 | originalAddress, 71 | originalAddress, 72 | 0.05 ether, 73 | 1 ether, 74 | address(0), 75 | abi.encodeWithSignature("doReentry()", 1) 76 | ) 77 | ); 78 | 79 | if (succeeded) { 80 | reentryDone = true; 81 | } else { 82 | if (dataInner.length > 0) { 83 | assembly { 84 | let data_size := mload(dataInner) 85 | revert(add(32, dataInner), data_size) 86 | } 87 | } else { 88 | revert("Function call reverted"); 89 | } 90 | } 91 | } 92 | } 93 | 94 | function addFunds() external payable {} 95 | } 96 | -------------------------------------------------------------------------------- /contracts/test-contracts/TestL1RevertContract.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | 3 | pragma solidity 0.8.24; 4 | 5 | contract TestL1RevertContract { 6 | function errorWithMessage() external pure { 7 | revert("Reverting with receive"); 8 | } 9 | 10 | function errorWithoutMessage() external pure { 11 | revert(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /contracts/test-contracts/TestL2MessageManager.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity 0.8.19; 3 | 4 | import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; 5 | import { L2MessageManager } from "../messageService/l2/L2MessageManager.sol"; 6 | import { IGenericErrors } from "../interfaces/IGenericErrors.sol"; 7 | 8 | contract TestL2MessageManager is Initializable, L2MessageManager, IGenericErrors { 9 | /// @custom:oz-upgrades-unsafe-allow constructor 10 | constructor() { 11 | _disableInitializers(); 12 | } 13 | 14 | function initialize(address _pauserManager, address _l1l2MessageSetter) public initializer { 15 | if (_pauserManager == address(0)) { 16 | revert ZeroAddressNotAllowed(); 17 | } 18 | 19 | if (_l1l2MessageSetter == address(0)) { 20 | revert ZeroAddressNotAllowed(); 21 | } 22 | 23 | __ERC165_init(); 24 | __Context_init(); 25 | __AccessControl_init(); 26 | __L2MessageManager_init(_l1l2MessageSetter); 27 | 28 | _grantRole(DEFAULT_ADMIN_ROLE, msg.sender); 29 | _grantRole(PAUSE_MANAGER_ROLE, _pauserManager); 30 | } 31 | 32 | function tryInitialize(address _l1l2MessageSetter) external { 33 | __L2MessageManager_init(_l1l2MessageSetter); 34 | } 35 | 36 | function updateL1L2MessageStatusToClaimed(bytes32 _messageHash) external { 37 | _updateL1L2MessageStatusToClaimed(_messageHash); 38 | } 39 | 40 | function setLastAnchoredL1MessageNumber(uint256 _messageNumber) external { 41 | lastAnchoredL1MessageNumber = _messageNumber; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /contracts/test-contracts/TestL2MessageService.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity 0.8.19; 3 | 4 | import { L2MessageService } from "../messageService/l2/L2MessageService.sol"; 5 | 6 | contract TestL2MessageService is L2MessageService { 7 | address public originalSender; 8 | bool private reentryDone; 9 | 10 | function setLastAnchoredL1MessageNumber(uint256 _messageNumber) external { 11 | lastAnchoredL1MessageNumber = _messageNumber; 12 | } 13 | 14 | function canSendMessage(address _to, uint256 _fee, bytes calldata _calldata) external payable { 15 | this.sendMessage{ value: msg.value }(_to, _fee, _calldata); 16 | } 17 | 18 | function setSender() external payable { 19 | (bool success, bytes memory data) = msg.sender.call(abi.encodeWithSignature("sender()")); 20 | if (success) { 21 | originalSender = abi.decode(data, (address)); 22 | } 23 | } 24 | 25 | function callMessageServiceBase(address _messageServiceBase) external payable { 26 | (bool success, ) = _messageServiceBase.call(abi.encodeWithSignature("withOnlyMessagingService()")); 27 | if (!success) { 28 | revert("Not authorized"); 29 | } 30 | } 31 | 32 | function doReentry() external payable { 33 | address originalAddress; 34 | 35 | (bool success, bytes memory data) = msg.sender.call(abi.encodeWithSignature("sender()")); 36 | if (success) { 37 | originalAddress = abi.decode(data, (address)); 38 | } 39 | 40 | if (!reentryDone) { 41 | (bool succeeded, bytes memory dataInner) = msg.sender.call( 42 | abi.encodeWithSignature( 43 | "claimMessage(address,address,uint256,uint256,address,bytes,uint256)", 44 | originalAddress, 45 | originalAddress, 46 | 0.05 ether, 47 | 1 ether, 48 | address(0), 49 | abi.encodeWithSignature("doReentry()") 50 | ) 51 | ); 52 | 53 | if (succeeded) { 54 | reentryDone = true; 55 | } else { 56 | if (dataInner.length > 0) { 57 | assembly { 58 | let data_size := mload(dataInner) 59 | revert(add(32, dataInner), data_size) 60 | } 61 | } else { 62 | revert("Function call reverted"); 63 | } 64 | } 65 | } 66 | } 67 | 68 | function addFunds() external payable {} 69 | 70 | function makeItRevert() external payable { 71 | revert(); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /contracts/test-contracts/TestLineaRollup.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity 0.8.24; 3 | 4 | import { LineaRollup } from "../LineaRollup.sol"; 5 | 6 | contract TestLineaRollup is LineaRollup { 7 | function addRollingHash(uint256 _messageNumber, bytes32 _messageHash) external { 8 | _addRollingHash(_messageNumber, _messageHash); 9 | } 10 | 11 | function setRollingHash(uint256 _messageNumber, bytes32 _rollingHash) external { 12 | rollingHashes[_messageNumber] = _rollingHash; 13 | } 14 | 15 | function setLastTimeStamp(uint256 _timestamp) external { 16 | currentTimestamp = _timestamp; 17 | } 18 | 19 | function validateL2ComputedRollingHash(uint256 _rollingHashMessageNumber, bytes32 _rollingHash) external view { 20 | _validateL2ComputedRollingHash(_rollingHashMessageNumber, _rollingHash); 21 | } 22 | 23 | function calculateY(bytes calldata _data, bytes32 _x) external pure returns (bytes32 y) { 24 | return _calculateY(_data, _x); 25 | } 26 | 27 | function setupParentShnarf(bytes32 _shnarf, uint256 _finalBlockNumber) external { 28 | shnarfFinalBlockNumbers[_shnarf] = _finalBlockNumber; 29 | } 30 | 31 | function setupParentDataShnarf(bytes32 _parentDataHash, bytes32 _shnarf) external { 32 | dataShnarfHashes[_parentDataHash] = _shnarf; 33 | } 34 | 35 | function setLastFinalizedBlock(uint256 _blockNumber) external { 36 | currentL2BlockNumber = _blockNumber; 37 | } 38 | 39 | function setupParentFinalizedStateRoot(bytes32 _parentDataHash, bytes32 _blockStateRoot) external { 40 | dataFinalStateRootHashes[_parentDataHash] = _blockStateRoot; 41 | } 42 | 43 | function setupStartingBlockForDataHash(bytes32 _dataHash, uint256 _blockNumber) external { 44 | dataStartingBlock[_dataHash] = _blockNumber; 45 | } 46 | 47 | function setLastFinalizedShnarf(bytes32 _lastFinalizedShnarf) external { 48 | currentFinalizedShnarf = _lastFinalizedShnarf; 49 | } 50 | 51 | function setShnarfFinalBlockNumber(bytes32 _shnarf, uint256 _finalBlockNumber) external { 52 | shnarfFinalBlockNumbers[_shnarf] = _finalBlockNumber; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /contracts/test-contracts/TestLineaSurgeXP.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity 0.8.19; 3 | 4 | /// @dev Test contract to test LXP-L minting 5 | interface ITransferSurgeXP { 6 | function transfer(address _address, uint256 _amount) external returns (bool); 7 | } 8 | 9 | contract TestLineaSurgeXP { 10 | /// @dev In a real contract, this would be permissioned to avoid abuse. 11 | function testTransfer(address _contractAddress, address _recipient, uint256 _amount) external returns (bool) { 12 | return ITransferSurgeXP(_contractAddress).transfer(_recipient, _amount); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /contracts/test-contracts/TestMessageServiceBase.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity >=0.8.19 <=0.8.24; 3 | 4 | import { MessageServiceBase } from "../messageService/MessageServiceBase.sol"; 5 | 6 | contract TestMessageServiceBase is MessageServiceBase { 7 | function initialize(address _messageService, address _remoteSender) external initializer { 8 | __MessageServiceBase_init(_messageService); 9 | _setRemoteSender(_remoteSender); 10 | } 11 | 12 | function withOnlyMessagingService() external onlyMessagingService {} 13 | 14 | function withOnlyAuthorizedRemoteSender() external onlyAuthorizedRemoteSender {} 15 | 16 | function tryInitialize(address _messageService, address _remoteSender) external { 17 | __MessageServiceBase_init(_messageService); 18 | _setRemoteSender(_remoteSender); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /contracts/test-contracts/TestPauseManager.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity >=0.8.19 <=0.8.24; 3 | 4 | import { PauseManager } from "../messageService/lib/PauseManager.sol"; 5 | 6 | contract TestPauseManager is PauseManager { 7 | function initialize() public initializer { 8 | __AccessControl_init(); 9 | _grantRole(DEFAULT_ADMIN_ROLE, msg.sender); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /contracts/test-contracts/TestPublicInputVerifier.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity 0.8.24; 3 | 4 | import { IPlonkVerifier } from "../interfaces/l1/IPlonkVerifier.sol"; 5 | 6 | /// @dev Test verifier contract that returns true. 7 | contract TestPublicInputVerifier is IPlonkVerifier { 8 | uint256 public expectedPublicInput; 9 | 10 | constructor(uint256 _expectedPublicInput) { 11 | expectedPublicInput = _expectedPublicInput; 12 | } 13 | 14 | function Verify(bytes calldata, uint256[] calldata _publicInput) external view returns (bool) { 15 | return expectedPublicInput == _publicInput[0]; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /contracts/test-contracts/TestRateLimiter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity >=0.8.19 <=0.8.24; 3 | 4 | import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; 5 | import { RateLimiter } from "../messageService/lib/RateLimiter.sol"; 6 | 7 | contract TestRateLimiter is Initializable, RateLimiter { 8 | // we need eth to test the limits with 9 | function initialize(uint256 _periodInSeconds, uint256 _limitInWei) public initializer { 10 | __AccessControl_init(); 11 | 12 | __RateLimiter_init(_periodInSeconds, _limitInWei); 13 | _grantRole(DEFAULT_ADMIN_ROLE, msg.sender); 14 | } 15 | 16 | // @dev this is needed to get at the internal function 17 | function withdrawSomeAmount(uint256 _amount) external { 18 | _addUsedAmount(_amount); 19 | } 20 | 21 | function tryInitialize(uint256 _periodInSeconds, uint256 _limitInWei) external { 22 | __RateLimiter_init(_periodInSeconds, _limitInWei); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /contracts/test-contracts/TestReceivingContract.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | 3 | pragma solidity 0.8.19; 4 | 5 | contract TestReceivingContract { 6 | fallback() external payable {} 7 | 8 | receive() external payable {} 9 | } 10 | -------------------------------------------------------------------------------- /contracts/test-contracts/TestSparseMerkleTreeVerifier.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity 0.8.24; 3 | 4 | import { SparseMerkleTreeVerifier } from "../messageService/lib/SparseMerkleTreeVerifier.sol"; 5 | 6 | contract TestSparseMerkleTreeVerifier { 7 | using SparseMerkleTreeVerifier for *; 8 | 9 | function verifyMerkleProof( 10 | bytes32 _leafHash, 11 | bytes32[] calldata _proof, 12 | uint32 _leafIndex, 13 | bytes32 _root 14 | ) external pure returns (bool) { 15 | return SparseMerkleTreeVerifier._verifyMerkleProof(_leafHash, _proof, _leafIndex, _root); 16 | } 17 | 18 | function efficientKeccak(bytes32 _left, bytes32 _right) external pure returns (bytes32 value) { 19 | return SparseMerkleTreeVerifier._efficientKeccak(_left, _right); 20 | } 21 | 22 | function getLeafHash( 23 | address _from, 24 | address _to, 25 | uint256 _fee, 26 | uint256 _value, 27 | uint256 _messageNumber, 28 | bytes calldata _calldata 29 | ) external pure returns (bytes32) { 30 | return keccak256(abi.encodePacked(_from, _to, _fee, _value, _messageNumber, _calldata)); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /contracts/test-contracts/TestUtils.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity 0.8.24; 3 | 4 | import { Utils } from "../lib/Utils.sol"; 5 | 6 | contract TestUtils { 7 | function efficientKeccak(bytes32 _left, bytes32 _right) external pure returns (bytes32 value) { 8 | return Utils._efficientKeccak(_left, _right); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /contracts/token/ITokenMinter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity 0.8.19; 3 | 4 | /** 5 | * @title Token Minter Interface. 6 | * @author ConsenSys Software Inc. 7 | * @custom:security-contact security-report@linea.build 8 | */ 9 | interface ITokenMinter { 10 | /** 11 | * @notice Mints a single token amount for a single recipient. 12 | * @param _to The address receiving the token amount. 13 | * @param _amount The amount of token to receive. 14 | * @dev Only the MINTER_ROLE can mint these tokens 15 | */ 16 | function mint(address _to, uint256 _amount) external; 17 | 18 | /** 19 | * @notice Mints a single token amount for a multiple recipients. 20 | * @param _to The addresses receiving the token amount. 21 | * @param _amount The amount of token to receive. 22 | * @dev Only the MINTER_ROLE can mint these tokens 23 | */ 24 | function batchMint(address[] calldata _to, uint256 _amount) external; 25 | 26 | /** 27 | * @notice Mints a 1:1 amounts for multiple recipients. 28 | * @param _to The addresses receiving the token amount. 29 | * @param _amounts The amounts of token to receive. 30 | * @dev Only the MINTER_ROLE can mint these tokens 31 | */ 32 | function batchMintMultiple(address[] calldata _to, uint256[] calldata _amounts) external; 33 | } 34 | -------------------------------------------------------------------------------- /contracts/token/ITokenMintingRateLimiter.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity 0.8.19; 3 | 4 | /** 5 | * @title Token Minting Rate Limiter Interface. 6 | * @author ConsenSys Software Inc. 7 | * @custom:security-contact security-report@linea.build 8 | */ 9 | interface ITokenMintingRateLimiter { 10 | /** 11 | * @dev Thrown when a parameter is the zero address. 12 | */ 13 | error ZeroAddressNotAllowed(); 14 | 15 | /** 16 | * @dev Thrown when an amount breaches the limit in the period. 17 | */ 18 | error RateLimitExceeded(); 19 | 20 | /** 21 | * @dev Thrown when the period is initialised to zero. 22 | */ 23 | error PeriodIsZero(); 24 | 25 | /** 26 | * @dev Thrown when the limit is initialised to zero. 27 | */ 28 | error LimitIsZero(); 29 | 30 | /** 31 | * @dev Thrown when array lengths are mismatched. 32 | */ 33 | error ArrayLengthsDoNotMatch(); 34 | 35 | /** 36 | * @dev Emitted when the Rate Limit is initialized. 37 | */ 38 | event RateLimitInitialized(uint256 mintingPeriodInSeconds, uint256 mintingLimit, uint256 currentPeriodEnd); 39 | 40 | /** 41 | * @dev Emitted when the limit is changed. 42 | * @dev If the current used amount is higher than the new limit, the used amount is lowered to the limit. 43 | */ 44 | event LimitAmountChanged( 45 | address indexed amountChangeBy, 46 | uint256 amount, 47 | bool amountUsedLoweredToLimit, 48 | bool usedAmountResetToZero 49 | ); 50 | 51 | /** 52 | * @notice Resets the rate limit amount to the amount specified. 53 | * @param _amount sets the new limit amount. 54 | * @dev Requires RATE_LIMIT_SETTER_ROLE. 55 | */ 56 | function resetRateLimitAmount(uint256 _amount) external; 57 | } 58 | -------------------------------------------------------------------------------- /contracts/token/MyToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity 0.8.19; 3 | 4 | import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 5 | import { AccessControl } from "@openzeppelin/contracts/access/AccessControl.sol"; 6 | 7 | contract MyToken is ERC20, AccessControl { 8 | error TokenIsSoulBound(); 9 | 10 | bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); 11 | 12 | constructor(address minter) ERC20("MyToken", "MTK") { 13 | _grantRole(DEFAULT_ADMIN_ROLE, minter); 14 | _grantRole(MINTER_ROLE, minter); 15 | } 16 | 17 | function mint(address _to, uint256 _amount) external onlyRole(MINTER_ROLE) { 18 | _mint(_to, _amount); 19 | } 20 | 21 | function batchMint(address[] calldata _to, uint256 _amount) external onlyRole(MINTER_ROLE) { 22 | uint256 addressLength = _to.length; 23 | 24 | for (uint256 i; i < addressLength; ) { 25 | unchecked { 26 | _mint(_to[i], _amount); 27 | ++i; 28 | } 29 | } 30 | } 31 | 32 | function batchMintMultiple(address[] calldata _to, uint256[] calldata _amounts) external onlyRole(MINTER_ROLE) { 33 | require(_to.length == _amounts.length, "Array lengths do not match"); 34 | 35 | uint256 addressLength = _to.length; 36 | for (uint256 i; i < addressLength; ) { 37 | unchecked { 38 | _mint(_to[i], _amounts[i]); 39 | ++i; 40 | } 41 | } 42 | } 43 | 44 | function transfer(address, uint256) public virtual override returns (bool) { 45 | revert TokenIsSoulBound(); 46 | } 47 | 48 | function transferFrom(address, address, uint256) public virtual override returns (bool) { 49 | revert TokenIsSoulBound(); 50 | } 51 | 52 | function approve(address, uint256) public virtual override returns (bool) { 53 | revert TokenIsSoulBound(); 54 | } 55 | 56 | function increaseAllowance(address, uint256) public virtual override returns (bool) { 57 | revert TokenIsSoulBound(); 58 | } 59 | 60 | function decreaseAllowance(address, uint256) public virtual override returns (bool) { 61 | revert TokenIsSoulBound(); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /contracts/tokenBridge/BridgedToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity 0.8.19; 3 | 4 | import { ERC20PermitUpgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PermitUpgradeable.sol"; 5 | 6 | /** 7 | * @title BridgedToken Contract 8 | * @notice ERC20 token created when a native token is bridged to a target chain. 9 | * @custom:security-contact security-report@linea.build 10 | */ 11 | contract BridgedToken is ERC20PermitUpgradeable { 12 | address public bridge; 13 | uint8 public _decimals; 14 | /** 15 | * @notice Initializes the BridgedToken contract. 16 | * @dev Disables OpenZeppelin's initializer mechanism for safety. 17 | */ 18 | 19 | /// @dev Keep free storage slots for future implementation updates to avoid storage collision. 20 | uint256[50] private __gap; 21 | 22 | error OnlyBridge(address bridgeAddress); 23 | 24 | /// @dev Disable constructor for safety 25 | /// @custom:oz-upgrades-unsafe-allow constructor 26 | constructor() { 27 | _disableInitializers(); 28 | } 29 | 30 | function initialize(string memory _tokenName, string memory _tokenSymbol, uint8 _tokenDecimals) external initializer { 31 | __ERC20_init(_tokenName, _tokenSymbol); 32 | __ERC20Permit_init(_tokenName); 33 | bridge = msg.sender; 34 | _decimals = _tokenDecimals; 35 | } 36 | 37 | /// @dev Ensures call come from the bridge. 38 | modifier onlyBridge() { 39 | if (msg.sender != bridge) revert OnlyBridge(bridge); 40 | _; 41 | } 42 | 43 | /** 44 | * @dev Called by the bridge to mint tokens during a bridge transaction. 45 | * @param _recipient The address to receive the minted tokens. 46 | * @param _amount The amount of tokens to mint. 47 | */ 48 | function mint(address _recipient, uint256 _amount) external onlyBridge { 49 | _mint(_recipient, _amount); 50 | } 51 | 52 | /** 53 | * @dev Called by the bridge to burn tokens during a bridge transaction. 54 | * @dev User should first have allowed the bridge to spend tokens on their behalf. 55 | * @param _account The account from which tokens will be burned. 56 | * @param _amount The amount of tokens to burn. 57 | */ 58 | function burn(address _account, uint256 _amount) external onlyBridge { 59 | _spendAllowance(_account, msg.sender, _amount); 60 | _burn(_account, _amount); 61 | } 62 | 63 | /** 64 | * @dev Overrides ERC20 default function to support tokens with different decimals. 65 | * @return The number of decimal. 66 | */ 67 | function decimals() public view override returns (uint8) { 68 | return _decimals; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /contracts/tokenBridge/CustomBridgedToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity 0.8.19; 3 | 4 | import { BridgedToken } from "./BridgedToken.sol"; 5 | 6 | /** 7 | * @title Custom BridgedToken Contract 8 | * @notice Custom ERC20 token manually deployed for the Linea TokenBridge 9 | */ 10 | contract CustomBridgedToken is BridgedToken { 11 | function initializeV2( 12 | string memory _tokenName, 13 | string memory _tokenSymbol, 14 | uint8 _tokenDecimals, 15 | address _bridge 16 | ) public reinitializer(2) { 17 | __ERC20_init(_tokenName, _tokenSymbol); 18 | __ERC20Permit_init(_tokenName); 19 | bridge = _bridge; 20 | _decimals = _tokenDecimals; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /contracts/tokenBridge/mocks/ERC20MintBurn.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | pragma solidity ^0.8.0; 3 | 4 | import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 5 | 6 | contract MockERC20MintBurn is ERC20 { 7 | constructor(string memory _tokenName, string memory _tokenSymbol) ERC20(_tokenName, _tokenSymbol) {} 8 | 9 | function mint(address _account, uint256 _amount) public returns (bool) { 10 | _mint(_account, _amount); 11 | return true; 12 | } 13 | 14 | function burn(address _account, uint256 _amount) public returns (bool) { 15 | _burn(_account, _amount); 16 | return true; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /contracts/tokenBridge/mocks/ERC20NoNameMintBurn.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | pragma solidity ^0.8.0; 3 | 4 | contract MockERC20NoNameMintBurn { 5 | uint8 public decimals; 6 | 7 | mapping(address => uint256) public balanceOf; 8 | mapping(address => mapping(address => uint256)) public allowance; 9 | 10 | event Transfer(address indexed from, address indexed to, uint256 value); 11 | event Approval(address indexed owner, address indexed spender, uint256 value); 12 | event Mint(address indexed account, uint256 value); 13 | 14 | constructor() { 15 | decimals = 18; 16 | } 17 | 18 | function transfer(address _to, uint256 _value) public returns (bool) { 19 | require(balanceOf[msg.sender] >= _value, "Insufficient balance"); 20 | balanceOf[msg.sender] -= _value; 21 | balanceOf[_to] += _value; 22 | emit Transfer(msg.sender, _to, _value); 23 | return true; 24 | } 25 | 26 | function approve(address _spender, uint256 _value) public returns (bool) { 27 | allowance[msg.sender][_spender] = _value; 28 | emit Approval(msg.sender, _spender, _value); 29 | return true; 30 | } 31 | 32 | function transferFrom(address _from, address _to, uint256 _value) public returns (bool) { 33 | require(balanceOf[_from] >= _value, "Insufficient balance"); 34 | require(allowance[_from][msg.sender] >= _value, "Insufficient allowance"); 35 | balanceOf[_from] -= _value; 36 | balanceOf[_to] += _value; 37 | allowance[_from][msg.sender] -= _value; 38 | emit Transfer(_from, _to, _value); 39 | return true; 40 | } 41 | 42 | function mint(address _account, uint256 _value) public returns (bool) { 43 | balanceOf[_account] += _value; 44 | emit Mint(_account, _value); 45 | return true; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /contracts/tokenBridge/mocks/ERC20UnknownDecimals.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | pragma solidity ^0.8.0; 3 | 4 | import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 5 | 6 | contract ERC20UnknownDecimals is ERC20 { 7 | constructor(string memory _tokenName, string memory _tokenSymbol) ERC20(_tokenName, _tokenSymbol) {} 8 | 9 | function decimals() public view virtual override returns (uint8) { 10 | revert("Forced failure"); 11 | } 12 | 13 | function mint(address _account, uint256 _value) public returns (bool) { 14 | _mint(_account, _value); 15 | return true; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /contracts/tokenBridge/mocks/ERC20WeirdNameSymbol.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | pragma solidity ^0.8.0; 3 | 4 | contract MockERC20WeirdNameSymbol { 5 | uint8 public decimals; 6 | 7 | mapping(address => uint256) public balanceOf; 8 | mapping(address => mapping(address => uint256)) public allowance; 9 | 10 | event Transfer(address indexed from, address indexed to, uint256 value); 11 | event Approval(address indexed owner, address indexed spender, uint256 value); 12 | event Mint(address indexed account, uint256 value); 13 | 14 | constructor() { 15 | decimals = 18; 16 | } 17 | 18 | function name() public pure returns (bytes1) { 19 | return 0x00; 20 | } 21 | 22 | function symbol() public pure returns (bytes1) { 23 | return 0x01; 24 | } 25 | 26 | function transfer(address _to, uint256 _value) public returns (bool) { 27 | require(balanceOf[msg.sender] >= _value, "Insufficient balance"); 28 | balanceOf[msg.sender] -= _value; 29 | balanceOf[_to] += _value; 30 | emit Transfer(msg.sender, _to, _value); 31 | return true; 32 | } 33 | 34 | function approve(address _spender, uint256 _value) public returns (bool) { 35 | allowance[msg.sender][_spender] = _value; 36 | emit Approval(msg.sender, _spender, _value); 37 | return true; 38 | } 39 | 40 | function transferFrom(address _from, address _to, uint256 _value) public returns (bool) { 41 | require(balanceOf[_from] >= _value, "Insufficient balance"); 42 | require(allowance[_from][msg.sender] >= _value, "Insufficient allowance"); 43 | balanceOf[_from] -= _value; 44 | balanceOf[_to] += _value; 45 | allowance[_from][msg.sender] -= _value; 46 | emit Transfer(_from, _to, _value); 47 | return true; 48 | } 49 | 50 | function mint(address _account, uint256 _value) public returns (bool) { 51 | balanceOf[_account] += _value; 52 | emit Mint(_account, _value); 53 | return true; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /contracts/tokenBridge/mocks/ERCFees.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | pragma solidity ^0.8.0; 3 | 4 | import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 5 | 6 | uint16 constant FEES_PERCENTAGE_MULTIPLIER = 10000; 7 | 8 | contract ERC20Fees is ERC20 { 9 | uint16 public feePercentage; 10 | 11 | /** 12 | * @dev Constructor that gives _msgSender() all of existing tokens. 13 | * @param _tokenName string memory token name 14 | * @param _tokenSymbol string memory token symbol 15 | * @param _feePercentage uint16 fee percentage with FEE_PERCENTAGE_MULTIPLIER 16 | */ 17 | constructor( 18 | string memory _tokenName, 19 | string memory _tokenSymbol, 20 | uint16 _feePercentage 21 | ) ERC20(_tokenName, _tokenSymbol) { 22 | feePercentage = _feePercentage; 23 | } 24 | 25 | function mint(address _account, uint256 _amount) public returns (bool) { 26 | _mint(_account, _amount); 27 | return true; 28 | } 29 | 30 | function _transfer(address _sender, address _recipient, uint256 _amount) internal virtual override { 31 | _burn(_sender, (_amount * feePercentage) / FEES_PERCENTAGE_MULTIPLIER); 32 | super._transfer( 33 | _sender, 34 | _recipient, 35 | (_amount * (FEES_PERCENTAGE_MULTIPLIER - feePercentage)) / FEES_PERCENTAGE_MULTIPLIER 36 | ); 37 | } 38 | 39 | function burn(address _account, uint256 _amount) public returns (bool) { 40 | _burn(_account, _amount); 41 | return true; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /contracts/tokenBridge/mocks/MessageBridgeV2/MockMessageServiceV2.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | pragma solidity >=0.8.19 <=0.8.24; 3 | 4 | import { IMessageService } from "../../../interfaces/IMessageService.sol"; 5 | import { IGenericErrors } from "../../../interfaces/IGenericErrors.sol"; 6 | import { PauseManager } from "../../../messageService/lib/PauseManager.sol"; 7 | import { L1MessageManager } from "../../../messageService/l1/L1MessageManager.sol"; 8 | 9 | contract MockMessageServiceV2 is L1MessageManager, IMessageService, PauseManager, IGenericErrors { 10 | address internal messageSender = address(0); 11 | uint256 public nextMessageNumber = 1; 12 | 13 | /** 14 | * @notice Adds a message for sending cross-chain and emits MessageSent. 15 | * @dev The message number is preset (nextMessageNumber) and only incremented at the end if successful for the next caller. 16 | * @dev This function should be called with a msg.value = _value + _fee. The fee will be paid on the destination chain. 17 | * @param _to The address the message is intended for. 18 | * @param _fee The fee being paid for the message delivery. 19 | * @param _calldata The calldata to pass to the recipient. 20 | */ 21 | function sendMessage( 22 | address _to, 23 | uint256 _fee, 24 | bytes calldata _calldata 25 | ) external payable whenTypeAndGeneralNotPaused(L1_L2_PAUSE_TYPE) { 26 | if (_to == address(0)) { 27 | revert ZeroAddressNotAllowed(); 28 | } 29 | 30 | if (_fee > msg.value) { 31 | revert ValueSentTooLow(); 32 | } 33 | 34 | uint256 messageNumber = nextMessageNumber; 35 | uint256 valueSent = msg.value - _fee; 36 | 37 | bytes32 messageHash = keccak256(abi.encode(msg.sender, _to, _fee, valueSent, messageNumber, _calldata)); 38 | 39 | // @dev Status check and revert is in the message manager 40 | outboxL1L2MessageStatus[messageHash] = OUTBOX_STATUS_SENT; 41 | 42 | nextMessageNumber++; 43 | 44 | emit MessageSent(msg.sender, _to, _fee, valueSent, messageNumber, _calldata, messageHash); 45 | } 46 | 47 | // When called within the context of the delivered call returns the sender from the other layer 48 | // otherwise returns the zero address 49 | function sender() external view returns (address) { 50 | return messageSender; 51 | } 52 | 53 | // Placeholder 54 | function claimMessage( 55 | address _from, 56 | address _to, 57 | uint256 _fee, 58 | uint256 _value, 59 | address payable _feeRecipient, 60 | bytes calldata _calldata, 61 | uint256 _nonce 62 | ) external {} 63 | } 64 | -------------------------------------------------------------------------------- /contracts/tokenBridge/mocks/MockMessageService.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity 0.8.19; 3 | 4 | import { IMessageService } from "../../interfaces/IMessageService.sol"; 5 | 6 | contract MockMessageService is IMessageService { 7 | uint256 public constant CALL_GAS_LIMIT = 1000000; 8 | address internal messageSender = address(0); 9 | 10 | function sendMessage(address _to, uint256 _fee, bytes calldata _calldata) external payable { 11 | require(msg.value >= _fee, "MessageService: Value too low"); 12 | messageSender = msg.sender; 13 | uint256 _value = msg.value - _fee; 14 | (bool success, bytes memory result) = _to.call{ value: _value, gas: CALL_GAS_LIMIT }(_calldata); 15 | 16 | // This is used to return the same revert message as the contract called returns it 17 | if (success == false) { 18 | assembly { 19 | revert(add(result, 32), mload(result)) 20 | } 21 | } 22 | } 23 | 24 | // When called within the context of the delivered call returns the sender from the other layer 25 | // otherwise returns the zero address 26 | function sender() external view returns (address) { 27 | return messageSender; 28 | } 29 | 30 | // Placeholder 31 | function claimMessage( 32 | address _from, 33 | address _to, 34 | uint256 _fee, 35 | uint256 _value, 36 | address payable _feeRecipient, 37 | bytes calldata _calldata, 38 | uint256 _nonce 39 | ) external {} 40 | } 41 | -------------------------------------------------------------------------------- /contracts/tokenBridge/mocks/MockTokenBridge.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity 0.8.19; 3 | 4 | import { TokenBridge } from "../TokenBridge.sol"; 5 | 6 | contract MockTokenBridge is TokenBridge { 7 | function setNativeMappingValue(address token, address value) external { 8 | nativeToBridgedToken[1][token] = value; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /contracts/tokenBridge/mocks/Reentrancy/MaliciousERC777.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | pragma solidity ^0.8.0; 3 | 4 | import { ReentrancyContract } from "./ReentrancyContract.sol"; 5 | 6 | contract MaliciousERC777 { 7 | mapping(address => uint256) public balanceOf; 8 | ReentrancyContract private reentrancyContract; 9 | 10 | constructor(address _reentrancyContract) { 11 | reentrancyContract = ReentrancyContract(_reentrancyContract); 12 | } 13 | 14 | function mint(address _to, uint256 _amount) external { 15 | balanceOf[_to] += _amount; 16 | } 17 | 18 | function transferFrom(address _from, address _to, uint256 _amount) external { 19 | reentrancyContract.beforeTokenTransfer(); 20 | 21 | balanceOf[_from] -= _amount; 22 | balanceOf[_to] += _amount; 23 | } 24 | 25 | function name() external pure returns (string memory) { 26 | return "Token"; 27 | } 28 | 29 | function symbol() external pure returns (string memory) { 30 | return "Token"; 31 | } 32 | 33 | function decimals() external pure returns (uint8) { 34 | return 18; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /contracts/tokenBridge/mocks/Reentrancy/ReentrancyContract.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.0; 3 | 4 | import { TokenBridge } from "../../TokenBridge.sol"; 5 | 6 | contract ReentrancyContract { 7 | // The Linea `TokenBridge` contract 8 | TokenBridge private tokenBridge; 9 | 10 | // A simple ERC777 token with transfer hooks for this PoC 11 | address private token; 12 | 13 | // Counts how often we re-entered the bridge from `beforeTokenTransfer` below. 14 | uint256 private counter; 15 | 16 | constructor(address _tokenBridge) { 17 | counter = 0; 18 | tokenBridge = TokenBridge(_tokenBridge); 19 | } 20 | 21 | function setToken(address _token) external { 22 | token = _token; 23 | } 24 | 25 | function beforeTokenTransfer() external { 26 | counter++; 27 | if (counter == 5) { 28 | // Stop the re-entrancy loop 29 | return; 30 | } else if (counter == 4) { 31 | // The final re-entrancy. Send the full token amount. 32 | tokenBridge.bridgeToken(token, 20, address(this)); 33 | } else { 34 | // Keep the loop going with 1 wei. 35 | tokenBridge.bridgeToken(token, 1, address(this)); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /contracts/tokenBridge/mocks/UpgradedBridgedToken.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: AGPL-3.0 2 | pragma solidity 0.8.19; 3 | 4 | import { BridgedToken } from "../BridgedToken.sol"; 5 | 6 | contract UpgradedBridgedToken is BridgedToken { 7 | function isUpgraded() external pure returns (bool) { 8 | return true; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /contracts/verifiers/test/TestPlonkVerifierFull.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | // Copyright 2023 Consensys Software Inc. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | // Code generated by gnark DO NOT EDIT 18 | 19 | pragma solidity ^0.8.0; 20 | 21 | import { PlonkVerifierFull } from "../PlonkVerifierFull.sol"; 22 | 23 | contract TestPlonkVerifierFull is PlonkVerifierFull { 24 | function testVerifier(bytes calldata proof, uint256[] calldata pi) public view { 25 | require(PlonkVerifierFull.Verify(proof, pi), "verification failed!"); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /contracts/verifiers/test/TestPlonkVerifierFullLarge.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Apache-2.0 2 | 3 | // Copyright 2023 Consensys Software Inc. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | 17 | // Code generated by gnark DO NOT EDIT 18 | 19 | pragma solidity 0.8.19; 20 | 21 | import { PlonkVerifierFullLarge } from "../PlonkVerifierFullLarge.sol"; 22 | 23 | contract TestPlonkVerifierFullLarge is PlonkVerifierFullLarge { 24 | function testVerifier(bytes calldata proof, uint256[] calldata pi) public view { 25 | require(PlonkVerifierFullLarge.Verify(proof, pi), "verification failed!"); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /deploy/01_deploy_IntegrationTestTrueVerifier.ts: -------------------------------------------------------------------------------- 1 | import { DeployFunction } from "hardhat-deploy/types"; 2 | import { HardhatRuntimeEnvironment } from "hardhat/types"; 3 | import { deployFromFactory } from "../scripts/hardhat/utils"; 4 | import { validateDeployBranchAndTags } from "../utils/auditedDeployVerifier"; 5 | import { getDeployedContractAddress, tryStoreAddress } from "../utils/storeAddress"; 6 | import { tryVerifyContract } from "../utils/verifyContract"; 7 | import { ethers } from "hardhat"; 8 | 9 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 10 | validateDeployBranchAndTags(hre.network.name); 11 | 12 | const { deployments } = hre; 13 | const contractName = "IntegrationTestTrueVerifier"; 14 | const existingContractAddress = await getDeployedContractAddress(contractName, deployments); 15 | 16 | const provider = ethers.provider; 17 | 18 | if (existingContractAddress === undefined) { 19 | console.log(`Deploying initial version, NB: the address will be saved if env SAVE_ADDRESS=true.`); 20 | } else { 21 | console.log(`Deploying new version, NB: ${existingContractAddress} will be overwritten if env SAVE_ADDRESS=true.`); 22 | } 23 | const contract = await deployFromFactory(contractName, provider); 24 | const contractAddress = await contract.getAddress(); 25 | console.log(`${contractName} deployed at ${contractAddress}`); 26 | 27 | process.env.PLONKVERIFIER_ADDRESS = contractAddress; 28 | 29 | const deployTx = contract.deploymentTransaction(); 30 | if (!deployTx) { 31 | throw "Deployment transaction not found."; 32 | } 33 | 34 | await tryStoreAddress(hre.network.name, contractName, contractAddress, deployTx.hash); 35 | 36 | await tryVerifyContract(contractAddress); 37 | }; 38 | export default func; 39 | func.tags = ["IntegrationTestTrueVerifier"]; 40 | -------------------------------------------------------------------------------- /deploy/02_deploy_PlonkVerifierDev.ts: -------------------------------------------------------------------------------- 1 | import { DeployFunction } from "hardhat-deploy/types"; 2 | import { HardhatRuntimeEnvironment } from "hardhat/types"; 3 | import { deployFromFactory } from "../scripts/hardhat/utils"; 4 | import { validateDeployBranchAndTags } from "../utils/auditedDeployVerifier"; 5 | import { getDeployedContractAddress, tryStoreAddress } from "../utils/storeAddress"; 6 | import { tryVerifyContract } from "../utils/verifyContract"; 7 | import { ethers } from "hardhat"; 8 | 9 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 10 | const { deployments } = hre; 11 | validateDeployBranchAndTags(hre.network.name); 12 | 13 | const contractName = "PlonkVerifierDev"; 14 | const existingContractAddress = await getDeployedContractAddress(contractName, deployments); 15 | 16 | const provider = ethers.provider; 17 | 18 | if (existingContractAddress === undefined) { 19 | console.log(`Deploying initial version, NB: the address will be saved if env SAVE_ADDRESS=true.`); 20 | } else { 21 | console.log(`Deploying new version, NB: ${existingContractAddress} will be overwritten if env SAVE_ADDRESS=true.`); 22 | } 23 | const contract = await deployFromFactory(contractName, provider); 24 | const contractAddress = await contract.getAddress(); 25 | console.log(`${contractName} deployed at ${contractAddress}`); 26 | 27 | process.env.PLONKVERIFIER_ADDRESS = contractAddress; 28 | 29 | const deployTx = contract.deploymentTransaction(); 30 | if (!deployTx) { 31 | throw "Deployment transaction not found."; 32 | } 33 | 34 | await tryStoreAddress(hre.network.name, contractName, contractAddress, deployTx.hash); 35 | 36 | await tryVerifyContract(contractAddress); 37 | }; 38 | export default func; 39 | func.tags = ["PlonkVerifierDev"]; 40 | -------------------------------------------------------------------------------- /deploy/03_deploy_PlonkVerifierFull.ts: -------------------------------------------------------------------------------- 1 | import { DeployFunction } from "hardhat-deploy/types"; 2 | import { HardhatRuntimeEnvironment } from "hardhat/types"; 3 | import { deployFromFactory } from "../scripts/hardhat/utils"; 4 | import { validateDeployBranchAndTags } from "../utils/auditedDeployVerifier"; 5 | import { getDeployedContractAddress, tryStoreAddress } from "../utils/storeAddress"; 6 | import { tryVerifyContract } from "../utils/verifyContract"; 7 | import { ethers } from "hardhat"; 8 | 9 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 10 | const { deployments } = hre; 11 | validateDeployBranchAndTags(hre.network.name); 12 | 13 | const contractName = "PlonkVerifierFull"; 14 | const existingContractAddress = await getDeployedContractAddress(contractName, deployments); 15 | 16 | const provider = ethers.provider; 17 | 18 | if (existingContractAddress === undefined) { 19 | console.log(`Deploying initial version, NB: the address will be saved if env SAVE_ADDRESS=true.`); 20 | } else { 21 | console.log(`Deploying new version, NB: ${existingContractAddress} will be overwritten if env SAVE_ADDRESS=true.`); 22 | } 23 | const contract = await deployFromFactory(contractName, provider); 24 | const contractAddress = await contract.getAddress(); 25 | console.log(`${contractName} deployed at ${contractAddress}`); 26 | 27 | process.env.PLONKVERIFIER_ADDRESS = contractAddress; 28 | 29 | const deployTx = contract.deploymentTransaction(); 30 | if (!deployTx) { 31 | throw "Deployment transaction not found."; 32 | } 33 | 34 | await tryStoreAddress(hre.network.name, contractName, contractAddress, deployTx.hash); 35 | 36 | await tryVerifyContract(contractAddress); 37 | }; 38 | export default func; 39 | func.tags = ["PlonkVerifierFull"]; 40 | -------------------------------------------------------------------------------- /deploy/04_deploy_PlonkVerifierForDataAggregation.ts: -------------------------------------------------------------------------------- 1 | import { DeployFunction } from "hardhat-deploy/types"; 2 | import { HardhatRuntimeEnvironment } from "hardhat/types"; 3 | import { deployFromFactory } from "../scripts/hardhat/utils"; 4 | import { validateDeployBranchAndTags } from "../utils/auditedDeployVerifier"; 5 | import { getDeployedContractAddress, tryStoreAddress } from "../utils/storeAddress"; 6 | import { tryVerifyContract } from "../utils/verifyContract"; 7 | import { ethers } from "hardhat"; 8 | 9 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 10 | const { deployments } = hre; 11 | validateDeployBranchAndTags(hre.network.name); 12 | 13 | const contractName = "PlonkVerifierForDataAggregation"; 14 | const existingContractAddress = await getDeployedContractAddress(contractName, deployments); 15 | 16 | const provider = ethers.provider; 17 | 18 | if (existingContractAddress === undefined) { 19 | console.log(`Deploying initial version, NB: the address will be saved if env SAVE_ADDRESS=true.`); 20 | } else { 21 | console.log(`Deploying new version, NB: ${existingContractAddress} will be overwritten if env SAVE_ADDRESS=true.`); 22 | } 23 | const contract = await deployFromFactory(contractName, provider); 24 | const contractAddress = await contract.getAddress(); 25 | console.log(`${contractName} deployed at ${contractAddress}`); 26 | 27 | process.env.PLONKVERIFIER_ADDRESS = contractAddress; 28 | 29 | const deployTx = contract.deploymentTransaction(); 30 | if (!deployTx) { 31 | throw "Deployment transaction not found."; 32 | } 33 | 34 | await tryStoreAddress(hre.network.name, contractName, contractAddress, deployTx.hash); 35 | 36 | await tryVerifyContract(contractAddress); 37 | }; 38 | export default func; 39 | func.tags = ["PlonkVerifierForDataAggregation"]; 40 | -------------------------------------------------------------------------------- /deploy/04_deploy_PlonkVerifierForMultiTypeDataAggregation.ts: -------------------------------------------------------------------------------- 1 | import { DeployFunction } from "hardhat-deploy/types"; 2 | import { HardhatRuntimeEnvironment } from "hardhat/types"; 3 | import { deployFromFactory } from "../scripts/hardhat/utils"; 4 | import { validateDeployBranchAndTags } from "../utils/auditedDeployVerifier"; 5 | import { getDeployedContractAddress, tryStoreAddress } from "../utils/storeAddress"; 6 | import { tryVerifyContract } from "../utils/verifyContract"; 7 | import { ethers } from "hardhat"; 8 | 9 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 10 | const { deployments } = hre; 11 | validateDeployBranchAndTags(hre.network.name); 12 | 13 | const contractName = "PlonkVerifierForMultiTypeDataAggregation"; 14 | const existingContractAddress = await getDeployedContractAddress(contractName, deployments); 15 | 16 | const provider = ethers.provider; 17 | 18 | if (existingContractAddress === undefined) { 19 | console.log(`Deploying initial version, NB: the address will be saved if env SAVE_ADDRESS=true.`); 20 | } else { 21 | console.log(`Deploying new version, NB: ${existingContractAddress} will be overwritten if env SAVE_ADDRESS=true.`); 22 | } 23 | const contract = await deployFromFactory(contractName, provider); 24 | const contractAddress = await contract.getAddress(); 25 | console.log(`${contractName} deployed at ${contractAddress}`); 26 | 27 | process.env.PLONKVERIFIER_ADDRESS = contractAddress; 28 | 29 | const deployTx = contract.deploymentTransaction(); 30 | if (!deployTx) { 31 | throw "Deployment transaction not found."; 32 | } 33 | 34 | await tryStoreAddress(hre.network.name, contractName, contractAddress, deployTx.hash); 35 | 36 | await tryVerifyContract(contractAddress); 37 | }; 38 | export default func; 39 | func.tags = ["PlonkVerifierForMultiTypeDataAggregation"]; 40 | -------------------------------------------------------------------------------- /deploy/04_deploy_PlonkVerifierFullLarge.ts: -------------------------------------------------------------------------------- 1 | import { DeployFunction } from "hardhat-deploy/types"; 2 | import { HardhatRuntimeEnvironment } from "hardhat/types"; 3 | import { deployFromFactory } from "../scripts/hardhat/utils"; 4 | import { validateDeployBranchAndTags } from "../utils/auditedDeployVerifier"; 5 | import { getDeployedContractAddress, tryStoreAddress } from "../utils/storeAddress"; 6 | import { tryVerifyContract } from "../utils/verifyContract"; 7 | import { ethers } from "hardhat"; 8 | 9 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 10 | const { deployments } = hre; 11 | validateDeployBranchAndTags(hre.network.name); 12 | 13 | const contractName = "PlonkVerifierFullLarge"; 14 | const existingContractAddress = await getDeployedContractAddress(contractName, deployments); 15 | 16 | const provider = ethers.provider; 17 | 18 | if (existingContractAddress === undefined) { 19 | console.log(`Deploying initial version, NB: the address will be saved if env SAVE_ADDRESS=true.`); 20 | } else { 21 | console.log(`Deploying new version, NB: ${existingContractAddress} will be overwritten if env SAVE_ADDRESS=true.`); 22 | } 23 | const contract = await deployFromFactory(contractName, provider); 24 | const contractAddress = await contract.getAddress(); 25 | console.log(`${contractName} deployed at ${contractAddress}`); 26 | 27 | process.env.PLONKVERIFIER_ADDRESS = contractAddress; 28 | 29 | const deployTx = contract.deploymentTransaction(); 30 | if (!deployTx) { 31 | throw "Deployment transaction not found."; 32 | } 33 | 34 | await tryStoreAddress(hre.network.name, contractName, contractAddress, deployTx.hash); 35 | 36 | await tryVerifyContract(contractAddress); 37 | }; 38 | export default func; 39 | func.tags = ["PlonkVerifierFullLarge"]; 40 | -------------------------------------------------------------------------------- /deploy/05_deploy_Timelock.ts: -------------------------------------------------------------------------------- 1 | import { ethers } from "hardhat"; 2 | import { DeployFunction } from "hardhat-deploy/types"; 3 | import { HardhatRuntimeEnvironment } from "hardhat/types"; 4 | import { deployFromFactory, requireEnv } from "../scripts/hardhat/utils"; 5 | import { get1559Fees } from "../scripts/utils"; 6 | import { validateDeployBranchAndTags } from "../utils/auditedDeployVerifier"; 7 | import { getDeployedContractAddress, tryStoreAddress } from "../utils/storeAddress"; 8 | import { tryVerifyContractWithConstructorArgs } from "../utils/verifyContract"; 9 | 10 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 11 | const { deployments } = hre; 12 | validateDeployBranchAndTags(hre.network.name); 13 | 14 | const contractName = "TimeLock"; 15 | const existingContractAddress = await getDeployedContractAddress(contractName, deployments); 16 | 17 | const provider = ethers.provider; 18 | 19 | // This should be the safe 20 | const timeLockProposers = requireEnv("TIMELOCK_PROPOSERS"); 21 | 22 | // This should be the safe 23 | const timelockExecutors = requireEnv("TIMELOCK_EXECUTORS"); 24 | 25 | // This should be the safe 26 | const adminAddress = requireEnv("TIMELOCK_ADMIN_ADDRESS"); 27 | 28 | const minDelay = process.env.MIN_DELAY || 0; 29 | 30 | if (existingContractAddress === undefined) { 31 | console.log(`Deploying initial version, NB: the address will be saved if env SAVE_ADDRESS=true.`); 32 | } else { 33 | console.log(`Deploying new version, NB: ${existingContractAddress} will be overwritten if env SAVE_ADDRESS=true.`); 34 | } 35 | const contract = await deployFromFactory( 36 | contractName, 37 | provider, 38 | minDelay, 39 | timeLockProposers?.split(","), 40 | timelockExecutors?.split(","), 41 | adminAddress, 42 | await get1559Fees(provider), 43 | ); 44 | const contractAddress = await contract.getAddress(); 45 | 46 | console.log(`${contractName} deployed at ${contractAddress}`); 47 | 48 | const deployTx = contract.deploymentTransaction(); 49 | if (!deployTx) { 50 | throw "Deployment transaction not found."; 51 | } 52 | 53 | await tryStoreAddress(hre.network.name, contractName, contractAddress, deployTx.hash); 54 | const args = [minDelay, timeLockProposers?.split(","), timelockExecutors?.split(","), adminAddress]; 55 | 56 | await tryVerifyContractWithConstructorArgs( 57 | contractAddress, 58 | "contracts/messageService/lib/TimeLock.sol:TimeLock", 59 | args, 60 | ); 61 | }; 62 | export default func; 63 | func.tags = ["Timelock"]; 64 | -------------------------------------------------------------------------------- /deploy/06_deploy_LineaRollupImplementation.ts: -------------------------------------------------------------------------------- 1 | import { ethers, upgrades } from "hardhat"; 2 | import { DeployFunction } from "hardhat-deploy/types"; 3 | import { HardhatRuntimeEnvironment } from "hardhat/types"; 4 | import { requireEnv } from "../scripts/hardhat/utils"; 5 | import { validateDeployBranchAndTags } from "../utils/auditedDeployVerifier"; 6 | import { getDeployedContractAddress } from "../utils/storeAddress"; 7 | import { tryVerifyContract } from "../utils/verifyContract"; 8 | 9 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 10 | const { deployments } = hre; 11 | validateDeployBranchAndTags(hre.network.name); 12 | 13 | const contractName = "LineaRollup"; 14 | const existingContractAddress = await getDeployedContractAddress(contractName, deployments); 15 | 16 | const proxyAddress = requireEnv("LINEA_ROLLUP_ADDRESS"); 17 | 18 | const factory = await ethers.getContractFactory("LineaRollup"); 19 | 20 | if (existingContractAddress === undefined) { 21 | console.log(`Deploying initial version, NB: the address will be saved if env SAVE_ADDRESS=true.`); 22 | } else { 23 | console.log(`Deploying new version, NB: ${existingContractAddress} will be overwritten if env SAVE_ADDRESS=true.`); 24 | } 25 | 26 | console.log("Deploying Contract..."); 27 | const newContract = await upgrades.deployImplementation(factory, { 28 | kind: "transparent", 29 | }); 30 | 31 | const contract = newContract.toString(); 32 | 33 | console.log(`Contract deployed at ${contract}`); 34 | 35 | const upgradeCallUsingSecurityCouncil = ethers.concat([ 36 | "0x99a88ec4", 37 | ethers.AbiCoder.defaultAbiCoder().encode(["address", "address"], [proxyAddress, newContract]), 38 | ]); 39 | 40 | console.log("Encoded Tx Upgrade from Security Council:", "\n", upgradeCallUsingSecurityCouncil); 41 | 42 | console.log("\n"); 43 | 44 | await tryVerifyContract(contract); 45 | }; 46 | 47 | export default func; 48 | func.tags = ["LineaRollupImplementation"]; 49 | -------------------------------------------------------------------------------- /deploy/06_deploy_LineaRollupWithReinitialization.ts: -------------------------------------------------------------------------------- 1 | import { ethers, upgrades } from "hardhat"; 2 | import { DeployFunction } from "hardhat-deploy/types"; 3 | import { HardhatRuntimeEnvironment } from "hardhat/types"; 4 | import { requireEnv } from "../scripts/hardhat/utils"; 5 | import { LineaRollupInit__factory } from "../typechain-types"; 6 | import { validateDeployBranchAndTags } from "../utils/auditedDeployVerifier"; 7 | import { getDeployedContractAddress } from "../utils/storeAddress"; 8 | import { tryVerifyContract } from "../utils/verifyContract"; 9 | 10 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 11 | const { deployments } = hre; 12 | validateDeployBranchAndTags(hre.network.name); 13 | 14 | const contractName = "LineaRollupInit"; 15 | const existingContractAddress = await getDeployedContractAddress(contractName, deployments); 16 | 17 | const proxyAddress = requireEnv("LINEA_ROLLUP_ADDRESS"); 18 | const initialL2BlockNumber = "3"; 19 | const initialStateRootHash = "0x3450000000000000000000000000000000000000000000000000000000000000"; 20 | 21 | const factory = await ethers.getContractFactory("LineaRollupInit"); 22 | 23 | if (existingContractAddress === undefined) { 24 | console.log(`Deploying initial version, NB: the address will be saved if env SAVE_ADDRESS=true.`); 25 | } else { 26 | console.log(`Deploying new version, NB: ${existingContractAddress} will be overwritten if env SAVE_ADDRESS=true.`); 27 | } 28 | 29 | console.log("Deploying Contract..."); 30 | const newContract = await upgrades.deployImplementation(factory, { 31 | kind: "transparent", 32 | }); 33 | 34 | const contract = newContract.toString(); 35 | 36 | console.log(`Contract deployed at ${contract}`); 37 | 38 | // The encoding should be used through the safe. 39 | const upgradeCallWithReinitializationUsingSecurityCouncil = ethers.concat([ 40 | "0x9623609d", 41 | ethers.AbiCoder.defaultAbiCoder().encode( 42 | ["address", "address", "bytes"], 43 | [ 44 | proxyAddress, 45 | newContract, 46 | LineaRollupInit__factory.createInterface().encodeFunctionData("initializeV2", [ 47 | initialL2BlockNumber, 48 | initialStateRootHash, 49 | ]), 50 | ], 51 | ), 52 | ]); 53 | 54 | console.log( 55 | "Encoded Tx Upgrade with Reinitialization from Security Council:", 56 | "\n", 57 | upgradeCallWithReinitializationUsingSecurityCouncil, 58 | ); 59 | console.log("\n"); 60 | 61 | await tryVerifyContract(contract); 62 | }; 63 | 64 | export default func; 65 | func.tags = ["LineaRollupWithReinitialization"]; 66 | -------------------------------------------------------------------------------- /deploy/07_deploy_L2MessageService.ts: -------------------------------------------------------------------------------- 1 | import { DeployFunction } from "hardhat-deploy/types"; 2 | import { HardhatRuntimeEnvironment } from "hardhat/types"; 3 | import { deployUpgradableFromFactory, requireEnv } from "../scripts/hardhat/utils"; 4 | import { validateDeployBranchAndTags } from "../utils/auditedDeployVerifier"; 5 | import { getDeployedContractAddress, tryStoreAddress } from "../utils/storeAddress"; 6 | import { tryVerifyContract } from "../utils/verifyContract"; 7 | 8 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 9 | const { deployments } = hre; 10 | validateDeployBranchAndTags(hre.network.name); 11 | 12 | const contractName = "L2MessageService"; 13 | const existingContractAddress = await getDeployedContractAddress(contractName, deployments); 14 | 15 | const L2MessageService_securityCouncil = requireEnv("L2MSGSERVICE_SECURITY_COUNCIL"); 16 | const L2MessageService_l1l2MessageSetter = requireEnv("L2MSGSERVICE_L1L2_MESSAGE_SETTER"); 17 | const L2MessageService_rateLimitPeriod = requireEnv("L2MSGSERVICE_RATE_LIMIT_PERIOD"); 18 | const L2MessageService_rateLimitAmount = requireEnv("L2MSGSERVICE_RATE_LIMIT_AMOUNT"); 19 | 20 | if (existingContractAddress === undefined) { 21 | console.log(`Deploying initial version, NB: the address will be saved if env SAVE_ADDRESS=true.`); 22 | } else { 23 | console.log(`Deploying new version, NB: ${existingContractAddress} will be overwritten if env SAVE_ADDRESS=true.`); 24 | } 25 | 26 | const contract = await deployUpgradableFromFactory( 27 | "L2MessageService", 28 | [ 29 | L2MessageService_securityCouncil, 30 | L2MessageService_l1l2MessageSetter, 31 | L2MessageService_rateLimitPeriod, 32 | L2MessageService_rateLimitAmount, 33 | ], 34 | { 35 | initializer: "initialize(address,address,uint256,uint256)", 36 | unsafeAllow: ["constructor"], 37 | }, 38 | ); 39 | const contractAddress = await contract.getAddress(); 40 | const txReceipt = await contract.deploymentTransaction()?.wait(); 41 | if (!txReceipt) { 42 | throw "Contract deployment transaction receipt not found."; 43 | } 44 | console.log(`${contractName} deployed: address=${contractAddress} blockNumber=${txReceipt.blockNumber}`); 45 | 46 | await tryStoreAddress(hre.network.name, contractName, contractAddress, txReceipt.hash); 47 | 48 | await tryVerifyContract(contractAddress); 49 | }; 50 | export default func; 51 | func.tags = ["L2MessageService"]; 52 | -------------------------------------------------------------------------------- /deploy/07_deploy_L2MessageServiceImplementation.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from "hardhat/types"; 2 | import { DeployFunction } from "hardhat-deploy/types"; 3 | import { getDeployedContractAddress } from "../utils/storeAddress"; 4 | import { tryVerifyContract } from "../utils/verifyContract"; 5 | import { validateDeployBranchAndTags } from "../utils/auditedDeployVerifier"; 6 | import { ethers, upgrades } from "hardhat"; 7 | 8 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 9 | const { deployments } = hre; 10 | validateDeployBranchAndTags(hre.network.name); 11 | 12 | const contractName = "L2MessageService"; 13 | const existingContractAddress = await getDeployedContractAddress(contractName, deployments); 14 | 15 | const factory = await ethers.getContractFactory("L2MessageService"); 16 | 17 | if (existingContractAddress === undefined) { 18 | console.log(`Deploying initial version, NB: the address will be saved if env SAVE_ADDRESS=true.`); 19 | } else { 20 | console.log(`Deploying new version, NB: ${existingContractAddress} will be overwritten if env SAVE_ADDRESS=true.`); 21 | } 22 | 23 | console.log("Deploying Contract..."); 24 | const newContract = await upgrades.deployImplementation(factory, { 25 | kind: "transparent", 26 | }); 27 | 28 | const contract = newContract.toString(); 29 | 30 | console.log(`Contract deployed at ${contract}`); 31 | 32 | await tryVerifyContract(contract); 33 | }; 34 | export default func; 35 | func.tags = ["L2MessageServiceImplementation"]; 36 | -------------------------------------------------------------------------------- /deploy/08_deploy_BridgedToken.ts: -------------------------------------------------------------------------------- 1 | import { ethers, network, upgrades } from "hardhat"; 2 | import { DeployFunction } from "hardhat-deploy/types"; 3 | import { HardhatRuntimeEnvironment } from "hardhat/types"; 4 | import { BridgedToken } from "../typechain-types"; 5 | import { validateDeployBranchAndTags } from "../utils/auditedDeployVerifier"; 6 | import { getDeployedContractAddress, tryStoreAddress } from "../utils/storeAddress"; 7 | import { tryVerifyContract } from "../utils/verifyContract"; 8 | 9 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 10 | const { deployments } = hre; 11 | validateDeployBranchAndTags(hre.network.name); 12 | 13 | const contractName = "BridgedToken"; 14 | const existingContractAddress = await getDeployedContractAddress(contractName, deployments); 15 | 16 | const chainId = (await ethers.provider.getNetwork()).chainId; 17 | console.log(`Current network's chainId is ${chainId}`); 18 | 19 | if (existingContractAddress === undefined) { 20 | console.log(`Deploying initial version, NB: the address will be saved if env SAVE_ADDRESS=true.`); 21 | } else { 22 | console.log(`Deploying new version, NB: ${existingContractAddress} will be overwritten if env SAVE_ADDRESS=true.`); 23 | } 24 | 25 | // Deploy beacon for bridged token 26 | const BridgedToken = await ethers.getContractFactory(contractName); 27 | 28 | const bridgedToken = (await upgrades.deployBeacon(BridgedToken)) as unknown as BridgedToken; 29 | await bridgedToken.waitForDeployment(); 30 | 31 | const bridgedTokenAddress = await bridgedToken.getAddress(); 32 | process.env.BRIDGED_TOKEN_ADDRESS = bridgedTokenAddress; 33 | 34 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 35 | // @ts-ignore 36 | const deployTx = bridgedToken.deployTransaction; 37 | if (!deployTx) { 38 | throw "Contract deployment transaction receipt not found."; 39 | } 40 | 41 | await tryStoreAddress(network.name, contractName, bridgedTokenAddress, deployTx.hash); 42 | 43 | console.log(`BridgedToken beacon deployed on ${network.name}, at address:`, bridgedTokenAddress); 44 | 45 | await tryVerifyContract(bridgedTokenAddress); 46 | }; 47 | export default func; 48 | func.tags = ["BridgedToken"]; 49 | -------------------------------------------------------------------------------- /deploy/10_deploy_LXPToken.ts: -------------------------------------------------------------------------------- 1 | import { ethers } from "hardhat"; 2 | import { DeployFunction } from "hardhat-deploy/types"; 3 | import { HardhatRuntimeEnvironment } from "hardhat/types"; 4 | import { deployFromFactory, requireEnv } from "../scripts/hardhat/utils"; 5 | import { get1559Fees } from "../scripts/utils"; 6 | import { validateDeployBranchAndTags } from "../utils/auditedDeployVerifier"; 7 | import { getDeployedContractAddress, tryStoreAddress } from "../utils/storeAddress"; 8 | import { tryVerifyContractWithConstructorArgs } from "../utils/verifyContract"; 9 | 10 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 11 | const { deployments } = hre; 12 | validateDeployBranchAndTags(hre.network.name); 13 | 14 | const contractName = "LineaVoyageXP"; 15 | const existingContractAddress = await getDeployedContractAddress(contractName, deployments); 16 | const provider = ethers.provider; 17 | 18 | const adminAddress = requireEnv("LINEA_VOYAGE_XP_ADMIN_ADDRESS"); 19 | 20 | if (existingContractAddress === undefined) { 21 | console.log(`Deploying initial version, NB: the address will be saved if env SAVE_ADDRESS=true.`); 22 | } else { 23 | console.log(`Deploying new version, NB: ${existingContractAddress} will be overwritten if env SAVE_ADDRESS=true.`); 24 | } 25 | const contract = await deployFromFactory(contractName, provider, adminAddress, await get1559Fees(provider)); 26 | const contractAddress = await contract.getAddress(); 27 | 28 | console.log(`${contractName} deployed at ${contractAddress}`); 29 | 30 | const deployTx = contract.deploymentTransaction(); 31 | if (!deployTx) { 32 | throw "Contract deployment transaction receipt not found."; 33 | } 34 | 35 | await tryStoreAddress(hre.network.name, contractName, contractAddress, deployTx.hash); 36 | 37 | const args = [adminAddress]; 38 | 39 | await tryVerifyContractWithConstructorArgs(contractAddress, "contracts/token/LineaVoyageXP.sol:LineaVoyageXP", args); 40 | }; 41 | export default func; 42 | func.tags = ["LineaVoyageXPToken"]; 43 | -------------------------------------------------------------------------------- /deploy/10_deploy_SurgeXPToken.ts: -------------------------------------------------------------------------------- 1 | import { ethers } from "hardhat"; 2 | import { DeployFunction } from "hardhat-deploy/types"; 3 | import { HardhatRuntimeEnvironment } from "hardhat/types"; 4 | import { deployFromFactory, requireEnv } from "../scripts/hardhat/utils"; 5 | import { get1559Fees } from "../scripts/utils"; 6 | import { validateDeployBranchAndTags } from "../utils/auditedDeployVerifier"; 7 | import { getDeployedContractAddress, tryStoreAddress } from "../utils/storeAddress"; 8 | import { tryVerifyContractWithConstructorArgs } from "../utils/verifyContract"; 9 | 10 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 11 | const { deployments } = hre; 12 | validateDeployBranchAndTags(hre.network.name); 13 | 14 | const contractName = "LineaSurgeXP"; 15 | const existingContractAddress = await getDeployedContractAddress(contractName, deployments); 16 | const provider = ethers.provider; 17 | 18 | const adminAddress = requireEnv("LINEA_SURGE_XP_ADMIN_ADDRESS"); 19 | const minterAddress = requireEnv("LINEA_SURGE_XP_MINTER_ADDRESS"); 20 | const transferAddresses = requireEnv("LINEA_SURGE_XP_TRANSFER_ADDRESSES")?.split(","); 21 | 22 | console.log(transferAddresses); 23 | if (existingContractAddress === undefined) { 24 | console.log(`Deploying initial version, NB: the address will be saved if env SAVE_ADDRESS=true.`); 25 | } else { 26 | console.log(`Deploying new version, NB: ${existingContractAddress} will be overwritten if env SAVE_ADDRESS=true.`); 27 | } 28 | const contract = await deployFromFactory( 29 | contractName, 30 | provider, 31 | adminAddress, 32 | minterAddress, 33 | transferAddresses, 34 | await get1559Fees(provider), 35 | ); 36 | const contractAddress = await contract.getAddress(); 37 | 38 | console.log(`${contractName} deployed at ${contractAddress}`); 39 | 40 | const deployTx = contract.deploymentTransaction(); 41 | if (!deployTx) { 42 | throw "Contract deployment transaction receipt not found."; 43 | } 44 | 45 | await tryStoreAddress(hre.network.name, contractName, contractAddress, deployTx.hash); 46 | 47 | const args = [adminAddress, minterAddress, transferAddresses]; 48 | 49 | await tryVerifyContractWithConstructorArgs(contractAddress, "contracts/token/LineaSurgeXP.sol:LineaSurgeXP", args); 50 | }; 51 | export default func; 52 | func.tags = ["LineaSurgeXPToken"]; 53 | -------------------------------------------------------------------------------- /deploy/11_deploy_CustomBridgedToken.ts: -------------------------------------------------------------------------------- 1 | import { ethers, network } from "hardhat"; 2 | import { DeployFunction } from "hardhat-deploy/types"; 3 | import { HardhatRuntimeEnvironment } from "hardhat/types"; 4 | import { deployUpgradableFromFactory, requireEnv } from "../scripts/hardhat/utils"; 5 | import { validateDeployBranchAndTags } from "../utils/auditedDeployVerifier"; 6 | import { getDeployedContractAddress, tryStoreAddress } from "../utils/storeAddress"; 7 | import { tryVerifyContract } from "../utils/verifyContract"; 8 | 9 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 10 | const { deployments } = hre; 11 | validateDeployBranchAndTags(hre.network.name); 12 | 13 | const contractName = "CustomBridgedToken"; 14 | const existingContractAddress = await getDeployedContractAddress(contractName, deployments); 15 | 16 | const CustomTokenBridge_name = requireEnv("CUSTOMTOKENBRIDGE_NAME"); 17 | const CustomTokenBridge_symbol = requireEnv("CUSTOMTOKENBRIDGE_SYMBOL"); 18 | const CustomTokenBridge_decimals = requireEnv("CUSTOMTOKENBRIDGE_DECIMALS"); 19 | const CustomTokenBridge_bridge_address = requireEnv("CUSTOMTOKENBRIDGE_BRIDGE_ADDRESS"); 20 | 21 | const chainId = (await ethers.provider.getNetwork()).chainId; 22 | console.log(`Current network's chainId is ${chainId}`); 23 | 24 | if (existingContractAddress === undefined) { 25 | console.log(`Deploying initial version, NB: the address will be saved if env SAVE_ADDRESS=true.`); 26 | } else { 27 | console.log(`Deploying new version, NB: ${existingContractAddress} will be overwritten if env SAVE_ADDRESS=true.`); 28 | } 29 | 30 | // Deploy proxy for custom bridged token 31 | const customBridgedToken = await deployUpgradableFromFactory( 32 | contractName, 33 | [CustomTokenBridge_name, CustomTokenBridge_symbol, CustomTokenBridge_decimals, CustomTokenBridge_bridge_address], 34 | { 35 | initializer: "initializeV2(string,string,uint8,address)", 36 | unsafeAllow: ["constructor"], 37 | }, 38 | ); 39 | 40 | await customBridgedToken.waitForDeployment(); 41 | const customBridgedTokenAddress = await customBridgedToken.getAddress(); 42 | 43 | const deployTx = customBridgedToken.deploymentTransaction(); 44 | if (!deployTx) { 45 | throw "Contract deployment transaction receipt not found."; 46 | } 47 | 48 | await tryStoreAddress(network.name, contractName, customBridgedTokenAddress, deployTx.hash); 49 | 50 | console.log(`CustomBridgedToken deployed on ${network.name}, at address:`, customBridgedTokenAddress); 51 | 52 | await tryVerifyContract(customBridgedTokenAddress); 53 | }; 54 | export default func; 55 | func.tags = ["CustomBridgedToken"]; 56 | -------------------------------------------------------------------------------- /deploy/11_deploy_MYToken.ts: -------------------------------------------------------------------------------- 1 | import { ethers } from "hardhat"; 2 | import { DeployFunction } from "hardhat-deploy/types"; 3 | import { HardhatRuntimeEnvironment } from "hardhat/types"; 4 | import { deployFromFactory, requireEnv } from "../scripts/hardhat/utils"; 5 | import { get1559Fees } from "../scripts/utils"; 6 | import { getDeployedContractAddress, tryStoreAddress } from "../utils/storeAddress"; 7 | import { tryVerifyContractWithConstructorArgs } from "../utils/verifyContract"; 8 | 9 | const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { 10 | const { deployments } = hre; 11 | const contractName = "MyToken"; 12 | const existingContractAddress = await getDeployedContractAddress(contractName, deployments); 13 | const provider = ethers.provider; 14 | 15 | const adminAddress = requireEnv("MYTOKEN_ADMIN_ADDRESS"); 16 | 17 | if (existingContractAddress === undefined) { 18 | console.log(`Deploying initial version, NB: the address will be saved if env SAVE_ADDRESS=true.`); 19 | } else { 20 | console.log(`Deploying new version, NB: ${existingContractAddress} will be overwritten if env SAVE_ADDRESS=true.`); 21 | } 22 | const contract = await deployFromFactory(contractName, provider, adminAddress, await get1559Fees(provider)); 23 | 24 | const contractAddress = await contract.getAddress(); 25 | console.log(`${contractName} deployed at ${contractAddress}`); 26 | 27 | const deployTx = contract.deploymentTransaction(); 28 | if (!deployTx) { 29 | throw "Contract deployment transaction receipt not found."; 30 | } 31 | 32 | await tryStoreAddress(hre.network.name, contractName, contractAddress, deployTx.hash); 33 | 34 | const args = [adminAddress]; 35 | 36 | await tryVerifyContractWithConstructorArgs(contractAddress, "contracts/token/MyToken.sol:MyToken", args); 37 | }; 38 | export default func; 39 | func.tags = ["MYToken"]; 40 | -------------------------------------------------------------------------------- /deploy/13_deploy_TestEIP4844.ts: -------------------------------------------------------------------------------- 1 | import { ethers } from "hardhat"; 2 | import { DeployFunction } from "hardhat-deploy/types"; 3 | import { deployFromFactory } from "../scripts/hardhat/utils"; 4 | import { get1559Fees } from "../scripts/utils"; 5 | 6 | const func: DeployFunction = async function () { 7 | const contractName = "TestEIP4844"; 8 | 9 | const provider = ethers.provider; 10 | 11 | const contract = await deployFromFactory(contractName, provider, await get1559Fees(provider)); 12 | const contractAddress = await contract.getAddress(); 13 | 14 | console.log(`${contractName} deployed at ${contractAddress}`); 15 | 16 | const deployTx = contract.deploymentTransaction(); 17 | if (!deployTx) { 18 | throw "Contract deployment transaction receipt not found."; 19 | } 20 | }; 21 | export default func; 22 | func.tags = ["TestEIP4844"]; 23 | -------------------------------------------------------------------------------- /deployments.json: -------------------------------------------------------------------------------- 1 | { 2 | "zkevm_dev": { 3 | "BridgedToken": "0x90Ca839E598F14a892aE77bc46Ad8327f9a3E65C", 4 | "TokenBridge": "0x16B41c0D2796f724B77EE059A60c3c27036673c8" 5 | }, 6 | "hardhat": { 7 | "l1TokenBeacon": "0xDC11f7E700A4c898AE5CAddB1082cFfa76512aDD", 8 | "l2TokenBeacon": "0x51A1ceB83B83F1985a81C295d1fF28Afef186E02" 9 | }, 10 | "l2": { 11 | "BridgedToken": "0x5AABddC53F8B4d0f7Ba856e9d8340325f6680493", 12 | "TokenBridge": "0x3807833f55F7dfea3931dda85F6e8f2E7d6A6821" 13 | } 14 | } -------------------------------------------------------------------------------- /gnosisZodiac.d.ts: -------------------------------------------------------------------------------- 1 | declare module "@gnosis.pm/zodiac/dist/esm"; 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "linea-contracts", 3 | "engines": { 4 | "node": ">=18", 5 | "pnpm": ">=9" 6 | }, 7 | "scripts": { 8 | "build": "npx hardhat compile", 9 | "test": "npx hardhat test", 10 | "test:reportgas": "REPORT_GAS=true npx hardhat test", 11 | "coverage": "npx hardhat coverage", 12 | "prettier:fix": "prettier -w '**/*.{js,ts,sol}'", 13 | "lint:sol:fix": "solhint --fix --noPrompt 'contracts/**/*.sol'", 14 | "lint:ts:fix": "npx eslint --fix '**/*.{js,ts}'", 15 | "lint:fix": "pnpm run lint:sol:fix && npm run lint:ts:fix && npm run prettier:fix" 16 | }, 17 | "devDependencies": { 18 | "@ethereumjs/util": "^9.0.2", 19 | "@nomicfoundation/hardhat-ethers": "^3.0.5", 20 | "@nomicfoundation/hardhat-network-helpers": "^1.0.10", 21 | "@nomicfoundation/hardhat-toolbox": "^4.0.0", 22 | "@nomicfoundation/hardhat-verify": "^1.1.0", 23 | "@openzeppelin/contracts": "^4.9.3", 24 | "@openzeppelin/contracts-upgradeable": "^4.9.3", 25 | "@openzeppelin/hardhat-upgrades": "^2.5.0", 26 | "@safe-global/protocol-kit": "^3.0.0", 27 | "@safe-global/safe-core-sdk-types": "^4.0.0", 28 | "@typechain/hardhat": "9.0.0", 29 | "@types/diff": "^5.2.0", 30 | "@types/yargs": "^17.0.32", 31 | "@typescript-eslint/eslint-plugin": "^7.10.0", 32 | "@typescript-eslint/parser": "^7.10.0", 33 | "c-kzg": "^2.1.2", 34 | "colors": "^1.4.0", 35 | "dotenv": "^16.4.4", 36 | "edit-json-file": "^1.8.0", 37 | "eslint": "8.57.0", 38 | "eslint-config-prettier": "^9.1.0", 39 | "eslint-plugin-prettier": "^5.1.3", 40 | "ethers": "^6.12.0", 41 | "hardhat": "^2.22.3", 42 | "hardhat-deploy": "^0.12.3", 43 | "hardhat-storage-layout": "^0.1.7", 44 | "hardhat-tracer": "^2.8.2", 45 | "prettier": "^3.2.5", 46 | "prettier-plugin-solidity": "^1.3.1", 47 | "solhint": "^4.1.1", 48 | "yargs": "^17.7.2" 49 | }, 50 | "dependencies": { 51 | "csv-parser": "^3.0.0" 52 | } 53 | } -------------------------------------------------------------------------------- /scripts/cli.ts: -------------------------------------------------------------------------------- 1 | const HEXADECIMAL_REGEX = new RegExp("^0[xX][0-9a-fA-F]+$"); 2 | 3 | const ADDRESS_HEX_STR_SIZE = 42; 4 | const PRIVKEY_HEX_STR_SIZE = 66; 5 | const HASH_HEX_STR_SIZE = 66; 6 | 7 | function sanitizeHexBytes(paramName: string, value: string, expectedSize: number) { 8 | // TODO: add hexadecimal regex match 9 | if (!value.startsWith("0x")) { 10 | value = "0x" + value; 11 | } 12 | 13 | if (!HEXADECIMAL_REGEX.test(value)) { 14 | throw new Error(`${paramName}: '${value}' is not a valid Hexadecimal notation!`); 15 | } 16 | if (value.length !== expectedSize) { 17 | throw new Error(`${paramName} has size ${value.length} expected ${expectedSize}`); 18 | } 19 | return value; 20 | } 21 | 22 | function sanitizeAddress(argName: string) { 23 | return (input: string) => { 24 | return sanitizeHexBytes(argName, input, ADDRESS_HEX_STR_SIZE); 25 | }; 26 | } 27 | 28 | function sanitizePrivKey(argName: string) { 29 | return (input: string) => { 30 | return sanitizeHexBytes(argName, input, PRIVKEY_HEX_STR_SIZE); 31 | }; 32 | } 33 | 34 | function sanitizeHash(argName: string) { 35 | return (input: string) => { 36 | return sanitizeHexBytes(argName, input, HASH_HEX_STR_SIZE); 37 | }; 38 | } 39 | 40 | function assertIsNumber(argName: string) { 41 | return (input: string) => { 42 | if (typeof input != "number" || isNaN(input)) { 43 | throw Error(`${argName} must be a valid number. Got: '${input}'`); 44 | } 45 | return input; 46 | }; 47 | } 48 | 49 | export { sanitizeHexBytes, sanitizeAddress, sanitizePrivKey, sanitizeHash, assertIsNumber }; 50 | -------------------------------------------------------------------------------- /scripts/gnosis/create4-8SafeL1.ts: -------------------------------------------------------------------------------- 1 | import { EthersAdapter, SafeFactory } from "@safe-global/protocol-kit"; 2 | import { ethers } from "hardhat"; 3 | import { requireEnv } from "../hardhat/utils"; 4 | 5 | const main = async () => { 6 | const RPC_URL = requireEnv("BLOCKCHAIN_NODE"); 7 | const SAFE_OWNER1_PRIVATE_KEY = requireEnv("SAFE_OWNER1_PRIVATE_KEY"); 8 | const SAFE_OWNERS = requireEnv("SAFE_OWNERS"); 9 | const provider = new ethers.JsonRpcProvider(RPC_URL); 10 | const signer = new ethers.Wallet(SAFE_OWNER1_PRIVATE_KEY, provider); 11 | 12 | const ethAdapter = new EthersAdapter({ ethers, signerOrProvider: signer }); 13 | 14 | const chainId = await ethAdapter.getChainId(); 15 | console.log(`ChainId: ${chainId}`); 16 | 17 | // const safeVersion = '1.3.0' 18 | // const isL1SafeMasterCopy = false 19 | const safeFactory = await SafeFactory.create({ ethAdapter: ethAdapter }); 20 | 21 | const safeAccountConfig = { 22 | threshold: 4, // Setting the Threshold to 4 23 | owners: SAFE_OWNERS?.split(","), 24 | }; 25 | console.log("Deploying 4/8 safe.."); 26 | 27 | const safeSdkOwner1 = await safeFactory.deploySafe({ safeAccountConfig }); 28 | const safeAddress = await safeSdkOwner1.getAddress(); 29 | 30 | console.log(`4/8 Safe deployed at: ${safeAddress}`); 31 | }; 32 | 33 | main() 34 | .then(() => process.exit(0)) 35 | .catch((error) => { 36 | console.error(error); 37 | process.exit(1); 38 | }); 39 | -------------------------------------------------------------------------------- /scripts/gnosis/create4-8SafeL2.ts: -------------------------------------------------------------------------------- 1 | import { EthersAdapter, SafeFactory } from "@safe-global/protocol-kit"; 2 | import { ethers } from "ethers"; 3 | import { requireEnv } from "../hardhat/utils"; 4 | import { get1559Fees } from "../utils"; 5 | 6 | const main = async () => { 7 | const RPC_URL = requireEnv("BLOCKCHAIN_NODE"); 8 | const SAFE_OWNER1_PRIVATE_KEY = requireEnv("SAFE_OWNER1_PRIVATE_KEY"); 9 | const SAFE_OWNERS = requireEnv("SAFE_OWNERS"); 10 | const provider = new ethers.JsonRpcProvider(RPC_URL); 11 | const signer = new ethers.Wallet(SAFE_OWNER1_PRIVATE_KEY, provider); 12 | 13 | const ethAdapter = new EthersAdapter({ ethers, signerOrProvider: signer }); 14 | 15 | const chainId = await ethAdapter.getChainId(); 16 | console.log(`ChainId: ${chainId}`); 17 | const eip1559Fees = await get1559Fees(provider); 18 | 19 | const txOptions = { 20 | maxFeePerGas: eip1559Fees.maxFeePerGas?.toString(), 21 | maxPriorityFeePerGas: eip1559Fees.maxPriorityFeePerGas?.toString(), 22 | }; 23 | 24 | // const safeVersion = '1.3.0' 25 | // const isL1SafeMasterCopy = false 26 | const safeFactory = await SafeFactory.create({ ethAdapter: ethAdapter }); 27 | 28 | const safeAccountConfig = { 29 | threshold: 4, // Setting the Threshold to 4 30 | owners: SAFE_OWNERS?.split(","), 31 | }; 32 | console.log("Deploying 4/8 safe.."); 33 | 34 | const safeSdkOwner1 = await safeFactory.deploySafe({ safeAccountConfig, saltNonce: "123", options: txOptions }); 35 | const safeAddress = await safeSdkOwner1.getAddress(); 36 | 37 | console.log(`4/8 Safe deployed at: ${safeAddress}`); 38 | }; 39 | 40 | main() 41 | .then(() => process.exit(0)) 42 | .catch((error) => { 43 | console.error(error); 44 | process.exit(1); 45 | }); 46 | -------------------------------------------------------------------------------- /scripts/gnosis/create5-8SafeL1.ts: -------------------------------------------------------------------------------- 1 | import { EthersAdapter, SafeFactory } from "@safe-global/protocol-kit"; 2 | import { ethers } from "ethers"; 3 | import { requireEnv } from "../hardhat/utils"; 4 | 5 | const main = async () => { 6 | const RPC_URL = requireEnv("BLOCKCHAIN_NODE"); 7 | const SAFE_OWNER1_PRIVATE_KEY = requireEnv("SAFE_OWNER1_PRIVATE_KEY"); 8 | const SAFE_OWNERS = requireEnv("SAFE_OWNERS"); 9 | const provider = new ethers.JsonRpcProvider(RPC_URL); 10 | const signer = new ethers.Wallet(SAFE_OWNER1_PRIVATE_KEY, provider); 11 | 12 | const ethAdapter = new EthersAdapter({ ethers, signerOrProvider: signer }); 13 | 14 | const chainId = await ethAdapter.getChainId(); 15 | console.log(`ChainId: ${chainId}`); 16 | 17 | // const safeVersion = '1.3.0' 18 | // const isL1SafeMasterCopy = false 19 | const safeFactory = await SafeFactory.create({ ethAdapter: ethAdapter }); 20 | 21 | const safeAccountConfig = { 22 | threshold: 5, // Setting the Threshold to 5 23 | owners: SAFE_OWNERS?.split(","), 24 | }; 25 | console.log("Deploying 5/8 safe.."); 26 | 27 | const safeSdkOwner1 = await safeFactory.deploySafe({ safeAccountConfig }); 28 | const safeAddress = safeSdkOwner1.getAddress(); 29 | 30 | console.log(`5/8 Safe deployed at: ${safeAddress}`); 31 | }; 32 | 33 | main() 34 | .then(() => process.exit(0)) 35 | .catch((error) => { 36 | console.error(error); 37 | process.exit(1); 38 | }); 39 | -------------------------------------------------------------------------------- /scripts/gnosis/create5-8SafeL2.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-var-requires */ 2 | import { EthersAdapter, SafeFactory } from "@safe-global/protocol-kit"; 3 | import { ethers } from "ethers"; 4 | import { requireEnv } from "../hardhat/utils"; 5 | import { get1559Fees } from "../utils"; 6 | 7 | const main = async () => { 8 | const RPC_URL = requireEnv("BLOCKCHAIN_NODE"); 9 | const SAFE_OWNER1_PRIVATE_KEY = requireEnv("SAFE_OWNER1_PRIVATE_KEY"); 10 | const SAFE_OWNERS = requireEnv("SAFE_OWNERS"); 11 | const provider = new ethers.JsonRpcProvider(RPC_URL); 12 | const signer = new ethers.Wallet(SAFE_OWNER1_PRIVATE_KEY, provider); 13 | 14 | const ethAdapter = new EthersAdapter({ ethers, signerOrProvider: signer }); 15 | 16 | const chainId = await ethAdapter.getChainId(); 17 | console.log(`ChainId: ${chainId}`); 18 | const eip1559Fees = await get1559Fees(provider); 19 | 20 | const txOptions = { 21 | maxFeePerGas: eip1559Fees.maxFeePerGas?.toString(), 22 | maxPriorityFeePerGas: eip1559Fees.maxPriorityFeePerGas?.toString(), 23 | }; 24 | 25 | // const safeVersion = '1.3.0' 26 | // const isL1SafeMasterCopy = false 27 | const safeFactory = await SafeFactory.create({ ethAdapter: ethAdapter }); 28 | 29 | const safeAccountConfig = { 30 | threshold: 5, // Setting the Threshold to 5 31 | owners: SAFE_OWNERS?.split(","), 32 | }; 33 | console.log("Deploying 5/8 safe.."); 34 | 35 | const safeSdkOwner1 = await safeFactory.deploySafe({ safeAccountConfig, saltNonce: "123", options: txOptions }); 36 | const safeAddress = safeSdkOwner1.getAddress(); 37 | 38 | console.log(`5/8 Safe deployed at: ${safeAddress}`); 39 | }; 40 | 41 | main() 42 | .then(() => process.exit(0)) 43 | .catch((error) => { 44 | console.error(error); 45 | process.exit(1); 46 | }); 47 | -------------------------------------------------------------------------------- /scripts/gnosis/createSecurityCouncilSafeL1.ts: -------------------------------------------------------------------------------- 1 | import { EthersAdapter, SafeFactory } from "@safe-global/protocol-kit"; 2 | import { ethers } from "ethers"; 3 | import { requireEnv } from "../hardhat/utils"; 4 | 5 | const main = async () => { 6 | const RPC_URL = requireEnv("BLOCKCHAIN_NODE"); 7 | const SAFE_OWNER1_PRIVATE_KEY = requireEnv("SAFE_OWNER1_PRIVATE_KEY"); 8 | const SAFE_OWNERS = requireEnv("SAFE_OWNERS"); 9 | const provider = new ethers.JsonRpcProvider(RPC_URL); 10 | const signer = new ethers.Wallet(SAFE_OWNER1_PRIVATE_KEY, provider); 11 | 12 | const ethAdapter = new EthersAdapter({ ethers, signerOrProvider: signer }); 13 | 14 | const chainId = await ethAdapter.getChainId(); 15 | console.log(`ChainId: ${chainId}`); 16 | 17 | // const safeVersion = '1.3.0' 18 | // const isL1SafeMasterCopy = false 19 | const safeFactory = await SafeFactory.create({ ethAdapter: ethAdapter }); 20 | 21 | const safeAccountConfig = { 22 | threshold: 1, // Setting the Threshold to 1 23 | owners: SAFE_OWNERS?.split(","), 24 | }; 25 | console.log("Deploying Security Council safe.."); 26 | 27 | const safeSdkOwner1 = await safeFactory.deploySafe({ safeAccountConfig }); 28 | const safeAddress = await safeSdkOwner1.getAddress(); 29 | 30 | console.log(`Security Council Safe deployed at: ${safeAddress}`); 31 | }; 32 | 33 | main() 34 | .then(() => process.exit(0)) 35 | .catch((error) => { 36 | console.error(error); 37 | process.exit(1); 38 | }); 39 | -------------------------------------------------------------------------------- /scripts/gnosis/createSecurityCouncilSafeL2.ts: -------------------------------------------------------------------------------- 1 | import { EthersAdapter, SafeFactory } from "@safe-global/protocol-kit"; 2 | import { ethers } from "ethers"; 3 | import { requireEnv } from "../hardhat/utils"; 4 | import { get1559Fees } from "../utils"; 5 | 6 | const main = async () => { 7 | const RPC_URL = requireEnv("BLOCKCHAIN_NODE"); 8 | const SAFE_OWNER1_PRIVATE_KEY = requireEnv("SAFE_OWNER1_PRIVATE_KEY"); 9 | const SAFE_OWNERS = requireEnv("SAFE_OWNERS"); 10 | const provider = new ethers.JsonRpcProvider(RPC_URL); 11 | const signer = new ethers.Wallet(SAFE_OWNER1_PRIVATE_KEY, provider); 12 | 13 | const ethAdapter = new EthersAdapter({ ethers, signerOrProvider: signer }); 14 | 15 | const chainId = await ethAdapter.getChainId(); 16 | console.log(`ChainId: ${chainId}`); 17 | const eip1559Fees = await get1559Fees(provider); 18 | 19 | // const safeVersion = '1.3.0' 20 | // const isL1SafeMasterCopy = false 21 | const safeFactory = await SafeFactory.create({ ethAdapter: ethAdapter }); 22 | 23 | const safeAccountConfig = { 24 | threshold: 1, // Setting the Threshold to 1 25 | owners: SAFE_OWNERS?.split(","), 26 | }; 27 | console.log("Deploying Security Council safe.."); 28 | 29 | const txOptions = { 30 | maxFeePerGas: eip1559Fees.maxFeePerGas?.toString(), 31 | maxPriorityFeePerGas: eip1559Fees.maxPriorityFeePerGas?.toString(), 32 | }; 33 | 34 | const safeSdkOwner1 = await safeFactory.deploySafe({ safeAccountConfig, saltNonce: "123", options: txOptions }); 35 | const safeAddress = await safeSdkOwner1.getAddress(); 36 | 37 | console.log(`Security Council Safe deployed at: ${safeAddress}`); 38 | }; 39 | 40 | main() 41 | .then(() => process.exit(0)) 42 | .catch((error) => { 43 | console.error(error); 44 | process.exit(1); 45 | }); 46 | -------------------------------------------------------------------------------- /scripts/gnosis/encodeProoflessOutput.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-explicit-any */ 2 | import fs from "fs"; 3 | import path from "path"; 4 | import yargs from "yargs/yargs"; 5 | import { hideBin } from "yargs/helpers"; 6 | 7 | /*******************************USAGE****************************************************************** 8 | ts-node ./scripts/gnosis/encodeProoflessOutput.ts --proofless-file "./prooflessExample.json" 9 | *******************************************************************************************************/ 10 | 11 | const argv = yargs(hideBin(process.argv)) 12 | .option("proofless-file", { 13 | describe: "Your proofless file name and location", 14 | type: "string", 15 | demandOption: true, 16 | }) 17 | .parseSync(); 18 | 19 | // reading JSON file 20 | function readJsonFile(filePath: string): unknown { 21 | const rawdata = fs.readFileSync(filePath); 22 | const jsonData = JSON.parse(rawdata.toString()); 23 | return jsonData; 24 | } 25 | 26 | // formating data 27 | function formatData(data: any): Array { 28 | return [ 29 | data.parentStateRootHash, 30 | data.dataHashes, 31 | data.dataParentHash, 32 | data.finalBlockNumber, 33 | data.lastFinalizedTimestamp, 34 | data.finalTimestamp, 35 | data.l1RollingHash, 36 | data.l1RollingHashMessageNumber, 37 | data.l2MerkleRoots, 38 | data.l2MerkleTreesDepth, 39 | data.l2MessagingBlocksOffsets, 40 | ]; 41 | } 42 | 43 | async function main(args: typeof argv) { 44 | const filePath = path.join(__dirname, args.prooflessFile); 45 | const readJsonData = readJsonFile(filePath); 46 | const formattedFinalizationData = formatData(readJsonData); 47 | 48 | console.log("_finalizationData:"); 49 | console.log(JSON.stringify(formattedFinalizationData)); 50 | console.log("\n"); 51 | } 52 | 53 | main(argv) 54 | .then(() => process.exit(0)) 55 | .catch((error) => { 56 | console.error(error); 57 | process.exit(1); 58 | }); 59 | -------------------------------------------------------------------------------- /scripts/gnosis/increaseSafeThresholdL1.ts: -------------------------------------------------------------------------------- 1 | import Safe, { EthersAdapter } from "@safe-global/protocol-kit"; 2 | import { ethers } from "ethers"; 3 | import { requireEnv } from "../hardhat/utils"; 4 | 5 | const main = async () => { 6 | const SAFE_ADDRESS = requireEnv("SAFE_ADDRESS"); 7 | const RPC_URL = requireEnv("BLOCKCHAIN_NODE"); 8 | const SAFE_OWNER1_PRIVATE_KEY = requireEnv("SAFE_OWNER1_PRIVATE_KEY"); 9 | const SAFE_NEW_THRESHOLD = requireEnv("SAFE_NEW_THRESHOLD"); 10 | 11 | const provider = new ethers.JsonRpcProvider(RPC_URL); 12 | const signer = new ethers.Wallet(SAFE_OWNER1_PRIVATE_KEY, provider); 13 | 14 | const ethAdapter = new EthersAdapter({ ethers, signerOrProvider: signer }); 15 | 16 | const safeSdk = await Safe.create({ ethAdapter, safeAddress: SAFE_ADDRESS }); 17 | 18 | // Display initial threshold & owners 19 | const threshold = await safeSdk.getThreshold(); 20 | console.log("Safe's current threshold: ", threshold); 21 | 22 | const currentOwners = await safeSdk.getOwners(); 23 | console.log("Safe's owners :", currentOwners); 24 | 25 | // Threshold change 26 | const safeTransaction = await safeSdk.createChangeThresholdTx(parseInt(SAFE_NEW_THRESHOLD)); 27 | const txResponse = await safeSdk.executeTransaction(safeTransaction); 28 | await txResponse.transactionResponse?.wait(); 29 | 30 | // Display new threshold 31 | const newThreshold = await safeSdk.getThreshold(); 32 | console.log("Safe's new threshold: ", newThreshold); 33 | }; 34 | 35 | main() 36 | .then(() => process.exit(0)) 37 | .catch((error) => { 38 | console.error(error); 39 | process.exit(1); 40 | }); 41 | -------------------------------------------------------------------------------- /scripts/gnosis/increaseSafeThresholdL2.ts: -------------------------------------------------------------------------------- 1 | import Safe, { EthersAdapter } from "@safe-global/protocol-kit"; 2 | import { ethers } from "ethers"; 3 | import { requireEnv } from "../hardhat/utils"; 4 | import { get1559Fees } from "../utils"; 5 | 6 | const main = async () => { 7 | const SAFE_ADDRESS = requireEnv("SAFE_ADDRESS"); 8 | const RPC_URL = requireEnv("BLOCKCHAIN_NODE"); 9 | const SAFE_OWNER1_PRIVATE_KEY = requireEnv("SAFE_OWNER1_PRIVATE_KEY"); 10 | const SAFE_NEW_THRESHOLD = requireEnv("SAFE_NEW_THRESHOLD"); 11 | 12 | const provider = new ethers.JsonRpcProvider(RPC_URL); 13 | const signer = new ethers.Wallet(SAFE_OWNER1_PRIVATE_KEY, provider); 14 | 15 | const ethAdapter = new EthersAdapter({ ethers, signerOrProvider: signer }); 16 | 17 | const safeSdk = await Safe.create({ ethAdapter, safeAddress: SAFE_ADDRESS }); 18 | 19 | const chainId = await ethAdapter.getChainId(); 20 | console.log(`ChainId: ${chainId}`); 21 | const eip1559Fees = await get1559Fees(provider); 22 | 23 | // Display initial threshold & owners 24 | const threshold = await safeSdk.getThreshold(); 25 | console.log("Safe's current threshold: ", threshold); 26 | 27 | const currentOwners = await safeSdk.getOwners(); 28 | console.log("Safe's owners :", currentOwners); 29 | 30 | // Threshold change 31 | const safeTransaction = await safeSdk.createChangeThresholdTx(parseInt(SAFE_NEW_THRESHOLD)); 32 | const txResponse = await safeSdk.executeTransaction(safeTransaction, { 33 | maxFeePerGas: eip1559Fees.maxFeePerGas?.toString(), 34 | maxPriorityFeePerGas: eip1559Fees.maxPriorityFeePerGas?.toString(), 35 | }); 36 | await txResponse.transactionResponse?.wait(); 37 | 38 | // Display new threshold 39 | const newThreshold = await safeSdk.getThreshold(); 40 | console.log("Safe's new threshold: ", newThreshold); 41 | }; 42 | 43 | main() 44 | .then(() => process.exit(0)) 45 | .catch((error) => { 46 | console.error(error); 47 | process.exit(1); 48 | }); 49 | -------------------------------------------------------------------------------- /scripts/gnosis/prooflessExample.json: -------------------------------------------------------------------------------- 1 | { 2 | "aggregatedProof": "", 3 | "aggregatedProverVersion": "", 4 | "aggregatedVerifierIndex": -1, 5 | "aggregatedProofPublicInput": "", 6 | "dataHashes": [ 7 | "0xe120003b9082214a6c381336afe870066a95168f92e84ecd762c0fb4921328ef" 8 | ], 9 | "dataParentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 10 | "parentStateRootHash": "0x2b50810f4ffe11d63122b6cce4c5039bdbc72e751089326ab03b71b2256fdde7", 11 | "lastFinalizedTimestamp": 0, 12 | "finalTimestamp": 1701159464, 13 | "finalBlockNumber": 1000503, 14 | "l1RollingHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 15 | "l1RollingHashMessageNumber": 0, 16 | "l2MerkleRoots": [], 17 | "l2MerkleTreesDepth": 5, 18 | "l2MessagingBlocksOffsets": "0x0000000000000000000000000000000000000000000000000000000000000000" 19 | } -------------------------------------------------------------------------------- /scripts/gnosis/queryContract.ts: -------------------------------------------------------------------------------- 1 | import { ethers } from "hardhat"; 2 | import { LineaRollup } from "../../typechain-types"; 3 | 4 | async function main() { 5 | // TESTING ON L1 6 | 7 | const factory = await ethers.getContractFactory("LineaRollup"); 8 | const proxyContract = factory.attach("0x41B186Dc7C46f08ADFdCe21Da1b07f605819E9Ab") as LineaRollup; 9 | 10 | const verifier0 = await proxyContract.verifiers(0); 11 | const verifier1 = await proxyContract.verifiers(1); 12 | const verifier2 = await proxyContract.verifiers(2); 13 | 14 | console.log({ verifier0, verifier1, verifier2 }); 15 | 16 | const limitInWei = await proxyContract.limitInWei(); 17 | const systemMigrationBlock = await proxyContract.systemMigrationBlock(); 18 | 19 | console.log({ "systemMigrationBlock:": systemMigrationBlock, "limitInWei:": limitInWei }); 20 | 21 | const outboxL1L2Mapping = await proxyContract.outboxL1L2MessageStatus( 22 | "0x0706629f2d6735d342c62fda7484482f77d9c2f53133e5b391d55b81a820ce27", 23 | ); 24 | console.log("outboxL1L2Mapping :", outboxL1L2Mapping); 25 | 26 | const dataStartingBlock = await proxyContract.dataStartingBlock( 27 | "0x0000000000000000000000000000000000000000000000000000000000000001", 28 | ); 29 | const dataEndingBlock = await proxyContract.dataEndingBlock( 30 | "0x0000000000000000000000000000000000000000000000000000000000000001", 31 | ); 32 | 33 | console.log("dataStartingBlock :", dataStartingBlock); 34 | console.log("dataEndingBlock :", dataEndingBlock); 35 | console.log("L1 Test done"); 36 | } 37 | 38 | main() 39 | .then(() => process.exit(0)) 40 | .catch((error) => { 41 | console.error(error); 42 | process.exit(1); 43 | }); 44 | -------------------------------------------------------------------------------- /scripts/hardhat/postCompile.ts: -------------------------------------------------------------------------------- 1 | import "colors"; 2 | import fs from "fs"; 3 | import path from "path"; 4 | import { artifacts } from "hardhat"; 5 | import Diff from "diff"; 6 | 7 | const UNCHANGED_COLOR = "grey"; 8 | const MAX_UNCHANGED_PART_LEN = 100; 9 | 10 | const EXPOSED_CONTRACTS = ["L2MessageService", "LineaRollup", "TimeLock"]; 11 | const CONTRACT_OUPUT_ABIS: { [contractName: string]: string } = { 12 | L2MessageService: "L2MessageService.abi", 13 | LineaRollup: "LineaRollupAlphaV4.abi", 14 | TimeLock: "TimeLock.abi", 15 | }; 16 | 17 | async function main() { 18 | const checkOnly = process.env.CHECK_ONLY === "1"; 19 | 20 | for (const contract of EXPOSED_CONTRACTS) { 21 | const abiPath = path.resolve("abi", CONTRACT_OUPUT_ABIS[contract]); 22 | 23 | if (checkOnly) { 24 | const currentAbi = JSON.parse(fs.readFileSync(abiPath, "utf8")); 25 | const stringifiedCurrentAbi = JSON.stringify(currentAbi, null, 2); 26 | 27 | const { stringifiedAbi, abi } = await readAbi(contract); 28 | 29 | if (stringifiedAbi !== stringifiedCurrentAbi) { 30 | showDiff(abi, currentAbi); 31 | 32 | throw new Error(`${contract} ABI has changed, please update it and commit the changes to the repository`); 33 | } 34 | } else { 35 | const { stringifiedAbi } = await readAbi(contract); 36 | 37 | fs.writeFileSync(abiPath, stringifiedAbi); 38 | } 39 | } 40 | } 41 | 42 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 43 | function showDiff(abi: any[], currentAbi: any[]) { 44 | const diff = Diff.diffJson(abi, currentAbi); 45 | 46 | diff.forEach((part) => { 47 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 48 | let color: any; 49 | 50 | if (part.added) { 51 | color = "green"; 52 | } else if (part.removed) { 53 | color = "red"; 54 | } else { 55 | color = UNCHANGED_COLOR; 56 | } 57 | 58 | let text = part.value; 59 | if (color === UNCHANGED_COLOR) { 60 | text = hideDiffChange(text); 61 | } 62 | 63 | console.error(text[color]); 64 | }); 65 | } 66 | 67 | async function readAbi(contract: string) { 68 | const artifact = await artifacts.readArtifact(contract); 69 | const abi = artifact.abi; 70 | 71 | const stringifiedAbi = JSON.stringify(abi, null, 2); 72 | 73 | return { stringifiedAbi, abi }; 74 | } 75 | 76 | function hideDiffChange(diffPart: string) { 77 | if (diffPart.length <= MAX_UNCHANGED_PART_LEN) { 78 | return diffPart; 79 | } 80 | 81 | const firstPart = diffPart.slice(0, MAX_UNCHANGED_PART_LEN / 2); 82 | const endPart = diffPart.slice(diffPart.length - MAX_UNCHANGED_PART_LEN / 2); 83 | 84 | return `${firstPart}...${endPart}`; 85 | } 86 | 87 | main() 88 | .then(() => process.exit(0)) 89 | .catch((error) => { 90 | console.error(error); 91 | process.exit(1); 92 | }); 93 | -------------------------------------------------------------------------------- /scripts/testEIP4844/MixAndMatch/aggregatedProof-1-114.json: -------------------------------------------------------------------------------- 1 | { 2 | "aggregatedProof": "0x1fe5267b8eafc819b3b74ab65b9e34362a35022232187314803267372d6ceffe2153541f479292f4ab57eeb145a192f1aed7f5ef9e0043db0d56313dec96eefb2015742f0bd1f0bc2d7580299c40b27631437a7463ce9dfcae3d22e421c7067c01229f2e356f2a1a334aa2518357628ff4c9c2603a5378500b7745a32a682959286db89403ce1630bd8f67b5d7215e4331cf12f4bbf1e2eafce24c7fca50b167298301b7267fdef114b5ebcafcfdc27725c332ebdce073cb4d20aedc741912ba02f66d94402a8c87effc0659255afdd704d9e84f00545d662127f5b5f0aac9fa00d3595236dd194c165f2021a6cd36f4354cdb45ff774df8e145804bdfca64f22ef402958c3659e87dfc8bfb59d006d65f5a690e1d5bf219abb9a0846e4b946c1b1f5bfa67e7a759230cfdbcc8c59ea1ea9e50ccc69080416ac59a63b3487a92141771b119932810469ed904f3054f36d9c8929cec6262719468c1784d07a0ea1a5836a08ce2d83344ac1a9c7225c0e43a51141a67c637a0c9c30bd98af734e40c7ab90abbb1866f10d6258a201d9a290987d82304f07032e9439a8fd017fbcb094a6c1007657ab3711ac1a106d230d6b49d3cf1ca5c6f5b0095e15c6c3673d20418aa76db1d96e38be28551e2c8913a7d48c0a56d9c922bf16db556b05e791c261b1f2cba652d6c368b60a63ddb350a12e256a915a27e464010e8fea18cb5c903c27f1683fcbcbb21399f76813288f38f68235b6f5a6a41139faf894c19a9af0fae4174b7fee8b9abfb50d49d59e27d766337307fb8b4d756f343f066672dc60991577ddcc2231b8dd215edbf78d8bd946067704f62a40bcb19593a78c0ea4f03bdd235742712148f7b7169e0767e3146bf27c19e3c74401c6d461cb55c4ccc1b853beae90d82a8929fe039b7ead8827b1d4443c5751bf00a5a14cc16f45d6c0188f7a7be76f133802e5f5a2c2834b5f916f62beec11fba816da5039d12fe1806c7fec2196075449a50fb2418a71c9faa09033f4f178683ee79e6af43b0e1ba2cd915cf409bcba2cdac3b6f1328eea241d2c85f39e7fb4e45aed4430b0826870ceeceeac26249914c76f53cd229baa5c6d1c63990670dcb29c573fe5259f9ca07191911ecf79c61edff2a672af0b92e917812e3929bed1edfbcb413ef121d2825ff7665487375108a686e5a8b6d06a934f1c926df0b50ebdf22f9366e33824922eccc7b55c619a0dcb6e9ba7a3df149f3ba8544e3f01b2356edcf8b4caad21622f29c3aef492d026dae7bd519ab733aa04e1dc2e785b842042ad3c7906168d7", 3 | "aggregatedProverVersion": "test", 4 | "aggregatedVerifierIndex": 1, 5 | "aggregatedProofPublicInput": "0x231e898779333073b4d50d1132d89d60e969d9a1e3acd03fa169b4122ecfa373", 6 | "dataHashes": [ 7 | "0x01f5853fa56ab910be0933f2ee811bbc437500dba4e38acbae17eab00eec9f95", 8 | "0x82694a9670032c50548d42dbf6f0d9d09febc4f2454796997ec9a4edc7f87106", 9 | "0x017b1d49c6c7947f83855cc16063ef19d02369540b97867855427b56cdaea487" 10 | ], 11 | "dataParentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 12 | "parentAggregationFinalShnarf": "0x4f64fe1ce613546d34d666d8258c13c6296820fd13114d784203feb91276e838", 13 | "finalShnarf": "0x01eac6954f735d506a9a7c519e62f1a3a75c0e48e058a6358be8d3896e93af10", 14 | "parentStateRootHash": "0x072ead6777750dc20232d1cee8dc9a395c2d350df4bbaa5096c6f59b214dcecd", 15 | "parentAggregationLastBlockTimestamp": 1683325137, 16 | "lastFinalizedBlockNumber": 0, 17 | "finalTimestamp": 1683335137, 18 | "finalBlockNumber": 114, 19 | "l1RollingHash": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", 20 | "l1RollingHashMessageNumber": 12, 21 | "l2MerkleRoots": [ 22 | "0x54ace467f69267f4e71233605888cb0161f115c83ffeb1f1c9430c9988432f4e" 23 | ], 24 | "l2MerkleTreesDepth": 5, 25 | "l2MessagingBlocksOffsets": "0x00000000000000000000000fffff" 26 | } -------------------------------------------------------------------------------- /scripts/testEIP4844/SixInOne/aggregatedProof-1-206.json: -------------------------------------------------------------------------------- 1 | {"aggregatedProof":"0x2fc9952c350bddaa650bb15052d8f95f7772c815930e7386a0a03deb0644d3b1079a2f36d960ea7cc807305bb81c629c2834deb1f178e750f2bab76feccd0ff01060cc6fe67165db076b4586f4f53712dc098652f69366fc4755740114a9965f1effe8d37bb54b3271bd2ddff55da7b79ed8544edb4b582ec6359fb3b445cf630a3e9022ec821960c8dd967001d05692823dc0e8940b22b3ff4f15be6cee8ebb1a96cd29a3200f9c22b38078fd5ab989b07fe1daaf6b061df62eb971f98bd0df254f1d5e9e9c219c02cda2f6af61358d690ec580e882147ca31a239a7a91a5022296ebd064299e3d1832a97780233d1d4e8741fbefec13db11498baf1975078a0f7f07fdec3c8bf59a02d0063fc1004f91c9ee9ebfc3fc398f7ce15e1bd93bd315985a58ec46e1f796f29c02bbbc5c0beff74746d3994811cee16b3ef530c3661017386f414e6bb7b72bca872691f7f9aa8d58beea238d5ca417b5c3e22f28c821b8a45ec2baf6876df001c6f89e86fc50a90c8c0218faaeb71750724506231f08cdce918b401871e6df2cdcdf88d3de0b28774b115ff5afb94f048815a5942108fe606ffa02373f3db7db56fac81fa1a81e78e16061c8fe7aa696d2bb3bb7d22921cfa38752132a8ae10823d6bbad8d8d8f3fb866a5aa14b9a9c6872cc3cdfb08fae4e751f73655fe3dfb365350925f888b45c0e6b687072295708d14fe14260fc439cc106f4abad7aee7a4f48f4d7902389d88f48baf8014482268848597180a8c0f9e65c1b7e89a68e0875f6f67bc887f2164e9a865cc2f8376cc0c879ef71f445304064673b569b968e9e101ce6836b53fc143535a4d5f0eab76dcc9fb741f681a34f38027207c478f8e69119d2ae44206218472601cfa8fddb2a7ea7afe1d2673be71e76d61653d47e9c7654995f823a8417477ee797dba72a4373360a325807176d33bb83675547ddff69399945259258658d6bcf75d4afef0387947c80b8d250cf17d3d938468ee61a4527a9bfd0a970f01134e198668a208629f150c294781fca3234d8a85370c1ce2bf16d2e129a9d8222afe7a4c80653c962885180ed12192c999f2abe229fef1600942ba39442702f3a87e212e81d22d434d6e97097d6a6bc09b2cd4f9562ffb1ca398d50dc881369634c2c3a4326e1768e79ca0156e74c9d0cd535050fbeaf4a029fc7b6faf8c00c59acd114295d2cf2fef4068","aggregatedProverVersion":"test","aggregatedVerifierIndex":0,"aggregatedProofPublicInput":"0x2c35ea1b78b59a5fac9a23a9071d617072de788f3e217828b89af03b4d890046","dataHashes":["0x01f5853fa56ab910be0933f2ee811bbc437500dba4e38acbae17eab00eec9f95","0x01a142b35ad91719145a4e3bf1d5402e6a73818db67312ade7a73ad5130ac618","0x017b1d49c6c7947f83855cc16063ef19d02369540b97867855427b56cdaea487","0x012cab32c78df416fe59f8f123e2ded2466a64e201bacddc8396231f335d2088","0x0159ba31314753be910d2abb9b7aeeafbefd58cc4163e8d3cc6695315960c7c1","0x017207990658280f269f538918209b2ab0f4e70c4b222aa8067ed327caf3c762"],"dataParentHash":"0x0000000000000000000000000000000000000000000000000000000000000000","parentStateRootHash":"0x072ead6777750dc20232d1cee8dc9a395c2d350df4bbaa5096c6f59b214dcecd","parentAggregationLastBlockTimestamp":1683325137,"lastFinalizedBlockNumber":0,"finalTimestamp":1683335137,"finalBlockNumber":206,"l1RollingHash":"0xdc8e70637c1048e1e0406c4ed6fab51a7489ccb52f37ddd2c135cb1aa18ec697","l1RollingHashMessageNumber":1,"l2MerkleRoots":["0xff0e2ae07c9c972f7ac6ab579a49376381d56f8101b37142cc52a4abef5cfb86"],"l2MerkleTreesDepth":5,"l2MessagingBlocksOffsets":"0x00000000000000000000000fffff"} 2 | -------------------------------------------------------------------------------- /scripts/testEIP4844/aggregatedProof-1-81.json: -------------------------------------------------------------------------------- 1 | { 2 | "aggregatedProof": "0x066df7ab7e98425f6f4420a9f84dc0778f5732a2e6867331d600b4be4ec4d71f2ed2cb00ae9b91d83b9acfdf5b9e99bc09f9330b0045a45c2e0b82174824990f118fda6919cce05f3e742b6d908b19012f19b7fa5a4859c841b0fb4245ef4cab2f917a55d05cf6fcf1e686da1200b414233313b2b83a644cb98839bf2d025ddb0abfffd32a4d9271da6c035bbd29a17b062a16b4552af74e866816e8fb93292b1e9dc02ea9586973ab019af9b518933ef2b43a07dfca130c96de11e3ea6ec76821bf76414ab318a24074c96a2d4f9ea8229b1f95069c9891f8b9630ebb43aa501b1883f214128097bb02d8db95004169206817394c98a2bcc2c16c07a53bda9a0ab02b425bea284f90e19d98c135384b2f53969a2bd6c9a6ed4db23c45c1a2dc009df63e685dd458c285ec91972639b1fe196d835b6b6bfe54dfb25eae69a5b8168a6c341ab0ccae820aa1d7bafb276e30069bd2a5dc12ffba4963dba95d1b8a09cb518f02ed373de651362b5dced18ed89abd7544b465d27abaaed924d54112175dc49c7c09077c059dc6e84055e3aa6012e83863965e84a123995ffc234b481dc0ccfe79c52c033e55ca247db94cd5f9a7f788f29e08757b76e8967341df60142484b43ece53794ece4fbddac059f760dbccb6924f5ad6eb7f2c86c91324ad1fec8d725a7d0a69152239a5107ffc8ad38265dd4b61dc613ff53ba935d052921ec3d15f7662d7155c7bb7a40d531ff813f7d121b158f508d5360524841d20ee08e041228a91088241a542927a74e63c4e60e78f7c93b6bc0da3f2e6a9938b7601476a105dd6e289e769f466eca691aa0ea2e4065fca6106b863eb0d44a62c6827909145988fce252cc48c7fc4e0861a5cd2e1e7af1ecc4d1ffbbb98ef2c6a4e0e07d160a13aa28fe18fc4f88af7283780c0806e1d4edfa6cb1bf1cace3e98610c69c3abf8c70af727fa69d9df7ad77e3f91cb7a1e8f8dfa9be34732bda6133900aac696aa73cd7575bf603a3efc6b4d701690c4565effe660333a721dc850890cc7b562ed0fc7a2796d998f2e9263536bf4f59c43668a767c19fe2a906970dd136ad4c7b96678691270ffa4c68178de6ec6548eca71cdb49eea6a0f9c0b96a82c6ecbb46e4aa32194782a15f372b39e7782986d6729fdfbf7927ec473c32aab092b217b3596081654c172a00cc8010b69a5d0abd27b365022249b9a5205f0582afb1f90670da3e66ce65ab5ecaf0cc810c8f76e9b93cebffc3ad0160afdea4c1cb4fbb0b8203fd43eeaef0d4644af49f751f7e72fdc351ebc5c7c3d229a8092", 3 | "aggregatedProverVersion": "test", 4 | "aggregatedVerifierIndex": 1, 5 | "aggregatedProofPublicInput": "0x0845ce6ad7b96ead3f07532f8c14efca7926d3b8a6b10254f1c4ba65bfb7f247", 6 | "dataHashes": [ 7 | "0x01f5853fa56ab910be0933f2ee811bbc437500dba4e38acbae17eab00eec9f95", 8 | "0x01a142b35ad91719145a4e3bf1d5402e6a73818db67312ade7a73ad5130ac618" 9 | ], 10 | "dataParentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 11 | "parentStateRootHash": "0x072ead6777750dc20232d1cee8dc9a395c2d350df4bbaa5096c6f59b214dcecd", 12 | "parentAggregationLastBlockTimestamp": 1683325137, 13 | "lastFinalizedBlockNumber": 0, 14 | "finalTimestamp": 1683335137, 15 | "finalBlockNumber": 81, 16 | "l1RollingHash": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", 17 | "l1RollingHashMessageNumber": 12, 18 | "l2MerkleRoots": [ 19 | "0x6de197db892fd7d3fe0a389452dae0c5d0520e23d18ad20327546e2189a7e3f1" 20 | ], 21 | "l2MerkleTreesDepth": 5, 22 | "l2MessagingBlocksOffsets": "0x00000000000000000000000fffff" 23 | } -------------------------------------------------------------------------------- /scripts/testEIP4844/aggregatedProof-82-153.json: -------------------------------------------------------------------------------- 1 | { 2 | "aggregatedProof": "0x1cbd99a6717d59c1f3d0b401f51837eca8880dba59e06ef6d3d51c7f8b84bf3b0e28362df993991e53093cf0a5bf33524f894518d29f7e3b7662a8760efffb1b24bf4a192ed312058d456656c5e62daeaa5f39d12d5f0356607176cb755825b20c7f5bb8491f456973ecd82b9a89d3624659f123ad992f928b38ea389fe7339200fe3b06f738f976714e7e5076ed5fa5b5016b136ee86495623e06511604a0e92e87d1418e3e7cb378b2517ef518faef4a82e50f68884554f8f5b0f6129502782259d9aaa5de29d64f9ec69bc6010912a38d583df837744febca28bfa0a6a36f1fa62e63efc84520986c9a2cbe74b188c59b9abf1b6db87ea1f342a85883570519f084912710ac88051f00fa087dacb0a64f32ac71f73389f7bebaa138de8be1013d6f79215afeae40e365c316728a19c16c6b4f949d2a5f91881169c1459e430af11d232c48ef074b1f8fc75413bfe586185fd7c3ad46812b374113c02a7e2f3008fd0abb1fc412864bee93af6fce5c13a5aca9c16119d1ff550a775c22ce842380046dcfb7f602f99e123d00c8fc8ae242230b93902940611adf2465faa3ae11baccaa27f958117b817759a24290916be764a6ad53c4b9e7fe8c3cc2c7216d2fa188627bc1a1a9f51086b8734587e82c5e5c712bd67e6a96e2f0a494a7c038002937e32c41ef5f763fc0cc377b56ef2371ff45d1d5f6af8fc1d0a9e09d695c13de57d0d34e961b0c82fb7395ab187c980be2c6ffc2f6cf3bdc06ab0daa67c7034b9850e8af9343962392cb7b0685b3db328e6ad0edc8ea9930167dd4c1fa1c030977b4a996f9441fdf123d22566f066e8689e19133c642cee2946262dd760d1549bca5f966b3982822b3c98b120e26d41f5e313a241d8a0d5a558f7fe712c32b06b94eb5a2b707c134302879964ce9d7c65f4a9d0e1e5a55e49b1b74a52f4c1f4a9d2e57c8665b5a1d44a98eefa8bc85213fd2a4b973f0663c921010a4c800001f52612168d24d80aeced4ac922d8bb7388cc762d76e47ba63a79bc41928ee08fb4c74eeed5d9fcf9d47de8d45d0f8ed96c71453713ce69b7fcaa1aa28a33a2f7f91189c1617c6c852585510a19c6e0902b1f7137e1d93ee97826e6b510a682eb6c8d277cbbf2343979b29355a8427059084a16bfddd83ec04b87b8be56927168f6c57d638f3c87357408ab999cc10dae428ea8d0df307bef18c87fd234c250f8aeb4438cb80f9543b4e74be92fbc170d3e94878e3d154656c53b9122f14f314da523fe7c79e5c50d530107a3b7a97727e25b95bf9c1f68a1e48d7bdfcc27e", 3 | "aggregatedProverVersion": "test", 4 | "aggregatedVerifierIndex": 1, 5 | "aggregatedProofPublicInput": "0x224c02f36233239efd78f5e99a2400bf60950d62c705b204797bd949a29aa993", 6 | "dataHashes": [ 7 | "0x01bdfef0d1ddb163bf8431ea63ad7166bcd69a72a4fa30342138335d7fac96f4", 8 | "0x0112b6fcf15707263de267fdc63c78cf9881654e88455b94fb8f9f7623223365" 9 | ], 10 | "dataParentHash": "0x01a142b35ad91719145a4e3bf1d5402e6a73818db67312ade7a73ad5130ac618", 11 | "parentStateRootHash": "0xf0f26782f7afb93f926cacb145f55530714f20b1356725e3971dc99e0ef8b591", 12 | "parentAggregationLastBlockTimestamp": 1683335137, 13 | "lastFinalizedBlockNumber": 81, 14 | "finalTimestamp": 1683355137, 15 | "finalBlockNumber": 153, 16 | "l1RollingHash": "0xcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", 17 | "l1RollingHashMessageNumber": 14, 18 | "l2MerkleRoots": [ 19 | "0xf82d0ea8590489e98ca4279f30bd4b32a4fd62e6574ddc4f606d6496096b3721" 20 | ], 21 | "l2MerkleTreesDepth": 5, 22 | "l2MessagingBlocksOffsets": "0x00000000000000000000000fffff" 23 | } -------------------------------------------------------------------------------- /scripts/tokenBridge/test/deployBridgedTokenBeacon.ts: -------------------------------------------------------------------------------- 1 | import { ethers, network, upgrades } from "hardhat"; 2 | import { tryStoreAddress } from "../../../utils/storeAddress"; 3 | import { tryVerifyContract } from "../../../utils/verifyContract"; 4 | 5 | export async function deployBridgedTokenBeacon(verbose = false) { 6 | const BridgedToken = await ethers.getContractFactory("BridgedToken"); 7 | 8 | const l1TokenBeacon = await upgrades.deployBeacon(BridgedToken); 9 | await l1TokenBeacon.waitForDeployment(); 10 | 11 | if (verbose) { 12 | console.log("L1TokenBeacon deployed, at address:", await l1TokenBeacon.getAddress()); 13 | } 14 | 15 | const l2TokenBeacon = await upgrades.deployBeacon(BridgedToken); 16 | await l2TokenBeacon.waitForDeployment(); 17 | if (verbose) { 18 | console.log("L2TokenBeacon deployed, at address:", await l2TokenBeacon.getAddress()); 19 | } 20 | 21 | await tryStoreAddress( 22 | network.name, 23 | "l1TokenBeacon", 24 | await l1TokenBeacon.getAddress(), 25 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 26 | // @ts-ignore 27 | l1TokenBeacon.deployTransaction.hash, 28 | ); 29 | 30 | await tryStoreAddress( 31 | network.name, 32 | "l2TokenBeacon", 33 | await l2TokenBeacon.getAddress(), 34 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 35 | // @ts-ignore 36 | l2TokenBeacon.deployTransaction.hash, 37 | ); 38 | 39 | await tryVerifyContract(await l1TokenBeacon.getAddress()); 40 | await tryVerifyContract(await l2TokenBeacon.getAddress()); 41 | 42 | return { l1TokenBeacon, l2TokenBeacon }; 43 | } 44 | -------------------------------------------------------------------------------- /scripts/tokenBridge/test/deployMock.ts: -------------------------------------------------------------------------------- 1 | import { deployTokenBridgeWithMockMessaging } from "./deployTokenBridges"; 2 | 3 | deployTokenBridgeWithMockMessaging(true) 4 | .then(() => { 5 | process.exitCode = 0; 6 | process.exit(); 7 | }) 8 | .catch((error) => { 9 | console.error(error); 10 | process.exitCode = 1; 11 | }); 12 | -------------------------------------------------------------------------------- /scripts/tokenBridge/test/deployTokenBridges.ts: -------------------------------------------------------------------------------- 1 | import { ethers, upgrades } from "hardhat"; 2 | 3 | import { TokenBridge } from "../../../typechain-types"; 4 | import { SupportedChainIds } from "../../../utils/supportedNetworks"; 5 | import { deployBridgedTokenBeacon } from "./deployBridgedTokenBeacon"; 6 | 7 | export async function deployTokenBridge(messageServiceAddress: string, verbose = false) { 8 | const [owner] = await ethers.getSigners(); 9 | const chainIds = [SupportedChainIds.GOERLI, SupportedChainIds.LINEA_TESTNET]; 10 | 11 | // Deploy beacon for bridged tokens 12 | const tokenBeacons = await deployBridgedTokenBeacon(verbose); 13 | 14 | // Deploying TokenBridges 15 | const TokenBridgeFactory = await ethers.getContractFactory("TokenBridge"); 16 | 17 | const l1TokenBridge = (await upgrades.deployProxy(TokenBridgeFactory, [ 18 | owner.address, 19 | messageServiceAddress, 20 | await tokenBeacons.l1TokenBeacon.getAddress(), 21 | chainIds[0], 22 | chainIds[1], 23 | [], // Reseved Addresses 24 | ])) as unknown as TokenBridge; 25 | await l1TokenBridge.waitForDeployment(); 26 | if (verbose) { 27 | console.log("L1TokenBridge deployed, at address:", await l1TokenBridge.getAddress()); 28 | } 29 | 30 | const l2TokenBridge = (await upgrades.deployProxy(TokenBridgeFactory, [ 31 | owner.address, 32 | messageServiceAddress, 33 | await tokenBeacons.l2TokenBeacon.getAddress(), 34 | chainIds[1], 35 | chainIds[0], 36 | [], // Reseved Addresses 37 | ])) as unknown as TokenBridge; 38 | await l2TokenBridge.waitForDeployment(); 39 | if (verbose) { 40 | console.log("L2TokenBridge deployed, at address:", await l2TokenBridge.getAddress()); 41 | } 42 | 43 | // Setting reciprocal addresses of TokenBridges 44 | await l1TokenBridge.setRemoteTokenBridge(await l2TokenBridge.getAddress()); 45 | await l2TokenBridge.setRemoteTokenBridge(await l1TokenBridge.getAddress()); 46 | if (verbose) { 47 | console.log("Reciprocal addresses of TokenBridges set"); 48 | } 49 | 50 | if (verbose) { 51 | console.log("Deployment finished"); 52 | } 53 | 54 | return { l1TokenBridge, l2TokenBridge, chainIds, ...tokenBeacons }; 55 | } 56 | 57 | export async function deployTokenBridgeWithMockMessaging(verbose = false) { 58 | const MessageServiceFactory = await ethers.getContractFactory("MockMessageService"); 59 | 60 | // Deploying mock messaging service 61 | const messageService = await MessageServiceFactory.deploy(); 62 | await messageService.waitForDeployment(); 63 | 64 | const deploymentVars = await deployTokenBridge(await messageService.getAddress(), verbose); 65 | return { messageService, ...deploymentVars }; 66 | } 67 | -------------------------------------------------------------------------------- /scripts/tokenBridge/test/deployTokens.ts: -------------------------------------------------------------------------------- 1 | import { ethers } from "hardhat"; 2 | import { MockERC20MintBurn } from "../../../typechain-types"; 3 | 4 | const tokenNames = ["L1USDT", "L1DAI", "L1WETH", "L2UNI", "L2SHIBA"]; 5 | 6 | export async function deployTokens(verbose = false) { 7 | const ERC20 = await ethers.getContractFactory("MockERC20MintBurn"); 8 | 9 | const tokens: { [name: string]: MockERC20MintBurn } = {}; 10 | 11 | for (const name of tokenNames) { 12 | tokens[name] = await ERC20.deploy(name, name); 13 | await tokens[name].waitForDeployment(); 14 | if (verbose) { 15 | console.log(name, "deployed"); 16 | } 17 | } 18 | 19 | return tokens; 20 | } 21 | -------------------------------------------------------------------------------- /scripts/upgrades/upgradeL2MessageService.ts: -------------------------------------------------------------------------------- 1 | import { ethers, upgrades } from "hardhat"; 2 | import { requireEnv } from "../hardhat/utils"; 3 | 4 | // NB: REMEMBER TO RENAME THE EXISTING CONTRACT TO SOMETHING ELSE TO RETAIN 5 | // THE SAME NAME FOR THE CONTRACT GOING FORWARD 6 | // THE TWO CONTRACTS MUST BE NAMED DIFFERENTLY 7 | 8 | async function main() { 9 | const newContractName = requireEnv("NEW_CONTRACT_NAME"); 10 | const proxyAddress = requireEnv("PROXY_ADDRESS"); 11 | 12 | if (!newContractName || !proxyAddress) { 13 | throw new Error(`PROXY_ADDRESS and CONTRACT_NAME env variables are undefined.`); 14 | } 15 | console.log(`Upgrading contract at ${proxyAddress}`); 16 | 17 | const newContract = await ethers.getContractFactory(newContractName); 18 | 19 | try { 20 | await upgrades.validateUpgrade(proxyAddress, newContract, { 21 | kind: "transparent", 22 | }); 23 | 24 | await upgrades.upgradeProxy(proxyAddress, newContract, { 25 | kind: "transparent", 26 | }); 27 | 28 | console.log(`Upgraded contract at ${proxyAddress} with a new version of ${newContractName}`); 29 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 30 | } catch (error: any) { 31 | console.error("Failed to upgrade the proxy contract", error.message); 32 | throw error; 33 | } 34 | } 35 | 36 | main() 37 | .then(() => process.exit(0)) 38 | .catch((error) => { 39 | console.error(error); 40 | process.exit(1); 41 | }); 42 | -------------------------------------------------------------------------------- /scripts/upgrades/upgradeLineaRollup.ts: -------------------------------------------------------------------------------- 1 | import { ethers, upgrades } from "hardhat"; 2 | import { requireEnv } from "../hardhat/utils"; 3 | 4 | async function main() { 5 | const newContractName = requireEnv("NEW_CONTRACT_NAME"); 6 | const oldContractName = requireEnv("OLD_CONTRACT_NAME"); 7 | const proxyAddress = requireEnv("PROXY_ADDRESS"); 8 | const libraryAddress = requireEnv("TRANSACTION_DECODER_ADDRESS"); 9 | const initialL2BlockNumber = requireEnv("LINEA_ROLLUP_INITIAL_L2_BLOCK_NUMBER"); 10 | const initialStateRootHash = requireEnv("LINEA_ROLLUP_INITIAL_STATE_ROOT_HASH"); 11 | 12 | if (!newContractName || !proxyAddress) { 13 | throw new Error(`PROXY_ADDRESS and CONTRACT_NAME env variables are undefined.`); 14 | } 15 | console.log(`Upgrading contract at ${proxyAddress}`); 16 | 17 | const oldContract = await ethers.getContractFactory(oldContractName, { 18 | libraries: { 19 | TransactionDecoder: libraryAddress, 20 | }, 21 | }); 22 | const newContract = await ethers.getContractFactory(newContractName, { 23 | libraries: { 24 | TransactionDecoder: libraryAddress, 25 | }, 26 | }); 27 | console.log("Importing contract"); 28 | await upgrades.forceImport(proxyAddress, oldContract, { 29 | kind: "transparent", 30 | }); 31 | 32 | try { 33 | await upgrades.validateUpgrade(proxyAddress, newContract, { 34 | kind: "transparent", 35 | unsafeAllow: ["external-library-linking"], 36 | }); 37 | 38 | await upgrades.upgradeProxy(proxyAddress, newContract, { 39 | call: { fn: "initializeV2", args: [initialL2BlockNumber, initialStateRootHash] }, 40 | kind: "transparent", 41 | unsafeAllow: ["external-library-linking"], 42 | }); 43 | 44 | console.log(`Upgraded contract at ${proxyAddress} with a new version of ${newContractName}`); 45 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 46 | } catch (error: any) { 47 | console.error("Failed to upgrade the proxy contract", error.message); 48 | throw error; 49 | } 50 | } 51 | 52 | main() 53 | .then(() => process.exit(0)) 54 | .catch((error) => { 55 | console.error(error); 56 | process.exit(1); 57 | }); 58 | -------------------------------------------------------------------------------- /scripts/upgrades/upgradeLineaRollupAlphaV3ToV4.ts: -------------------------------------------------------------------------------- 1 | import { ethers, upgrades } from "hardhat"; 2 | import { requireEnv } from "../hardhat/utils"; 3 | import fs from "fs"; 4 | 5 | const OPENZEPPELIN_DIRECTORY = `${__dirname}/../../.openzeppelin`; 6 | 7 | async function main() { 8 | const newContractName = requireEnv("NEW_CONTRACT_NAME"); 9 | const oldContractName = requireEnv("OLD_CONTRACT_NAME"); 10 | const proxyAddress = requireEnv("PROXY_ADDRESS"); 11 | const initialShnarfs = process.env.INITIAL_SHNARFS; 12 | const initialShnarfsBlockNumbers = process.env.INITIAL_SHNARFS_BLOCK_NUMBERS; 13 | 14 | if (fs.existsSync(OPENZEPPELIN_DIRECTORY)) { 15 | fs.rmSync(OPENZEPPELIN_DIRECTORY, { recursive: true, force: true }); 16 | } 17 | 18 | const initialShnarfsParam = initialShnarfs ? initialShnarfs.split(",") : []; 19 | const initialShnarfsBlockNumbersParam = initialShnarfsBlockNumbers ? initialShnarfsBlockNumbers.split(",") : []; 20 | 21 | console.log(`Upgrading contract at ${proxyAddress} from ${oldContractName} to ${newContractName}`); 22 | 23 | const oldContract = await ethers.getContractFactory(oldContractName); 24 | const newContract = await ethers.getContractFactory(newContractName); 25 | 26 | console.log("Importing contract"); 27 | await upgrades.forceImport(proxyAddress, oldContract, { 28 | kind: "transparent", 29 | }); 30 | 31 | try { 32 | await upgrades.upgradeProxy(proxyAddress, newContract, { 33 | call: { 34 | fn: "initializeParentShnarfsAndFinalizedState", 35 | args: [initialShnarfsParam, initialShnarfsBlockNumbersParam], 36 | }, 37 | kind: "transparent", 38 | // NOTE: THIS IS ONLY FOR TESTING. 39 | // TODO: this is because of the transient storage layout change. 40 | // Openzeppelin upgradeProxy validation does not allow variable removal even if the storage layout didn't change. 41 | unsafeSkipStorageCheck: true, 42 | }); 43 | 44 | console.log(`Upgraded contract at ${proxyAddress} from ${oldContractName} to ${newContractName}`); 45 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 46 | } catch (error: any) { 47 | console.error("Failed to upgrade the proxy contract", error.message); 48 | throw error; 49 | } 50 | } 51 | 52 | main() 53 | .then(() => process.exit(0)) 54 | .catch((error) => { 55 | console.error(error); 56 | process.exit(1); 57 | }); 58 | -------------------------------------------------------------------------------- /scripts/upgrades/upgradeLineaRollup_no_reinitialisation.ts: -------------------------------------------------------------------------------- 1 | import { ethers, upgrades } from "hardhat"; 2 | import { requireEnv } from "../hardhat/utils"; 3 | 4 | // NB: REMEMBER TO RENAME THE EXISTING CONTRACT TO SOMETHING ELSE TO RETAIN 5 | // THE SAME NAME FOR THE CONTRACT GOING FORWARD 6 | // THE TWO CONTRACTS MUST BE NAMED DIFFERENTLY 7 | 8 | async function main() { 9 | const newContractName = requireEnv("NEW_CONTRACT_NAME"); 10 | const oldContractName = requireEnv("OLD_CONTRACT_NAME"); 11 | const proxyAddress = requireEnv("PROXY_ADDRESS"); 12 | 13 | if (!newContractName || !proxyAddress) { 14 | throw new Error(`PROXY_ADDRESS and CONTRACT_NAME env variables are undefined.`); 15 | } 16 | console.log(`Upgrading contract at ${proxyAddress}`); 17 | 18 | const oldContract = await ethers.getContractFactory(oldContractName); 19 | const newContract = await ethers.getContractFactory(newContractName); 20 | 21 | console.log("Importing contract"); 22 | await upgrades.forceImport(proxyAddress, oldContract, { 23 | kind: "transparent", 24 | }); 25 | 26 | try { 27 | await upgrades.validateUpgrade(proxyAddress, newContract, { 28 | kind: "transparent", 29 | }); 30 | 31 | await upgrades.upgradeProxy(proxyAddress, newContract, { 32 | kind: "transparent", 33 | }); 34 | 35 | console.log(`Upgraded contract at ${proxyAddress} with a new version of ${newContractName}`); 36 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 37 | } catch (error: any) { 38 | console.error("Failed to upgrade the proxy contract", error.message); 39 | throw error; 40 | } 41 | } 42 | 43 | main() 44 | .then(() => process.exit(0)) 45 | .catch((error) => { 46 | console.error(error); 47 | process.exit(1); 48 | }); 49 | -------------------------------------------------------------------------------- /scripts/upgrades/upgradeLineaRollup_with_reinitialisation.ts: -------------------------------------------------------------------------------- 1 | import { ethers, upgrades } from "hardhat"; 2 | import { requireEnv } from "../hardhat/utils"; 3 | 4 | async function main() { 5 | const newContractName = requireEnv("NEW_CONTRACT_NAME"); 6 | const oldContractName = requireEnv("OLD_CONTRACT_NAME"); 7 | const proxyAddress = requireEnv("PROXY_ADDRESS"); 8 | const initialL2BlockNumber = requireEnv("LINEA_ROLLUP_INITIAL_L2_BLOCK_NUMBER"); 9 | const initialStateRootHash = requireEnv("LINEA_ROLLUP_INITIAL_STATE_ROOT_HASH"); 10 | 11 | if (!newContractName || !proxyAddress) { 12 | throw new Error(`PROXY_ADDRESS and CONTRACT_NAME env variables are undefined.`); 13 | } 14 | console.log(`Upgrading contract at ${proxyAddress}`); 15 | 16 | const oldContract = await ethers.getContractFactory(oldContractName); 17 | const newContract = await ethers.getContractFactory(newContractName); 18 | 19 | console.log("Importing contract"); 20 | await upgrades.forceImport(proxyAddress, oldContract, { 21 | kind: "transparent", 22 | }); 23 | 24 | try { 25 | await upgrades.validateUpgrade(proxyAddress, newContract, { 26 | kind: "transparent", 27 | }); 28 | 29 | await upgrades.upgradeProxy(proxyAddress, newContract, { 30 | call: { fn: "initializeV2", args: [initialL2BlockNumber, initialStateRootHash] }, 31 | kind: "transparent", 32 | }); 33 | 34 | console.log(`Upgraded contract at ${proxyAddress} with a new version of ${newContractName}`); 35 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 36 | } catch (error: any) { 37 | console.error("Failed to upgrade the proxy contract", error.message); 38 | throw error; 39 | } 40 | } 41 | 42 | main() 43 | .then(() => process.exit(0)) 44 | .catch((error) => { 45 | console.error(error); 46 | process.exit(1); 47 | }); 48 | -------------------------------------------------------------------------------- /scripts/utils.ts: -------------------------------------------------------------------------------- 1 | import { ethers } from "ethers"; 2 | import { HardhatEthersHelpers } from "hardhat/types"; 3 | 4 | /** 5 | * @param provider ethers JsonRpcProvider or HardhatEthersHelpers provider instance 6 | * @returns {Promise<{maxPriorityFeePerGas: *, maxFeePerGas: *}>} 7 | */ 8 | async function get1559Fees( 9 | provider: ethers.JsonRpcProvider | HardhatEthersHelpers["provider"], 10 | ): Promise<{ maxPriorityFeePerGas?: bigint; maxFeePerGas?: bigint }> { 11 | const { maxPriorityFeePerGas, maxFeePerGas } = await provider.getFeeData(); 12 | 13 | return { 14 | ...(maxPriorityFeePerGas ? { maxPriorityFeePerGas } : {}), 15 | ...(maxFeePerGas ? { maxFeePerGas } : {}), 16 | }; 17 | } 18 | 19 | export { get1559Fees }; 20 | -------------------------------------------------------------------------------- /test/Timelock.ts: -------------------------------------------------------------------------------- 1 | import { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers"; 2 | import { loadFixture } from "@nomicfoundation/hardhat-network-helpers"; 3 | import { expect } from "chai"; 4 | import { ethers } from "hardhat"; 5 | import { TimeLock } from "../typechain-types"; 6 | import { CANCELLER_ROLE, EXECUTOR_ROLE, PROPOSER_ROLE, TIMELOCK_ADMIN_ROLE } from "./utils/constants"; 7 | import { deployFromFactory } from "./utils/deployment"; 8 | 9 | describe("Timelock", () => { 10 | let contract: TimeLock; 11 | let proposer: SignerWithAddress; 12 | let executor: SignerWithAddress; 13 | 14 | async function deployTimeLockFixture() { 15 | return deployFromFactory( 16 | "TimeLock", 17 | 10, 18 | [proposer.address], 19 | [executor.address], 20 | ethers.ZeroAddress, 21 | ) as Promise; 22 | } 23 | 24 | before(async () => { 25 | [, proposer, executor] = await ethers.getSigners(); 26 | }); 27 | 28 | beforeEach(async () => { 29 | contract = await loadFixture(deployTimeLockFixture); 30 | }); 31 | 32 | describe("Initialization", () => { 33 | it("Timelock contract should have the 'TIMELOCK_ADMIN_ROLE' role", async () => { 34 | expect(await contract.hasRole(TIMELOCK_ADMIN_ROLE, await contract.getAddress())).to.be.true; 35 | }); 36 | 37 | it("Proposer address should have the 'PROPOSER_ROLE' role", async () => { 38 | expect(await contract.hasRole(PROPOSER_ROLE, proposer.address)).to.be.true; 39 | }); 40 | 41 | it("Proposer address should have the 'CANCELLER_ROLE' role", async () => { 42 | expect(await contract.hasRole(CANCELLER_ROLE, proposer.address)).to.be.true; 43 | }); 44 | 45 | it("Executor address should have the 'EXECUTOR_ROLE' role", async () => { 46 | expect(await contract.hasRole(EXECUTOR_ROLE, executor.address)).to.be.true; 47 | }); 48 | 49 | it("Should set the minDelay state variable with the value passed in the contructor params", async () => { 50 | expect(await contract.getMinDelay()).to.equal(10); 51 | }); 52 | }); 53 | }); 54 | -------------------------------------------------------------------------------- /test/Utils.ts: -------------------------------------------------------------------------------- 1 | import { loadFixture } from "@nomicfoundation/hardhat-network-helpers"; 2 | import { expect } from "chai"; 3 | import { TestUtils } from "../typechain-types"; 4 | import { deployFromFactory } from "./utils/deployment"; 5 | import { generateKeccak256, generateRandomBytes } from "./utils/helpers"; 6 | 7 | describe("Utils Library", () => { 8 | let contract: TestUtils; 9 | 10 | async function deployTestUtilsFixture() { 11 | return deployFromFactory("TestUtils"); 12 | } 13 | beforeEach(async () => { 14 | contract = (await loadFixture(deployTestUtilsFixture)) as TestUtils; 15 | }); 16 | 17 | describe("efficientKeccak", () => { 18 | it("Should return the correct keccak hash", async () => { 19 | const leftValue = generateRandomBytes(32); 20 | const rightValue = generateRandomBytes(32); 21 | const solidityKeccakHash = generateKeccak256(["bytes32", "bytes32"], [leftValue, rightValue]); 22 | expect(await contract.efficientKeccak(leftValue, rightValue)).to.equal(solidityKeccakHash); 23 | }); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /test/mimc.ts: -------------------------------------------------------------------------------- 1 | import { loadFixture } from "@nomicfoundation/hardhat-network-helpers"; 2 | import { expect } from "chai"; 3 | import { ethers } from "hardhat"; 4 | import { Mimc } from "../typechain-types"; 5 | import mimcTestData from "./testData/mimc-test-data.json"; 6 | import { deployFromFactory } from "./utils/deployment"; 7 | 8 | describe("Mimc", () => { 9 | let mimc: Mimc; 10 | 11 | async function deployMIMCFixture() { 12 | return deployFromFactory("Mimc") as Promise; 13 | } 14 | 15 | beforeEach(async () => { 16 | mimc = await loadFixture(deployMIMCFixture); 17 | }); 18 | 19 | describe("hash", () => { 20 | it("Should return mimc hash for each test case", async () => { 21 | for (const element of mimcTestData) { 22 | const msgs = ethers.concat(element.in); 23 | expect(await mimc.hash(msgs)).to.equal(element.out); 24 | } 25 | }); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /test/testData/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zikc2023/linea-contracts/b17e7c79b5647e47c175c6367dea30c3f1c66738/test/testData/.DS_Store -------------------------------------------------------------------------------- /test/testData/compressedData/aggregatedProof-1-155.json: -------------------------------------------------------------------------------- 1 | { 2 | "aggregatedProof": "0x156fc136d3378e4ee26c1ed5dedc78ba8633d18889b91cbceec0ca77f5ee4bda2bcd0cbaf22d2825defbbc8eb2a784fe28c960827e885e59bbbe19136b1a12dc24394f04d9b62f5a82e930e1faf46139ad292862f7d94199061cb502088fc31a1238d2036f151237916e97ae5c98af74217d11a5e4c55bdd672eae717a73b747115d06835a1cb874445d3e67e64e1bd74fbd2f8b0514a48499c82e4768d6c9092ef151507b9ee80b7b0553b1fdea76487c379356d87e611b5900b5625e74a5b011cd417c9fc75047d31f890a7645d5563b70ee6c2102f8276555b110d2ee25fb050c92bc82d9859f814d7f6f0499124aab73c0061a9057aca4eb871a9072cd5b09c8122eccfd69228a3776aeb6fcbb71cb92add91020aceb4a94e3fd8fcbc64214827d1912d64606f308b8323c15c82907d34d684bb10ff6cddd82d07282b06d0d35c25d675c020fc8fe204390ecdbf844a7d5de3533890ba6adb315a4ab7b7f16d3d23b86dce63747f3a1ebda731e3158fe1a2c301bd32a9a0eb270d68981ff12b61aae0ce0c446e660f22c3d5f8d38936ab127491efa727424cb8833d57bbe26e57fddcc891fefa01c40f81a281fcec1d64572ce90b0258ae03d5cac6eaa0b0ad62fcc93efa5fe00e6985319307c13260b21dc4287fe506dcd84615725638e085fbddadba6d0e410447fa32ff09125f620ff1d20649c26ca6a1d51e48cb66426f021b9640066f31e3ee2ff1789ff8cc0376ee9f822173449db3f37d75b0fef14b51dc58b58651e8d2dbdd33a908c8e6cdf4554d7dc9a2e60e1bb17332b0c950cd4749e129c4f21cafed31d1515f08e9b332d359ef2dc3e6916131bba752fd22abe2221691252d2ec1fa41e9b6b1d178ef73640162bf6379462c36c4c9980180a4f4fbfa02a77a4c378890027521ab75ba514c0c37ed668472711352c9805d9187a60a140a4764e9b4572e00509a58495cd2e98fc7802cd27015eff6e858a832c78ba5b339ef12772c6a51b66f19ed6de1534a91f76385cb15b46a3fde0896702676d278f4e8ae84d5eddf526a114d0f83ae68e603b89f5f06091fd7b6d14cb037f9961904da136e3c88188ec30d99b8c4166458744982ace206bfa3f23fa1c2b5163a3262b7b67e8b2ba45f0e66966a29baa29d1d31cda1d55ca73179bd4bf0ec5799e95ac4dd62247a3d05560c19abf5f8909ed898939f77744ff9ad8b9892a22ede896961d0b178c706eef2c649b8f78f0eedf4230641f56933252082faf26726b90eba46e27829047d6a20adff84e74ac6b2dcd1bbad668cedecd9237e3", 3 | "aggregatedProverVersion": "test", 4 | "aggregatedVerifierIndex": 1, 5 | "aggregatedProofPublicInput": "0x233fd3d94f86264d6b666cdcb455c1cb144d3dc399edc9d17bd50aa42ae789a2", 6 | "dataHashes": [ 7 | "0x7126453ddb4c09537a505a70bae0dd57a3f5daba4522fa1f79b760fb28efb35c", 8 | "0x82694a9670032c50548d42dbf6f0d9d09febc4f2454796997ec9a4edc7f87106", 9 | "0x08a70f876b12e010a0c34fe2bb03389fbeaf1749e9528359b7196df67a8c76fc", 10 | "0x93eb7218f429a6efeb1ce6931a3915e0a032131ca9ff6ccc5c8428178221aa4c" 11 | ], 12 | "dataParentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 13 | "parentAggregationFinalShnarf": "0x47452a1b9ebadfe02bdd02f580fa1eba17680d57eec968a591644d05d78ee84f", 14 | "finalShnarf": "0xdf1e9f621e3a89f02d44dbc266056d50d5d1524dc4d135f93b81619f3d674b7c", 15 | "parentStateRootHash": "0x072ead6777750dc20232d1cee8dc9a395c2d350df4bbaa5096c6f59b214dcecd", 16 | "parentAggregationLastBlockTimestamp": 1683325137, 17 | "lastFinalizedBlockNumber": 0, 18 | "finalTimestamp": 1683335137, 19 | "finalBlockNumber": 155, 20 | "l1RollingHash": "0xdc8e70637c1048e1e0406c4ed6fab51a7489ccb52f37ddd2c135cb1aa18ec697", 21 | "l1RollingHashMessageNumber": 1, 22 | "l2MerkleRoots": [ 23 | "0x8c11bf3dd28eeb8e951be357df5c22d4de2500ac61ecb04da92971c71b55585c" 24 | ], 25 | "l2MerkleTreesDepth": 5, 26 | "l2MessagingBlocksOffsets": "0x00000000000000000000000fffff" 27 | } -------------------------------------------------------------------------------- /test/testData/compressedData/multipleProofs/aggregatedProof-1-81.json: -------------------------------------------------------------------------------- 1 | { 2 | "aggregatedProof": "0x2e3885e2edddf27b3dd1026756eab3bc30cdd97f8baf1eb47326ae52a1cb20fa2a1b646bf931c981d18ee80f6790d83c625b2526f859018b2a09bf74c52eb1fc03154f7bce57fbcdb3b684e172bac86e85aa7bfbf835efe7802cdead993c69ee27807b0b66962e52ff22a986a1448750a2180f7e3700649e465e6f02781d0ca129a665c622a4c3568041c655f0bfdea424f01f7cace3e6a057df50390a529888016b15373389318665b1ad2aea58f37ca71bbeff16f0a195415d5e05da6e3f6d0b1b94baa49bbad54996cac0156deac58e78be8716a2e3051859a0a80b896bee0b9e07f58d33c1eab1fdf815b88f16441418bdc2c06b4db0014c5c76ba34395407091ce1fd23bea0e96c329cc0dd8c6ce3124f67225d88cc89c38456c6e06c5f10c005b390b82e83cfe90d034c6524fa14f533e3500ac922a7083a1ec677aa190374517ea4392f084978a1e0b980926277e14e316d79418a78ee4c358c0a6f7f12a4db54dc6bb0600271677e5391d367e91138ca5b3e6cc48c2e7a7c69dbd5c52e80de7258d7735688e643a612cbbc780d6a83bb205fbac475b0d2d16125caab118d89480050b60c3cb236965aaddd33fd71cf816044e825fda2ddfad47e048a065bf48f618244546d469d0f8a20934a2d1cc89528d8482e43717005361facd21292b82302d6b98a25ba919ce6962379d7c3573b3eb42cbdb6e832a2372e5229255f1e463defd6f8c84c4e7ed6efb6f1eca1e986db692f0e69bd48048bf81ce30a043de2f69cdcd84cfecd89be109855fe5b96b653e5ae59fd57720d6638aba0066c51b74cd344eed67f3e555b809bf1a640e1fce5fba4322986f6eca6d191870a0ab4a8a34e65f95b3a528148671890e55545e209b2d078607e0f038c426a1a0e9a7adecba9eb826239e641faa36501ffc2571016df36de0178cf9e35a3a6872e0e92ab1b3f31755d163e40996fc0de7aa33dd8512998d620a875a1c81101a1129306ea24b9a1903c9ae3f845efd49bcbec9d9404a0e8cf2d9952dd879e35fc25e4b477b794f57f7c7cef4aa7d14b96bd7718c42e89215ba53f5d06728a8d1627f28a3d03498e0bcad93ba064c89269cf58e9c5b0dab52348fb4a5b1af198252552d03fb8f2dab03f3937ce2866191aeac6adba98777813039b17d46ddc824f23954a25a33ed52b9d4a630c9606c4ff8bc5b2a1daaccbcc6905fcdd55f9920117364bc958a2894c03c5751f4ccc18eee330193a00492839467dd8f187242c662a36b03a7738d002ba7ab0260dfd4d953c3966df075dda1464c833f12f64e0a3", 3 | "aggregatedProverVersion": "test", 4 | "aggregatedVerifierIndex": 1, 5 | "aggregatedProofPublicInput": "0x216ea864c4d4392d0315997af776dbc1856686e376a07c85ed67f8509c14328e", 6 | "dataHashes": [ 7 | "0x7126453ddb4c09537a505a70bae0dd57a3f5daba4522fa1f79b760fb28efb35c", 8 | "0x82694a9670032c50548d42dbf6f0d9d09febc4f2454796997ec9a4edc7f87106" 9 | ], 10 | "dataParentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 11 | "parentAggregationFinalShnarf": "0x47452a1b9ebadfe02bdd02f580fa1eba17680d57eec968a591644d05d78ee84f", 12 | "finalShnarf": "0x6d2b3535e06f4778e03c8439145dd9b8e4ae312953b9ccc154ef73b8a00c26c1", 13 | "parentStateRootHash": "0x072ead6777750dc20232d1cee8dc9a395c2d350df4bbaa5096c6f59b214dcecd", 14 | "parentAggregationLastBlockTimestamp": 1683325137, 15 | "lastFinalizedBlockNumber": 0, 16 | "finalTimestamp": 1683335137, 17 | "finalBlockNumber": 81, 18 | "l1RollingHash": "0xdc8e70637c1048e1e0406c4ed6fab51a7489ccb52f37ddd2c135cb1aa18ec697", 19 | "l1RollingHashMessageNumber": 1, 20 | "l2MerkleRoots": [ 21 | "0x6de197db892fd7d3fe0a389452dae0c5d0520e23d18ad20327546e2189a7e3f1" 22 | ], 23 | "l2MerkleTreesDepth": 5, 24 | "l2MessagingBlocksOffsets": "0x00000000000000000000000fffff" 25 | } -------------------------------------------------------------------------------- /test/testData/compressedData/multipleProofs/aggregatedProof-82-153.json: -------------------------------------------------------------------------------- 1 | { 2 | "aggregatedProof": "0x07434925e18440eddd3542177a797ea482763232b75665733ec4675b5bfe302b2fd4fc88aaa050619bcf85066386f299fceeee5ad325f790fbc58bbc90d0d13911ab1f4e3441f67de658d4b04ba951e568e40b351c408ef501d92a3e1a4fe5e92e0852c024422c7c41800ba622533b2ae49dd2af351ccbc4b94c38a6347ad0fd21bc444b3bad60f8ddc06cd2b3416bf6d9dacaf67eee1474645a7f8cf1ee01451a60a46387ca859e7376b7b98ed84eeef04cc3830e3f2af41c080d71ef98f8a82fa51774b3b61a6bcf495cc0cdd539f6eb937776721d0c4d7520f5a4c2a9a95921c5c756ae545a63d1b83c5ef012f7906729c2628a4b816b2dc96c31bf0fbc682f924285c5656268ee09ad501662821e56c3d1783727b430c8bc86d7e0f1b8d42b53686a52767669efb5c9b529ddb2a9dc0b381f6db36152743486e79a56beba2e09d1f5c090f4ccea102f6f56e727c6e64c6b20e37bc15012286796037502c22731c2eb996ebb6ab21ddbc1176ab377216bd3cbfaaa8ee300fd6eef2c9dfee22b67f95af559ec1a27ab767d4a9f1a76057df8447da6abcd8ce65b4d9e0187110686ab8b63ae4f13cf5efd3c76ebf4325eae05c2ff20da38aca28edd2385dc4f0093ecb1cc8d469140b88df05ef854380c3662d5819e862425c44221b64040e60803dc8fe2a5afad8891b7a539b4efba92aa47d4ed663046e136e2a4252a00201cc462748f4728dc6cb2bfd52b87c20d304bea63dca42025deee6f87eae4190b02bb997a7a10ed4d527eb4bf419f82312a5f73ff473aea3e9df38eab57c5de68049ea94acfab78bbe6c7e4315278022eaa87bee804b59b9bc4d42c1dcdf43f881a7c70e8a4d1a9924d7b11078f31640684223f2f13debe05642fbd6964f4585921e74c16a0706a1d4cc69c1cb5ef603503a415c049b106461198f72bd12ef48620037560ef87cd91854ed45d1c9d0976a3c34ddb6cabc7e2bb3b9f38db88610208ccf73fad2597b3505fdc940e6bdd050159e9ead97af4b9db84f79db429229d21abcbc4d6a06c0abc60f9fb41d9980d293aafb07df564542480dc5ca84c3662050e9abdefd991a1fa9c8e41ab825a229047c7d4598ed96bd82534fdd4e82ba626bb33e672541da827ff62aa31476fcc7527a72965fb1943e6db5d9b1256a87114799095ca7a7ac76669c669907420ba0edcdc6245adc50be9d0699620948ae10fce8894eeb9037cd2f666c858595067e6e0a3e4d19a6e46618b1468ca6ffd282ba3c35ff26a2d622846327ffa96405a0094e3bab4f86c4842a0f33f336788f7", 3 | "aggregatedProverVersion": "test", 4 | "aggregatedVerifierIndex": 1, 5 | "aggregatedProofPublicInput": "0x0ecda6d6b122aa50210c937e14351066a6e98db71c066ace19abb75a3abdfda8", 6 | "dataHashes": [ 7 | "0xd1ef92f67e60ec41ee3b2f448024802d1608c138d4770ab1d3ada17facd6f0cc", 8 | "0xa54a0666ba33710a751591da5edb268dc309934de83a5efa03eefc6e2e384737" 9 | ], 10 | "dataParentHash": "0x82694a9670032c50548d42dbf6f0d9d09febc4f2454796997ec9a4edc7f87106", 11 | "parentAggregationFinalShnarf": "0x6d2b3535e06f4778e03c8439145dd9b8e4ae312953b9ccc154ef73b8a00c26c1", 12 | "finalShnarf": "0x4b7f110cbe7fcab315cd99683b2c7864bff2615903a3230d5bf2222b7a71a756", 13 | "parentStateRootHash": "0xf0f26782f7afb93f926cacb145f55530714f20b1356725e3971dc99e0ef8b591", 14 | "parentAggregationLastBlockTimestamp": 1683335137, 15 | "lastFinalizedBlockNumber": 81, 16 | "finalTimestamp": 1683355137, 17 | "finalBlockNumber": 153, 18 | "l1RollingHash": "0xcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", 19 | "l1RollingHashMessageNumber": 14, 20 | "l2MerkleRoots": [ 21 | "0xf82d0ea8590489e98ca4279f30bd4b32a4fd62e6574ddc4f606d6496096b3721" 22 | ], 23 | "l2MerkleTreesDepth": 5, 24 | "l2MessagingBlocksOffsets": "0x00000000000000000000000fffff" 25 | } -------------------------------------------------------------------------------- /test/testData/compressedData/test/aggregatedProof-1-46.json: -------------------------------------------------------------------------------- 1 | { 2 | "aggregatedProof": "0x04fde664831729a6c10adb0000d45a2599c435a1fe3ab7c8bb175f0e65c97bd51ac921e32d6c6193e61fa162ed8c10cea05f2ac8df6eeed5dd8b0868add8d25901382be84970b7be3d319e181caeda07f3eb729fd9e83b6abc5f4d436dd96487029aa1cdc6a1e5c0899df2a9f55006b53ca2d51c4fa17b7db85b43f33600321f0fcaf4442b5610c3f89d5742b7d54e705cd2d9eb4fe534787ad77f16655c0e5223f3ce2147316413d2eee1bf6a91be3aedda6366048717d12f14f00ccd32911026991de7668f509928c6ae8531821bc765b043e2ff3d9757fcc366ed30e7c0ad195da481673a509c904c4598b0b1eddea2a51c1057b8e18e9f0dc38cb7fe36fa073375fb5bc79ceb73ad19c49fceadb176bd29e92e43ccd26979f3a5fc9017870d1e3df8eeb040950b089ad2e3479bc6a4f36f92aa4e44d8182d91ecc197c0bd17f57557cccdf751f92392cd7600fad13b1c9a149d56925efe33665b1c1e621c1a0d3c1da9e4f5dc63dca01da18ab20b00a31844a15fb9aff446771bd641ae5800dafa3691b1370f83c98a359ccb2ac6ccbd9a480f4d45fe93bf1e51f330ac5a12fef3ffea2087bf02972b27aae9b53cb58d82fac3456908129d2d4394dc5fb0305b0de515c13e54f3d18c8796b53c41b1e23aacc20f69ecfc5c19947e0ceaec1e29ef9b7bdbff3a414db64a75119b3de9116263902d1039661faab7a9b9d82019e64e91dd6481d3d4c8f4afdb4bc422ece67fb926eacc6088dd342fca331ca90d7b206ee2ce275b79c47102621e138e675f49d7be5b97fce7e2821d4ec9021f28d6f3c3ba0c1ff7850ddc760ba380fb4465771cfe4496610c1b78a77e720d532b70f7924c9dfdaa80f0c977b001fe0bb9e26e367e0f3eedbc39734dc108058e2be068a04dde9dad752c77b9ccb69596dbbe178f675409dfcca090c11ec12c83051ed32c092a01f85d815a305958f450f4956ca44e79e6ae000ac6bf56b88adb09fd7b82de9c41533e514182bddfb9dcc4d016a9cdb8822a2711cd3da7d1419c0ec345b608d9376aa80a569153986f14b0f5d0dead54f31e63c70489bd6859900ea8067a9bef60092b8b0a761c508aa08a61d1886ae7262916c0755ace5370471692fa2101612ce4e3c07a5c183f9aa6e0946cb68eefca0749a9ed56a39d0c1729bd4db80f338c9d72f6838fcc5224bc34f7ffae48392c4d759ce317c62a27f11463d9293b3ae452e09838f9dbf9bcb8d203eb5d3799be428267354d9ad31d631b5438c25bf21889f387610be9440a063b84091ebc860545a9f1e50712bcdc5c", 3 | "aggregatedProverVersion": "test", 4 | "aggregatedVerifierIndex": 1, 5 | "aggregatedProofPublicInput": "0x0003c6614dc4dc4a556e2c1a4cab605304909a1b041b126ce7aacadb60737e83", 6 | "dataHashes": [ 7 | "0x7126453ddb4c09537a505a70bae0dd57a3f5daba4522fa1f79b760fb28efb35c" 8 | ], 9 | "dataParentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 10 | "parentAggregationFinalShnarf": "0x4f64fe1ce613546d34d666d8258c13c6296820fd13114d784203feb91276e838", 11 | "finalShnarf": "0xbdf49ce56a449bdc2d81414f78e229e5d4c05bc19a85b2b8e71fb9dafd4e3dd8", 12 | "parentStateRootHash": "0x072ead6777750dc20232d1cee8dc9a395c2d350df4bbaa5096c6f59b214dcecd", 13 | "parentAggregationLastBlockTimestamp": 1683325137, 14 | "lastFinalizedBlockNumber": 0, 15 | "finalTimestamp": 1683335137, 16 | "finalBlockNumber": 46, 17 | "l1RollingHash": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", 18 | "l1RollingHashMessageNumber": 12, 19 | "l2MerkleRoots": [ 20 | "0x97cd1539d08f7c0ba06ad836b2690eef50afd86609a0672517ec0ef8c1f94796" 21 | ], 22 | "l2MerkleTreesDepth": 5, 23 | "l2MessagingBlocksOffsets": "0x00000000000000000000000fffff" 24 | } 25 | -------------------------------------------------------------------------------- /test/testData/compressedDataEip4844/aggregatedProof-1-155.json: -------------------------------------------------------------------------------- 1 | { 2 | "aggregatedProof": "0x2a70e6b62c2d1b6e3d974214006dd9e69f33c49fcbdd533aa378bd2723fdb70c11fb268c4369913e4caff57f80525b746b1d3968343508340bf4680cd6f637520119eb7efbf10e70ae3fe1a545a08a124615cf9b43a263e6df8261ae020b7b991e36f9d2533cb6a08db37cadf377bff2d1d45e7fecccb6b21eed3b3a76210963267b4698e1899fbd8f4af9c961dfb7274929cbd942398670100ed6dcda1c862b12f71836c45c9d05939e5175a6fdb119d93573f9c05bc4a9b502cd4bcdd6997f23d50b7f160b1a49e951f84fa4d88c0898ca55c5bf201e36b423d76cc03578af2297153ae8ac60ebb1819eb397d1751dcfc735ff576ecc0a56ee783d1635bec1155739b3acab772645d0fa8600121e2ff05dffc1a0efb9131c3bf633fe8b84cf05e9ebd0f4acafe1d2d6fa892f5313082262a3131a6e72def4fdf1f14faab9740a25c521495d84b60e519860d7b20f50ab4727b02a585758ddfefdfd606bd9d82487d5fca90e9fc7dc2675c00800fd16fd161b0e9bba26bc629f31ecea7d1f7c06d55fe1e07fe33bfbba0f31e559beadfd2e3a6259877a1099bef567536c51530b814bf1b2ce4f60505a07d317a49aa0d230dcf8c17526c4a563083c0ff9692e2fc4b76a502cbf3cea69235266ccb0f848ddf3de1f600ec567f25656f4bc6fc92d399b74986c3441a9f33126607d267fc9090a76686b57391cf9c313ecb7e672285abd01c403d54eb35d99e30bebda2a3b04953dbf57be84850e9f3f82228eb325045c4383c2aba804e29ddde9ce37f27c9fd9a85cda7ff7a84722dfe0f88961207f8ad6b8012bb697fe1a3fb3d9b6a5f5aeb8add56d041f9517c62a418d3aef28b5d07ed39bc7f282dcbe5a4976c60be9096531d0ae5169726cba6820d88dab1c943d5774466d1f0522a54526674410bfe01c8af2a9faa4a900f113e061a0cc1ebf111f99bccd317376543e470af60640877815136f44067d0753e84deeb669232b5ecd42fef61a5491f263e0b00c2f55bc9746b2af69a9ace9e25884c877a117cdcb4a838939bf66a6a52845bcb6b32861f435b21aac35c058008e5d03d0491fd80a5cd0c8c962357c881e5e5a023bdb266cd075e3ea57ed7b7e7747d1cc1b2d6f3134fc47c7b802720e1a4168b5a510c2ffa4a99d93b50cc0c102127a3b0920a22cbe8625cd74859ce0a1bde887543dea920a93662a33bd2aa94dceac019b1e9d694ff95730caa8f4e6a756fbdc76829fe47649675ed4a605fce52425f72e1dce23e84df61cb66b5cd78bf32c0e69069e370d8adff4907e3ae4926a1a853c", 3 | "aggregatedProverVersion": "test", 4 | "aggregatedVerifierIndex": 1, 5 | "aggregatedProofPublicInput": "0x0df1432721cd0ba6be26f651291322ca2d0295b742341419ffae6739e0a2ff78", 6 | "dataHashes": [ 7 | "0x01f5853fa56ab910be0933f2ee811bbc437500dba4e38acbae17eab00eec9f95", 8 | "0x01a142b35ad91719145a4e3bf1d5402e6a73818db67312ade7a73ad5130ac618", 9 | "0x017b1d49c6c7947f83855cc16063ef19d02369540b97867855427b56cdaea487", 10 | "0x012cab32c78df416fe59f8f123e2ded2466a64e201bacddc8396231f335d2088" 11 | ], 12 | "dataParentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 13 | "parentAggregationFinalShnarf": "0x4f64fe1ce613546d34d666d8258c13c6296820fd13114d784203feb91276e838", 14 | "finalShnarf": "0xed80ecb6bd8ebf7f337754aedc1ae11ee79ad58e4ce57ce4784dbfef5df042c8", 15 | "parentStateRootHash": "0x072ead6777750dc20232d1cee8dc9a395c2d350df4bbaa5096c6f59b214dcecd", 16 | "parentAggregationLastBlockTimestamp": 1683325137, 17 | "lastFinalizedBlockNumber": 0, 18 | "finalTimestamp": 1683335137, 19 | "finalBlockNumber": 155, 20 | "l1RollingHash": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", 21 | "l1RollingHashMessageNumber": 12, 22 | "l2MerkleRoots": [ 23 | "0x8c11bf3dd28eeb8e951be357df5c22d4de2500ac61ecb04da92971c71b55585c" 24 | ], 25 | "l2MerkleTreesDepth": 5, 26 | "l2MessagingBlocksOffsets": "0x00000000000000000000000fffff" 27 | } 28 | -------------------------------------------------------------------------------- /test/testData/compressedDataEip4844/multipleProofs/aggregatedProof-1-81.json: -------------------------------------------------------------------------------- 1 | { 2 | "aggregatedProof": "0x0eecbbdf2e66fbb4be20e31d89919580e6bc9de27a60daf669e939c3ee96a5d4107178e215868da40c2f7c25e40069b38b800669f1eac7d3ea053f22d77eaf5510ab29616311a5e69b971371664a4d89ea2bb0096599373ffc774fe660b414192ada30788451ffee077f5f71579d55874aaf9b6a529303c1dfa284a2a3b98aa223ab5522e5470c23c3b60206cfc231649e033319ba25c82fc7c5df669697060a2e3c98aef44052f295d67039dd073e1b39f78970b9b58b2694d56907c150a3690407ab5015cb11e7b176f92a0a41af4a02624f69b697cb394fd679317d1487c212de5a4ebf02cbd7933fa8bdf92f1e05b897868639120d6e115ac01b2530e54e1a2c6c2f24bb0577a2affe84ea602ac0576caa5cd5be116e1f601198346e179e2c943cd266197f04c59b2f6245f1977e657621a9b06aef6bdea7871ffd85aada17ec658704232ec7ef73f16cd2ff698d8082eeac4bf6ae5c8f37490c257f593e2e5dc36d79d5c89d146c09a13a39530124f2f3cc9264ce22ebc96ee9111035cb09f3b6bb121f28faf3c759d0a053c2a633e723e7690441deab563d4d1066c82e08c9dd54a3674c6e2ed5e01745981f8b93c99fd9909866464c2c7e264bad9d1322e6b8e8f486908458c10bd97e60697213c200205afc75ad89a1f3e03d899c042dc0e5582f75b54552f46470103493664b93a08ff6b20128b43153b67750cb48135f7bea0c1d3dcadf9a6947c2818d14e63c4c438d7a8caaf09ed8a92a50d7052ab1823a38c4be7b6db35c5df216361b419ef5b8abb4e0f2f759091f8d14cc4216b3b71cfb4aca2e01d556503b83e78fc91d98591a7d9ca7708854db711eceed217fde3b154a87b8b6ac44e3829bebc9b838a4c8112ef844d6358835476b4f5b11326f6181bd4b84ea71017c385ee969e2a5bea3f1e39a87054490bd3a17472c2dcd9439648dffbbcfa9236d5b803dd9338a69cc5c692f3fcb428232a70b768516645545b47ff077cc1b10d9b75daf3105c9b18f0c2a2b3362b411a038eff38e0469620d2edbc049c21c814458f62629da37dd9ebe13f8fdd6eb306f9335e3b01212a573c144864560a91b3dad457d1575e7dad837fba065c0e1c7aa0e6396462b64472b02af58bab5f7ebb345bea55921bed9edca36214bd51fe36f91da78b1215869f155230bf2031183759fc4c19a590c3b975b54a09b2e47b4e88b1ffe842d108e527063bfc4383afffa9f49136380a8f23bf87c2505bed9188c36798a6e2f02319c610f89e4440135e564b1b0139cc996a83f854311a593a333e4e09ea9", 3 | "aggregatedProverVersion": "test", 4 | "aggregatedVerifierIndex": 1, 5 | "aggregatedProofPublicInput": "0x0ae2549360eb1c1c3a2790da224ca3eaaee3306618028cacdddad34631c4ca30", 6 | "dataHashes": [ 7 | "0x01f5853fa56ab910be0933f2ee811bbc437500dba4e38acbae17eab00eec9f95", 8 | "0x01a142b35ad91719145a4e3bf1d5402e6a73818db67312ade7a73ad5130ac618" 9 | ], 10 | "dataParentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 11 | "parentAggregationFinalShnarf": "0x4f64fe1ce613546d34d666d8258c13c6296820fd13114d784203feb91276e838", 12 | "finalShnarf": "0x3e0a8e2a9800f62403a1425d62375785866476c6d076da1c8368cdc6cba81a22", 13 | "parentStateRootHash": "0x072ead6777750dc20232d1cee8dc9a395c2d350df4bbaa5096c6f59b214dcecd", 14 | "parentAggregationLastBlockTimestamp": 1683325137, 15 | "lastFinalizedBlockNumber": 0, 16 | "finalTimestamp": 1683335137, 17 | "finalBlockNumber": 81, 18 | "l1RollingHash": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", 19 | "l1RollingHashMessageNumber": 12, 20 | "l2MerkleRoots": [ 21 | "0x6de197db892fd7d3fe0a389452dae0c5d0520e23d18ad20327546e2189a7e3f1" 22 | ], 23 | "l2MerkleTreesDepth": 5, 24 | "l2MessagingBlocksOffsets": "0x00000000000000000000000fffff" 25 | } 26 | -------------------------------------------------------------------------------- /test/testData/compressedDataEip4844/multipleProofs/aggregatedProof-82-153.json: -------------------------------------------------------------------------------- 1 | { 2 | "aggregatedProof": "0x2af758c8387f84d9709f7b56d19b65fff986249ecffdc25a797b9b321b98e2ea2fc483b86844010a65379a283aebfaa7d45006345428af04b455b36bea7757672b772f8371613c50cf07af5dbab3e37bfb1429f5e595e01e2857f7f4ddfa4472153c5015b822606c5b85b381ba29de9cbbecdb87459e34b909dcc3aea41cae2e1cdbc032cbfa34b8531c8eb3d9982795eae9521bf7fe94d52c59bc25d3168755215fe01b8caec1ec1bdd5f441e10f6ea251149a950456f05bbb3fcff22859de122f9917bd1af129ff613a9dee75282b798bac75ddff78eb797776997edd4ca2a02887b34cd21651b6e2b4c7824ef6b7791d20b0803cf3695134fa26405f3948128452e3ca5deda83c9da5b75205d810fd248c93ad157a55789bb971a64d2ee1a2cb2822f5a42c1e6fdee1f3c5d88dae7745fe3974a357d2aef4d9b6e42210a251f0dab56a39c8f1b7b07564bb449a69a4891be7cb797ff6f6f59ebb74fff41fc0c0c17ea434212b5df9c975275803557396e19e40213334798d3fbb086e875172b885146cf0e2163ccb41c4f25b8a3197273ecba0c918c8de939f373e6b4ed8008b2b3e266247c157a54786089e7a84a6800ff7d35d8e3ed28bc788726b300f2164397adb7ef570dba2243a36920ab17b28e5082aea8c26c4f6c64074eeaa6450afd2608b86418d8b728b39bafe5242bb1dd3d507c9c6a0ebbeb08182101572a102540fdf5638607d2cc211da91cee80297ad6c7ef5c19881b47aba910507403043edb213da07c2055980bc58d0006461dbc958e34f40cd9b32b3c3e7e397e51111b980db9d5a677fdd02baf2d7bd88eb1409e83f79855f0b767bdfa531efdfe14e123ca70ec25d2906932e05e2f7b1a529315d40f930430ef6f2a0f178258e106d44897b152d6c0980c5bf7f3d9a16261f01789633db6dcfbbbde854b0dbb862bec68e54fd73bd95f41b4027f434014af55c959c8a6fbe01d94723cca7933e201bf33400cc8b3b1e6c84be5953ff4b354460ff1bb433ed1341eae128e0b646028ac984cbe9e0eff68794da60c64e181097da7773f22192ee63c7bda763ffae2131039d9b0aac88646a6c4ddd2e5f0241bf8008c4a236187b92cbc1d9b949d63133639f5f8ca576b24e7f488ec29f0f00387ea263d953f44ced01e5e1a6df0662d70b7d746a028ba616265d47ea91bb4a5dc56d660e1f523412137dcf06b5c502320d94a0bd80a42cf79020c7d43c6c95df60933452bf0a13485b7cde0d7a54101b076b7a38809f4df4fe1f88d7734810ddafc6d833f96b7f78ce3ee9eb0df4f", 3 | "aggregatedProverVersion": "test", 4 | "aggregatedVerifierIndex": 1, 5 | "aggregatedProofPublicInput": "0x0dc563623574cbe237aa0a18c9647b97df4632a6448bbeed4751532eb4ef9cae", 6 | "dataHashes": [ 7 | "0x01bdfef0d1ddb163bf8431ea63ad7166bcd69a72a4fa30342138335d7fac96f4", 8 | "0x0112b6fcf15707263de267fdc63c78cf9881654e88455b94fb8f9f7623223365" 9 | ], 10 | "dataParentHash": "0x01a142b35ad91719145a4e3bf1d5402e6a73818db67312ade7a73ad5130ac618", 11 | "parentAggregationFinalShnarf": "0xae9e396a319ced70fe65ddbb9d2446de03896fe88ea4147faf25ba74de319882", 12 | "finalShnarf": "0xebc9a8f81920f483ee7e3926a97959774c1eaa161359b2f51434d8e59edff5fa", 13 | "parentStateRootHash": "0xf0f26782f7afb93f926cacb145f55530714f20b1356725e3971dc99e0ef8b591", 14 | "parentAggregationLastBlockTimestamp": 1683335137, 15 | "lastFinalizedBlockNumber": 81, 16 | "finalTimestamp": 1683355137, 17 | "finalBlockNumber": 153, 18 | "l1RollingHash": "0xcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc", 19 | "l1RollingHashMessageNumber": 14, 20 | "l2MerkleRoots": [ 21 | "0xf82d0ea8590489e98ca4279f30bd4b32a4fd62e6574ddc4f606d6496096b3721" 22 | ], 23 | "l2MerkleTreesDepth": 5, 24 | "l2MessagingBlocksOffsets": "0x00000000000000000000000fffff" 25 | } 26 | -------------------------------------------------------------------------------- /test/testData/compressedDataEip4844/test/aggregatedProof-1-46.json: -------------------------------------------------------------------------------- 1 | { 2 | "aggregatedProof": "0x24570565fd24348c56cfd932a330d287aca6159c35b4224322a516224810dcd00a68ca5a207dc8b09e292735a9b2967cc67ed466b4383110c2f462171084d46316c0b23e39772544cc95b6f40244b8d5f357b646172ef659e30b297f1379bbad0ade6efa45b74d0c09725a17e29d7642ff63381deb48ee66e7559dceaae2b71d009f45ecf3f2380c08276e2de3ecb4ce3da8861cd64772ac852a67e2876b59a110ae5f7bcf979abb255a24b948968ee764ceaa8cfccf5f3c4e57a8dabf200184254df480601f2ba1559e24f2f58a2d7142d208dcdb59806430c826d7320c1d752fb70096aaedacd98a30a6e8388fe33409cdd3be372adfc38c2e88fa6def7703213a41461841065832cb99493297f8ded793bc2744afc5dd05708e37d052ce11282405a42c22c28c585aee1a2f817e9d73a5d98b3bc308fecf072fcb88ea8207019ae34c5e6b3608ece99fb8e7774595b09222a07ac8547b8b94e81ba70bfc001d7adb14d58c63f9f4efd8d52fa9c4c831c1805045056d04a6162d6529be351a061ad47e92b1abf38e1b345070cee93dfb48bf85a698e36d8ebad71399cd3aa10dce66c1e492025a0928e727aa3edcdaf1ee0f2c97935a4a5f78a95dffc12c34102b980203b38d65e11dd1691df969f66fbf93e96017d3a2d8ab02846b4d3b422805cf2de5a424874145b5465dfd4788892090c2bfa890ef1051d0efd1ab96d70c290b8f8d4efbdcd252005ea8cfba0c717c77d1cefd904ec2c311795ccd5b3904f53fae81a1755a50ed93822bcaf3b980fe0330c2d5c549aea1465cde550ce0127d7999c374dab4ae6609361a5790d6ef264477e32a3779256c927464443d4d26b4488c46024bdf198029d46dfe146d4a3b65a16129561260f4768876ea53760f0538da8ab2350826ce23b03e2f34fb0dc6efd6e18bf55e842052400d46bf4719a4feb89b45b03edfea4fdca0ee1f7099f149b83118fe55000ba4c77247314110af3916b0381b2f148da5836bd0b4c267d8307c5d194aa317fa1c3a5cd001c021f69a1ebee91f7c94f5c6a0caa41fdd8ce21b8d5eef78fe6ea6e2fed3178b9624a556ef06a463e6194c38b5672a52dc72c38f1a668545a9864ab2536880a20e055f82c6f67bc1487e594576195951acf07ffacd75483783bcdb31d6b22c167324aaa21f7d7a963e35ac1f5076535b0449a781ca2ec2ef54874a10a434baca24055832ebfeb36701a644b55fa95b1e6b18a2c7607b2818fe1c5e1e97463f6b280a70f237fa8c77b6ca31975368c6b6c638e3057a593ef272d6cf2430d0e0f09c", 3 | "aggregatedProverVersion": "test", 4 | "aggregatedVerifierIndex": 1, 5 | "aggregatedProofPublicInput": "0x17b6b21d0512c370087f7357581500c0be3669d7ee796bfd682f28e5b6689cce", 6 | "dataHashes": [ 7 | "0x01f5853fa56ab910be0933f2ee811bbc437500dba4e38acbae17eab00eec9f95" 8 | ], 9 | "dataParentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 10 | "parentAggregationFinalShnarf": "0x4f64fe1ce613546d34d666d8258c13c6296820fd13114d784203feb91276e838", 11 | "finalShnarf": "0xbb198ef5bba4074d4cdf2603d841a6d40ce30faf9f935e0906dcf3d738b977e5", 12 | "parentStateRootHash": "0x072ead6777750dc20232d1cee8dc9a395c2d350df4bbaa5096c6f59b214dcecd", 13 | "parentAggregationLastBlockTimestamp": 1683325137, 14 | "lastFinalizedBlockNumber": 0, 15 | "finalTimestamp": 1683335137, 16 | "finalBlockNumber": 46, 17 | "l1RollingHash": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", 18 | "l1RollingHashMessageNumber": 12, 19 | "l2MerkleRoots": [ 20 | "0x97cd1539d08f7c0ba06ad836b2690eef50afd86609a0672517ec0ef8c1f94796" 21 | ], 22 | "l2MerkleTreesDepth": 5, 23 | "l2MessagingBlocksOffsets": "0x00000000000000000000000fffff" 24 | } 25 | -------------------------------------------------------------------------------- /test/testData/integrationWithProver/rolling-hash-history.json: -------------------------------------------------------------------------------- 1 | {"initialParentStateRootHash":"0x2b50810f4ffe11d63122b6cce4c5039bdbc72e751089326ab03b71b2256fdde7","initialFinalizedBlock":1000500,"initialShnarf":"0x0000000000000000000000000000000000000000000000000000000000000000","initialParentDataHash":"0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee","rollingHashHistory":[{"messageNumber":0,"rollingHash":"0x0000000000000000000000000000000000000000000000000000000000000000"},{"messageNumber":679,"rollingHash":"0xf1405ced8b9968baf9109259515bf7025a291b00ff7bfd6a4cdb51d40f4b367c"},{"messageNumber":680,"rollingHash":"0x73a55fc318bc3957ce7808096a918363345f0a7a770f4072db6b0b61c92e0b24"},{"messageNumber":681,"rollingHash":"0x91afc94781f3e8fbffddab1e56f5a99ba5de14653ec859c66efd343c1be4570f"}]} 2 | -------------------------------------------------------------------------------- /test/testData/mimc-test-data.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "in": [ 4 | "0x053dca111f5a4a9b99dd9a7ceb1870ea2f94d1a66c3313ed8f9998da6794daea" 5 | ], 6 | "out": "0x10e73aaa256aef633cbfdffbd9f8790ea61ba7e9ae777ae1ae68f76c094973ef" 7 | }, 8 | { 9 | "in": [ 10 | "0x103adbc490c2067eac112873462707eb2072813005a4ac3ab182135be3367424" 11 | ], 12 | "out": "0x0bd147e18a15e8fa89b21ac61ac10d2e35abcdd2b1341f6418d898779287c284" 13 | }, 14 | { 15 | "in": [ 16 | "0x0c2ab8155957bc96f22e91ca564ef3bf872cc0d36f3cf041fb23239fdfcebb25" 17 | ], 18 | "out": "0x060f2e1b3ea47643d1fc958b2656cd98494ce31ef03ad89ef197bb61bfd81ce1" 19 | }, 20 | { 21 | "in": [ 22 | "0x0d1a3c7869b8a5f7aa402f7d5fbb46f6d0027d02a5d7abc2f1521b9391bcc2bd", 23 | "0x08b72a98b302dec49dee7cab66799c48129d82439c51ce494a493e5100ea2a79" 24 | ], 25 | "out": "0x0d050fe6531aa6e431ee3661cd63573d69c67a316921fafec54a2bf5d8cb49d8" 26 | }, 27 | { 28 | "in": [ 29 | "0x0e01107131167cc592bd421bcdcfbed196e90d829e5a6b6cc275f94fc4cbac93", 30 | "0x0af4694129f690bb0445c7ffbf3881f8aff36f05c84cd64b248f5889ac3a2cc6" 31 | ], 32 | "out": "0x0df3e8a20787c7de555a006c1bea2eaf23e361f293c5d39a7c34c126cff7b60f" 33 | }, 34 | { 35 | "in": [ 36 | "0x055207393f0b9cb2aac69a27cc47bb1aba246ec8feb2e55ad4054eb0f5788f32", 37 | "0x0b0732797657d30c43673f62c94962e78531b0e9603211bbb1d13202f0cc3fec" 38 | ], 39 | "out": "0x075267e057ddbd06fb0b588050a211cd2349e889b71d7f8cc91e09e19e0fe46f" 40 | }, 41 | { 42 | "in": [ 43 | "0x00997dc1548caf4e82b3cd84747ddcf325a3ed26f9840cb45db21fa854ebbc6f", 44 | "0x00b77f9f1bc5b08fbe874b635264283704884eb8dbd2a5a6e73b33f0ff8d1537", 45 | "0x10b588d2213b1f5dca20cd8b8caf85ae1a22810bd611c8829fce4bf87735e785" 46 | ], 47 | "out": "0x0edab0778e9b34cf01dc2cb7edb9ec081c9a0544338ab8987c2c8742b9f41a06" 48 | }, 49 | { 50 | "in": [ 51 | "0x04c45e299845ed24b6a8c9859ec0a90d7fb11ad56afeff9aee70047167448c45", 52 | "0x126ba87ea05db08da85408e22454398d95ef19f6692177764911dadfa812ff79", 53 | "0x0c37c5b5d4dad04a001ad9dc1c88d2f8e4fd8b8d240a77afffed1d6634c91299" 54 | ], 55 | "out": "0x007373385295bdb3a04bbf5d21c496765ba55476eedd896a36c60b62d0cf6d8e" 56 | }, 57 | { 58 | "in": [ 59 | "0x0ad7c9a0288f1d0a6b0d740e0d7c34337b08d1ae81352518c0521e326bbd740a", 60 | "0x0efb7698fd33a04fdfc23805b61f89f22c019d44e8777639459cfdef21243e6e", 61 | "0x0b1bd9ca7eb6b4b3d5d2e3b2f7e6fcd5f029c7b536a8f10a8a25042b0dbbfb3b" 62 | ], 63 | "out": "0x0ed0317b4e637bb2bf7735cc06540496d3ca990b78f883857335992121af1692" 64 | }, 65 | { 66 | "in": [ 67 | "0x108f5c425a6c7d77ca9480845d2e246aad81c83ec78c16df05354e17311bd8c1", 68 | "0x090563b2391c74a74bf314adac0f174d5a67fe87c4ce119abc6f1d268e84885c", 69 | "0x0a84c7380a6be3b3447bc2adde464332f5ffa59a8093663471981e473404bd35", 70 | "0x0cb821da879b063a26b08960454f7b2b09d8a72b6722d2afd2ca673d51de0041" 71 | ], 72 | "out": "0x06b67adad32f83565ceb1243d75ca4f33a7af71207f28893a63ec3c43b7c516c" 73 | } 74 | ] -------------------------------------------------------------------------------- /test/tokenBridge/utils/permitHelper.ts: -------------------------------------------------------------------------------- 1 | import { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers"; 2 | import { ethers } from "ethers"; 3 | import { BridgedToken } from "../../../typechain-types"; 4 | 5 | const Permit = [ 6 | { name: "owner", type: "address" }, 7 | { name: "spender", type: "address" }, 8 | { name: "value", type: "uint256" }, 9 | { name: "nonce", type: "uint256" }, 10 | { name: "deadline", type: "uint256" }, 11 | ]; 12 | 13 | function buildData( 14 | owner: string, 15 | name: string, 16 | version: string, 17 | chainId: number, 18 | verifyingContract: string, 19 | spender: string, 20 | value: number, 21 | nonce: bigint, 22 | deadline: bigint, 23 | ) { 24 | return { 25 | domain: { name, version, chainId, verifyingContract }, 26 | types: { Permit }, 27 | value: { owner, spender, value, nonce, deadline }, 28 | }; 29 | } 30 | 31 | export async function getPermitData( 32 | wallet: SignerWithAddress, 33 | token: BridgedToken, 34 | nonce: bigint, 35 | chainId: number, 36 | spender: string, 37 | value: number, 38 | deadline: bigint, 39 | ) { 40 | const name = await token.name(); 41 | const data = buildData(wallet.address, name, "1", chainId, await token.getAddress(), spender, value, nonce, deadline); 42 | const signature = await wallet.signTypedData(data.domain, data.types, data.value); 43 | const { v, r, s } = ethers.Signature.from(signature); 44 | const permitCall = token.interface.encodeFunctionData("permit", [wallet.address, spender, value, deadline, v, r, s]); 45 | return permitCall; 46 | } 47 | -------------------------------------------------------------------------------- /test/upgrades/verify_L2MessageService_Upgrade.ts: -------------------------------------------------------------------------------- 1 | import { ethers, upgrades } from "hardhat"; 2 | 3 | // npx hardhat test --network linea_mainnet 4 | // THIS IS A MANUAL TEST TO VERIFY LINEA MAINNET DOES NOT BREAK 5 | // ALSO SEE PR FOR LAYOUT TABLE 6 | describe.skip("L2MessageService Upgrade from L2MessageService Linea Mainnet", () => { 7 | const mainnetProxyAddress = "0x508Ca82Df566dCD1B0DE8296e70a96332cD644ec"; 8 | 9 | describe("Collision", () => { 10 | it("Does not collide", async () => { 11 | const contract = await ethers.getContractFactory("L2MessageServiceLineaMainnet"); 12 | 13 | console.log("Importing contract"); 14 | await upgrades.forceImport(mainnetProxyAddress, contract, { 15 | kind: "transparent", 16 | }); 17 | 18 | const l2MessageServiceFactory = await ethers.getContractFactory("L2MessageService"); 19 | await upgrades.validateUpgrade(mainnetProxyAddress, l2MessageServiceFactory); 20 | }); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /test/upgrades/verify_LineaRollup_Upgrade.ts: -------------------------------------------------------------------------------- 1 | import { ethers, upgrades } from "hardhat"; 2 | 3 | // npx hardhat test --network mainnet 4 | // THIS IS A MANUAL TEST TO VERIFY MAINNET DOES NOT BREAK 5 | // ALSO SEE PR FOR LAYOUT TABLE 6 | describe.skip("LineaRollup Upgrade from ZkEvmMainnet", () => { 7 | const mainnetProxyAddress = "0xd19d4B5d358258f05D7B411E21A1460D11B0876F"; 8 | 9 | describe("Collision", () => { 10 | it("Does not collide", async () => { 11 | const contract = await ethers.getContractFactory("ZkEvmV2Mainnet"); 12 | 13 | console.log("Importing contract"); 14 | await upgrades.forceImport(mainnetProxyAddress, contract, { 15 | kind: "transparent", 16 | }); 17 | 18 | const LineaRollupFactory = await ethers.getContractFactory("LineaRollup"); 19 | await upgrades.validateUpgrade(mainnetProxyAddress, LineaRollupFactory); 20 | }); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /test/utils/deployment.ts: -------------------------------------------------------------------------------- 1 | import { DeployProxyOptions } from "@openzeppelin/hardhat-upgrades/src/utils"; 2 | import { ethers, upgrades } from "hardhat"; 3 | import { FactoryOptions } from "hardhat/types"; 4 | 5 | async function deployFromFactory(contractName: string, ...args: unknown[]) { 6 | const factory = await ethers.getContractFactory(contractName); 7 | const contract = await factory.deploy(...args); 8 | await contract.waitForDeployment(); 9 | return contract; 10 | } 11 | 12 | async function deployUpgradableFromFactory( 13 | contractName: string, 14 | args?: unknown[], 15 | opts?: DeployProxyOptions, 16 | factoryOpts?: FactoryOptions, 17 | ) { 18 | const factory = await ethers.getContractFactory(contractName, factoryOpts); 19 | const contract = await upgrades.deployProxy(factory, args, opts); 20 | await contract.waitForDeployment(); 21 | return contract; 22 | } 23 | 24 | export { deployFromFactory, deployUpgradableFromFactory }; 25 | -------------------------------------------------------------------------------- /test/utils/types.ts: -------------------------------------------------------------------------------- 1 | export type RawBlockData = { 2 | rootHash: string; 3 | timestamp: number; 4 | rlpEncodedTransactions: string[]; 5 | l2ToL1MsgHashes: string[]; 6 | batchReceptionIndices: number[]; 7 | fromAddresses: string; 8 | }; 9 | 10 | export type FormattedBlockData = Omit< 11 | RawBlockData, 12 | "rlpEncodedTransactions" | "timestamp" | "l2ToL1MsgHashes" | "fromAddresses" | "rootHash" 13 | > & { 14 | l2BlockTimestamp: number; 15 | transactions: string[]; 16 | l2ToL1MsgHashes: string[]; 17 | fromAddresses: string; 18 | blockRootHash: string; 19 | }; 20 | 21 | export type DebugData = { 22 | blocks: { 23 | txHashes: string[]; 24 | hashOfTxHashes: string; 25 | logHashes: string[]; 26 | hashOfLogHashes: string; 27 | hashOfPositions: string; 28 | HashForBlock: string; 29 | }[]; 30 | hashForAllBlocks: string; 31 | hashOfRootHashes: string; 32 | timestampHashes: string; 33 | finalHash: string; 34 | }; 35 | 36 | export type SubmissionData = { 37 | finalStateRootHash: string; 38 | firstBlockInData: bigint; 39 | finalBlockInData: bigint; 40 | snarkHash: string; 41 | }; 42 | 43 | export type ParentSubmissionData = { 44 | finalStateRootHash: string; 45 | firstBlockInData: bigint; 46 | finalBlockInData: bigint; 47 | shnarf: string; 48 | }; 49 | 50 | export type ParentAndExpectedShnarf = { 51 | parentShnarf: string; 52 | expectedShnarf: string; 53 | }; 54 | 55 | export type ShnarfData = { 56 | parentShnarf: string; 57 | snarkHash: string; 58 | finalStateRootHash: string; 59 | dataEvaluationPoint: string; 60 | dataEvaluationClaim: string; 61 | }; 62 | 63 | export type CalldataSubmissionData = SubmissionData & { 64 | compressedData: string; 65 | }; 66 | 67 | export type SubmissionAndCompressedData = { 68 | submissionData: SubmissionData; 69 | compressedData: string; 70 | }; 71 | 72 | export type FinalizationData = { 73 | aggregatedProof: string; 74 | finalBlockInData: bigint; 75 | lastFinalizedShnarf: string; 76 | shnarfData: ShnarfData; 77 | parentStateRootHash: string; 78 | lastFinalizedTimestamp: bigint; 79 | finalTimestamp: bigint; 80 | l1RollingHash: string; 81 | l1RollingHashMessageNumber: bigint; 82 | l2MerkleRoots: string[]; 83 | l2MerkleTreesDepth: bigint; 84 | l2MessagingBlocksOffsets: string; 85 | lastFinalizedL1RollingHash: string; 86 | lastFinalizedL1RollingHashMessageNumber: bigint; 87 | }; 88 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "./dist", 4 | "baseUrl": ".", 5 | "moduleResolution": "Node", 6 | "module": "CommonJS", 7 | "target": "ES2021", 8 | "sourceMap": true, 9 | "strict": true, 10 | "esModuleInterop": true, 11 | "alwaysStrict": true, 12 | "strictNullChecks": true, 13 | "noImplicitAny": true, 14 | "noImplicitReturns": true, 15 | "noImplicitThis": true, 16 | "noUnusedLocals": true, 17 | "resolveJsonModule": true, 18 | "forceConsistentCasingInFileNames": true, 19 | "skipLibCheck": true, 20 | }, 21 | "exclude": ["node_modules", "dist", "*.d.ts"] 22 | } 23 | -------------------------------------------------------------------------------- /utils/auditedDeployVerifier.ts: -------------------------------------------------------------------------------- 1 | import { execSync } from "child_process"; 2 | 3 | export function getGitBranch(): string { 4 | return execSync("git rev-parse --abbrev-ref HEAD").toString().trim(); 5 | } 6 | 7 | export function getGitCommitHash(): string { 8 | return execSync(`git rev-parse HEAD`).toString().trim(); 9 | } 10 | 11 | export function getGitTagsAtCommitHash(): string[] { 12 | // Get the tags pointing specifically to this commit hash! This is vital in making sure that commit has a valid tag. 13 | const tags = execSync(`git tag --points-at ${getGitCommitHash()}`).toString().trim(); 14 | return tags.length > 0 ? tags.split("\n") : []; 15 | } 16 | 17 | export function validateDeployBranchAndTags(networkName: string) { 18 | // Tag pattern - e.g. contract-audit-diligience-2022-08-28 19 | const tagPattern = /^contract-audit-\S+-\d{4}-\d{2}-\d{2}$/; 20 | const branchPattern = /^audit\/|main\//; 21 | 22 | const networksRequiringAuditedCode: string[] = ["mainnet", "linea_mainnet", "goerli", "linea_goerli"]; 23 | 24 | console.log("Validating if the network to deploy to requires an audited version."); 25 | 26 | if (networksRequiringAuditedCode.includes(networkName)) { 27 | const branch = getGitBranch(); 28 | const tags = getGitTagsAtCommitHash(); 29 | 30 | if (!branchPattern.test(branch)) { 31 | throw `You must deploy from an audit branch, you are on ${branch}`; 32 | } 33 | 34 | if (!tags.some((value) => tagPattern.test(value))) { 35 | throw "Tags for this branch are missing. Format 'contract-audit-FIRM-DATE'"; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /utils/deployments.ts: -------------------------------------------------------------------------------- 1 | import { GetContractTypeFromFactory } from "../typechain-types/common"; 2 | import { ProxyAdmin, ProxyAdmin__factory, TransparentUpgradeableProxy__factory } from "../typechain-types"; 3 | import { ContractFactory, Overrides, Wallet, ethers } from "ethers"; 4 | import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers"; 5 | 6 | export function getInitializerData( 7 | contractInterface: ethers.Interface, 8 | initializerFunctionName: string, 9 | args: unknown[], 10 | ) { 11 | const fragment = contractInterface.getFunction(initializerFunctionName); 12 | 13 | if (!fragment) { 14 | return "0x"; 15 | } 16 | 17 | return contractInterface.encodeFunctionData(fragment, args); 18 | } 19 | 20 | export const deployContract = async ( 21 | contractFactory: TFactory, 22 | deployer: Wallet | HardhatEthersSigner, 23 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 24 | args?: any[], 25 | overrides: Overrides = {}, 26 | ): Promise> => { 27 | const deploymentArgs = args || []; 28 | const instance = await contractFactory.connect(deployer).deploy(...deploymentArgs, overrides); 29 | return instance.waitForDeployment() as GetContractTypeFromFactory; 30 | }; 31 | 32 | export const deployUpgradableContract = async ( 33 | contractFactory: TFactory, 34 | deployer: Wallet | HardhatEthersSigner, 35 | admin: ProxyAdmin, 36 | initializerData = "0x", 37 | overrides: Overrides = {}, 38 | ): Promise> => { 39 | const instance = await deployContract(contractFactory, deployer, [], overrides); 40 | 41 | const proxy = await deployContract(new TransparentUpgradeableProxy__factory(), deployer, [ 42 | await instance.getAddress(), 43 | await admin.getAddress(), 44 | initializerData, 45 | ]); 46 | 47 | return proxy as GetContractTypeFromFactory; 48 | }; 49 | 50 | export async function deployUpgradableContractWithProxyAdmin( 51 | contractFactory: TFactory, 52 | deployer: Wallet | HardhatEthersSigner, 53 | initializer?: { 54 | functionName: string; 55 | args: unknown[]; 56 | }, 57 | overrides: Overrides = {}, 58 | ): Promise> { 59 | const proxyFactory = new ProxyAdmin__factory(deployer); 60 | 61 | const proxyAdmin = await deployContract(proxyFactory, deployer, [], overrides); 62 | 63 | let contract: GetContractTypeFromFactory; 64 | if (initializer) { 65 | const initializerData = getInitializerData(contractFactory.interface, initializer.functionName, initializer.args); 66 | contract = await deployUpgradableContract(contractFactory, deployer, proxyAdmin, initializerData, overrides); 67 | } else { 68 | contract = await deployUpgradableContract(contractFactory, deployer, proxyAdmin, "0x", overrides); 69 | } 70 | return contract; 71 | } 72 | -------------------------------------------------------------------------------- /utils/environmentHelper.ts: -------------------------------------------------------------------------------- 1 | import { TaskArguments } from "hardhat/types"; 2 | 3 | function getCliOrEnvValue(cliParam: string, envParam: string): string | undefined { 4 | const argv = process.argv; 5 | 6 | const cliParamIndex = argv.indexOf(cliParam); 7 | 8 | if (cliParamIndex != -1) { 9 | return argv[cliParamIndex + 1]; 10 | } else { 11 | //look in the .env 12 | const envVariable = process.env[envParam]; 13 | if (envVariable) { 14 | return envVariable; 15 | } 16 | } 17 | return undefined; 18 | } 19 | 20 | function getTaskCliOrEnvValue(taskArgs: TaskArguments, cliParam: string, envParam: string): string | undefined { 21 | if (taskArgs[cliParam] !== undefined) { 22 | return taskArgs[cliParam]; 23 | } else { 24 | //look in the .env 25 | const envVariable = process.env[envParam]; 26 | if (envVariable) { 27 | return envVariable; 28 | } 29 | } 30 | return undefined; 31 | } 32 | 33 | export { getCliOrEnvValue, getTaskCliOrEnvValue }; 34 | -------------------------------------------------------------------------------- /utils/readAddress.ts: -------------------------------------------------------------------------------- 1 | import fs from "fs"; 2 | import path from "path"; 3 | 4 | export const getDeployedContractOnNetwork = async ( 5 | networkName: string, 6 | contractName: string, 7 | ): Promise => { 8 | const filePath = path.join(__dirname, "..", "deployments", `${networkName}`, `${contractName}.json`); 9 | if (!fs.existsSync(filePath)) { 10 | return undefined; 11 | } 12 | const data = fs.readFileSync(filePath, "utf-8"); 13 | return JSON.parse(data).address; 14 | }; 15 | 16 | export const delay = (ms: number) => new Promise((res) => setTimeout(res, ms)); 17 | -------------------------------------------------------------------------------- /utils/supportedNetworks.ts: -------------------------------------------------------------------------------- 1 | export enum SupportedChainIds { 2 | MAINNET = 1, 3 | GOERLI = 5, 4 | LINEA_TESTNET = 59140, 5 | LINEA = 59144, 6 | } 7 | -------------------------------------------------------------------------------- /utils/verifyContract.ts: -------------------------------------------------------------------------------- 1 | import { run } from "hardhat"; 2 | import { delay } from "./storeAddress"; 3 | 4 | export async function tryVerifyContract(contractAddress: string) { 5 | if (process.env.VERIFY_CONTRACT) { 6 | console.log("Waiting 30 seconds for contract propagation..."); 7 | await delay(30000); 8 | console.log("Etherscan verification ongoing..."); 9 | // Verify contract 10 | try { 11 | await run("verify", { 12 | address: contractAddress, 13 | }); 14 | } catch (err) { 15 | console.log(`Error happened during verification: ${err}`); 16 | } 17 | console.log("Etherscan verification done."); 18 | } 19 | } 20 | 21 | export async function tryVerifyContractWithConstructorArgs( 22 | contractAddress: string, 23 | contractForVerification: string, 24 | args: unknown[], 25 | ) { 26 | if (process.env.VERIFY_CONTRACT) { 27 | console.log("Waiting 30 seconds for contract propagation..."); 28 | await delay(30000); 29 | console.log("Etherscan verification ongoing..."); 30 | 31 | // Verify contract 32 | try { 33 | await run("verify:verify", { 34 | address: contractAddress, 35 | contract: contractForVerification, 36 | constructorArguments: args, 37 | }); 38 | } catch (err) { 39 | console.log(`Error happened during verification: ${err}`); 40 | } 41 | console.log("Etherscan verification done."); 42 | } 43 | } 44 | --------------------------------------------------------------------------------