├── .env.example ├── .gas-snapshot ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── feature_request.md │ └── pr_request.md └── workflows │ └── push.yaml ├── .gitignore ├── .gitmodules ├── .prettierignore ├── .prettierrc ├── LICENSE ├── README.md ├── chainConfig.json ├── contracts ├── CapacitorFactory.sol ├── ExecutionManager.sol ├── ExecutionManagerDF.sol ├── OpenExecutionManager.sol ├── TransmitManager.sol ├── capacitors │ ├── BaseCapacitor.sol │ ├── HashChainCapacitor.sol │ └── SingleCapacitor.sol ├── decapacitors │ ├── HashChainDecapacitor.sol │ └── SingleDecapacitor.sol ├── examples │ ├── Counter.sol │ └── Messenger.sol ├── interfaces │ ├── ICapacitor.sol │ ├── ICapacitorFactory.sol │ ├── IDecapacitor.sol │ ├── IExecutionManager.sol │ ├── IHasher.sol │ ├── INativeRelay.sol │ ├── IPlug.sol │ ├── ISignatureVerifier.sol │ ├── ISocket.sol │ ├── ISwitchboard.sol │ └── ITransmitManager.sol ├── libraries │ ├── AddressAliasHelper.sol │ └── RescueFundsLib.sol ├── mocks │ ├── MockAccessControl.sol │ ├── MockOwnable.sol │ ├── MockPolygonL1Switchboard.sol │ ├── MockPolygonL2Switchboard.sol │ ├── MockSafe.sol │ └── fee-updater │ │ ├── SimulatorUtils.sol │ │ ├── SocketSimulator.sol │ │ └── SwitchboardSimulator.sol ├── socket │ ├── Socket.sol │ ├── SocketBase.sol │ ├── SocketBatcher.sol │ ├── SocketConfig.sol │ ├── SocketDst.sol │ └── SocketSrc.sol ├── switchboard │ ├── default-switchboards │ │ ├── FastSwitchboard.sol │ │ ├── OptimisticSwitchboard.sol │ │ └── SwitchboardBase.sol │ └── native │ │ ├── ArbitrumL1Switchboard.sol │ │ ├── ArbitrumL2Switchboard.sol │ │ ├── NativeSwitchboardBase.sol │ │ ├── OptimismSwitchboard.sol │ │ ├── PolygonL1Switchboard.sol │ │ └── PolygonL2Switchboard.sol └── utils │ ├── AccessControl.sol │ ├── AccessControlExtended.sol │ ├── AccessRoles.sol │ ├── Hasher.sol │ ├── Ownable.sol │ ├── SigIdentifiers.sol │ ├── SignatureVerifier.sol │ └── multisig │ ├── MultiSigWrapper.sol │ ├── SafeL2.sol │ └── proxies │ ├── IProxyCreationCallback.sol │ ├── SafeProxy.sol │ └── SafeProxyFactory.sol ├── deploy.sh ├── deployments ├── dev_addresses.json ├── dev_verification.json ├── prod_addresses.json ├── prod_verification.json ├── surge_addresses.json └── surge_verification.json ├── foundry.toml ├── funding.json ├── hardhat.config.ts ├── lib.tsconfig.json ├── package.json ├── remappings.txt ├── scripts ├── admin │ ├── rescueFunds.ts │ ├── rotate-owner │ │ ├── 1-nominate-multisig.ts │ │ ├── 1-nominate.ts │ │ ├── 2-claim-with-multisig.ts │ │ ├── 2-claim.ts │ │ ├── 3-add-signer.ts │ │ └── 3-migrate-roles-to-multisig.ts │ ├── setFees.ts │ ├── tripCommon.ts │ ├── tripGlobal.ts │ ├── untripPath.ts │ └── update-safe.ts ├── burn.ts ├── common │ ├── index.ts │ ├── siblings.ts │ ├── sigIdentifiers.ts │ └── switchboards.ts ├── constants │ ├── bridge.ts │ ├── config.ts │ ├── index.ts │ ├── networks.ts │ ├── overrides.ts │ └── types.ts ├── deploy │ ├── DEPLOY.md │ ├── config │ │ └── config.ts │ ├── deploy.ts │ ├── em-migration │ │ ├── backward-migrate-em.ts │ │ ├── check-migration.ts │ │ └── migrate-em.ts │ ├── helpers │ │ ├── capacitorCount.ts │ │ ├── checkBalance.ts │ │ ├── estimateGas.ts │ │ ├── fastSwitchboards.ts │ │ ├── send-msg │ │ │ ├── allPathTest.ts │ │ │ ├── outbound-load-test.ts │ │ │ ├── transmissionParamsTestScript.ts │ │ │ └── utils.ts │ │ └── switchboardData.ts │ ├── scripts │ │ ├── configureRoles.ts │ │ ├── configureSocket.ts │ │ ├── configureSwitchboards.ts │ │ ├── connect.ts │ │ ├── deploySocket.ts │ │ ├── deploySocketFor.ts │ │ ├── deploySwitchboard.ts │ │ ├── multicall.ts │ │ ├── registerSwitchboard.ts │ │ └── roles.ts │ ├── single-click-deploy │ │ ├── README.md │ │ ├── configureChain.ts │ │ └── integrators │ │ │ ├── deploySocket.ts │ │ │ ├── index.ts │ │ │ ├── utils.ts │ │ │ └── writeConfigs.ts │ ├── smoke-test.ts │ ├── switchboards │ │ ├── arbitrumL1Switchboard.ts │ │ ├── arbitrumL2Switchboard.ts │ │ ├── fastSwitchboard.ts │ │ ├── index.ts │ │ ├── optimismSwitchboard.ts │ │ ├── optimisticSwitchboard.ts │ │ ├── polygonL1Switchboard.ts │ │ └── polygonL2Switchboard.ts │ ├── utils │ │ ├── address.ts │ │ ├── index.ts │ │ ├── packetId.ts │ │ ├── relayer.ts │ │ ├── signature.ts │ │ ├── socket-signer.ts │ │ └── utils.ts │ ├── verify.ts │ └── writeChainConfig.ts ├── depositEthToOpstackChain.ts ├── limits-updater │ ├── initLimits.ts │ ├── query │ │ ├── get-integrations.ts │ │ ├── query-all-integrations.ts │ │ └── query-relayer-config.ts │ └── utils │ │ ├── relayer.config.ts │ │ ├── transaction-helper.ts │ │ └── types.ts ├── native-bridge-helpers │ ├── arbitrum │ │ ├── l1Tol2Relay.ts │ │ └── l2tol1Relay.ts │ ├── optimism │ │ ├── l1Tol2Relay.ts │ │ ├── l2tol1Relay.ts │ │ └── op-stack-native-withdrawals.ts │ └── polygon │ │ └── l2tol1Relay.ts ├── rpcConfig │ ├── constants │ │ ├── batcherSupportedChainSlug.ts │ │ ├── defaultFinalityBucket.ts │ │ ├── disabledDFFeeChains.ts │ │ ├── explorers.ts │ │ ├── feesUpdaterChainSlugs.ts │ │ ├── finality.ts │ │ ├── icons.ts │ │ ├── index.ts │ │ ├── reSyncInterval.ts │ │ ├── rpc.ts │ │ └── version.ts │ ├── rpcConfig.ts │ ├── txdata-builder │ │ ├── generate-calldata.ts │ │ └── util.ts │ ├── updateConstants.ts │ └── uploadS3Config.ts ├── socket-helpers │ ├── arb-estimate.ts │ ├── main.ts │ ├── op-n-eth-estimate.ts │ └── utils.ts └── transmitter │ └── propose.ts ├── src ├── addresses.ts ├── currency-util.ts ├── enums │ ├── arbChains.ts │ ├── arbL3Chains.ts │ ├── chainId.ts │ ├── chainSlug.ts │ ├── chainSlugToHardhatChainName.ts │ ├── chainSlugToId.ts │ ├── chainSlugToKey.ts │ ├── currency.ts │ ├── ethLikeChains.ts │ ├── hardhatChainName.ts │ ├── hardhatChainNameToSlug.ts │ ├── index.ts │ ├── mainnetIds.ts │ ├── native-tokens.ts │ ├── opStackChains.ts │ ├── polygonCDKChains.ts │ ├── testnetIds.ts │ └── zkStackChain.ts ├── index.ts ├── socket-types.ts └── transmission-utils.ts ├── tasks └── accounts.ts ├── test ├── IntegrationTest.t.sol ├── MultiSigWrapper.t.sol ├── Setup.t.sol ├── SocketSimulator.t.sol ├── capacitors │ ├── CapacitorFactory.t.sol │ ├── HashChainCapacitor.t.sol │ └── SingleCapacitor.t.sol ├── managers │ ├── ExecutionManager.t.sol │ ├── OpenExecutionManager.t.sol │ └── TransmitManager.t.sol ├── socket │ ├── SocketAdmin.t.sol │ ├── SocketBatcher.t.sol │ ├── SocketDst.t.sol │ └── SocketSrc.t.sol ├── switchboard │ ├── default-switchboards │ │ ├── FastSwitchboard.t.sol │ │ ├── OptimisticSwitchboard.t.sol │ │ └── SwitchboardBase.t.sol │ └── native │ │ ├── ArbitrumL1Switchboard.t.sol │ │ ├── ArbitrumL2Switchboard.t.sol │ │ ├── NativeBase.t.sol │ │ ├── OptimismSwitchboardL1L2.t.sol │ │ ├── OptimismSwitchboardL2L1.t.sol │ │ ├── PolygonL1Switchboard.t.sol │ │ └── PolygonL2Switchboard.t.sol └── utils │ ├── AccessControl.t.sol │ └── Ownable.t.sol ├── tsconfig.json └── yarn.lock /.env.example: -------------------------------------------------------------------------------- 1 | #global settings 2 | NODE_ENV="production" 3 | DOTENV_CONFIG_PATH=./.env 4 | DEPLOYMENT_MODE="prod" # dev | surge | prod 5 | 6 | # relayer urls 7 | RELAYER_API_KEY_DEV="" 8 | RELAYER_API_KEY_SURGE="" 9 | RELAYER_API_KEY_PROD="" 10 | 11 | RELAYER_URL_DEV="" 12 | RELAYER_URL_SURGE="" 13 | RELAYER_URL_PROD="" 14 | 15 | # dl api 16 | DL_API_DEV_URL="" 17 | DL_API_PROD_URL="" 18 | 19 | # etherscan verification 20 | ETHERSCAN_API_KEY=xxx 21 | POLYGONSCAN_API_KEY=xxx 22 | OPTIMISM_API_KEY=xxx 23 | ARBISCAN_API_KEY=xxx 24 | SNOWTRACE_API_KEY=xxx 25 | BSCSCAN_API_KEY=xxx 26 | AEVO_API_KEY=xxx 27 | LYRA_API_KEY=xxx 28 | XAI_API_KEY=xxx 29 | BASESCAN_API_KEY=xxx 30 | KINTO_API_KEY=xxx 31 | KINTO_DEVNET_API_KEY=xxx 32 | 33 | # rpc 34 | ARBITRUM_RPC='https://arb1.arbitrum.io/rpc' 35 | ARBITRUM_GOERLI_RPC='https://goerli-rollup.arbitrum.io/rpc' 36 | ARBITRUM_SEPOLIA_RPC='' 37 | 38 | OPTIMISM_RPC='https://mainnet.optimism.io' 39 | OPTIMISM_GOERLI_RPC='https://goerli.optimism.io' 40 | OPTIMISM_SEPOLIA_RPC='' 41 | 42 | POLYGON_RPC='https://rpc.ankr.com/polygon' 43 | POLYGON_MUMBAI_RPC='https://matic-mumbai.chainstacklabs.com' 44 | 45 | BSC_RPC='https://bsc-dataseed1.binance.org' 46 | BSC_TESTNET_RPC='https://data-seed-prebsc-1-s1.binance.org:8545' 47 | 48 | ETHEREUM_RPC='https://rpc.ankr.com/eth' 49 | GOERLI_RPC='https://rpc.ankr.com/eth_goerli' 50 | SEPOLIA_RPC='https://rpc.sepolia.org' 51 | 52 | AEVO_TESTNET_RPC='' 53 | AEVO_RPC='' 54 | LYRA_TESTNET_RPC='' 55 | LYRA_RPC='' 56 | XAI_TESTNET_RPC='' 57 | SX_NETWORK_TESTNET_RPC='' 58 | SX_NETWORK_RPC='' 59 | MODE_TESTNET_RPC='' 60 | VICTION_TESTNET_RPC='' 61 | BASE_RPC='' 62 | MODE_RPC='' 63 | ANCIENT8_TESTNET_RPC='' 64 | ANCIENT8_TESTNET2_RPC='' 65 | PARALLEL_RPC='' 66 | MANTLE_RPC='' 67 | REYA_CRONOS_RPC='' 68 | REYA_RPC='' 69 | SYNDR_SEPOLIA_L3_RPC='' 70 | POLYNOMIAL_TESTNET_RPC='' 71 | BOB_RPC='' 72 | KINTO_RPC='' 73 | KINTO_DEVNET_RPC='' 74 | SIPHER_FUNKI_TESTNET_RPC='' 75 | WINR_RPC='' 76 | BLAST_RPC='' 77 | 78 | # update these settings 79 | 80 | # SOCKET_OWNER_ADDRESS="" 81 | # SOCKET_SIGNER_KEY=xxx 82 | 83 | POLYNOMIAL_RPC='' 84 | SYNDR_RPC=' ' 85 | 86 | DL_API_DEV_URL='' 87 | DL_API_PROD_URL='' 88 | 89 | NEOX_TESTNET_RPC=' ' 90 | NEOX_T4_TESTNET_RPC=' ' 91 | NEOX_RPC=' ' 92 | GNOSIS_RPC=' ' 93 | LINEA_RPC=' ' 94 | ZKEVM_RPC=' ' 95 | AVALANCHE_RPC=' ' 96 | XLAYER_RPC=' ' 97 | MANTA_PACIFIC_RPC=' ' 98 | POLTER_TESTNET_RPC=' ' 99 | POLYGON_AMOY_RPC=' ' 100 | OPBNB_RPC=' ' 101 | GEIST_RPC=' ' 102 | 103 | ZERO_SEPOLIA_RPC=' ' 104 | 105 | ZERO_RPC=' ' 106 | 107 | ZKSYNC_RPC=' ' 108 | 109 | ARENA_Z_RPC=' ' 110 | 111 | INK_RPC=' ' 112 | 113 | SONIC_RPC=' ' 114 | 115 | BASE_SEPOLIA_RPC=' ' 116 | 117 | BERA_RPC=' ' 118 | 119 | B3_RPC=' ' 120 | 121 | UNICHAIN_RPC=' ' 122 | 123 | MONAD_TESTNET_RPC=' ' 124 | 125 | SCROLL_RPC=' ' 126 | 127 | SONEIUM_RPC=' ' 128 | 129 | SWELLCHAIN_RPC=' ' 130 | 131 | WORLD_CHAIN_RPC=' ' 132 | 133 | PLUME_RPC=' ' 134 | 135 | KATANA_RPC=' ' 136 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | --- 8 | 9 | **Describe the bug** 10 | A clear and concise description of what the bug is. 11 | 12 | **To Reproduce** 13 | Steps to reproduce the behavior 14 | 15 | **Expected behavior** 16 | A clear and concise description of what you expected to happen. 17 | 18 | **Additional context** 19 | Add any other context about the problem here. 20 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | --- 8 | 9 | **Is your feature request related to a problem? Please describe.** 10 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 11 | 12 | **Describe the solution you'd like** 13 | A clear and concise description of what you want to happen. 14 | 15 | **Describe alternatives you've considered** 16 | A clear and concise description of any alternative solutions or features you've considered. 17 | 18 | **Additional context** 19 | Add any other context or screenshots about the feature request here. 20 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/pr_request.md: -------------------------------------------------------------------------------- 1 | # Description 2 | 3 | Please include a summary of the changes and the related issue. Please also include relevant motivation and context. List any dependencies that are required for this change. 4 | 5 | Fixes # (issue) 6 | 7 | ## Type of change 8 | 9 | Please delete options that are not relevant. 10 | 11 | - [ ] Bug fix (non-breaking change which fixes an issue) 12 | - [ ] New feature (non-breaking change which adds functionality) 13 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) 14 | - [ ] This change requires a documentation update 15 | 16 | # How Has This Been Tested? 17 | 18 | Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration 19 | 20 | **Test Configuration**: 21 | 22 | - Toolchain: 23 | - SDK: 24 | 25 | # Checklist: 26 | 27 | - [ ] My code follows the style guidelines of this project 28 | - [ ] I have performed a self-review of my code 29 | - [ ] I have commented my code, particularly in hard-to-understand areas 30 | - [ ] I have made corresponding changes to the documentation 31 | - [ ] My changes generate no new warnings 32 | - [ ] I have added tests that prove my fix is effective or that my feature works 33 | - [ ] New and existing unit tests pass locally with my changes 34 | -------------------------------------------------------------------------------- /.github/workflows/push.yaml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: [push, pull_request] 4 | 5 | env: 6 | FOUNDRY_PROFILE: prod 7 | OPTIMISM_SEPOLIA_RPC: ${{ secrets.OPTIMISM_SEPOLIA_RPC }} 8 | SEPOLIA_RPC: ${{ secrets.SEPOLIA_RPC }} 9 | MAINNET_RPC: ${{ secrets.MAINNET_RPC }} 10 | 11 | jobs: 12 | tests: 13 | name: Build and Tests 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v2 17 | 18 | - name: Install Foundry 19 | uses: foundry-rs/foundry-toolchain@v1 20 | with: 21 | version: nightly 22 | 23 | - name: Install forge dependencies 24 | run: forge install 25 | 26 | - name: Set Node.js 18.x 27 | uses: actions/setup-node@v3 28 | with: 29 | node-version: 18.x 30 | 31 | - name: Run yarn install 32 | uses: borales/actions-yarn@v4 33 | with: 34 | cmd: install 35 | 36 | - name: Build bundle 37 | uses: borales/actions-yarn@v4 38 | with: 39 | cmd: build 40 | env: 41 | SOCKET_SIGNER_KEY: "562ed26cb2e52dbdf8cfbec91cd5370f236a997e54ebc1c1fb34d3237d4795f8" 42 | 43 | - name: Check contract sizes 44 | run: forge build --sizes 45 | 46 | - name: Run tests 47 | run: forge test 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | cache/ 3 | out/ 4 | node_modules/ 5 | scratchpad/ 6 | 7 | scripts/scratchpad/ 8 | #Hardhat files 9 | cache_hardhat/ 10 | artifacts/ 11 | src/types 12 | 13 | .vscode/ 14 | #Hardhat plugin files 15 | typechain-types/ 16 | 17 | .env 18 | .DS_Store 19 | 20 | .gas-snapshot/ 21 | scripts/deploy/gasEstimate.ts 22 | 23 | # coverage 24 | lcov.info 25 | 26 | dev_switchboards.json 27 | prod_switchboards.json 28 | switchboards.json 29 | 30 | devRpcConfig.ts 31 | devRpcConfig.json 32 | prodRpcConfig.ts 33 | prodRpcConfig.json 34 | 35 | artifacts-zk/ 36 | cache_hardhat-zk/ 37 | deployments-zk/ 38 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/forge-std"] 2 | path = lib/forge-std 3 | url = https://github.com/foundry-rs/forge-std 4 | [submodule "lib/openzeppelin-contracts"] 5 | path = lib/openzeppelin-contracts 6 | url = https://github.com/OpenZeppelin/openzeppelin-contracts 7 | [submodule "lib/contracts"] 8 | path = lib/contracts 9 | url = https://github.com/fx-portal/contracts 10 | [submodule "lib/solmate"] 11 | path = lib/solmate 12 | url = https://github.com/transmissions11/solmate 13 | [submodule "lib/safe-smart-account"] 14 | path = lib/safe-smart-account 15 | url = https://github.com/safe-global/safe-smart-account 16 | [submodule "lib/solady"] 17 | path = lib/solady 18 | url = https://github.com/Vectorized/solady 19 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | lib 2 | artifacts 3 | cache 4 | cache_hardhat 5 | 6 | dist 7 | node_modules 8 | out 9 | typechain-types 10 | scratchpad 11 | 12 | .DS_Store 13 | .env 14 | .env.example 15 | .gas-snapshot 16 | .gitignore 17 | .gitmodules 18 | .prettierignore 19 | deploy.sh 20 | foundry.toml 21 | LICENSE 22 | remappings.txt 23 | yarn.lock 24 | .github/* 25 | .prettierrc 26 | scratchpad 27 | lcov.info 28 | 29 | artifacts-zk/ 30 | cache_hardhat-zk/ 31 | deployments-zk/ 32 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "overrides": [ 3 | { 4 | "files": "*.sol", 5 | "options": { 6 | "tabWidth": 4, 7 | "printWidth": 80, 8 | "useTabs": false, 9 | "singleQuote": false, 10 | "bracketSpacing": false 11 | } 12 | }, 13 | { 14 | "files": ["*.js", "*.md"], 15 | "options": { 16 | "tabWidth": 2, 17 | "printWidth": 80, 18 | "useTabs": false, 19 | "semi": true, 20 | "singleQuote": true, 21 | "bracketSpacing": true, 22 | "trailingComma": "all" 23 | } 24 | } 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /chainConfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "8453": { 3 | "roleOwners": { 4 | "ownerAddress": "0xB0BBff6311B7F245761A7846d3Ce7B1b100C1836", 5 | "executorAddress": "0x42639d8fd154b72472e149a7d5ac13fa280303d9", 6 | "transmitterAddress": "0xfbc5ea2525bb827979e4c33b237cd47bcb8f81c5", 7 | "watcherAddress": "0x75ddddf61b8180d3837b7d8b98c062ca442e0e14", 8 | "feeUpdaterAddress": "0xfbc5ea2525bb827979e4c33b237cd47bcb8f81c5" 9 | }, 10 | "siblings": [1, 137, 42161, 10, 56, 34443] 11 | }, 12 | "31337": { 13 | "siblings": [], 14 | "timeout": 7200, 15 | "msgValueMaxThreshold": 10000000000000000, 16 | "overrides": { 17 | "type": 1, 18 | "gasLimit": 20000000, 19 | "gasPrice": 1000000000000 20 | } 21 | }, 22 | "34443": { 23 | "roleOwners": { 24 | "ownerAddress": "0xB0BBff6311B7F245761A7846d3Ce7B1b100C1836", 25 | "executorAddress": "0x42639d8fd154b72472e149a7d5ac13fa280303d9", 26 | "transmitterAddress": "0xfbc5ea2525bb827979e4c33b237cd47bcb8f81c5", 27 | "watcherAddress": "0x75ddddf61b8180d3837b7d8b98c062ca442e0e14", 28 | "feeUpdaterAddress": "0xfbc5ea2525bb827979e4c33b237cd47bcb8f81c5" 29 | }, 30 | "siblings": [1, 42161, 10, 8453] 31 | }, 32 | "60808": { 33 | "roleOwners": { 34 | "ownerAddress": "0xB0BBff6311B7F245761A7846d3Ce7B1b100C1836", 35 | "executorAddress": "0x42639d8fd154b72472e149a7d5ac13fa280303d9", 36 | "transmitterAddress": "0xfbc5ea2525bb827979e4c33b237cd47bcb8f81c5", 37 | "watcherAddress": "0x75ddddf61b8180d3837b7d8b98c062ca442e0e14", 38 | "feeUpdaterAddress": "0xfbc5ea2525bb827979e4c33b237cd47bcb8f81c5" 39 | }, 40 | "siblings": [42161, 10] 41 | }, 42 | "444444": { 43 | "roleOwners": { 44 | "ownerAddress": "0xB0BBff6311B7F245761A7846d3Ce7B1b100C1836", 45 | "executorAddress": "0x42639d8fd154b72472e149a7d5ac13fa280303d9", 46 | "transmitterAddress": "0xfbc5ea2525bb827979e4c33b237cd47bcb8f81c5", 47 | "watcherAddress": "0x75ddddf61b8180d3837b7d8b98c062ca442e0e14", 48 | "feeUpdaterAddress": "0xfbc5ea2525bb827979e4c33b237cd47bcb8f81c5" 49 | }, 50 | "siblings": [421614, 80001, 11155111] 51 | }, 52 | "2863311531": { 53 | "roleOwners": { 54 | "ownerAddress": "0xB0BBff6311B7F245761A7846d3Ce7B1b100C1836", 55 | "executorAddress": "0x42639d8fd154b72472e149a7d5ac13fa280303d9", 56 | "transmitterAddress": "0xfbc5ea2525bb827979e4c33b237cd47bcb8f81c5", 57 | "watcherAddress": "0x75ddddf61b8180d3837b7d8b98c062ca442e0e14", 58 | "feeUpdaterAddress": "0xfbc5ea2525bb827979e4c33b237cd47bcb8f81c5" 59 | }, 60 | "siblings": [421614, 11155420] 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /contracts/CapacitorFactory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | pragma solidity 0.8.19; 3 | 4 | import "./interfaces/ICapacitorFactory.sol"; 5 | import "./capacitors/SingleCapacitor.sol"; 6 | import "./decapacitors/SingleDecapacitor.sol"; 7 | 8 | import "./libraries/RescueFundsLib.sol"; 9 | import "./utils/AccessControl.sol"; 10 | import {RESCUE_ROLE} from "./utils/AccessRoles.sol"; 11 | 12 | /** 13 | * @title CapacitorFactory 14 | * @notice Factory contract for creating capacitor and decapacitor pairs. 15 | * @dev The capacitorType_ parameter determines the type of capacitor and decapacitor to deploy. 16 | * @dev More types can be introduced by deploying new contract and pointing to it on Socket. 17 | */ 18 | contract CapacitorFactory is ICapacitorFactory, AccessControl { 19 | uint256 private constant SINGLE_CAPACITOR = 1; 20 | 21 | // min packet length to avoid div by 0 in fee calculations 22 | uint256 public constant minAllowedPacketLength = 1; 23 | 24 | // admin initialized max value for max packet length 25 | uint256 public immutable maxAllowedPacketLength; 26 | 27 | error PacketLengthNotAllowed(); 28 | 29 | /** 30 | * @notice initializes and grants RESCUE_ROLE to owner. 31 | * @param owner_ The address of the owner of the contract. 32 | * @param maxAllowedPacketLength_ The max length allowed for capacitors 33 | */ 34 | constructor( 35 | address owner_, 36 | uint256 maxAllowedPacketLength_ 37 | ) AccessControl(owner_) { 38 | _grantRole(RESCUE_ROLE, owner_); 39 | maxAllowedPacketLength = maxAllowedPacketLength_; 40 | } 41 | 42 | /** 43 | * @notice Creates a new capacitor and decapacitor pair based on the given type. 44 | * @dev It sets the CapacitorFactory owner as owner of new Capacitor and Decapacitor 45 | * @param capacitorType_ The type of capacitor to be created. Can be SINGLE_CAPACITOR or HASH_CHAIN_CAPACITOR. 46 | * @dev siblingChainSlug_ sibling chain slug can be used for chain specific capacitors, useful while expanding to non-EVM chains. 47 | * @param maxPacketLength_ is not being used with single capacitor system, will be useful with batching. 48 | */ 49 | function deploy( 50 | uint256 capacitorType_, 51 | uint32 /** siblingChainSlug_ */, 52 | uint256 maxPacketLength_ 53 | ) external override returns (ICapacitor, IDecapacitor) { 54 | if ( 55 | maxPacketLength_ < minAllowedPacketLength || 56 | maxPacketLength_ > maxAllowedPacketLength 57 | ) revert PacketLengthNotAllowed(); 58 | 59 | // fetch the capacitor factory owner 60 | address owner = this.owner(); 61 | 62 | if (capacitorType_ == SINGLE_CAPACITOR) { 63 | return ( 64 | // msg.sender is socket address 65 | new SingleCapacitor(msg.sender, owner), 66 | new SingleDecapacitor(owner) 67 | ); 68 | } 69 | revert InvalidCapacitorType(); 70 | } 71 | 72 | /** 73 | * @notice Rescues funds from the contract if they are locked by mistake. 74 | * @param token_ The address of the token contract. 75 | * @param rescueTo_ The address where rescued tokens need to be sent. 76 | * @param amount_ The amount of tokens to be rescued. 77 | */ 78 | function rescueFunds( 79 | address token_, 80 | address rescueTo_, 81 | uint256 amount_ 82 | ) external onlyRole(RESCUE_ROLE) { 83 | RescueFundsLib.rescueFunds(token_, rescueTo_, amount_); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /contracts/OpenExecutionManager.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | pragma solidity 0.8.19; 3 | import "./ExecutionManagerDF.sol"; 4 | 5 | /** 6 | * @title OpenExecutionManager 7 | * @dev ExecutionManager contract with open execution 8 | */ 9 | contract OpenExecutionManager is ExecutionManagerDF { 10 | /** 11 | * @dev Constructor for OpenExecutionManager contract 12 | * @param owner_ Address of the contract owner 13 | * @param chainSlug_ chain slug used to identify current chain 14 | * @param signatureVerifier_ Address of the signature verifier contract 15 | * @param socket_ Address of the socket contract 16 | */ 17 | constructor( 18 | address owner_, 19 | uint32 chainSlug_, 20 | ISocket socket_, 21 | ISignatureVerifier signatureVerifier_ 22 | ) ExecutionManagerDF(owner_, chainSlug_, socket_, signatureVerifier_) {} 23 | 24 | /** 25 | * @notice This function allows all executors. 26 | * @notice As executor recovered here is used for fee accounting, it is critical to provide a valid 27 | * signature else it can deprive the executor of their payout 28 | * @param packedMessage Packed message to be executed 29 | * @param sig Signature of the message 30 | * @return executor Address of the executor 31 | * @return isValidExecutor Boolean value indicating whether the executor is valid or not 32 | */ 33 | function isExecutor( 34 | bytes32 packedMessage, 35 | bytes memory sig 36 | ) external view override returns (address executor, bool isValidExecutor) { 37 | executor = signatureVerifier__.recoverSigner(packedMessage, sig); 38 | isValidExecutor = true; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /contracts/capacitors/BaseCapacitor.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | pragma solidity 0.8.19; 3 | 4 | import "../interfaces/ICapacitor.sol"; 5 | import "../utils/AccessControl.sol"; 6 | import "../libraries/RescueFundsLib.sol"; 7 | import {RESCUE_ROLE} from "../utils/AccessRoles.sol"; 8 | 9 | /** 10 | * @title BaseCapacitor 11 | * @dev Abstract base contract for the Capacitors. Implements shared functionality and provides 12 | * access control. 13 | */ 14 | abstract contract BaseCapacitor is ICapacitor, AccessControl { 15 | /// address of socket 16 | address public immutable socket; 17 | 18 | /// an incrementing count for the next packet that is being created 19 | uint64 internal _nextPacketCount; 20 | 21 | /// tracks the count of next packet that will be sealed 22 | uint64 internal _nextSealCount; 23 | 24 | /// maps the packet count with the root hash of that packet 25 | mapping(uint64 => bytes32) internal _roots; 26 | 27 | // Error triggered when not called by socket 28 | error OnlySocket(); 29 | 30 | /** 31 | * @dev Throws if called by any account other than the socket. 32 | */ 33 | modifier onlySocket() { 34 | if (msg.sender != socket) revert OnlySocket(); 35 | _; 36 | } 37 | 38 | /** 39 | * @dev Initializes the contract with the specified socket address. 40 | * @param socket_ The address of the socket contract. 41 | * @param owner_ The address of the owner of the capacitor contract. 42 | */ 43 | constructor(address socket_, address owner_) AccessControl(owner_) { 44 | socket = socket_; 45 | _grantRole(RESCUE_ROLE, owner_); 46 | } 47 | 48 | /** 49 | * @dev Returns the count of the latest packet that finished filling. 50 | * @dev Returns 0 in case 0 or 1 packets are filled, hence this case should be considered by the caller 51 | * @return lastFilledPacket count of the latest packet. 52 | */ 53 | function getLastFilledPacket() 54 | external 55 | view 56 | returns (uint256 lastFilledPacket) 57 | { 58 | return _nextPacketCount == 0 ? 0 : _nextPacketCount - 1; 59 | } 60 | 61 | /** 62 | * @dev Rescues funds from the contract. 63 | * @param token_ The address of the token to rescue. 64 | * @param rescueTo_ The address of the user to rescue tokens for. 65 | * @param amount_ The amount of tokens to rescue. 66 | */ 67 | function rescueFunds( 68 | address token_, 69 | address rescueTo_, 70 | uint256 amount_ 71 | ) external onlyRole(RESCUE_ROLE) { 72 | RescueFundsLib.rescueFunds(token_, rescueTo_, amount_); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /contracts/capacitors/SingleCapacitor.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | pragma solidity 0.8.19; 3 | 4 | import "./BaseCapacitor.sol"; 5 | 6 | /** 7 | * @title SingleCapacitor 8 | * @notice A capacitor that adds a single message to each packet. 9 | * @dev This contract inherits from the `BaseCapacitor` contract, which provides the 10 | * basic storage and common function implementations. 11 | */ 12 | contract SingleCapacitor is BaseCapacitor { 13 | // Error triggered when no new packet/message is there to be sealed 14 | error NoPendingPacket(); 15 | 16 | /** 17 | * @notice emitted when a new message is added to a packet 18 | * @param packedMessage the message packed with payload, fees and config 19 | * @param packetCount an incremental id assigned to each new packet created on this capacitor 20 | * @param newRootHash Hash of full packet. Same as packedMessage since this capacitor has one message per packet. 21 | */ 22 | event MessageAdded( 23 | bytes32 packedMessage, 24 | uint64 packetCount, 25 | bytes32 newRootHash 26 | ); 27 | 28 | /** 29 | * @dev Initializes the contract with the specified socket address. 30 | * @param socket_ The address of the socket contract. 31 | * @param owner_ The address of the owner of the capacitor contract. 32 | */ 33 | constructor( 34 | address socket_, 35 | address owner_ 36 | ) BaseCapacitor(socket_, owner_) {} 37 | 38 | /** 39 | * @inheritdoc ICapacitor 40 | */ 41 | function getMaxPacketLength() external pure override returns (uint256) { 42 | return 1; 43 | } 44 | 45 | /** 46 | * @inheritdoc ICapacitor 47 | */ 48 | function addPackedMessage( 49 | bytes32 packedMessage_ 50 | ) external override onlySocket { 51 | uint64 packetCount = _nextPacketCount++; 52 | _roots[packetCount] = packedMessage_; 53 | 54 | // as it is a single capacitor, here root and packed message are same 55 | emit MessageAdded(packedMessage_, packetCount, packedMessage_); 56 | } 57 | 58 | /** 59 | * @inheritdoc ICapacitor 60 | */ 61 | function sealPacket( 62 | uint256 63 | ) external override onlySocket returns (bytes32, uint64) { 64 | uint64 packetCount = _nextSealCount++; 65 | if (_roots[packetCount] == bytes32(0)) revert NoPendingPacket(); 66 | 67 | bytes32 root = _roots[packetCount]; 68 | return (root, packetCount); 69 | } 70 | 71 | /** 72 | * @inheritdoc ICapacitor 73 | */ 74 | function getNextPacketToBeSealed() 75 | external 76 | view 77 | override 78 | returns (bytes32, uint64) 79 | { 80 | uint64 toSeal = _nextSealCount; 81 | return (_roots[toSeal], toSeal); 82 | } 83 | 84 | /** 85 | * @dev Returns the root hash of the packet with the specified count. 86 | * @param count_ The count of the packet. 87 | * @return The root hash of the packet. 88 | */ 89 | function getRootByCount( 90 | uint64 count_ 91 | ) external view override returns (bytes32) { 92 | return _roots[count_]; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /contracts/decapacitors/HashChainDecapacitor.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | pragma solidity 0.8.19; 3 | 4 | import "../interfaces/IDecapacitor.sol"; 5 | import "../libraries/RescueFundsLib.sol"; 6 | import "../utils/AccessControl.sol"; 7 | import {RESCUE_ROLE} from "../utils/AccessRoles.sol"; 8 | 9 | /** 10 | * @title HashChainDecapacitor 11 | * @notice This is an experimental contract and have known bugs 12 | * @notice A contract that verifies whether a message is part of a hash chain or not. 13 | * @dev This contract implements the `IDecapacitor` interface. 14 | */ 15 | contract HashChainDecapacitor is IDecapacitor, AccessControl { 16 | /** 17 | * @notice Initializes the HashChainDecapacitor contract with the owner's address. 18 | * @param owner_ The address of the contract owner. 19 | */ 20 | constructor(address owner_) AccessControl(owner_) { 21 | _grantRole(RESCUE_ROLE, owner_); 22 | } 23 | 24 | /** 25 | * @notice Verifies whether a message is included in the given hash chain. 26 | * @param root_ The root of the hash chain. 27 | * @param packedMessage_ The packed message whose inclusion in the hash chain needs to be verified. 28 | * @param proof_ The proof for the inclusion of the packed message in the hash chain. 29 | * @return True if the packed message is included in the hash chain and the provided root is the calculated root; otherwise, false. 30 | */ 31 | function verifyMessageInclusion( 32 | bytes32 root_, 33 | bytes32 packedMessage_, 34 | bytes calldata proof_ 35 | ) external pure override returns (bool) { 36 | bytes32[] memory chain = abi.decode(proof_, (bytes32[])); 37 | uint256 len = chain.length; 38 | bytes32 generatedRoot; 39 | bool isIncluded; 40 | for (uint256 i = 0; i < len; ) { 41 | generatedRoot = keccak256(abi.encode(generatedRoot, chain[i])); 42 | if (chain[i] == packedMessage_) isIncluded = true; 43 | unchecked { 44 | ++i; 45 | } 46 | } 47 | 48 | return root_ == generatedRoot && isIncluded; 49 | } 50 | 51 | /** 52 | * @notice Rescues funds from the contract if they are locked by mistake. 53 | * @param token_ The address of the token contract. 54 | * @param rescueTo_ The address where rescued tokens need to be sent. 55 | * @param amount_ The amount of tokens to be rescued. 56 | */ 57 | function rescueFunds( 58 | address token_, 59 | address rescueTo_, 60 | uint256 amount_ 61 | ) external onlyRole(RESCUE_ROLE) { 62 | RescueFundsLib.rescueFunds(token_, rescueTo_, amount_); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /contracts/decapacitors/SingleDecapacitor.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | pragma solidity 0.8.19; 3 | 4 | import "../interfaces/IDecapacitor.sol"; 5 | import "../libraries/RescueFundsLib.sol"; 6 | import "../utils/AccessControl.sol"; 7 | import {RESCUE_ROLE} from "../utils/AccessRoles.sol"; 8 | 9 | /** 10 | * @title SingleDecapacitor 11 | * @notice A decapacitor that verifies messages by checking if the packed message is equal to the root. 12 | * @dev This contract inherits from the `IDecapacitor` interface, which 13 | * defines the functions for verifying message inclusion. 14 | */ 15 | contract SingleDecapacitor is IDecapacitor, AccessControl { 16 | /** 17 | * @notice Initializes the SingleDecapacitor contract with an owner address. 18 | * @param owner_ The address of the contract owner 19 | */ 20 | constructor(address owner_) AccessControl(owner_) { 21 | _grantRole(RESCUE_ROLE, owner_); 22 | } 23 | 24 | /** 25 | * @inheritdoc IDecapacitor 26 | * @dev Just checks if root equals packed message since each packet has single message. 27 | * @dev Proof is ignored in this capacitor. 28 | */ 29 | function verifyMessageInclusion( 30 | bytes32 root_, 31 | bytes32 packedMessage_, 32 | bytes calldata /* proof */ 33 | ) external pure override returns (bool isIncluded) { 34 | return root_ == packedMessage_; 35 | } 36 | 37 | /** 38 | * @notice Rescues funds from the contract if they are locked by mistake. 39 | * @param token_ The address of the token contract. 40 | * @param rescueTo_ The address where rescued tokens need to be sent. 41 | * @param amount_ The amount of tokens to be rescued. 42 | */ 43 | function rescueFunds( 44 | address token_, 45 | address rescueTo_, 46 | uint256 amount_ 47 | ) external onlyRole(RESCUE_ROLE) { 48 | RescueFundsLib.rescueFunds(token_, rescueTo_, amount_); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /contracts/interfaces/ICapacitor.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | pragma solidity 0.8.19; 3 | 4 | /** 5 | * @title ICapacitor 6 | * @dev Interface for a Capacitor contract that stores and manages messages in packets 7 | */ 8 | interface ICapacitor { 9 | /** 10 | * @notice adds the packed message to a packet 11 | * @dev this should be only executable by socket 12 | * @param packedMessage the message packed with payload, fees and config 13 | */ 14 | function addPackedMessage(bytes32 packedMessage) external; 15 | 16 | /** 17 | * @notice returns the latest packet details which needs to be sealed 18 | * @return root root hash of the latest packet which is not yet sealed 19 | * @return packetCount latest packet id which is not yet sealed 20 | */ 21 | function getNextPacketToBeSealed() 22 | external 23 | view 24 | returns (bytes32 root, uint64 packetCount); 25 | 26 | /** 27 | * @notice returns the root of packet for given id 28 | * @param id the id assigned to packet 29 | * @return root root hash corresponding to given id 30 | */ 31 | function getRootByCount(uint64 id) external view returns (bytes32 root); 32 | 33 | /** 34 | * @notice returns the maxPacketLength 35 | * @return maxPacketLength of the capacitor 36 | */ 37 | function getMaxPacketLength() 38 | external 39 | view 40 | returns (uint256 maxPacketLength); 41 | 42 | /** 43 | * @notice seals the packet 44 | * @dev indicates the packet is ready to be shipped and no more messages can be added now. 45 | * @dev this should be called by socket only 46 | * @param batchSize_ used with packet batching capacitors 47 | * @return root root hash of the packet 48 | * @return packetCount id of the packed sealed 49 | */ 50 | function sealPacket( 51 | uint256 batchSize_ 52 | ) external returns (bytes32 root, uint64 packetCount); 53 | } 54 | -------------------------------------------------------------------------------- /contracts/interfaces/ICapacitorFactory.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | pragma solidity 0.8.19; 3 | 4 | import "./ICapacitor.sol"; 5 | import "./IDecapacitor.sol"; 6 | 7 | /** 8 | * @title ICapacitorFactory 9 | * @notice Interface for a factory contract that deploys new instances of `ICapacitor` and `IDecapacitor` contracts. 10 | */ 11 | interface ICapacitorFactory { 12 | /** 13 | * @dev Emitted when an invalid capacitor type is requested during deployment. 14 | */ 15 | error InvalidCapacitorType(); 16 | 17 | /** 18 | * @notice Deploys a new instance of an `ICapacitor` and `IDecapacitor` contract with the specified parameters. 19 | * @param capacitorType The type of the capacitor to be deployed. 20 | * @param siblingChainSlug The identifier of the sibling chain. 21 | * @param maxPacketLength The maximum length of a packet. 22 | * @return Returns the deployed `ICapacitor` and `IDecapacitor` contract instances. 23 | */ 24 | function deploy( 25 | uint256 capacitorType, 26 | uint32 siblingChainSlug, 27 | uint256 maxPacketLength 28 | ) external returns (ICapacitor, IDecapacitor); 29 | } 30 | -------------------------------------------------------------------------------- /contracts/interfaces/IDecapacitor.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | pragma solidity 0.8.19; 3 | 4 | /** 5 | * @title IDecapacitor interface 6 | * @notice Interface for a contract that verifies if a packed message is part of a packet or not 7 | */ 8 | interface IDecapacitor { 9 | /** 10 | * @notice Returns true if packed message is part of root. 11 | * @param root_ root hash of the packet. 12 | * @param packedMessage_ packed message which needs to be verified. 13 | * @param proof_ proof used to determine the inclusion 14 | * @dev This function is kept as view instead of pure, as in future we may have stateful decapacitors 15 | * @return isIncluded boolean indicating whether the message is included in the packet or not. 16 | */ 17 | function verifyMessageInclusion( 18 | bytes32 root_, 19 | bytes32 packedMessage_, 20 | bytes calldata proof_ 21 | ) external returns (bool isIncluded); 22 | } 23 | -------------------------------------------------------------------------------- /contracts/interfaces/IHasher.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | pragma solidity 0.8.19; 3 | 4 | import "./ISocket.sol"; 5 | 6 | /** 7 | * @title IHasher 8 | * @notice Interface for hasher contract that calculates the packed message 9 | */ 10 | interface IHasher { 11 | /** 12 | * @notice returns the bytes32 hash of the message packed 13 | * @param srcChainSlug src chain slug 14 | * @param srcPlug address of plug at source 15 | * @param dstChainSlug remote chain slug 16 | * @param dstPlug address of plug at remote 17 | * @param messageDetails contains message details, see ISocket for more details 18 | */ 19 | function packMessage( 20 | uint32 srcChainSlug, 21 | address srcPlug, 22 | uint32 dstChainSlug, 23 | address dstPlug, 24 | ISocket.MessageDetails memory messageDetails 25 | ) external returns (bytes32); 26 | } 27 | -------------------------------------------------------------------------------- /contracts/interfaces/INativeRelay.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | pragma solidity 0.8.19; 3 | 4 | /** 5 | * @title INativeRelay 6 | * @notice Interface for the NativeRelay contract which is used to relay packets between two chains. 7 | * It allows for the reception of messages on the PolygonRootReceiver and the initiation of native confirmations 8 | * for the given packet ID. 9 | * @dev this is only used by SocketBatcher currently 10 | */ 11 | interface INativeRelay { 12 | /** 13 | * @notice receiveMessage on PolygonRootReceiver 14 | * @param receivePacketProof receivePacketProof The proof of the packet being received on the Polygon network. 15 | */ 16 | function receiveMessage(bytes memory receivePacketProof) external; 17 | 18 | /** 19 | * @notice Function to initiate a native confirmation for the given packet ID. 20 | * @dev The function can be called with maxSubmissionCost, maxGas, and gasPriceBid to customize the confirmation transaction, 21 | * or with no parameters to use default values. 22 | * @param packetId The ID of the packet to initiate confirmation for. 23 | * @param maxSubmissionCost The maximum submission cost of the transaction. 24 | * @param maxGas The maximum gas limit of the transaction. 25 | * @param gasPriceBid The gas price bid for the transaction. 26 | * @param callValueRefundAddress l2 call value gets credited here on L2 if retryable txn times out or gets cancelled 27 | * @param remoteRefundAddress gasLimit x maxFeePerGas - execution cost gets credited here on L2 balance 28 | */ 29 | function initiateNativeConfirmation( 30 | bytes32 packetId, 31 | uint256 maxSubmissionCost, 32 | uint256 maxGas, 33 | uint256 gasPriceBid, 34 | address callValueRefundAddress, 35 | address remoteRefundAddress 36 | ) external payable; 37 | 38 | /** 39 | * @notice Function to initiate a native confirmation for the given packet ID, using default values for transaction parameters. 40 | * @param packetId The ID of the packet to initiate confirmation for. 41 | */ 42 | function initiateNativeConfirmation(bytes32 packetId) external; 43 | } 44 | -------------------------------------------------------------------------------- /contracts/interfaces/IPlug.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | pragma solidity 0.8.19; 3 | 4 | /** 5 | * @title IPlug 6 | * @notice Interface for a plug contract that executes the message received from a source chain. 7 | */ 8 | interface IPlug { 9 | /** 10 | * @dev this should be only executable by socket 11 | * @notice executes the message received from source chain 12 | * @notice It is expected to have original sender checks in the destination plugs using payload 13 | * @param srcChainSlug_ chain slug of source 14 | * @param payload_ the data which is needed by plug at inbound call on remote 15 | */ 16 | function inbound( 17 | uint32 srcChainSlug_, 18 | bytes calldata payload_ 19 | ) external payable; 20 | } 21 | -------------------------------------------------------------------------------- /contracts/interfaces/ISignatureVerifier.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | pragma solidity 0.8.19; 3 | 4 | /** 5 | * @title Signature Verifier 6 | * @notice Verifies the signatures and returns the address of signer recovered from the input signature or digest. 7 | */ 8 | interface ISignatureVerifier { 9 | /** 10 | * @notice returns the address of signer recovered from input signature and digest 11 | */ 12 | function recoverSigner( 13 | bytes32 digest_, 14 | bytes memory signature_ 15 | ) external pure returns (address signer); 16 | } 17 | -------------------------------------------------------------------------------- /contracts/interfaces/ITransmitManager.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | pragma solidity 0.8.19; 3 | 4 | /** 5 | * @title ITransmitManager 6 | * @dev The interface for a transmit manager contract 7 | */ 8 | interface ITransmitManager { 9 | /** 10 | * @notice Checks if a given transmitter is authorized to send transactions to the destination chain. 11 | * @param siblingSlug The unique identifier for the sibling chain. 12 | * @param digest The digest of the message being signed. 13 | * @param signature The signature of the message being signed. 14 | * @return The address of the transmitter and a boolean indicating whether the transmitter is authorized or not. 15 | */ 16 | function checkTransmitter( 17 | uint32 siblingSlug, 18 | bytes32 digest, 19 | bytes calldata signature 20 | ) external view returns (address, bool); 21 | 22 | /** 23 | * @notice sets the transmission fee needed to transmit message to given `siblingSlug_` 24 | * @dev recovered address should add have feeUpdater role for `siblingSlug_` 25 | * @param nonce_ The incremental nonce to prevent signature replay 26 | * @param siblingSlug_ sibling id for which fee updater is registered 27 | * @param transmissionFees_ digest which is signed by transmitter 28 | * @param signature_ signature 29 | */ 30 | function setTransmissionFees( 31 | uint256 nonce_, 32 | uint32 siblingSlug_, 33 | uint128 transmissionFees_, 34 | bytes calldata signature_ 35 | ) external; 36 | 37 | /** 38 | * @notice receives fees from Execution manager 39 | * @dev this function can be used to keep track of fees received for each slug 40 | * @param siblingSlug_ sibling id for which fee updater is registered 41 | */ 42 | function receiveFees(uint32 siblingSlug_) external payable; 43 | } 44 | -------------------------------------------------------------------------------- /contracts/libraries/AddressAliasHelper.sol: -------------------------------------------------------------------------------- 1 | // Copyright 2021-2022, Offchain Labs, Inc. 2 | // For license information, see https://github.com/nitro/blob/master/LICENSE 3 | // SPDX-License-Identifier: BUSL-1.1 4 | 5 | pragma solidity 0.8.19; 6 | 7 | library AddressAliasHelper { 8 | uint160 internal constant _OFFSET = 9 | uint160(0x1111000000000000000000000000000000001111); 10 | 11 | /// @notice Utility function that converts the address in the L1 that submitted a tx to 12 | /// the inbox to the msg.sender viewed in the L2 13 | /// @param l1Address_ the address in the L1 that triggered the tx to L2 14 | /// @return l2Address L2 address as viewed in msg.sender 15 | function applyL1ToL2Alias( 16 | address l1Address_ 17 | ) internal pure returns (address l2Address) { 18 | unchecked { 19 | l2Address = address(uint160(l1Address_) + _OFFSET); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /contracts/libraries/RescueFundsLib.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | pragma solidity 0.8.19; 3 | 4 | import "solmate/utils/SafeTransferLib.sol"; 5 | 6 | error ZeroAddress(); 7 | 8 | /** 9 | * @title RescueFundsLib 10 | * @dev A library that provides a function to rescue funds from a contract. 11 | */ 12 | 13 | library RescueFundsLib { 14 | /** 15 | * @dev The address used to identify ETH. 16 | */ 17 | address public constant ETH_ADDRESS = 18 | address(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE); 19 | 20 | /** 21 | * @dev thrown when the given token address don't have any code 22 | */ 23 | error InvalidTokenAddress(); 24 | 25 | /** 26 | * @dev Rescues funds from a contract. 27 | * @param token_ The address of the token contract. 28 | * @param rescueTo_ The address of the user. 29 | * @param amount_ The amount of tokens to be rescued. 30 | */ 31 | function rescueFunds( 32 | address token_, 33 | address rescueTo_, 34 | uint256 amount_ 35 | ) internal { 36 | if (rescueTo_ == address(0)) revert ZeroAddress(); 37 | 38 | if (token_ == ETH_ADDRESS) { 39 | SafeTransferLib.safeTransferETH(rescueTo_, amount_); 40 | } else { 41 | if (token_.code.length == 0) revert InvalidTokenAddress(); 42 | SafeTransferLib.safeTransfer(ERC20(token_), rescueTo_, amount_); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /contracts/mocks/MockAccessControl.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | pragma solidity 0.8.19; 3 | 4 | import "../utils/AccessControl.sol"; 5 | 6 | contract MockAccessControl is AccessControl { 7 | bytes32 public constant ROLE_GIRAFFE = keccak256("ROLE_GIRAFFE"); 8 | bytes32 public constant ROLE_HIPPO = keccak256("ROLE_HIPPO"); 9 | 10 | constructor(address owner_) AccessControl(owner_) {} 11 | 12 | function giraffe() external onlyRole(ROLE_GIRAFFE) {} 13 | 14 | function hippo() external onlyRole(ROLE_HIPPO) {} 15 | 16 | function animal() external {} 17 | } 18 | -------------------------------------------------------------------------------- /contracts/mocks/MockOwnable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | pragma solidity 0.8.19; 3 | 4 | import "../utils/Ownable.sol"; 5 | 6 | contract MockOwnable is Ownable { 7 | constructor(address owner_) Ownable(owner_) {} 8 | 9 | function ownerFunction() external onlyOwner {} 10 | 11 | function publicFunction() external {} 12 | } 13 | -------------------------------------------------------------------------------- /contracts/mocks/MockPolygonL1Switchboard.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | pragma solidity 0.8.19; 3 | 4 | import "../switchboard/native/PolygonL1Switchboard.sol"; 5 | 6 | contract MockPolygonL1Switchboard is PolygonL1Switchboard { 7 | constructor( 8 | uint32 chainSlug_, 9 | address checkpointManager_, 10 | address fxRoot_, 11 | address owner_, 12 | address socket_, 13 | ISignatureVerifier signatureVerifier_ 14 | ) 15 | PolygonL1Switchboard( 16 | chainSlug_, 17 | checkpointManager_, 18 | fxRoot_, 19 | owner_, 20 | socket_, 21 | signatureVerifier_ 22 | ) 23 | {} 24 | 25 | function receivePacket(bytes memory data_) external { 26 | _processMessageFromChild(data_); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /contracts/mocks/MockPolygonL2Switchboard.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | pragma solidity 0.8.19; 3 | 4 | import "../switchboard/native/PolygonL2Switchboard.sol"; 5 | 6 | contract MockPolygonL2Switchboard is PolygonL2Switchboard { 7 | constructor( 8 | uint32 chainSlug_, 9 | address fxChild_, 10 | address owner_, 11 | address socket_, 12 | ISignatureVerifier signatureVerifier_ 13 | ) 14 | PolygonL2Switchboard( 15 | chainSlug_, 16 | fxChild_, 17 | owner_, 18 | socket_, 19 | signatureVerifier_ 20 | ) 21 | {} 22 | 23 | function receivePacket( 24 | uint256 id, 25 | address rootMessageSender_, 26 | bytes memory data_ 27 | ) external { 28 | _processMessageFromRoot(id, rootMessageSender_, data_); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /contracts/mocks/MockSafe.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | pragma solidity 0.8.19; 3 | 4 | import "safe-smart-account/common/Enum.sol"; 5 | 6 | contract MockSafe { 7 | uint256 public threshold = 1; 8 | uint256 public nonce = 0; 9 | address public lastTo; 10 | uint256 public lastValue; 11 | bytes public lastData; 12 | 13 | function setThreshold(uint256 _threshold) external { 14 | threshold = _threshold; 15 | } 16 | 17 | function execTransaction( 18 | address to, 19 | uint256 value, 20 | bytes calldata data, 21 | Enum.Operation, 22 | uint256, 23 | uint256, 24 | uint256, 25 | address, 26 | address payable, 27 | bytes memory 28 | ) external payable returns (bool success) { 29 | lastTo = to; 30 | lastValue = value; 31 | lastData = data; 32 | return true; 33 | } 34 | 35 | function getThreshold() external view returns (uint256) { 36 | return threshold; 37 | } 38 | 39 | function getTransactionHash( 40 | address to, 41 | uint256 value, 42 | bytes calldata data, 43 | Enum.Operation operation, 44 | uint256, 45 | uint256, 46 | uint256, 47 | address, 48 | address, 49 | uint256 _nonce 50 | ) external pure returns (bytes32) { 51 | return keccak256(abi.encode(to, value, data, operation, _nonce)); 52 | } 53 | 54 | function getLastTransaction() 55 | external 56 | view 57 | returns (address, uint256, bytes memory) 58 | { 59 | return (lastTo, lastValue, lastData); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /contracts/mocks/fee-updater/SimulatorUtils.sol: -------------------------------------------------------------------------------- 1 | pragma solidity 0.8.19; 2 | 3 | import "../../interfaces/IDecapacitor.sol"; 4 | import "../../interfaces/ISocket.sol"; 5 | import "../../interfaces/ISignatureVerifier.sol"; 6 | import {TRANSMITTER_ROLE, EXECUTOR_ROLE} from "../../utils/AccessRoles.sol"; 7 | import "../../utils/AccessControlExtended.sol"; 8 | 9 | contract SimulatorUtils is AccessControlExtended { 10 | ISocket public socket__; 11 | ISignatureVerifier public signatureVerifier__; 12 | 13 | error InsufficientMsgValue(); 14 | 15 | constructor( 16 | address socket_, 17 | address signatureVerifier_, 18 | address signer_, 19 | uint32 siblingSlug_ 20 | ) AccessControlExtended(msg.sender) { 21 | socket__ = ISocket(socket_); 22 | signatureVerifier__ = ISignatureVerifier(signatureVerifier_); 23 | _grantRoleWithSlug(TRANSMITTER_ROLE, siblingSlug_, signer_); 24 | _grantRole(EXECUTOR_ROLE, signer_); 25 | } 26 | 27 | // TM 28 | function checkTransmitter( 29 | uint32 siblingSlug_, 30 | bytes32 digest_, 31 | bytes calldata signature_ 32 | ) external view returns (address, bool) { 33 | address transmitter = signatureVerifier__.recoverSigner( 34 | digest_, 35 | signature_ 36 | ); 37 | _hasRoleWithSlug(TRANSMITTER_ROLE, siblingSlug_, transmitter); 38 | 39 | return (transmitter, true); 40 | } 41 | 42 | // EM 43 | function updateExecutionFees(address, uint128, bytes32) external view { 44 | if (msg.sender != address(socket__)) return; 45 | } 46 | 47 | function verifyParams( 48 | bytes32 executionParams_, 49 | uint256 msgValue_ 50 | ) external pure { 51 | uint256 params = uint256(executionParams_); 52 | uint8 paramType = uint8(params >> 248); 53 | 54 | if (paramType == 0) return; 55 | uint256 expectedMsgValue = uint256(uint248(params)); 56 | if (msgValue_ < expectedMsgValue) revert InsufficientMsgValue(); 57 | } 58 | 59 | function isExecutor( 60 | bytes32 packedMessage, 61 | bytes memory sig 62 | ) external view returns (address executor, bool isValidExecutor) { 63 | executor = signatureVerifier__.recoverSigner(packedMessage, sig); 64 | _hasRole(EXECUTOR_ROLE, executor); 65 | isValidExecutor = true; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /contracts/socket/Socket.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | pragma solidity 0.8.19; 3 | 4 | import "./SocketDst.sol"; 5 | import {SocketSrc} from "./SocketSrc.sol"; 6 | 7 | /** 8 | * @title Socket 9 | * @notice Core-contract containing all the core-socket utilities. 10 | * @dev This contract inherits from SocketSrc and SocketDst 11 | */ 12 | contract Socket is SocketSrc, SocketDst { 13 | /* 14 | * @notice constructor for creating a new Socket contract instance. 15 | * @param chainSlug_ The unique identifier of the chain this socket is deployed on. 16 | * @param hasher_ The address of the Hasher contract used to pack the message before transmitting them. 17 | * @param capacitorFactory_ The address of the CapacitorFactory contract used to create new Capacitor and DeCapacitor contracts. 18 | * @param owner_ The address of the owner who has the initial admin role. 19 | * @param version_ The version string which is hashed and stored in socket. 20 | */ 21 | constructor( 22 | uint32 chainSlug_, 23 | address hasher_, 24 | address capacitorFactory_, 25 | address owner_, 26 | string memory version_ 27 | ) AccessControlExtended(owner_) SocketBase(chainSlug_, version_) { 28 | hasher__ = IHasher(hasher_); 29 | capacitorFactory__ = ICapacitorFactory(capacitorFactory_); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /contracts/switchboard/default-switchboards/OptimisticSwitchboard.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | pragma solidity 0.8.19; 3 | 4 | import "./SwitchboardBase.sol"; 5 | 6 | /** 7 | * @title OptimisticSwitchboard 8 | * @notice A contract that extends the SwitchboardBase contract and implements the 9 | * allowPacket and fee getter functions. 10 | */ 11 | contract OptimisticSwitchboard is SwitchboardBase { 12 | /** 13 | * @notice Creates an OptimisticSwitchboard instance with the specified parameters. 14 | * @param owner_ The address of the contract owner. 15 | * @param socket_ The address of the socket contract. 16 | * @param chainSlug_ The chain slug. 17 | * @param timeoutInSeconds_ The timeout period in seconds after which proposals become valid if not tripped. 18 | * @param signatureVerifier_ The address of the signature verifier contract 19 | */ 20 | constructor( 21 | address owner_, 22 | address socket_, 23 | uint32 chainSlug_, 24 | uint256 timeoutInSeconds_, 25 | ISignatureVerifier signatureVerifier_ 26 | ) 27 | AccessControlExtended(owner_) 28 | SwitchboardBase( 29 | socket_, 30 | chainSlug_, 31 | timeoutInSeconds_, 32 | signatureVerifier_ 33 | ) 34 | {} 35 | 36 | /** 37 | * @inheritdoc ISwitchboard 38 | */ 39 | function allowPacket( 40 | bytes32, 41 | bytes32 packetId_, 42 | uint256 proposalCount_, 43 | uint32 srcChainSlug_, 44 | uint256 proposeTime_ 45 | ) external view override returns (bool) { 46 | uint64 packetCount = uint64(uint256(packetId_)); 47 | 48 | // any relevant trips triggered or invalid packet count. 49 | if ( 50 | isGlobalTipped || 51 | isPathTripped[srcChainSlug_] || 52 | isProposalTripped[packetId_][proposalCount_] || 53 | packetCount < initialPacketCount[srcChainSlug_] 54 | ) return false; 55 | 56 | // time to detect and call trip is not over. 57 | if (block.timestamp - proposeTime_ < timeoutInSeconds) return false; 58 | 59 | // enough time has passed without trip 60 | return true; 61 | } 62 | 63 | /** 64 | * @inheritdoc ISwitchboard 65 | */ 66 | function setFees( 67 | uint256 nonce_, 68 | uint32 dstChainSlug_, 69 | uint128 switchboardFees_, 70 | uint128 verificationOverheadFees_, 71 | bytes calldata signature_ 72 | ) external override { 73 | address feesUpdater = signatureVerifier__.recoverSigner( 74 | keccak256( 75 | abi.encode( 76 | FEES_UPDATE_SIG_IDENTIFIER, 77 | address(this), 78 | chainSlug, 79 | dstChainSlug_, 80 | nonce_, 81 | switchboardFees_, 82 | verificationOverheadFees_ 83 | ) 84 | ), 85 | signature_ 86 | ); 87 | 88 | _checkRoleWithSlug(FEES_UPDATER_ROLE, dstChainSlug_, feesUpdater); 89 | // Nonce is used by gated roles and we don't expect nonce to reach the max value of uint256 90 | unchecked { 91 | if (nonce_ != nextNonce[feesUpdater]++) revert InvalidNonce(); 92 | } 93 | 94 | Fees storage fee = fees[dstChainSlug_]; 95 | fee.verificationOverheadFees = verificationOverheadFees_; 96 | fee.switchboardFees = switchboardFees_; 97 | 98 | emit SwitchboardFeesSet(dstChainSlug_, fee); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /contracts/switchboard/native/ArbitrumL2Switchboard.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | pragma solidity 0.8.19; 3 | 4 | import "openzeppelin-contracts/contracts/vendor/arbitrum/IArbSys.sol"; 5 | 6 | import "../../libraries/AddressAliasHelper.sol"; 7 | import "./NativeSwitchboardBase.sol"; 8 | 9 | /** 10 | 11 | @title ArbitrumL2Switchboard 12 | @dev A contract that facilitates communication between the Ethereum mainnet and 13 | the Arbitrum Layer 2 network by handling incoming and outgoing messages through the Arbitrum Sys contract. 14 | Inherits from NativeSwitchboardBase contract that handles communication with 15 | other Layer 1 networks. 16 | */ 17 | contract ArbitrumL2Switchboard is NativeSwitchboardBase { 18 | IArbSys public immutable arbsys__ = IArbSys(address(100)); 19 | 20 | /** 21 | * @dev Modifier that checks if the sender of the transaction is the remote native switchboard on the L1 network. 22 | * If not, reverts with an InvalidSender error message. 23 | */ 24 | modifier onlyRemoteSwitchboard() override { 25 | if ( 26 | msg.sender != 27 | AddressAliasHelper.applyL1ToL2Alias(remoteNativeSwitchboard) 28 | ) revert InvalidSender(); 29 | _; 30 | } 31 | 32 | /** 33 | * @dev Constructor function that sets initial values for the arbsys__, and the NativeSwitchboardBase parent contract. 34 | * @param chainSlug_ A uint32 representing the ID of the L2 network. 35 | * @param owner_ The address that will have the default admin role in the AccessControl parent contract. 36 | * @param socket_ The address of the Ethereum mainnet Native Meta-Transaction Executor contract. 37 | */ 38 | constructor( 39 | uint32 chainSlug_, 40 | address owner_, 41 | address socket_, 42 | ISignatureVerifier signatureVerifier_ 43 | ) 44 | AccessControlExtended(owner_) 45 | NativeSwitchboardBase(socket_, chainSlug_, signatureVerifier_) 46 | {} 47 | 48 | /** 49 | * @dev Sends a message to the L1 network requesting a confirmation for the packet with the specified packet ID. 50 | * @param packetId_ A bytes32 representing the ID of the packet to be confirmed. 51 | */ 52 | function initiateNativeConfirmation(bytes32 packetId_) external { 53 | bytes memory data = _encodeRemoteCall(packetId_); 54 | 55 | arbsys__.sendTxToL1(remoteNativeSwitchboard, data); 56 | emit InitiatedNativeConfirmation(packetId_); 57 | } 58 | 59 | /** 60 | @dev Internal function to encode a remote call to L1. 61 | receivePacket on the Arbitrum L2 chain. 62 | @param packetId_ The ID of the packet to receive. 63 | @return data A bytes array containing the encoded function call. 64 | */ 65 | function _encodeRemoteCall( 66 | bytes32 packetId_ 67 | ) internal view returns (bytes memory data) { 68 | data = abi.encodeWithSelector( 69 | this.receivePacket.selector, 70 | packetId_, 71 | _getRoot(packetId_) 72 | ); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /contracts/utils/AccessRoles.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | pragma solidity 0.8.19; 3 | 4 | // contains role hashes used in socket dl for various different operations 5 | 6 | // used to rescue funds 7 | bytes32 constant RESCUE_ROLE = keccak256("RESCUE_ROLE"); 8 | // used to withdraw fees 9 | bytes32 constant WITHDRAW_ROLE = keccak256("WITHDRAW_ROLE"); 10 | // used to trip switchboards 11 | bytes32 constant TRIP_ROLE = keccak256("TRIP_ROLE"); 12 | // used to un trip switchboards 13 | bytes32 constant UN_TRIP_ROLE = keccak256("UN_TRIP_ROLE"); 14 | // used by governance 15 | bytes32 constant GOVERNANCE_ROLE = keccak256("GOVERNANCE_ROLE"); 16 | //used by executors which executes message at destination 17 | bytes32 constant EXECUTOR_ROLE = keccak256("EXECUTOR_ROLE"); 18 | // used by transmitters who seal and propose packets in socket 19 | bytes32 constant TRANSMITTER_ROLE = keccak256("TRANSMITTER_ROLE"); 20 | // used by switchboard watchers who work against transmitters 21 | bytes32 constant WATCHER_ROLE = keccak256("WATCHER_ROLE"); 22 | // used by fee updaters responsible for updating fees at switchboards, transmit manager and execution manager 23 | bytes32 constant FEES_UPDATER_ROLE = keccak256("FEES_UPDATER_ROLE"); 24 | -------------------------------------------------------------------------------- /contracts/utils/Hasher.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | pragma solidity 0.8.19; 3 | 4 | import "../interfaces/IHasher.sol"; 5 | import "../interfaces/ISocket.sol"; 6 | import "../libraries/RescueFundsLib.sol"; 7 | 8 | import "../utils/AccessControl.sol"; 9 | import {RESCUE_ROLE} from "../utils/AccessRoles.sol"; 10 | 11 | /** 12 | * @title Hasher 13 | * @notice contract for hasher contract that calculates the packed message 14 | * @dev This contract is modular component in socket to support different message packing algorithms in case of blockchains 15 | * not supporting this type of packing. 16 | */ 17 | contract Hasher is IHasher, AccessControl { 18 | /** 19 | * @notice initializes and grants RESCUE_ROLE to owner. 20 | * @param owner_ The address of the owner of the contract. 21 | */ 22 | constructor(address owner_) AccessControl(owner_) { 23 | _grantRole(RESCUE_ROLE, owner_); 24 | } 25 | 26 | /// @inheritdoc IHasher 27 | function packMessage( 28 | uint32 srcChainSlug_, 29 | address srcPlug_, 30 | uint32 dstChainSlug_, 31 | address dstPlug_, 32 | ISocket.MessageDetails memory messageDetails_ 33 | ) external pure override returns (bytes32) { 34 | return 35 | keccak256( 36 | abi.encode( 37 | srcChainSlug_, 38 | srcPlug_, 39 | dstChainSlug_, 40 | dstPlug_, 41 | messageDetails_.msgId, 42 | messageDetails_.minMsgGasLimit, 43 | messageDetails_.executionParams, 44 | messageDetails_.executionFee, 45 | messageDetails_.payload 46 | ) 47 | ); 48 | } 49 | 50 | /** 51 | * @notice Rescues funds from the contract if they are locked by mistake. 52 | * @param token_ The address of the token contract. 53 | * @param rescueTo_ The address where rescued tokens need to be sent. 54 | * @param amount_ The amount of tokens to be rescued. 55 | */ 56 | function rescueFunds( 57 | address token_, 58 | address rescueTo_, 59 | uint256 amount_ 60 | ) external onlyRole(RESCUE_ROLE) { 61 | RescueFundsLib.rescueFunds(token_, rescueTo_, amount_); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /contracts/utils/Ownable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | pragma solidity 0.8.19; 3 | 4 | /** 5 | * @title Ownable 6 | * @dev The Ownable contract provides a simple way to manage ownership of a contract 7 | * and allows for ownership to be transferred to a nominated address. 8 | */ 9 | abstract contract Ownable { 10 | address private _owner; 11 | address private _nominee; 12 | 13 | event OwnerNominated(address indexed nominee); 14 | event OwnerClaimed(address indexed claimer); 15 | 16 | error OnlyOwner(); 17 | error OnlyNominee(); 18 | 19 | /** 20 | * @dev Sets the contract's owner to the address that is passed to the constructor. 21 | */ 22 | constructor(address owner_) { 23 | _claimOwner(owner_); 24 | } 25 | 26 | /** 27 | * @dev Modifier that restricts access to only the contract's owner. 28 | * Throws an error if the caller is not the owner. 29 | */ 30 | modifier onlyOwner() { 31 | if (msg.sender != _owner) revert OnlyOwner(); 32 | _; 33 | } 34 | 35 | /** 36 | * @dev Returns the current owner of the contract. 37 | */ 38 | function owner() external view returns (address) { 39 | return _owner; 40 | } 41 | 42 | /** 43 | * @dev Returns the current nominee for ownership of the contract. 44 | */ 45 | function nominee() external view returns (address) { 46 | return _nominee; 47 | } 48 | 49 | /** 50 | * @dev Allows the current owner to nominate a new owner for the contract. 51 | * Throws an error if the caller is not the owner. 52 | * Emits an `OwnerNominated` event with the address of the nominee. 53 | */ 54 | function nominateOwner(address nominee_) external { 55 | if (msg.sender != _owner) revert OnlyOwner(); 56 | _nominee = nominee_; 57 | emit OwnerNominated(_nominee); 58 | } 59 | 60 | /** 61 | * @dev Allows the nominated owner to claim ownership of the contract. 62 | * Throws an error if the caller is not the nominee. 63 | * Sets the nominated owner as the new owner of the contract. 64 | * Emits an `OwnerClaimed` event with the address of the new owner. 65 | */ 66 | function claimOwner() external { 67 | if (msg.sender != _nominee) revert OnlyNominee(); 68 | _claimOwner(msg.sender); 69 | } 70 | 71 | /** 72 | * @dev Internal function that sets the owner of the contract to the specified address 73 | * and sets the nominee to address(0). 74 | */ 75 | function _claimOwner(address claimer_) internal { 76 | _owner = claimer_; 77 | _nominee = address(0); 78 | emit OwnerClaimed(claimer_); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /contracts/utils/SigIdentifiers.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | pragma solidity 0.8.19; 3 | 4 | // contains unique identifiers which are hashes of strings, they help in making signature digest unique 5 | // hence preventing signature replay attacks 6 | 7 | // default switchboards 8 | bytes32 constant TRIP_PATH_SIG_IDENTIFIER = keccak256("TRIP_PATH"); 9 | bytes32 constant TRIP_PROPOSAL_SIG_IDENTIFIER = keccak256("TRIP_PROPOSAL"); 10 | bytes32 constant TRIP_GLOBAL_SIG_IDENTIFIER = keccak256("TRIP_GLOBAL"); 11 | 12 | bytes32 constant UN_TRIP_PATH_SIG_IDENTIFIER = keccak256("UN_TRIP_PATH"); 13 | bytes32 constant UN_TRIP_GLOBAL_SIG_IDENTIFIER = keccak256("UN_TRIP_GLOBAL"); 14 | 15 | // native switchboards 16 | bytes32 constant TRIP_NATIVE_SIG_IDENTIFIER = keccak256("TRIP_NATIVE"); 17 | bytes32 constant UN_TRIP_NATIVE_SIG_IDENTIFIER = keccak256("UN_TRIP_NATIVE"); 18 | 19 | // value threshold, price and fee updaters 20 | bytes32 constant FEES_UPDATE_SIG_IDENTIFIER = keccak256("FEES_UPDATE"); 21 | bytes32 constant RELATIVE_NATIVE_TOKEN_PRICE_UPDATE_SIG_IDENTIFIER = keccak256( 22 | "RELATIVE_NATIVE_TOKEN_PRICE_UPDATE" 23 | ); 24 | bytes32 constant MSG_VALUE_MIN_THRESHOLD_SIG_IDENTIFIER = keccak256( 25 | "MSG_VALUE_MIN_THRESHOLD_UPDATE" 26 | ); 27 | bytes32 constant MSG_VALUE_MAX_THRESHOLD_SIG_IDENTIFIER = keccak256( 28 | "MSG_VALUE_MAX_THRESHOLD_UPDATE" 29 | ); 30 | -------------------------------------------------------------------------------- /contracts/utils/SignatureVerifier.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | pragma solidity 0.8.19; 3 | 4 | import "../interfaces/ISignatureVerifier.sol"; 5 | import "openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol"; 6 | import "../libraries/RescueFundsLib.sol"; 7 | import "../utils/AccessControl.sol"; 8 | import {RESCUE_ROLE} from "../utils/AccessRoles.sol"; 9 | 10 | /** 11 | * @title Signature Verifier 12 | * @notice Verifies the signatures and returns the address of signer recovered from the input signature or digest. 13 | * @dev This contract is modular component in socket to support different signing algorithms. 14 | */ 15 | contract SignatureVerifier is ISignatureVerifier, AccessControl { 16 | /* 17 | * @dev Error thrown when signature length is invalid 18 | */ 19 | error InvalidSigLength(); 20 | 21 | /** 22 | * @notice initializes and grants RESCUE_ROLE to owner. 23 | * @param owner_ The address of the owner of the contract. 24 | */ 25 | constructor(address owner_) AccessControl(owner_) { 26 | _grantRole(RESCUE_ROLE, owner_); 27 | } 28 | 29 | /** 30 | * @notice returns the address of signer recovered from input signature and digest 31 | * @param digest_ The message digest to be signed 32 | * @param signature_ The signature to be verified 33 | * @return signer The address of the signer 34 | */ 35 | function recoverSigner( 36 | bytes32 digest_, 37 | bytes memory signature_ 38 | ) public pure override returns (address signer) { 39 | bytes32 digest = keccak256( 40 | abi.encodePacked("\x19Ethereum Signed Message:\n32", digest_) 41 | ); 42 | // recovered signer is checked for the valid roles later 43 | signer = ECDSA.recover(digest, signature_); 44 | } 45 | 46 | /** 47 | * @notice Rescues funds from the contract if they are locked by mistake. 48 | * @param token_ The address of the token contract. 49 | * @param rescueTo_ The address where rescued tokens need to be sent. 50 | * @param amount_ The amount of tokens to be rescued. 51 | */ 52 | function rescueFunds( 53 | address token_, 54 | address rescueTo_, 55 | uint256 amount_ 56 | ) external onlyRole(RESCUE_ROLE) { 57 | RescueFundsLib.rescueFunds(token_, rescueTo_, amount_); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /contracts/utils/multisig/proxies/IProxyCreationCallback.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity >=0.7.0 <0.9.0; 3 | import "./SafeProxy.sol"; 4 | 5 | /** 6 | * @title IProxyCreationCallback 7 | * @dev An interface for a contract that implements a callback function to be executed after the creation of a proxy instance. 8 | */ 9 | interface IProxyCreationCallback { 10 | /** 11 | * @dev Function to be called after the creation of a SafeProxy instance. 12 | * @param proxy The newly created SafeProxy instance. 13 | * @param _singleton The address of the singleton contract used to create the proxy. 14 | * @param initializer The initializer function call data. 15 | * @param saltNonce The nonce used to generate the salt for the proxy deployment. 16 | */ 17 | function proxyCreated( 18 | SafeProxy proxy, 19 | address _singleton, 20 | bytes calldata initializer, 21 | uint256 saltNonce 22 | ) external; 23 | } 24 | -------------------------------------------------------------------------------- /contracts/utils/multisig/proxies/SafeProxy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: LGPL-3.0-only 2 | pragma solidity >=0.7.0 <0.9.0; 3 | 4 | /** 5 | * @title IProxy - Helper interface to access the singleton address of the Proxy on-chain. 6 | * @author Richard Meissner - @rmeissner 7 | */ 8 | interface IProxy { 9 | function masterCopy() external view returns (address); 10 | } 11 | 12 | /** 13 | * @title SafeProxy - Generic proxy contract allows to execute all transactions applying the code of a master contract. 14 | * @author Stefan George - 15 | * @author Richard Meissner - 16 | */ 17 | contract SafeProxy { 18 | // Singleton always needs to be first declared variable, to ensure that it is at the same location in the contracts to which calls are delegated. 19 | // To reduce deployment costs this variable is internal and needs to be retrieved via `getStorageAt` 20 | address internal singleton; 21 | 22 | /** 23 | * @notice Constructor function sets address of singleton contract. 24 | * @param _singleton Singleton address. 25 | */ 26 | constructor(address _singleton) { 27 | require(_singleton != address(0), "Invalid singleton address provided"); 28 | singleton = _singleton; 29 | } 30 | 31 | /// @dev Fallback function forwards all transactions and returns all received return data. 32 | fallback() external payable { 33 | // solhint-disable-next-line no-inline-assembly 34 | assembly { 35 | let _singleton := and( 36 | sload(0), 37 | 0xffffffffffffffffffffffffffffffffffffffff 38 | ) 39 | // 0xa619486e == keccak("masterCopy()"). The value is right padded to 32-bytes with 0s 40 | if eq( 41 | calldataload(0), 42 | 0xa619486e00000000000000000000000000000000000000000000000000000000 43 | ) { 44 | mstore(0, _singleton) 45 | return(0, 0x20) 46 | } 47 | calldatacopy(0, 0, calldatasize()) 48 | let success := delegatecall( 49 | gas(), 50 | _singleton, 51 | 0, 52 | calldatasize(), 53 | 0, 54 | 0 55 | ) 56 | returndatacopy(0, 0, returndatasize()) 57 | if eq(success, 0) { 58 | revert(0, returndatasize()) 59 | } 60 | return(0, returndatasize()) 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # keep package.json version updated 4 | # setup chain details 5 | npx ts-node scripts/deploy/writeChainConfig.ts 6 | 7 | # deploy contracts 8 | # update overrides in config.ts if needed 9 | npx hardhat run scripts/deploy/deploy.ts 10 | 11 | # publish package 12 | yarn build 13 | npm publish 14 | 15 | # upload s3 config 16 | npx ts-node scripts/rpcConfig/uploadS3Config.ts 17 | -------------------------------------------------------------------------------- /foundry.toml: -------------------------------------------------------------------------------- 1 | [profile.default] 2 | src = 'contracts' 3 | out = 'out' 4 | libs = ['lib'] 5 | test = 'test' 6 | 7 | solc_version = '0.8.19' 8 | optimizer = true 9 | optimizer_runs = 99999 10 | via_ir = false 11 | 12 | verbosity = 3 13 | 14 | # ignore solc warnings for missing license 15 | ignored_error_codes = [1878] 16 | gas_price = 1 17 | 18 | path_pattern = 'test/Socket.t.sol' 19 | 20 | [profile.prod] 21 | optimizer = true 22 | optimizer_runs = 200 23 | via_ir = false 24 | 25 | 26 | # See more config options https://github.com/gakonst/foundry/tree/master/config 27 | -------------------------------------------------------------------------------- /funding.json: -------------------------------------------------------------------------------- 1 | { 2 | "opRetro": { 3 | "projectId": "0xe8833ceee8beb2b3fb0f7f2dcef576f6f9cf20e35d8e53324d71b0ed47b01982" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /lib.tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2018", 4 | "module": "commonjs", 5 | "strict": true, 6 | "esModuleInterop": true, 7 | "outDir": "dist", 8 | "declaration": true, 9 | "resolveJsonModule": true 10 | }, 11 | "include": ["./src"] 12 | } 13 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@socket.tech/dl-core", 3 | "license": "UNLICENSED", 4 | "version": "2.42.0", 5 | "description": "Smart contracts for socket data layer.", 6 | "main": "./dist/src/index.js", 7 | "types": "./dist/src/index.d.ts", 8 | "files": [ 9 | "dist", 10 | "artifacts/abi" 11 | ], 12 | "publishConfig": { 13 | "access": "public" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "git+https://github.com/SocketDotTech/socket-DL.git" 18 | }, 19 | "devDependencies": { 20 | "@arbitrum/sdk": "^3.1.13", 21 | "@aws-sdk/client-s3": "^3.465.0", 22 | "@eth-optimism/sdk": "^3.2.3", 23 | "@ethersproject/bytes": "^5.7.0", 24 | "@fxportal/maticjs-fxportal": "^1.1.1", 25 | "@maticnetwork/maticjs": "^3.5.0", 26 | "@maticnetwork/maticjs-ethers": "^1.0.2", 27 | "@matterlabs/hardhat-zksync": "^1.2.0", 28 | "@nomicfoundation/hardhat-verify": "^2.0.12", 29 | "@nomiclabs/hardhat-ethers": "^2.1.1", 30 | "@nomiclabs/hardhat-etherscan": "^3.1.0", 31 | "@socket.tech/dl-common": "1.0.12-test.1", 32 | "@socket.tech/dl-core": "2.17.0-test.3", 33 | "@typechain/ethers-v5": "^10.0.0", 34 | "@typechain/hardhat": "^6.0.0", 35 | "@types/node": "^18.11.9", 36 | "@types/yargs": "^17.0.22", 37 | "dotenv": "^16.0.3", 38 | "ethers": "^5.6.6", 39 | "hardhat": "^2.22.7", 40 | "hardhat-abi-exporter": "^2.10.1", 41 | "hardhat-change-network": "^0.0.7", 42 | "hardhat-deploy": "^0.11.20", 43 | "hardhat-preprocessor": "^0.1.4", 44 | "pre-commit": "^1.2.2", 45 | "prettier": "^2.3.1", 46 | "prettier-plugin-solidity": "^1.0.0-beta.13", 47 | "ts-node": "^10.7.0", 48 | "typechain": "^8.0.0", 49 | "typescript": "^4.6.4", 50 | "zksync-ethers": "5" 51 | }, 52 | "scripts": { 53 | "lint": "prettier \"./**\" --write", 54 | "build": "hardhat export-abi && tsc --project lib.tsconfig.json", 55 | "tsc": "tsc --project lib.tsconfig.json", 56 | "abi": "hardhat export-abi", 57 | "compile": "forge build", 58 | "test": "prettier --write $(git diff --name-only --diff-filter d | xargs) && forge test", 59 | "setup": "node --experimental-specifier-resolution=node --loader ts-node/esm scripts/deploy/single-click-deploy/integrators/index.ts" 60 | }, 61 | "pre-commit": [ 62 | "lint", 63 | "compile" 64 | ], 65 | "dependencies": { 66 | "axios": "^1.3.6", 67 | "prompts": "^2.4.2", 68 | "yargs": "^17.7.1" 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /remappings.txt: -------------------------------------------------------------------------------- 1 | ds-test/=lib/forge-std/lib/ds-test/src/ 2 | forge-std/=lib/forge-std/src/ 3 | openzeppelin-contracts/=lib/openzeppelin-contracts/ 4 | fx-portal/=lib/contracts/contracts/ 5 | solmate/=lib/solmate/src/ 6 | safe-smart-account/=lib/safe-smart-account/contracts/ 7 | solady/=lib/solady/src/ -------------------------------------------------------------------------------- /scripts/admin/rotate-owner/3-add-signer.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SocketDotTech/socket-DL/5dc41faeea2751bada01b2d6348f205ea3e61a24/scripts/admin/rotate-owner/3-add-signer.ts -------------------------------------------------------------------------------- /scripts/admin/tripCommon.ts: -------------------------------------------------------------------------------- 1 | import { BigNumberish } from "ethers"; 2 | import { 3 | IntegrationTypes, 4 | ChainSlug, 5 | DeploymentMode, 6 | isTestnet, 7 | isMainnet, 8 | } from "../../src"; 9 | import { mode } from "../deploy/config/config"; 10 | import { getAllAddresses, DeploymentAddresses } from "@socket.tech/dl-core"; 11 | import dotenv from "dotenv"; 12 | 13 | dotenv.config(); 14 | export const deploymentMode = process.env.DEPLOYMENT_MODE as DeploymentMode; 15 | 16 | export type SummaryObj = { 17 | chain: ChainSlug; 18 | siblingChain?: ChainSlug; 19 | nonce: number; 20 | currentTripStatus: boolean; 21 | newTripStatus: boolean; 22 | signature: string; 23 | hasRole: boolean; 24 | gasLimit?: BigNumberish; 25 | gasPrice?: BigNumberish; 26 | type?: number; 27 | }; 28 | 29 | /** 30 | * Usable flags 31 | * --sendtx Send trip tx 32 | * Default is false, only check trip status. 33 | * Eg. npx --sendtx ts-node scripts/admin/rescueFunds.ts 34 | 35 | * --chains Run only for specified chains. 36 | * Default is all chains. 37 | * Eg. npx --chains=10,2999 ts-node scripts/admin/tripGlobal.ts 38 | * 39 | * --sibling_chains Run only for specified sibling chains. (used for unTripPath only) 40 | * Default is all sibling chains. 41 | * Eg. npx --sibling_chains=10,2999 ts-node scripts/admin/tripGlobal.ts 42 | * 43 | * --testnets Run for testnets. 44 | * Default is false. 45 | * 46 | * --integration Run for sepcified integration type. Can be fast or optimistic. 47 | * Default is fast. 48 | */ 49 | 50 | export const addresses: DeploymentAddresses = getAllAddresses(mode); 51 | export const testnets = process.env.npm_config_testnets == "true"; 52 | export let activeChainSlugs: string[]; 53 | if (testnets) 54 | activeChainSlugs = Object.keys(addresses).filter((c) => 55 | isTestnet(parseInt(c)) 56 | ); 57 | else 58 | activeChainSlugs = Object.keys(addresses).filter((c) => 59 | isMainnet(parseInt(c)) 60 | ); 61 | export const sendTx = process.env.npm_config_sendtx == "true"; 62 | export const trip = process.env.npm_config_trip == "true"; 63 | export const untrip = process.env.npm_config_untrip == "true"; 64 | export const integrationType = ( 65 | process.env.npm_config_integration 66 | ? process.env.npm_config_integration.toUpperCase() 67 | : IntegrationTypes.fast 68 | ) as IntegrationTypes; 69 | export let filterChains = process.env.npm_config_chains 70 | ? process.env.npm_config_chains.split(",").map((c) => Number(c)) 71 | : activeChainSlugs.map((c) => Number(c)); 72 | 73 | export let siblingFilterChains = process.env.npm_config_sibling_chains 74 | ? process.env.npm_config_sibling_chains.split(",").map((c) => Number(c)) 75 | : undefined; 76 | 77 | export const printSummary = (summary: SummaryObj[]) => { 78 | console.log("\n======== UPDATE SUMMARY ==========\n"); 79 | for (let summaryObj of summary) { 80 | let { chain, ...rest } = summaryObj; 81 | console.log(formatMsg(String(chain), rest)); 82 | } 83 | }; 84 | 85 | export const formatMsg = (title: string, data: any) => { 86 | let message = `====== ${title} ======\n`; 87 | 88 | // Iterate through the object's key-value pairs 89 | for (const key in data) { 90 | if (data.hasOwnProperty(key)) { 91 | message += `${key}: ${data[key]}\n`; 92 | } 93 | } 94 | return message; 95 | }; 96 | -------------------------------------------------------------------------------- /scripts/burn.ts: -------------------------------------------------------------------------------- 1 | import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; 2 | import { ethers } from "hardhat"; 3 | 4 | const usdc = "0x0240c3151FE3e5bdBB1894F59C5Ed9fE71ba0a5E"; 5 | 6 | const deposit = async () => { 7 | const socketSigners: SignerWithAddress[] = await ethers.getSigners(); 8 | const socketSigner: SignerWithAddress = socketSigners[0]; 9 | const tx = await socketSigner.sendTransaction({ 10 | to: usdc, 11 | // data: "0x42966c6800000000000000000000000000000000000000000000000000000000030d2394", 12 | // data: "0x6ccae054000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000005fd7d0d6b91cc4787bcb86ca47e0bd4ea0346d3400000000000000000000000000000000000000000000000000000000000f4240", 13 | type: 1, 14 | // gasLimit: 300_000, 15 | gasPrice: 100_000_000, 16 | nonce: 242, 17 | value: "1350000000000000000", 18 | }); 19 | console.log(tx.hash); 20 | await tx.wait(); 21 | console.log("done"); 22 | }; 23 | 24 | deposit() 25 | .then(() => process.exit(0)) 26 | .catch((error: Error) => { 27 | console.error(error); 28 | process.exit(1); 29 | }); 30 | -------------------------------------------------------------------------------- /scripts/common/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./siblings"; 2 | export * from "./switchboards"; 3 | export * from "./sigIdentifiers"; 4 | -------------------------------------------------------------------------------- /scripts/common/siblings.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ChainSlug, 3 | getAddresses, 4 | Integrations, 5 | DeploymentMode, 6 | ChainSocketAddresses, 7 | ChainAddresses, 8 | } from "../../src"; 9 | 10 | export const getSiblings = ( 11 | deploymentMode: DeploymentMode, 12 | chainSlug: ChainSlug 13 | ): ChainSlug[] => { 14 | try { 15 | const integrations: Integrations = getAddresses( 16 | chainSlug, 17 | deploymentMode 18 | ).integrations; 19 | if (!integrations) return [] as ChainSlug[]; 20 | 21 | return Object.keys(integrations).map( 22 | (chainSlug) => parseInt(chainSlug) as ChainSlug 23 | ); 24 | } catch (error) { 25 | return [] as ChainSlug[]; 26 | } 27 | }; 28 | 29 | export const getSiblingsFromAddresses = ( 30 | addresses: ChainSocketAddresses 31 | ): ChainSlug[] => { 32 | try { 33 | const integrations: Integrations = addresses.integrations; 34 | if (!integrations) return [] as ChainSlug[]; 35 | 36 | const chains = []; 37 | Object.keys(integrations).map((chainSlug) => { 38 | const integration: ChainAddresses = integrations[chainSlug]; 39 | if (integration.FAST) chains.push(parseInt(chainSlug) as ChainSlug); 40 | }); 41 | 42 | return chains; 43 | } catch (error) { 44 | return [] as ChainSlug[]; 45 | } 46 | }; 47 | -------------------------------------------------------------------------------- /scripts/common/sigIdentifiers.ts: -------------------------------------------------------------------------------- 1 | import { utils } from "ethers"; 2 | 3 | export const TRIP_PATH_SIG_IDENTIFIER = utils.id("TRIP_PATH"); 4 | export const TRIP_PROPOSAL_SIG_IDENTIFIER = utils.id("TRIP_PROPOSAL"); 5 | export const TRIP_GLOBAL_SIG_IDENTIFIER = utils.id("TRIP_GLOBAL"); 6 | 7 | export const UN_TRIP_PATH_SIG_IDENTIFIER = utils.id("UN_TRIP_PATH"); 8 | export const UN_TRIP_GLOBAL_SIG_IDENTIFIER = utils.id("UN_TRIP_GLOBAL"); 9 | 10 | // native switchboards 11 | export const TRIP_NATIVE_SIG_IDENTIFIER = utils.id("TRIP_NATIVE"); 12 | export const UN_TRIP_NATIVE_SIG_IDENTIFIER = utils.id("UN_TRIP_NATIVE"); 13 | 14 | // value threshold, price and fee updaters 15 | export const FEES_UPDATE_SIG_IDENTIFIER = utils.id("FEES_UPDATE"); 16 | export const RELATIVE_NATIVE_TOKEN_PRICE_UPDATE_SIG_IDENTIFIER = utils.id( 17 | "RELATIVE_NATIVE_TOKEN_PRICE_UPDATE" 18 | ); 19 | export const MSG_VALUE_MIN_THRESHOLD_SIG_IDENTIFIER = utils.id( 20 | "MSG_VALUE_MIN_THRESHOLD_UPDATE" 21 | ); 22 | export const MSG_VALUE_MAX_THRESHOLD_SIG_IDENTIFIER = utils.id( 23 | "MSG_VALUE_MAX_THRESHOLD_UPDATE" 24 | ); 25 | -------------------------------------------------------------------------------- /scripts/common/switchboards.ts: -------------------------------------------------------------------------------- 1 | import { Contract, Wallet, utils } from "ethers"; 2 | import { StaticJsonRpcProvider } from "@ethersproject/providers"; 3 | import { 4 | IntegrationTypes, 5 | ChainSlug, 6 | getSwitchboardAddress, 7 | DeploymentMode, 8 | } from "../../src"; 9 | import { getProviderFromChainSlug } from "../constants"; 10 | import FastSwitchboardABI from "@socket.tech/dl-core/artifacts/abi/FastSwitchboard.json"; 11 | import NativeSwitchboardABI from "@socket.tech/dl-core/artifacts/abi/NativeSwitchboardBase.json"; 12 | import { getRoleHash } from "../deploy/utils/utils"; 13 | 14 | const sbContracts: { [key: string]: Contract } = {}; 15 | export const getSwitchboardInstance = ( 16 | chain: ChainSlug, 17 | siblingChain: ChainSlug, 18 | integrationType: IntegrationTypes, 19 | mode: DeploymentMode 20 | ): Contract | undefined => { 21 | let switchboardAddress: string; 22 | try { 23 | switchboardAddress = getSwitchboardAddress( 24 | chain, 25 | siblingChain, 26 | integrationType, 27 | mode 28 | ); 29 | } catch (e) { 30 | // means no switchboard found for given params 31 | return; 32 | } 33 | if (!sbContracts[`${chain}${siblingChain}${switchboardAddress}`]) { 34 | const provider: StaticJsonRpcProvider = getProviderFromChainSlug(chain); 35 | 36 | if (!process.env.SOCKET_SIGNER_KEY) 37 | throw new Error("SOCKET_SIGNER_KEY not set"); 38 | 39 | const signer: Wallet = new Wallet(process.env.SOCKET_SIGNER_KEY, provider); 40 | 41 | sbContracts[`${chain}${siblingChain}${switchboardAddress}`] = new Contract( 42 | switchboardAddress, 43 | integrationType == IntegrationTypes.native 44 | ? NativeSwitchboardABI 45 | : FastSwitchboardABI, 46 | signer 47 | ); 48 | } 49 | return sbContracts[`${chain}${siblingChain}${switchboardAddress}`]; 50 | }; 51 | 52 | export const checkRole = async ( 53 | role: string, 54 | instance: Contract, 55 | address: string = "" 56 | ): Promise => { 57 | if (!address) address = await instance.signer.getAddress(); 58 | return await instance.callStatic["hasRole(bytes32,address)"]( 59 | getRoleHash(role), 60 | address 61 | ); 62 | }; 63 | -------------------------------------------------------------------------------- /scripts/constants/bridge.ts: -------------------------------------------------------------------------------- 1 | import { constants } from "ethers"; 2 | import { ChainSlug } from "../../src"; 3 | 4 | export const bridgeConsts = { 5 | inbox: { 6 | [ChainSlug.MAINNET]: "0x4Dbd4fc535Ac27206064B68FfCf827b0A60BAB3f", 7 | [ChainSlug.SEPOLIA]: "0xaAe29B0366299461418F5324a79Afc425BE5ae21", 8 | [ChainSlug.ARBITRUM]: constants.AddressZero, 9 | [ChainSlug.ARBITRUM_SEPOLIA]: constants.AddressZero, 10 | }, 11 | bridge: { 12 | [ChainSlug.MAINNET]: "0x8315177aB297bA92A06054cE80a67Ed4DBd7ed3a", 13 | [ChainSlug.SEPOLIA]: "0x38f918D0E9F1b721EDaA41302E399fa1B79333a9", 14 | [ChainSlug.ARBITRUM]: constants.AddressZero, 15 | [ChainSlug.ARBITRUM_SEPOLIA]: constants.AddressZero, 16 | }, 17 | outbox: { 18 | [ChainSlug.MAINNET]: "0x0B9857ae2D4A3DBe74ffE1d7DF045bb7F96E4840", 19 | [ChainSlug.SEPOLIA]: "0x65f07C7D521164a4d5DaC6eB8Fac8DA067A3B78F", 20 | [ChainSlug.ARBITRUM]: constants.AddressZero, 21 | [ChainSlug.ARBITRUM_SEPOLIA]: constants.AddressZero, 22 | }, 23 | fxChild: { 24 | [ChainSlug.POLYGON_MAINNET]: "0x8397259c983751DAf40400790063935a11afa28a", 25 | }, 26 | checkpointManager: { 27 | [ChainSlug.HARDHAT]: "0x86e4dc95c7fbdbf52e33d563bbdb00823894c287", 28 | [ChainSlug.MAINNET]: "0x86e4dc95c7fbdbf52e33d563bbdb00823894c287", 29 | [ChainSlug.GOERLI]: "0x2890bA17EfE978480615e330ecB65333b880928e", 30 | }, 31 | fxRoot: { 32 | [ChainSlug.HARDHAT]: "0xfe5e5D361b2ad62c541bAb87C45a0B9B018389a2", 33 | [ChainSlug.MAINNET]: "0xfe5e5D361b2ad62c541bAb87C45a0B9B018389a2", 34 | [ChainSlug.GOERLI]: "0x3d1d3E34f7fB6D26245E6640E1c50710eFFf15bA", 35 | }, 36 | crossDomainMessenger: { 37 | [ChainSlug.OPTIMISM]: { 38 | [ChainSlug.MAINNET]: "0x25ace71c97B33Cc4729CF772ae268934F7ab5fA1", 39 | [ChainSlug.OPTIMISM]: "0x4200000000000000000000000000000000000007", 40 | }, 41 | [ChainSlug.OPTIMISM_GOERLI]: { 42 | [ChainSlug.GOERLI]: "0x5086d1eEF304eb5284A0f6720f79403b4e9bE294", 43 | [ChainSlug.OPTIMISM_GOERLI]: "0x4200000000000000000000000000000000000007", 44 | }, 45 | [ChainSlug.OPTIMISM_SEPOLIA]: { 46 | [ChainSlug.SEPOLIA]: "0x58Cc85b8D04EA49cC6DBd3CbFFd00B4B8D6cb3ef", 47 | [ChainSlug.OPTIMISM_SEPOLIA]: 48 | "0x4200000000000000000000000000000000000007", 49 | }, 50 | [ChainSlug.LYRA_TESTNET]: { 51 | [ChainSlug.SEPOLIA]: "0x28976A1DF6e6689Bfe555780CD46dcFcF5552979", 52 | [ChainSlug.LYRA_TESTNET]: "0x4200000000000000000000000000000000000007", 53 | }, 54 | [ChainSlug.LYRA]: { 55 | [ChainSlug.MAINNET]: "0x5456f02c08e9A018E42C39b351328E5AA864174A", 56 | [ChainSlug.LYRA]: "0x4200000000000000000000000000000000000007", 57 | }, 58 | }, 59 | }; 60 | -------------------------------------------------------------------------------- /scripts/constants/config.ts: -------------------------------------------------------------------------------- 1 | import { ChainSlug, IntegrationTypes, NativeSwitchboard } from "../../src"; 2 | import chainConfig from "../../chainConfig.json"; 3 | 4 | const TIMEOUT = 7200; 5 | export const maxAllowedPacketLength = 10; 6 | 7 | // return chain specific timeout if present else default value 8 | export const timeout = (chain: number): number => { 9 | if (chainConfig[chain]) { 10 | if (chainConfig[chain].timeout && !isNaN(chainConfig[chain].timeout!)) 11 | return chainConfig[chain].timeout!; 12 | } 13 | return TIMEOUT; 14 | }; 15 | 16 | export const getDefaultIntegrationType = ( 17 | chain: ChainSlug, 18 | sibling: ChainSlug 19 | ): IntegrationTypes => { 20 | return switchboards?.[chain]?.[sibling] 21 | ? IntegrationTypes.native 22 | : IntegrationTypes.fast; 23 | }; 24 | 25 | export const switchboards = { 26 | [ChainSlug.ARBITRUM_SEPOLIA]: { 27 | [ChainSlug.SEPOLIA]: { 28 | switchboard: NativeSwitchboard.ARBITRUM_L2, 29 | }, 30 | }, 31 | [ChainSlug.ARBITRUM]: { 32 | [ChainSlug.MAINNET]: { 33 | switchboard: NativeSwitchboard.ARBITRUM_L2, 34 | }, 35 | }, 36 | [ChainSlug.OPTIMISM]: { 37 | [ChainSlug.MAINNET]: { 38 | switchboard: NativeSwitchboard.OPTIMISM, 39 | }, 40 | }, 41 | [ChainSlug.OPTIMISM_SEPOLIA]: { 42 | [ChainSlug.SEPOLIA]: { 43 | switchboard: NativeSwitchboard.OPTIMISM, 44 | }, 45 | }, 46 | [ChainSlug.LYRA_TESTNET]: { 47 | [ChainSlug.SEPOLIA]: { 48 | switchboard: NativeSwitchboard.OPTIMISM, 49 | }, 50 | }, 51 | // [ChainSlug.LYRA]: { 52 | // [ChainSlug.MAINNET]: { 53 | // switchboard: NativeSwitchboard.OPTIMISM, 54 | // }, 55 | // }, 56 | [ChainSlug.POLYGON_MAINNET]: { 57 | [ChainSlug.MAINNET]: { 58 | switchboard: NativeSwitchboard.POLYGON_L2, 59 | }, 60 | }, 61 | [ChainSlug.SEPOLIA]: { 62 | [ChainSlug.ARBITRUM_SEPOLIA]: { 63 | switchboard: NativeSwitchboard.ARBITRUM_L1, 64 | }, 65 | [ChainSlug.OPTIMISM_SEPOLIA]: { 66 | switchboard: NativeSwitchboard.OPTIMISM, 67 | }, 68 | [ChainSlug.LYRA_TESTNET]: { 69 | switchboard: NativeSwitchboard.OPTIMISM, 70 | }, 71 | }, 72 | [ChainSlug.MAINNET]: { 73 | [ChainSlug.ARBITRUM]: { 74 | switchboard: NativeSwitchboard.ARBITRUM_L1, 75 | }, 76 | [ChainSlug.OPTIMISM]: { 77 | switchboard: NativeSwitchboard.OPTIMISM, 78 | }, 79 | [ChainSlug.POLYGON_MAINNET]: { 80 | switchboard: NativeSwitchboard.POLYGON_L1, 81 | }, 82 | [ChainSlug.LYRA]: { 83 | switchboard: NativeSwitchboard.OPTIMISM, 84 | }, 85 | }, 86 | }; 87 | -------------------------------------------------------------------------------- /scripts/constants/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./networks"; 2 | export * from "./bridge"; 3 | export * from "./config"; 4 | export * from "./types"; 5 | -------------------------------------------------------------------------------- /scripts/constants/networks.ts: -------------------------------------------------------------------------------- 1 | import { config as dotenvConfig } from "dotenv"; 2 | import { ethers } from "ethers"; 3 | import { resolve } from "path"; 4 | import { 5 | ChainId, 6 | ChainSlug, 7 | ChainSlugToId, 8 | hardhatChainNameToSlug, 9 | HardhatChainName, 10 | chainSlugToHardhatChainName, 11 | zkStackChain, 12 | } from "../../src"; 13 | 14 | import "@matterlabs/hardhat-zksync-node/dist/type-extensions"; 15 | import { 16 | Wallet as zkWallet, 17 | Provider, 18 | } from "@matterlabs/hardhat-zksync/node_modules/zksync-ethers"; 19 | 20 | const dotenvConfigPath: string = process.env.DOTENV_CONFIG_PATH || "./.env"; 21 | dotenvConfig({ path: resolve(__dirname, dotenvConfigPath) }); 22 | 23 | function createReverseEnumMap(enumObj: any) { 24 | const reverseMap = new Map(); 25 | for (const [key, value] of Object.entries(enumObj)) { 26 | reverseMap.set(String(value) as unknown as string, String(key)); 27 | } 28 | return reverseMap; 29 | } 30 | export const chainIdReverseMap = createReverseEnumMap(ChainId); 31 | 32 | export const chainIdToSlug = (chainId: ChainId) => { 33 | const chainName = chainIdReverseMap.get(chainId.toString()); 34 | return ChainSlug[chainName as keyof typeof ChainSlug]; 35 | }; 36 | 37 | export const rpcKeys = (chainSlug: ChainSlug) => { 38 | const chainName = chainSlugToHardhatChainName[chainSlug].toString(); 39 | return `${chainName.toUpperCase()}_RPC`; 40 | }; 41 | 42 | export function getJsonRpcUrl(chain: ChainSlug): string { 43 | let chainRpcKey = rpcKeys(chain); 44 | if (!chainRpcKey) throw Error(`Chain ${chain} not found in rpcKey`); 45 | let rpc = process.env[chainRpcKey]; 46 | if (!rpc) { 47 | throw new Error( 48 | `RPC not configured for chain ${chain}. Missing env variable : ${chainRpcKey}` 49 | ); 50 | } 51 | return rpc; 52 | } 53 | 54 | export const getProviderFromChainSlug = (chainSlug: ChainSlug) => { 55 | const jsonRpcUrl = getJsonRpcUrl(chainSlug); 56 | return new ethers.providers.StaticJsonRpcProvider(jsonRpcUrl); 57 | }; 58 | 59 | export const getProviderFromChainId = (chainId: ChainId) => { 60 | return getProviderFromChainSlug(chainIdToSlug(chainId)); 61 | }; 62 | 63 | export const getProviderFromChainName = (chainName: HardhatChainName) => { 64 | return getProviderFromChainSlug(hardhatChainNameToSlug[chainName]); 65 | }; 66 | 67 | export const getZkWallet = (chainSlug: ChainSlug) => { 68 | if (!zkStackChain.includes(chainSlug)) 69 | throw new Error(`Chain ${chainSlug} is not a zkStack chain`); 70 | if (!process.env.SOCKET_SIGNER_KEY) 71 | throw new Error("SOCKET_SIGNER_KEY not set"); 72 | const rpc = getJsonRpcUrl(chainSlug); 73 | const provider = new Provider(rpc); 74 | return new zkWallet(process.env.SOCKET_SIGNER_KEY, provider); 75 | }; 76 | -------------------------------------------------------------------------------- /scripts/constants/types.ts: -------------------------------------------------------------------------------- 1 | import { ChainSlug } from "../../src"; 2 | 3 | export type RoleOwners = { 4 | ownerAddress: string; 5 | executorAddress: string; 6 | transmitterAddress: string; 7 | watcherAddress: string; 8 | feeUpdaterAddress: string; 9 | }; 10 | 11 | export type ChainConfig = { 12 | roleOwners: RoleOwners; 13 | siblings: ChainSlug[]; 14 | timeout?: number; 15 | msgValueMaxThreshold?: string; 16 | overrides?: { 17 | type?: number; 18 | gasLimit?: string; 19 | gasPrice?: string; 20 | }; 21 | }; 22 | 23 | export type ChainConfigs = { 24 | [chainSlug in ChainSlug]?: ChainConfig; 25 | }; 26 | -------------------------------------------------------------------------------- /scripts/deploy/deploy.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ChainSlug, 3 | DeploymentAddresses, 4 | MainnetIds, 5 | TestnetIds, 6 | } from "../../src"; 7 | import { configureRoles } from "./scripts/configureRoles"; 8 | import { deployForChains } from "./scripts/deploySocketFor"; 9 | import { configureSwitchboards } from "./scripts/configureSwitchboards"; 10 | import { connectPlugs } from "./scripts/connect"; 11 | import prompts from "prompts"; 12 | import { executionManagerVersion } from "./config/config"; 13 | 14 | const main = async () => { 15 | try { 16 | const response = await prompts([ 17 | { 18 | name: "chainType", 19 | type: "select", 20 | message: "Select chains network type", 21 | choices: [ 22 | { 23 | title: "Mainnet", 24 | value: "mainnet", 25 | }, 26 | { 27 | title: "Testnet", 28 | value: "testnet", 29 | }, 30 | ], 31 | }, 32 | ]); 33 | 34 | const chainOptions = 35 | response.chainType === "mainnet" ? MainnetIds : TestnetIds; 36 | let choices = chainOptions.map((chain) => ({ 37 | title: chain.toString(), 38 | value: chain, 39 | })); 40 | 41 | const chainsResponse = await prompts([ 42 | { 43 | name: "chains", 44 | type: "multiselect", 45 | message: "Select chains to connect", 46 | choices, 47 | }, 48 | { 49 | name: "siblings", 50 | type: "multiselect", 51 | message: "Select sibling chains to connect", 52 | choices, 53 | }, 54 | ]); 55 | 56 | const chains = chainsResponse.chains; 57 | const siblings = chainsResponse.siblings; 58 | const allChains = [...chains, ...siblings]; 59 | console.log("allChains: ", allChains); 60 | 61 | choices = chains.map((chain) => ({ 62 | title: chain.toString(), 63 | value: chain, 64 | })); 65 | 66 | const safeResponse = await prompts([ 67 | { 68 | name: "chains", 69 | type: "multiselect", 70 | message: "Select chains to use Safe as owner", 71 | choices, 72 | }, 73 | ]); 74 | 75 | let addresses: DeploymentAddresses = await deployForChains( 76 | allChains, 77 | safeResponse.chains, 78 | executionManagerVersion 79 | ); 80 | 81 | if (chains.length === 0) { 82 | console.log("No siblings selected!"); 83 | return; 84 | } 85 | 86 | await configureRoles( 87 | addresses, 88 | chains, 89 | siblings, 90 | safeResponse.chains, 91 | true, 92 | executionManagerVersion 93 | ); 94 | addresses = await configureSwitchboards( 95 | addresses, 96 | chains, 97 | siblings, 98 | safeResponse.chains, 99 | executionManagerVersion 100 | ); 101 | await connectPlugs(addresses, chains, siblings); 102 | } catch (error) { 103 | console.log("Error:", error); 104 | } 105 | }; 106 | 107 | main() 108 | .then(() => process.exit(0)) 109 | .catch((error: Error) => { 110 | console.error(error); 111 | process.exit(1); 112 | }); 113 | -------------------------------------------------------------------------------- /scripts/deploy/em-migration/backward-migrate-em.ts: -------------------------------------------------------------------------------- 1 | import { 2 | CORE_CONTRACTS, 3 | DeploymentAddresses, 4 | MainnetIds, 5 | ROLES, 6 | TestnetIds, 7 | } from "../../../src"; 8 | import { deployForChains } from "../scripts/deploySocketFor"; 9 | import prompts from "prompts"; 10 | import { checkAndUpdateRoles } from "../scripts/roles"; 11 | import { 12 | executorAddresses, 13 | mode, 14 | ownerAddresses, 15 | transmitterAddresses, 16 | } from "../config/config"; 17 | import { configureExecutionManagers } from "./migrate-em"; 18 | 19 | const deploy = async () => { 20 | try { 21 | const response = await prompts([ 22 | { 23 | name: "chainType", 24 | type: "select", 25 | message: "Select chains network type", 26 | choices: [ 27 | { 28 | title: "Mainnet", 29 | value: "mainnet", 30 | }, 31 | { 32 | title: "Testnet", 33 | value: "testnet", 34 | }, 35 | ], 36 | }, 37 | ]); 38 | 39 | const chainOptions = 40 | response.chainType === "mainnet" ? MainnetIds : TestnetIds; 41 | let choices = chainOptions.map((chain) => ({ 42 | title: chain.toString(), 43 | value: chain, 44 | })); 45 | 46 | const configResponse = await prompts([ 47 | { 48 | name: "chains", 49 | type: "multiselect", 50 | message: "Select sibling chains to connect", 51 | choices, 52 | }, 53 | ]); 54 | 55 | const chains = [...configResponse.chains]; 56 | 57 | const emVersion = CORE_CONTRACTS.ExecutionManager; 58 | const addresses: DeploymentAddresses = await deployForChains( 59 | chains, 60 | emVersion 61 | ); 62 | 63 | await checkAndUpdateRoles( 64 | { 65 | userSpecificRoles: [ 66 | { 67 | userAddress: ownerAddresses[mode], 68 | filterRoles: [ 69 | ROLES.RESCUE_ROLE, 70 | ROLES.GOVERNANCE_ROLE, 71 | ROLES.WITHDRAW_ROLE, 72 | ROLES.FEES_UPDATER_ROLE, 73 | ], 74 | }, 75 | { 76 | userAddress: transmitterAddresses[mode], 77 | filterRoles: [ROLES.FEES_UPDATER_ROLE], 78 | }, 79 | { 80 | userAddress: executorAddresses[mode], 81 | filterRoles: [ROLES.EXECUTOR_ROLE], 82 | }, 83 | ], 84 | contractName: emVersion, 85 | filterChains: chains, 86 | filterSiblingChains: chains, 87 | sendTransaction: true, 88 | newRoleStatus: true, 89 | }, 90 | addresses 91 | ); 92 | await configureExecutionManagers(chains, addresses); 93 | } catch (error) { 94 | console.log("Error:", error); 95 | } 96 | }; 97 | 98 | // npx hardhat run scripts/deploy/em-migration/backward-migrate-em.ts 99 | deploy(); 100 | 101 | // run this script, update s3 config version and upload s3 config 102 | // run em fees updater 103 | // run the ./check-migration script to test if new EM is set and it has initial fees 104 | -------------------------------------------------------------------------------- /scripts/deploy/helpers/checkBalance.ts: -------------------------------------------------------------------------------- 1 | import { config as dotenvConfig } from "dotenv"; 2 | import axios from "axios"; 3 | 4 | dotenvConfig(); 5 | import { ChainSlugToKey } from "../../../src"; 6 | import { utils } from "ethers"; 7 | 8 | import { chains, mode } from "../config/config"; 9 | import { getProviderFromChainSlug } from "../../constants/networks"; 10 | 11 | // check balance of owner address on all chains 12 | export const checkBalance = async () => { 13 | try { 14 | // parallelize chains 15 | await Promise.all( 16 | chains.map(async (chainSlug) => { 17 | const provider = await getProviderFromChainSlug(chainSlug); 18 | // let ownerAddress = process.env.SOCKET_OWNER_ADDRESS; 19 | let ownerAddress = "0x752B38FA38F53dF7fa60e6113CFd9094b7e040Aa"; 20 | if (!ownerAddress) throw Error("owner address not present"); 21 | console.log( 22 | chainSlug, 23 | " ", 24 | ChainSlugToKey[chainSlug], 25 | " : ", 26 | utils.formatEther(await provider.getBalance(ownerAddress)) 27 | ); 28 | }) 29 | ); 30 | } catch (error) { 31 | console.log("Error while checking balance", error); 32 | } 33 | }; 34 | 35 | const main = async () => { 36 | await checkBalance(); 37 | }; 38 | 39 | main() 40 | .then(() => process.exit(0)) 41 | .catch((error: Error) => { 42 | console.error(error); 43 | process.exit(1); 44 | }); 45 | -------------------------------------------------------------------------------- /scripts/deploy/helpers/estimateGas.ts: -------------------------------------------------------------------------------- 1 | require("dotenv").config(); 2 | import axios from "axios"; 3 | 4 | const deployerAddr = "0x752B38FA38F53dF7fa60e6113CFd9094b7e040Aa"; 5 | const apiKey = process.env.POLYGONSCAN_API_KEY; 6 | const startBlock = "39623757"; 7 | const endBlock = "39661457"; 8 | const gasPrice = 25; 9 | const url = `https://api.polygonscan.com/api?module=account&action=txlist&address=${deployerAddr}&sort=asc&apikey=${apiKey}${ 10 | startBlock ? "&startBlock=" + startBlock : "" 11 | }${endBlock ? "&endBlock=" + endBlock : ""}`; 12 | 13 | // This script queries a set of txn between `startBlock` and `endBlock`. The result is used to get the sum of gasUsed 14 | // for all the txns. Final sum is multiplied with gasPrice to get the total cost required to simulate them on chain. 15 | async function main() { 16 | const { data } = await axios.get(url); 17 | 18 | let total = 0; 19 | data.result.forEach((tx) => { 20 | total += parseInt(tx.gasUsed); 21 | }); 22 | 23 | // adding up 10% for opcode diff and addresses 24 | total = Math.ceil(total + total * 0.1); 25 | 26 | const costInEth = (total * gasPrice) / 1000000000; 27 | console.log(costInEth); 28 | } 29 | 30 | main(); 31 | -------------------------------------------------------------------------------- /scripts/deploy/helpers/fastSwitchboards.ts: -------------------------------------------------------------------------------- 1 | import { utils } from "ethers"; 2 | import { ethers } from "hardhat"; 3 | 4 | import { DeploymentAddresses, getAllAddresses, ChainSlug } from "../../../src"; 5 | import { mode, chains } from "../config/config"; 6 | import { getProviderFromChainSlug } from "../../constants"; 7 | 8 | const main = async (srcChains: ChainSlug[], dstChains: ChainSlug[]) => { 9 | try { 10 | let addresses: DeploymentAddresses; 11 | try { 12 | addresses = getAllAddresses(mode); 13 | } catch (error) { 14 | addresses = {} as DeploymentAddresses; 15 | } 16 | let srcChainSlugs = srcChains ?? chains; 17 | let dstChainSlugs = dstChains ?? chains; 18 | 19 | let data: any[] = []; 20 | await Promise.all( 21 | srcChainSlugs.map(async (chainSlug) => { 22 | let fastSwitchboardAddress = 23 | addresses[chainSlug as ChainSlug]?.FastSwitchboard; 24 | if (!fastSwitchboardAddress) return; 25 | 26 | let siblingChains = dstChainSlugs.filter((s) => chainSlug !== s); 27 | 28 | await Promise.all( 29 | siblingChains.map(async (siblingChain) => { 30 | let provider = getProviderFromChainSlug(chainSlug as ChainSlug); 31 | let Contract = await ethers.getContractFactory("FastSwitchboard"); 32 | let instance = Contract.attach(fastSwitchboardAddress).connect( 33 | provider 34 | ); 35 | let result = await instance["totalWatchers(uint32)"](siblingChain); 36 | 37 | let digest = utils.keccak256( 38 | utils.defaultAbiCoder.encode( 39 | ["address", "uint32", "bytes32", "uint256"], 40 | // ["address", "uint32", "bytes32", "uint256", "bytes32"], 41 | [ 42 | fastSwitchboardAddress?.toLowerCase(), 43 | chainSlug, 44 | "0x00aa36a841667f3df292b3ed613d66b39dd2d8327d2ef5a80000000000000000", 45 | 0, 46 | // "0x80b582422ec90d907e218c10e879241ddf21d3274e03÷18de902f4abece0ac6c5" 47 | ] 48 | ) 49 | ); 50 | 51 | data.push({ 52 | chainSlug, 53 | siblingChain, 54 | totalWatchers: result.toNumber(), 55 | digest, 56 | fastSwitchboardAddress, 57 | }); 58 | }) 59 | ); 60 | }) 61 | ); 62 | console.table(data); 63 | } catch (error) { 64 | console.log(error); 65 | } 66 | }; 67 | 68 | let srcChains = [ChainSlug.ARBITRUM_GOERLI]; 69 | let dstChains = [ChainSlug.AEVO_TESTNET]; 70 | main(srcChains, dstChains); 71 | -------------------------------------------------------------------------------- /scripts/deploy/helpers/send-msg/allPathTest.ts: -------------------------------------------------------------------------------- 1 | import { config as dotenvConfig } from "dotenv"; 2 | dotenvConfig(); 3 | import { 4 | ChainSlug, 5 | MainnetIds, 6 | TestnetIds, 7 | isMainnet, 8 | isTestnet, 9 | } from "../../../../src"; 10 | import { sendCounterBridgeMsg } from "./utils"; 11 | 12 | const getSiblingSlugs = (chainSlug: ChainSlug): ChainSlug[] => { 13 | if (isTestnet(chainSlug)) 14 | return TestnetIds.filter( 15 | (siblingChainSlug) => chainSlug !== siblingChainSlug 16 | ); 17 | if (isMainnet(chainSlug)) 18 | return MainnetIds.filter( 19 | (siblingChainSlug) => chainSlug !== siblingChainSlug 20 | ); 21 | return []; 22 | }; 23 | 24 | const config = { 25 | msgGasLimit: "200000", 26 | payloadSize: 100, // for counter add operation 27 | executionParams: 28 | "0x0000000000000000000000000000000000000000000000000000000000000000", 29 | transmissionParams: 30 | "0x0000000000000000000000000000000000000000000000000000000000000000", 31 | }; 32 | 33 | export const sendMessagesToAllPaths = async (params: { 34 | senderChains: ChainSlug[]; 35 | receiverChains: ChainSlug[]; 36 | }) => { 37 | try { 38 | let { senderChains, receiverChains } = params; 39 | 40 | console.log("================= checking for : ", params); 41 | let activeChainSlugs = 42 | senderChains.length > 0 ? senderChains : [...MainnetIds, ...TestnetIds]; 43 | 44 | // parallelize chains 45 | await Promise.all( 46 | activeChainSlugs.map(async (chainSlug) => { 47 | const siblingSlugs = getSiblingSlugs(chainSlug); 48 | await Promise.all( 49 | siblingSlugs.map(async (siblingSlug) => { 50 | if ( 51 | receiverChains.length > 0 && 52 | !receiverChains.includes(siblingSlug) 53 | ) 54 | return; 55 | console.log( 56 | "sending message from ", 57 | chainSlug, 58 | " to ", 59 | siblingSlug 60 | ); 61 | const { 62 | payloadSize, 63 | msgGasLimit, 64 | executionParams, 65 | transmissionParams, 66 | } = config; 67 | await sendCounterBridgeMsg( 68 | chainSlug, 69 | siblingSlug, 70 | msgGasLimit, 71 | payloadSize, 72 | executionParams, 73 | transmissionParams 74 | ); 75 | }) 76 | ); 77 | }) 78 | ); 79 | } catch (error) { 80 | console.log("Error while sending outbound tx", error); 81 | } 82 | }; 83 | 84 | const main = async () => { 85 | let senderChains = [ChainSlug.OPTIMISM_SEPOLIA]; 86 | let receiverChains = [ChainSlug.ARBITRUM_SEPOLIA]; 87 | await sendMessagesToAllPaths({ senderChains, receiverChains }); 88 | }; 89 | 90 | main() 91 | .then(() => process.exit(0)) 92 | .catch((error: Error) => { 93 | console.error(error); 94 | process.exit(1); 95 | }); 96 | 97 | // npx ts-node scripts/deploy/helpers/send-msg/allPathTest.ts 98 | -------------------------------------------------------------------------------- /scripts/deploy/helpers/send-msg/transmissionParamsTestScript.ts: -------------------------------------------------------------------------------- 1 | import { sendCounterBridgeMsg } from "./utils"; 2 | import { ChainSlug } from "../../../../src"; 3 | 4 | const config = { 5 | chainSlug: ChainSlug.OPTIMISM_SEPOLIA, 6 | siblingSlug: ChainSlug.ARBITRUM_SEPOLIA, 7 | msgGasLimit: "200000", 8 | payloadSize: 100, // for counter add operation 9 | executionParams: 10 | "0x0000000000000000000000000000000000000000000000000000000000000000", 11 | }; 12 | 13 | const transmissionParams = [ 14 | "0x0101000000010000000000000000000000000000000000000000000000000000", 15 | "0x0101000000020000000000000000000000000000000000000000000000000000", 16 | "0x0101000000030000000000000000000000000000000000000000000000000000", 17 | ]; 18 | const sendMsgsWithVaryingParams = async () => { 19 | for (const param of transmissionParams) { 20 | try { 21 | const { 22 | msgGasLimit, 23 | payloadSize, 24 | executionParams, 25 | chainSlug, 26 | siblingSlug, 27 | } = config; 28 | console.log( 29 | `\n\n Sending message with transmission params: ${JSON.stringify( 30 | param 31 | )}` 32 | ); 33 | await sendCounterBridgeMsg( 34 | chainSlug, 35 | siblingSlug, 36 | msgGasLimit, 37 | payloadSize, 38 | executionParams, 39 | param 40 | ); 41 | console.log( 42 | `Message sent with transmission params: ${JSON.stringify(param)}` 43 | ); 44 | } catch (error) { 45 | console.error( 46 | `Failed to send message with transmission params: ${JSON.stringify( 47 | param 48 | )}` 49 | ); 50 | console.error(error); 51 | } 52 | } 53 | }; 54 | 55 | sendMsgsWithVaryingParams(); 56 | 57 | // usage: 58 | // npx ts-node scripts/deploy/helpers/send-msg/transmissionParamsTestScript.ts 59 | -------------------------------------------------------------------------------- /scripts/deploy/scripts/deploySocketFor.ts: -------------------------------------------------------------------------------- 1 | import { ReturnObj, deploySocket } from "../scripts/deploySocket"; 2 | import { 3 | ChainSlug, 4 | ChainSocketAddresses, 5 | DeploymentAddresses, 6 | getAllAddresses, 7 | } from "../../../src"; 8 | import { mode } from "../config/config"; 9 | import { storeAddresses } from "../utils"; 10 | import { SocketSigner } from "@socket.tech/dl-common"; 11 | import { getSocketSigner } from "../utils/socket-signer"; 12 | 13 | export const deployForChains = async ( 14 | chains: ChainSlug[], 15 | safeChains: ChainSlug[], 16 | executionManagerVersion: string 17 | ): Promise => { 18 | let addresses: DeploymentAddresses; 19 | try { 20 | try { 21 | addresses = getAllAddresses(mode); 22 | } catch (error) { 23 | addresses = {} as DeploymentAddresses; 24 | } 25 | 26 | await Promise.all( 27 | chains.map(async (chain: ChainSlug) => { 28 | let allDeployed = false; 29 | 30 | let chainAddresses: ChainSocketAddresses = addresses[chain] 31 | ? (addresses[chain] as ChainSocketAddresses) 32 | : ({} as ChainSocketAddresses); 33 | 34 | const signer: SocketSigner = await getSocketSigner( 35 | chain, 36 | chainAddresses, 37 | false, 38 | true 39 | ); 40 | 41 | while (!allDeployed) { 42 | const results: ReturnObj = await deploySocket( 43 | executionManagerVersion, 44 | signer, 45 | chain, 46 | safeChains.includes(chain), 47 | mode, 48 | chainAddresses 49 | ); 50 | 51 | await storeAddresses(results.deployedAddresses, chain, mode); 52 | 53 | allDeployed = results.allDeployed; 54 | chainAddresses = results.deployedAddresses; 55 | addresses[chain] = results.deployedAddresses; 56 | } 57 | }) 58 | ); 59 | } catch (error) { 60 | console.log("Error in deploying setup contracts", error); 61 | throw error; 62 | } 63 | 64 | return addresses; 65 | }; 66 | -------------------------------------------------------------------------------- /scripts/deploy/scripts/multicall.ts: -------------------------------------------------------------------------------- 1 | import { Contract } from "ethers"; 2 | 3 | export const multicall = async ( 4 | socketBatcher: Contract, 5 | calls: { target: string; callData: string }[] 6 | ): Promise => { 7 | try { 8 | const result = await socketBatcher.callStatic.multicall(calls); 9 | return result[1]; 10 | } catch (error) { 11 | console.log("Error performing multicall:", error); 12 | throw error; 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /scripts/deploy/single-click-deploy/README.md: -------------------------------------------------------------------------------- 1 | # Socket DL deployment 2 | 3 | ## Local Development 4 | 5 | ### Prereqs 6 | 7 | - Hardhat 8 | - Foundry 9 | - NodeJS (Supported version: "^14.0.0 || ^16.0.0 || ^18.0.0") 10 | - Yarn 11 | 12 | ### Setup 13 | 14 | Clone project and install dependencies. 15 | 16 | - Clone the repository 17 | `git clone https://github.com/SocketDotTech/socket-dl` 18 | 19 | - Move to repository folder 20 | `cd socket-dl` 21 | 22 | - Install forge dependencies 23 | `forge install` 24 | 25 | - Install node modules 26 | `yarn install` 27 | 28 | ### Deploy 29 | 30 | Deployments use [Hardhat](https://github.com/NomicFoundation/hardhat) 31 | 32 | # Setup config and env: 33 | 34 | - Run command: `yarn setup` and select first option `Add chain configs`. 35 | - Add all the required details, you can skip configs which are not required by leaving blank and pressing enter. 36 | - Once done, go to .env and check if owner address, rpc and private key are correctly set! 37 | - Next compile contracts, `npx hardhat compile` 38 | 39 | # Deploy contracts: 40 | 41 | - Ensure you have enough balance in your account to deploy 10-12 contracts. 42 | - Next compile contracts, `npx hardhat compile` 43 | - Run command: `yarn setup` and select second option, this will deploy contracts and store them in `prod_addresses.json`. 44 | 45 | # Create a PR: 46 | 47 | - Once contracts are deployed, push them to the repo and create a PR 48 | - contracts will be used by SOCKET to run the infra and connect them with existing deployments on other chains. 49 | 50 | # FAQ: 51 | 52 | - Max msg value transfer limit: Socket DL supports native asset bridge between 2 chains, the max value which can be bridged is controlled by this value. 53 | - Timeout: Socket DL supports Fast and Optimistic Switchboards which has 1/n trust assumption from watchers, find more here https://developer.socket.tech/Learn/Components/Switchboards. 54 | In case no one trips a packet in this timeout period, the switchboard considers the packet valid. Socket DL assumes it to be 2 hrs by default. 55 | - Transactions are reverting with insufficient balance or other gas problems: 56 | Go to `chainConfig.json` present in the root. You can configure overrides there which are used in all the transactions going through. 57 | 58 | For example: 59 | ``` 60 | "overrides": { 61 | "type": 1, 62 | "gasLimit": 20000000, 63 | "gasPrice": 1000000000000 64 | } 65 | ``` 66 | -------------------------------------------------------------------------------- /scripts/deploy/single-click-deploy/integrators/index.ts: -------------------------------------------------------------------------------- 1 | import prompts from "prompts"; 2 | 3 | import { deploySocket } from "./deploySocket"; 4 | import { writeConfigs } from "./writeConfigs"; 5 | 6 | async function main() { 7 | const response = await prompts([ 8 | { 9 | name: "option", 10 | type: "select", 11 | message: "What would you like to do?", 12 | choices: [ 13 | { 14 | title: "Add chain configs", 15 | value: "add", 16 | }, 17 | { 18 | title: "Deploy contracts", 19 | value: "deploy", 20 | }, 21 | { title: "Exit", value: "exit" }, 22 | ], 23 | }, 24 | ]); 25 | 26 | switch (response.option) { 27 | case "add": 28 | await writeConfigs(); 29 | break; 30 | case "deploy": 31 | await deploySocket(); 32 | break; 33 | case "exit": 34 | process.exit(0); 35 | } 36 | } 37 | 38 | async function start() { 39 | while (true) { 40 | await main(); 41 | } 42 | } 43 | 44 | (async () => { 45 | start(); 46 | })(); 47 | -------------------------------------------------------------------------------- /scripts/deploy/switchboards/arbitrumL1Switchboard.ts: -------------------------------------------------------------------------------- 1 | import { bridgeConsts } from "../../constants"; 2 | import { ChainSlug } from "../../../src"; 3 | 4 | export const arbitrumL1Switchboard = ( 5 | chainSlug: ChainSlug, 6 | socketAddress: string, 7 | sigVerifierAddress: string, 8 | owner: string 9 | ) => { 10 | return { 11 | contractName: "ArbitrumL1Switchboard", 12 | args: [ 13 | chainSlug, 14 | bridgeConsts.inbox[chainSlug], 15 | owner, 16 | socketAddress, 17 | bridgeConsts.bridge[chainSlug], 18 | bridgeConsts.outbox[chainSlug], 19 | sigVerifierAddress, 20 | ], 21 | path: "contracts/switchboard/native/ArbitrumL1Switchboard.sol", 22 | }; 23 | }; 24 | -------------------------------------------------------------------------------- /scripts/deploy/switchboards/arbitrumL2Switchboard.ts: -------------------------------------------------------------------------------- 1 | import { ChainSlug } from "../../../src"; 2 | 3 | export const arbitrumL2Switchboard = ( 4 | chainSlug: ChainSlug, 5 | socketAddress: string, 6 | sigVerifierAddress: string, 7 | owner: string 8 | ) => { 9 | return { 10 | contractName: "ArbitrumL2Switchboard", 11 | args: [chainSlug, owner, socketAddress, sigVerifierAddress], 12 | path: "contracts/switchboard/native/ArbitrumL2Switchboard.sol", 13 | }; 14 | }; 15 | -------------------------------------------------------------------------------- /scripts/deploy/switchboards/fastSwitchboard.ts: -------------------------------------------------------------------------------- 1 | import { timeout } from "../../constants"; 2 | import { CORE_CONTRACTS, ChainSlug } from "../../../src"; 3 | 4 | export const fastSwitchboard = ( 5 | chainSlug: ChainSlug, 6 | socketAddress: string, 7 | sigVerifierAddress: string, 8 | owner: string 9 | ) => { 10 | return { 11 | contractName: CORE_CONTRACTS.FastSwitchboard, 12 | args: [ 13 | owner, 14 | socketAddress, 15 | chainSlug, 16 | timeout(chainSlug), 17 | sigVerifierAddress, 18 | ], 19 | path: "contracts/switchboard/default-switchboards/FastSwitchboard.sol", 20 | }; 21 | }; 22 | -------------------------------------------------------------------------------- /scripts/deploy/switchboards/index.ts: -------------------------------------------------------------------------------- 1 | import { IntegrationTypes, NativeSwitchboard, ChainSlug } from "../../../src"; 2 | 3 | import { fastSwitchboard } from "./fastSwitchboard"; 4 | import { optimisticSwitchboard } from "./optimisticSwitchboard"; 5 | 6 | // natives 7 | import { arbitrumL1Switchboard } from "./arbitrumL1Switchboard"; 8 | import { arbitrumL2Switchboard } from "./arbitrumL2Switchboard"; 9 | import { optimismSwitchboard } from "./optimismSwitchboard"; 10 | import { polygonL1Switchboard } from "./polygonL1Switchboard"; 11 | import { polygonL2Switchboard } from "./polygonL2Switchboard"; 12 | import { switchboards } from "../../constants"; 13 | 14 | export const getSwitchboardDeployData = ( 15 | integrationType: IntegrationTypes, 16 | localChain: ChainSlug, 17 | remoteChain: ChainSlug | string, 18 | socketAddress: string, 19 | sigVerifierAddress: string, 20 | owner: string 21 | ) => { 22 | if ( 23 | integrationType === IntegrationTypes.fast || 24 | integrationType === IntegrationTypes.fast2 25 | ) { 26 | return fastSwitchboard( 27 | localChain, 28 | socketAddress, 29 | sigVerifierAddress, 30 | owner 31 | ); 32 | } else if (integrationType === IntegrationTypes.optimistic) { 33 | return optimisticSwitchboard( 34 | localChain, 35 | socketAddress, 36 | sigVerifierAddress, 37 | owner 38 | ); 39 | } else if (integrationType === IntegrationTypes.native) { 40 | const switchboardType = 41 | switchboards[localChain]?.[remoteChain]?.["switchboard"]; 42 | if (switchboardType === NativeSwitchboard.ARBITRUM_L1) { 43 | return arbitrumL1Switchboard( 44 | localChain, 45 | socketAddress, 46 | sigVerifierAddress, 47 | owner 48 | ); 49 | } else if (switchboardType === NativeSwitchboard.ARBITRUM_L2) { 50 | return arbitrumL2Switchboard( 51 | localChain, 52 | socketAddress, 53 | sigVerifierAddress, 54 | owner 55 | ); 56 | } else if (switchboardType === NativeSwitchboard.OPTIMISM) { 57 | return optimismSwitchboard( 58 | localChain, 59 | remoteChain as ChainSlug, 60 | socketAddress, 61 | sigVerifierAddress, 62 | owner 63 | ); 64 | } else if (switchboardType === NativeSwitchboard.POLYGON_L1) { 65 | return polygonL1Switchboard( 66 | localChain, 67 | socketAddress, 68 | sigVerifierAddress, 69 | owner 70 | ); 71 | } else if (switchboardType === NativeSwitchboard.POLYGON_L2) { 72 | return polygonL2Switchboard( 73 | localChain, 74 | socketAddress, 75 | sigVerifierAddress, 76 | owner 77 | ); 78 | } else { 79 | return { contractName: "", args: [], path: "" }; 80 | } 81 | } else { 82 | // TODO: handle invalid data 83 | return { contractName: "", args: [], path: "" }; 84 | } 85 | }; 86 | -------------------------------------------------------------------------------- /scripts/deploy/switchboards/optimismSwitchboard.ts: -------------------------------------------------------------------------------- 1 | import { ChainSlug, isL1 } from "../../../src"; 2 | import { bridgeConsts } from "../../constants"; 3 | 4 | const receiveGasLimit = 300000; 5 | 6 | export const optimismSwitchboard = ( 7 | chainSlug: ChainSlug, 8 | remoteChainSlug: ChainSlug, 9 | socketAddress: string, 10 | sigVerifierAddress: string, 11 | owner: string 12 | ) => { 13 | let crossDomainMessengerAddress: string; 14 | if (isL1(chainSlug)) { 15 | crossDomainMessengerAddress = 16 | bridgeConsts.crossDomainMessenger[remoteChainSlug][chainSlug]; 17 | } else { 18 | crossDomainMessengerAddress = 19 | bridgeConsts.crossDomainMessenger[chainSlug][chainSlug]; 20 | } 21 | 22 | if (!crossDomainMessengerAddress || crossDomainMessengerAddress == "") { 23 | throw new Error("Wrong chainSlug - crossDomainMessengerAddress is null"); 24 | } 25 | 26 | return { 27 | contractName: "OptimismSwitchboard", 28 | args: [ 29 | chainSlug, 30 | receiveGasLimit, 31 | owner, 32 | socketAddress, 33 | crossDomainMessengerAddress, 34 | sigVerifierAddress, 35 | ], 36 | path: "contracts/switchboard/native/OptimismSwitchboard.sol", 37 | }; 38 | }; 39 | -------------------------------------------------------------------------------- /scripts/deploy/switchboards/optimisticSwitchboard.ts: -------------------------------------------------------------------------------- 1 | import { CORE_CONTRACTS, ChainSlug } from "../../../src"; 2 | import { timeout } from "../../constants"; 3 | 4 | export const optimisticSwitchboard = ( 5 | chainSlug: ChainSlug, 6 | socketAddress: string, 7 | sigVerifierAddress: string, 8 | owner: string 9 | ) => { 10 | return { 11 | contractName: CORE_CONTRACTS.OptimisticSwitchboard, 12 | args: [ 13 | owner, 14 | socketAddress, 15 | chainSlug, 16 | timeout(chainSlug), 17 | sigVerifierAddress, 18 | ], 19 | path: "contracts/switchboard/default-switchboards/OptimisticSwitchboard.sol", 20 | }; 21 | }; 22 | -------------------------------------------------------------------------------- /scripts/deploy/switchboards/polygonL1Switchboard.ts: -------------------------------------------------------------------------------- 1 | import { ChainSlug } from "../../../src"; 2 | import { bridgeConsts } from "../../constants"; 3 | 4 | export const polygonL1Switchboard = ( 5 | chainSlug: ChainSlug, 6 | socketAddress: string, 7 | sigVerifierAddress: string, 8 | owner: string 9 | ) => { 10 | return { 11 | contractName: "PolygonL1Switchboard", 12 | args: [ 13 | chainSlug, 14 | bridgeConsts.checkpointManager[chainSlug], 15 | bridgeConsts.fxRoot[chainSlug], 16 | owner, 17 | socketAddress, 18 | sigVerifierAddress, 19 | ], 20 | path: "contracts/switchboard/native/PolygonL1Switchboard.sol", 21 | }; 22 | }; 23 | -------------------------------------------------------------------------------- /scripts/deploy/switchboards/polygonL2Switchboard.ts: -------------------------------------------------------------------------------- 1 | import { ChainSlug } from "../../../src"; 2 | import { bridgeConsts } from "../../constants"; 3 | 4 | export const polygonL2Switchboard = ( 5 | chainSlug: ChainSlug, 6 | socketAddress: string, 7 | sigVerifierAddress: string, 8 | owner: string 9 | ) => { 10 | return { 11 | contractName: "PolygonL2Switchboard", 12 | args: [ 13 | chainSlug, 14 | bridgeConsts.fxChild[chainSlug], 15 | owner, 16 | socketAddress, 17 | sigVerifierAddress, 18 | ], 19 | path: "contracts/switchboard/native/PolygonL2Switchboard.sol", 20 | }; 21 | }; 22 | -------------------------------------------------------------------------------- /scripts/deploy/utils/address.ts: -------------------------------------------------------------------------------- 1 | import { ChainSlug, IntegrationTypes } from "../../../src"; 2 | 3 | function getSwitchboardAddress( 4 | chainSlug: ChainSlug | string, 5 | integrationType: IntegrationTypes, 6 | config: any 7 | ) { 8 | if (integrationType === IntegrationTypes.fast) { 9 | return config?.["FastSwitchboard"]; 10 | } else if (integrationType === IntegrationTypes.fast2) { 11 | return config?.["FastSwitchboard2"]; 12 | } else if (integrationType === IntegrationTypes.optimistic) { 13 | return config?.["OptimisticSwitchboard"]; 14 | } else 15 | return config?.["integrations"]?.[chainSlug]?.[integrationType]?.[ 16 | "switchboard" 17 | ]; 18 | } 19 | 20 | function getCapacitorAddress( 21 | chainSlug: ChainSlug, 22 | integrationType: IntegrationTypes, 23 | config: any 24 | ) { 25 | return config?.["integrations"]?.[chainSlug]?.[integrationType]?.[ 26 | "capacitor" 27 | ]; 28 | } 29 | 30 | function getDecapacitorAddress( 31 | chainSlug: ChainSlug, 32 | integrationType: IntegrationTypes, 33 | config: any 34 | ) { 35 | return config?.["integrations"]?.[chainSlug]?.[integrationType]?.[ 36 | "decapacitor" 37 | ]; 38 | } 39 | 40 | export { getSwitchboardAddress, getCapacitorAddress, getDecapacitorAddress }; 41 | -------------------------------------------------------------------------------- /scripts/deploy/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./address"; 2 | export * from "./utils"; 3 | export * from "./relayer"; 4 | -------------------------------------------------------------------------------- /scripts/deploy/utils/packetId.ts: -------------------------------------------------------------------------------- 1 | import { BigNumber } from "ethers"; 2 | import { hexZeroPad } from "ethers/lib/utils"; 3 | 4 | interface PackedDetails { 5 | chainSlug: number; 6 | capacitorAddr: string; 7 | packetNonce: string; 8 | } 9 | 10 | export const unpackPacketId = (packetId: BigNumber): PackedDetails => { 11 | const packetIdHex = packetId.toHexString(); 12 | const slugLength = packetIdHex.length - 58; 13 | 14 | const chainSlug = parseInt( 15 | BigNumber.from(`0x${packetIdHex.substring(2, 2 + slugLength)}`).toString() 16 | ); 17 | const capacitorAddr = `0x${packetIdHex.substring( 18 | 2 + slugLength, 19 | 40 + 2 + slugLength 20 | )}`; 21 | const packetNonce = BigNumber.from( 22 | `0x${packetIdHex.substring(40 + 2 + slugLength)}` 23 | ).toString(); 24 | 25 | return { 26 | chainSlug, 27 | capacitorAddr, 28 | packetNonce, 29 | }; 30 | }; 31 | 32 | export const packPacketId = ( 33 | chainSlug: number, 34 | capacitorAddr: string, 35 | packetNonce: string 36 | ): string => { 37 | const nonce = BigNumber.from(packetNonce).toHexString(); 38 | const nonceHex = 39 | nonce.length <= 16 ? hexZeroPad(nonce, 8).substring(2) : nonce.substring(2); 40 | const id = 41 | BigNumber.from(chainSlug).toHexString() + 42 | capacitorAddr.substring(2) + 43 | nonceHex; 44 | 45 | return BigNumber.from(id).toString(); 46 | }; 47 | 48 | export function encodePacketId( 49 | chainSlug: number, 50 | capacitorAddress: string, 51 | packetCount: number 52 | ) { 53 | const encodedValue = 54 | (BigInt(chainSlug) << BigInt(224)) | 55 | (BigInt(capacitorAddress) << BigInt(64)) | 56 | BigInt(packetCount); 57 | 58 | // Ensure the result is a 32-byte hex string (bytes32 in Solidity) 59 | const resultHex = encodedValue.toString(16).padStart(64, "0"); 60 | return "0x" + resultHex; 61 | } 62 | -------------------------------------------------------------------------------- /scripts/deploy/utils/relayer.ts: -------------------------------------------------------------------------------- 1 | import { BigNumber, BigNumberish } from "ethers"; 2 | import { getRelayAPIKEY, getRelayUrl } from "./utils"; 3 | import { axiosPost } from "@socket.tech/dl-common"; 4 | import { mode } from "../config/config"; 5 | import { ChainSlugToId } from "../../../src"; 6 | 7 | interface RequestObj { 8 | to: string; 9 | data: string; 10 | chainSlug: number; 11 | value?: string | BigNumber; 12 | gasPrice?: BigNumberish; 13 | gasLimit?: BigNumberish; 14 | type?: number; 15 | } 16 | 17 | export const relayTx = async (params: RequestObj) => { 18 | try { 19 | let { to, data, chainSlug, gasPrice, value, type, gasLimit } = params; 20 | let url = await getRelayUrl(mode); 21 | let config = { 22 | headers: { 23 | "x-api-key": getRelayAPIKEY(mode), 24 | }, 25 | }; 26 | let body = { 27 | to, 28 | data, 29 | value, 30 | chainId: ChainSlugToId[chainSlug], 31 | gasLimit, 32 | gasPrice, 33 | type, 34 | sequential: false, 35 | source: "LoadTester", 36 | }; 37 | let response = await axiosPost(url!, body, config); 38 | if (response?.success) return response?.data; 39 | else { 40 | console.log("error in relaying tx", response); 41 | return { hash: "" }; 42 | } 43 | } catch (error) { 44 | console.log("uncaught error", error); 45 | } 46 | }; 47 | -------------------------------------------------------------------------------- /scripts/deploy/utils/signature.ts: -------------------------------------------------------------------------------- 1 | import { arrayify, defaultAbiCoder, keccak256 } from "ethers/lib/utils"; 2 | 3 | const createSignature = async (digest, signer) => { 4 | return await signer.signMessage(arrayify(digest)); 5 | }; 6 | 7 | const createDigest = (sigIdentifier, srcSlug, dstSlug, nonce, gasLimit) => { 8 | return keccak256( 9 | defaultAbiCoder.encode( 10 | ["string", "uint256", "uint256", "uint256", "uint256"], 11 | [sigIdentifier, srcSlug, dstSlug, nonce, gasLimit] 12 | ) 13 | ); 14 | }; 15 | 16 | export { createSignature, createDigest }; 17 | -------------------------------------------------------------------------------- /scripts/deploy/utils/socket-signer.ts: -------------------------------------------------------------------------------- 1 | import { SocketSigner } from "@socket.tech/dl-common"; 2 | import { Wallet } from "ethers"; 3 | 4 | import { 5 | ChainSlugToId, 6 | ChainSocketAddresses, 7 | CORE_CONTRACTS, 8 | } from "../../../src"; 9 | import { getProviderFromChainSlug } from "../../constants"; 10 | import { getRelayAPIKEY, getRelayUrl } from "./utils"; 11 | import { mode } from "../config/config"; 12 | 13 | export const getSocketSigner = async ( 14 | chainSlug: number, 15 | addresses: ChainSocketAddresses, 16 | useSafe: boolean = false, 17 | useEOA: boolean = true 18 | ): Promise => { 19 | const provider = getProviderFromChainSlug(chainSlug); 20 | const wallet: Wallet = new Wallet( 21 | process.env.SOCKET_SIGNER_KEY as string, 22 | provider 23 | ); 24 | 25 | const safeAddress = 26 | addresses["SocketSafeProxy"] && useSafe ? addresses["SocketSafeProxy"] : ""; 27 | const safeWrapperAddress = 28 | addresses["SocketSafeProxy"] && useSafe 29 | ? addresses[CORE_CONTRACTS.MultiSigWrapper] 30 | : ""; 31 | 32 | return new SocketSigner( 33 | provider, 34 | ChainSlugToId[chainSlug], 35 | safeAddress, 36 | safeWrapperAddress, 37 | await getRelayUrl(mode), 38 | getRelayAPIKEY(mode), 39 | wallet, 40 | useSafe, 41 | useEOA 42 | ); 43 | }; 44 | -------------------------------------------------------------------------------- /scripts/deploy/verify.ts: -------------------------------------------------------------------------------- 1 | import hre from "hardhat"; 2 | import fs from "fs"; 3 | 4 | import { deploymentsPath, storeUnVerifiedParams, verify } from "./utils/utils"; 5 | import { mode } from "./config/config"; 6 | import { HardhatChainName, ChainSlugToKey, ChainSlug } from "../../src"; 7 | 8 | export type VerifyParams = { 9 | [chain in HardhatChainName]?: VerifyArgs[]; 10 | }; 11 | export type VerifyArgs = [string, string, string, any[]]; 12 | 13 | /** 14 | * Deploys network-independent socket contracts 15 | */ 16 | export const main = async () => { 17 | try { 18 | const path = deploymentsPath + `${mode}_verification.json`; 19 | if (!fs.existsSync(path)) { 20 | throw new Error("addresses.json not found"); 21 | } 22 | let verificationParams: VerifyParams = JSON.parse( 23 | fs.readFileSync(path, "utf-8") 24 | ); 25 | 26 | const chains = Object.keys(verificationParams); 27 | if (!chains) return; 28 | 29 | for (let chainIndex = 0; chainIndex < chains.length; chainIndex++) { 30 | const chain = parseInt(chains[chainIndex]) as ChainSlug; 31 | 32 | hre.changeNetwork(ChainSlugToKey[chain]); 33 | const chainParams: VerifyArgs[] = verificationParams[chain]; 34 | const unverifiedChainParams: VerifyArgs[] = []; 35 | if (chainParams.length) { 36 | const len = chainParams.length; 37 | for (let index = 0; index < len!; index++) { 38 | const res = await verify(...chainParams[index]); 39 | if (!res) { 40 | unverifiedChainParams.push(chainParams[index]); 41 | } 42 | } 43 | } 44 | 45 | await storeUnVerifiedParams(unverifiedChainParams, chain, mode); 46 | } 47 | } catch (error) { 48 | console.log("Error in verifying contracts", error); 49 | } 50 | }; 51 | 52 | main() 53 | .then(() => process.exit(0)) 54 | .catch((error: Error) => { 55 | console.error(error); 56 | process.exit(1); 57 | }); 58 | -------------------------------------------------------------------------------- /scripts/deploy/writeChainConfig.ts: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | import fs from "fs"; 3 | import { addChainToSDK } from "./single-click-deploy/integrators/writeConfigs"; 4 | import { updateConstants } from "../rpcConfig/updateConstants"; 5 | 6 | const configFilePath = path.join(__dirname, `/../../`); 7 | const configPath = configFilePath + ".env"; 8 | const configExamplePath = configFilePath + ".env.example"; 9 | 10 | const main = async () => { 11 | try { 12 | const { response, isAlreadyAdded } = await addChainToSDK(); 13 | if (!isAlreadyAdded) { 14 | await updateConstants( 15 | response.chainName, 16 | response.explorer, 17 | response.icon 18 | ); 19 | } 20 | 21 | appendToEnvFile( 22 | configPath, 23 | `${response.chainName.toUpperCase()}_RPC`, 24 | `\n${response.chainName.toUpperCase()}_RPC=${response.rpc}\n`, 25 | ".env" 26 | ); 27 | appendToEnvFile( 28 | configExamplePath, 29 | `${response.chainName.toUpperCase()}_RPC`, 30 | `\n${response.chainName.toUpperCase()}_RPC=' '\n`, 31 | ".env.example" 32 | ); 33 | } catch (error) { 34 | console.log("Error:", error); 35 | } 36 | }; 37 | 38 | async function appendToEnvFile(path, key, stringToAppend, fileName) { 39 | try { 40 | let configsString = ""; 41 | const outputExists = fs.existsSync(path); 42 | 43 | if (outputExists) { 44 | configsString = fs.readFileSync(path, "utf-8"); 45 | const envObject = parseEnvFile(path); 46 | const keys = Object.keys(envObject).filter((k) => k === key); 47 | if (keys.length > 0) return; 48 | } 49 | 50 | configsString = configsString + stringToAppend; 51 | 52 | fs.writeFileSync(path, configsString); 53 | console.log("Created env"); 54 | } catch (error) { 55 | console.log(error); 56 | } 57 | } 58 | 59 | export const parseEnvFile = (filePath) => { 60 | try { 61 | // Read the file content 62 | const content = fs.readFileSync(filePath, { encoding: "utf-8" }); 63 | const envObject = {}; 64 | 65 | // Split content into lines 66 | content.split(/\r?\n/).forEach((line) => { 67 | // Remove leading and trailing whitespaces 68 | line = line.trim(); 69 | 70 | // Ignore empty lines and lines starting with `#` (comments) 71 | if (line !== "" && !line.startsWith("#")) { 72 | // Split the line into key and value by the first `=` 73 | let [key, ...value] = line.split("="); 74 | key = key.trim(); 75 | let finalValue = value.join("=").trim(); // Join back the value in case it contains `=` 76 | if ( 77 | (finalValue.startsWith('"') && finalValue.endsWith('"')) || 78 | (finalValue.startsWith("'") && finalValue.endsWith("'")) 79 | ) { 80 | finalValue = finalValue.substring(1, finalValue.length - 1); 81 | } 82 | // Only add to the object if the key is not empty 83 | if (key) { 84 | envObject[key] = finalValue; 85 | } 86 | } 87 | }); 88 | 89 | return envObject; 90 | } catch (error) { 91 | console.error("Failed to read the .env file:", error); 92 | return {}; 93 | } 94 | }; 95 | 96 | main() 97 | .then(() => process.exit(0)) 98 | .catch((error: Error) => { 99 | console.error(error); 100 | process.exit(1); 101 | }); 102 | -------------------------------------------------------------------------------- /scripts/depositEthToOpstackChain.ts: -------------------------------------------------------------------------------- 1 | import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers"; 2 | import { ethers } from "hardhat"; 3 | 4 | // const l1StandardBridgeProxy = "0x4082C9647c098a6493fb499EaE63b5ce3259c574"; // aevo 5 | const l1StandardBridgeProxy = "0x61E44dC0dae6888B5a301887732217d5725B0bFf"; // lyra 6 | 7 | const value = "1900000000000000000"; // 0.1 eth 8 | // const value = "0"; // 0.1 eth 9 | 10 | const deposit = async () => { 11 | const socketSigners: SignerWithAddress[] = await ethers.getSigners(); 12 | const socketSigner: SignerWithAddress = socketSigners[0]; 13 | const tx = await socketSigner.sendTransaction({ 14 | to: l1StandardBridgeProxy, 15 | data: "0xb1a1a8820000000000000000000000000000000000000000000000000000000000030d4000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000", 16 | value, 17 | type: 1, 18 | gasPrice: 32_000_000_000, 19 | // nonce: 450, 20 | }); 21 | console.log(tx.hash); 22 | await tx.wait(); 23 | console.log("done"); 24 | }; 25 | 26 | deposit() 27 | .then(() => process.exit(0)) 28 | .catch((error: Error) => { 29 | console.error(error); 30 | process.exit(1); 31 | }); 32 | -------------------------------------------------------------------------------- /scripts/limits-updater/initLimits.ts: -------------------------------------------------------------------------------- 1 | import { config as dotenvConfig } from "dotenv"; 2 | dotenvConfig(); 3 | 4 | import { 5 | ChainAddresses, 6 | ChainSocketAddresses, 7 | Integrations, 8 | ChainSlug, 9 | } from "../../src"; 10 | import { getAddresses } from "../deploy/utils"; 11 | import { mode } from "../deploy/config/config"; 12 | 13 | export const setLimitsForAChainSlug = async (chainSlugCode: ChainSlug) => { 14 | try { 15 | console.log(`setting initLimits for chainSlug: ${chainSlugCode}`); 16 | 17 | const deployedAddressConfig = (await getAddresses( 18 | chainSlugCode, 19 | mode 20 | )) as ChainSocketAddresses; 21 | 22 | console.log( 23 | `deployedAddressConfig are: ${JSON.stringify(deployedAddressConfig)}` 24 | ); 25 | 26 | const integrations: Integrations = 27 | deployedAddressConfig.integrations as Integrations; 28 | 29 | console.log(`integrations are: ${JSON.stringify(integrations)}`); 30 | 31 | //get TransmitManager Address 32 | const transmitManagerAddress = 33 | deployedAddressConfig.TransmitManager as string; 34 | 35 | if (integrations) { 36 | console.log(`For sourceChainId: ${chainSlugCode} \n`); 37 | 38 | const keys = Object.keys(integrations); 39 | const values = Object.values(integrations); 40 | 41 | for (let i = 0; i < keys.length; i++) { 42 | const key = keys[i].toString(); 43 | const dstChainId = parseInt(key); 44 | const chainAddresses: ChainAddresses = values[i]; 45 | 46 | const chainSlugCode = "optimism-goerli"; 47 | } 48 | 49 | console.log(`-------------------------------------\n\n`); 50 | } 51 | } catch (error) { 52 | console.log("Error while sending transaction", error); 53 | throw error; 54 | } 55 | }; 56 | 57 | // npx ts-node scripts/limits-updater/initLimits.ts 58 | export const setLimits = async () => { 59 | try { 60 | setLimitsForAChainSlug(ChainSlug.OPTIMISM_GOERLI); 61 | } catch (error) { 62 | console.log("Error while sending transaction", error); 63 | throw error; 64 | } 65 | }; 66 | 67 | setLimits() 68 | .then(() => process.exit(0)) 69 | .catch((error: Error) => { 70 | console.error(error); 71 | process.exit(1); 72 | }); 73 | -------------------------------------------------------------------------------- /scripts/limits-updater/query/get-integrations.ts: -------------------------------------------------------------------------------- 1 | import { config as dotenvConfig } from "dotenv"; 2 | dotenvConfig(); 3 | 4 | import { ChainSocketAddresses, ChainSlug } from "../../../src"; 5 | import { getAddresses } from "../../deploy/utils"; 6 | import { mode } from "../../deploy/config/config"; 7 | 8 | // npx ts-node scripts/deploy/get-integrations.ts 9 | export const getIntegrationsForAChainSlug = async (chainSlug: ChainSlug) => { 10 | const deployedAddressConfig: ChainSocketAddresses = (await getAddresses( 11 | chainSlug, 12 | mode 13 | )) as ChainSocketAddresses; 14 | 15 | console.log( 16 | `for chainSlugCode: ${chainSlug} , looked-up deployedAddressConfigs: ${JSON.stringify( 17 | deployedAddressConfig 18 | )}` 19 | ); 20 | }; 21 | 22 | // npx ts-node scripts/limits-updater/query/get-integrations.ts 23 | export const getIntegrations = async () => { 24 | try { 25 | getIntegrationsForAChainSlug(ChainSlug.ARBITRUM_GOERLI); 26 | } catch (error) { 27 | console.log("Error while sending transaction", error); 28 | throw error; 29 | } 30 | }; 31 | 32 | getIntegrations() 33 | .then(() => process.exit(0)) 34 | .catch((error: Error) => { 35 | console.error(error); 36 | process.exit(1); 37 | }); 38 | -------------------------------------------------------------------------------- /scripts/limits-updater/query/query-all-integrations.ts: -------------------------------------------------------------------------------- 1 | import { config as dotenvConfig } from "dotenv"; 2 | dotenvConfig(); 3 | 4 | import { 5 | ChainAddresses, 6 | ChainSocketAddresses, 7 | Configs, 8 | Integrations, 9 | } from "../../../src"; 10 | import { 11 | getAddresses, 12 | getChainSlugsFromDeployedAddresses, 13 | } from "../../deploy/utils"; 14 | import { mode } from "../../deploy/config/config"; 15 | 16 | // npx ts-node scripts/limits-updater/query-all-integrations.ts 17 | export const main = async () => { 18 | const chainSlugsDecoded: string[] = (await getChainSlugsFromDeployedAddresses( 19 | mode 20 | )) as string[]; 21 | 22 | console.log(`-------------------------------------\n\n`); 23 | 24 | for (let slugIndex = 0; slugIndex < chainSlugsDecoded.length; slugIndex++) { 25 | const chainSlug = parseInt(chainSlugsDecoded[slugIndex]); 26 | 27 | const addresses = (await getAddresses( 28 | chainSlug, 29 | mode 30 | )) as ChainSocketAddresses; 31 | 32 | const integrations: Integrations = addresses.integrations as Integrations; 33 | 34 | const transmitManager: string = addresses.TransmitManager as string; 35 | 36 | if (integrations) { 37 | console.log(`For sourceChainId: ${chainSlug} \n`); 38 | 39 | const keys = Object.keys(integrations); 40 | const values = Object.values(integrations); 41 | 42 | for (let i = 0; i < keys.length; i++) { 43 | const key = keys[i].toString(); 44 | const chainAddresses: ChainAddresses = values[i]; 45 | 46 | console.log(`for remoteChainId: ${key}`); 47 | 48 | if (chainAddresses.FAST) { 49 | const config: Configs = chainAddresses.FAST as Configs; 50 | console.log(`FAST Switchboard address is: ${config.switchboard}`); 51 | } 52 | 53 | if (chainAddresses.OPTIMISTIC) { 54 | const config: Configs = chainAddresses.OPTIMISTIC as Configs; 55 | console.log( 56 | `Optimistic Switchboard address is: ${config.switchboard}` 57 | ); 58 | } 59 | 60 | if (chainAddresses.NATIVE_BRIDGE) { 61 | const config: Configs = chainAddresses.NATIVE_BRIDGE as Configs; 62 | console.log(`Native Switchboard address is: ${config.switchboard}`); 63 | } 64 | } 65 | 66 | console.log(`-------------------------------------\n\n`); 67 | } 68 | } 69 | }; 70 | 71 | main() 72 | .then(() => process.exit(0)) 73 | .catch((error: Error) => { 74 | console.error(error); 75 | process.exit(1); 76 | }); 77 | -------------------------------------------------------------------------------- /scripts/limits-updater/query/query-relayer-config.ts: -------------------------------------------------------------------------------- 1 | import { ChainSlug } from "@socket.tech/dl-core"; 2 | import { loadRelayerConfigs } from "../utils/relayer.config"; 3 | 4 | // npx ts-node scripts/query-relayer-config.ts 5 | export const main = async () => { 6 | const relayerConfigs = loadRelayerConfigs(); 7 | console.log(`relayerConfigs: ${relayerConfigs.size}`); 8 | console.log( 9 | `relayerConfig value: ${JSON.stringify( 10 | relayerConfigs.get(ChainSlug.ARBITRUM) 11 | )}` 12 | ); 13 | }; 14 | 15 | main() 16 | .then(() => process.exit(0)) 17 | .catch((error: Error) => { 18 | console.error(error); 19 | process.exit(1); 20 | }); 21 | -------------------------------------------------------------------------------- /scripts/limits-updater/utils/relayer.config.ts: -------------------------------------------------------------------------------- 1 | import { RelayerConfig, relayTxSpeed } from "./types"; 2 | import { Signer } from "ethers"; 3 | import { config as dotenvConfig } from "dotenv"; 4 | import { resolve } from "path"; 5 | import { StaticJsonRpcProvider } from "@ethersproject/providers"; 6 | import { DefenderRelaySigner } from "defender-relay-client/lib/ethers"; 7 | import { getJsonRpcUrl } from "../../constants"; 8 | import { ChainSlugToKey } from "../../../src"; 9 | const dotenvConfigPath: string = 10 | process.env.DOTENV_CONFIG_PATH || "../../../.env"; 11 | dotenvConfig({ path: resolve(__dirname, dotenvConfigPath) }); 12 | 13 | export const loadRelayerConfigs = (): Map => { 14 | const relayerConfigs: Map = new Map< 15 | number, 16 | RelayerConfig 17 | >(); 18 | 19 | const rpcs = (process.env.RPC_LIST || "").split(",") as string[]; 20 | const ozRelayerKeys = (process.env.OZ_RELAYER_KEY_LIST || "").split( 21 | "," 22 | ) as string[]; 23 | const ozRelayerSecrets = (process.env.OZ_RELAYER_SECRET_LIST || "").split( 24 | "," 25 | ) as string[]; 26 | 27 | const chains: string[] = (process.env.CHAIN_LIST || "").split( 28 | "," 29 | ) as string[]; 30 | 31 | if ( 32 | rpcs.length !== chains.length || 33 | ozRelayerKeys.length !== chains.length || 34 | ozRelayerSecrets.length !== chains.length 35 | ) { 36 | throw new Error("Configs length don't match chain list length"); 37 | } 38 | 39 | chains.map(async (chain, index) => { 40 | relayerConfigs.set(parseInt(chain), { 41 | chainId: parseInt(chain), 42 | rpc: rpcs[index], 43 | ozRelayerKey: ozRelayerKeys[index], 44 | ozRelayerSecret: ozRelayerSecrets[index], 45 | }); 46 | }); 47 | 48 | return relayerConfigs; 49 | }; 50 | 51 | const relayerConfigs: Map = loadRelayerConfigs(); 52 | 53 | export const getRpcProvider = (chainSlug: number) => { 54 | return new StaticJsonRpcProvider(getJsonRpcUrl(ChainSlugToKey[chainSlug])); 55 | }; 56 | 57 | export const getSigner = (chainSlug: number) => { 58 | //get RelayerConfig for the chainId 59 | const relayerConfig: RelayerConfig = relayerConfigs.get( 60 | chainSlug 61 | ) as RelayerConfig; 62 | 63 | const provider: StaticJsonRpcProvider = new StaticJsonRpcProvider( 64 | relayerConfig.rpc 65 | ); 66 | 67 | const signer: Signer = new DefenderRelaySigner( 68 | { 69 | apiKey: relayerConfig.ozRelayerKey, 70 | apiSecret: relayerConfig.ozRelayerSecret, 71 | }, 72 | provider, 73 | { speed: relayTxSpeed } 74 | ); 75 | 76 | return signer; 77 | }; 78 | -------------------------------------------------------------------------------- /scripts/limits-updater/utils/transaction-helper.ts: -------------------------------------------------------------------------------- 1 | import { getRpcProvider } from "./relayer.config"; 2 | 3 | export const getTransactionReceipt = async ( 4 | transactionHash: string, 5 | chainSlug: number 6 | ) => { 7 | return await getRpcProvider(chainSlug).getTransaction(transactionHash); 8 | }; 9 | 10 | export const isTransactionSuccessful = async ( 11 | transactionHash: string, 12 | chainSlug: number 13 | ) => { 14 | const txReceipt: any = await getRpcProvider(chainSlug).getTransaction( 15 | transactionHash 16 | ); 17 | return txReceipt.status == 1 ? true : false; 18 | }; 19 | -------------------------------------------------------------------------------- /scripts/limits-updater/utils/types.ts: -------------------------------------------------------------------------------- 1 | import { ChainSlug } from "../../../src/types"; 2 | 3 | export type Speed = "safeLow" | "average" | "fast" | "fastest"; 4 | 5 | export const relayTxSpeed: Speed = 6 | (process.env.RELAY_TX_SPEED as Speed) || "fast"; 7 | 8 | export interface RelayerConfig { 9 | chainId: ChainSlug; 10 | rpc: string; 11 | ozRelayerKey: string; 12 | ozRelayerSecret: string; 13 | } 14 | -------------------------------------------------------------------------------- /scripts/native-bridge-helpers/arbitrum/l2tol1Relay.ts: -------------------------------------------------------------------------------- 1 | import { config as dotenvConfig } from "dotenv"; 2 | dotenvConfig(); 3 | 4 | import { providers, Wallet } from "ethers"; 5 | import { getJsonRpcUrl } from "../../constants"; 6 | import { L2ToL1MessageStatus, L2TransactionReceipt } from "@arbitrum/sdk"; 7 | import { 8 | HardhatChainName, 9 | hardhatChainNameToSlug, 10 | getAllAddresses, 11 | } from "../../../src"; 12 | 13 | // https://goerli.arbiscan.io/txsExit to check message status 14 | const l1Chain = HardhatChainName.GOERLI; 15 | const l2Chain = HardhatChainName.ARBITRUM_GOERLI; 16 | const sealTxHash = 17 | "0x0113020a1e3b9f814a78791b9719bf583bb0f25075cde1e754af99f1dcf137a7"; 18 | 19 | import { mode } from "../../deploy/config/config"; 20 | 21 | const walletPrivateKey = process.env.SOCKET_SIGNER_KEY!; 22 | const l1Provider = new providers.JsonRpcProvider(getJsonRpcUrl(l1Chain)); 23 | const l2Provider = new providers.JsonRpcProvider(getJsonRpcUrl(l2Chain)); 24 | 25 | const l1Wallet = new Wallet(walletPrivateKey, l1Provider); 26 | 27 | // usage: npx hardhat run scripts/native-bridge-helpers/arbitrum/l2tol1Relay.ts 28 | export const main = async () => { 29 | try { 30 | const addresses = getAllAddresses(mode); 31 | if ( 32 | !addresses[hardhatChainNameToSlug[l1Chain]] || 33 | !addresses[hardhatChainNameToSlug[l2Chain]] 34 | ) { 35 | throw new Error("Deployed Addresses not found"); 36 | } 37 | 38 | const receipt = await l2Provider.getTransactionReceipt(sealTxHash); 39 | const l2Receipt = new L2TransactionReceipt(receipt); 40 | 41 | /** 42 | * Note that in principle, a single transaction could trigger any number of outgoing messages; the common case will be there's only one. 43 | * For the sake of this script, we assume there's only one / just grad the first one. 44 | */ 45 | const messages = await l2Receipt.getL2ToL1Messages(l1Wallet); 46 | const l2ToL1Msg = messages[0]; 47 | 48 | const status = await l2ToL1Msg.status(l2Provider); 49 | console.log(status, ": status (0- unconfirmed, 1- confirmed, 2- executed)"); 50 | /** 51 | * Check if already executed 52 | */ 53 | if (status == L2ToL1MessageStatus.EXECUTED) { 54 | console.log(`Message already executed! Nothing else to do here`); 55 | process.exit(1); 56 | } 57 | 58 | /** 59 | * before we try to execute out message, we need to make sure the l2 block it's included in is confirmed! (It can only be confirmed after the dispute period; Arbitrum is an optimistic rollup after-all) 60 | * waitUntilReadyToExecute() waits until the item outbox entry exists 61 | */ 62 | const timeToWaitMs = 1000 * 60; 63 | console.log( 64 | "Waiting for the outbox entry to be created. This only happens when the L2 block is confirmed on L1, ~1 week after it's creation." 65 | ); 66 | await l2ToL1Msg.waitUntilReadyToExecute(l2Provider, timeToWaitMs); 67 | console.log("Outbox entry exists! Trying to execute now"); 68 | 69 | /** 70 | * Now that its confirmed and not executed, we can execute our message in its outbox entry. 71 | */ 72 | const res = await l2ToL1Msg.execute(l2Provider); 73 | const rec = await res.wait(); 74 | console.log("Done! Your transaction is executed", rec); 75 | } catch (error) { 76 | console.log("Error while sending transaction", error); 77 | throw error; 78 | } 79 | }; 80 | 81 | main() 82 | .then(() => process.exit(0)) 83 | .catch((error: Error) => { 84 | console.error(error); 85 | process.exit(1); 86 | }); 87 | -------------------------------------------------------------------------------- /scripts/native-bridge-helpers/optimism/l2tol1Relay.ts: -------------------------------------------------------------------------------- 1 | import { providers, Wallet } from "ethers"; 2 | import { CrossChainMessenger, MessageStatus } from "@eth-optimism/sdk"; 3 | import { getJsonRpcUrl } from "../../constants"; 4 | import { HardhatChainName, ChainId } from "../../../src"; 5 | 6 | // get providers for source and destination 7 | const l1ChainId = ChainId.SEPOLIA; 8 | const l2ChainId = ChainId.OPTIMISM_SEPOLIA; 9 | 10 | const walletPrivateKey = process.env.SOCKET_SIGNER_KEY!; 11 | const l1Provider = new providers.JsonRpcProvider(getJsonRpcUrl(l1ChainId)); 12 | const l1Wallet = new Wallet(walletPrivateKey, l1Provider); 13 | 14 | const sealTxHash = ""; 15 | 16 | export const main = async () => { 17 | const crossChainMessenger = new CrossChainMessenger({ 18 | l1ChainId, 19 | l2ChainId, 20 | l1SignerOrProvider: l1Wallet, 21 | l2SignerOrProvider: new providers.JsonRpcProvider(getJsonRpcUrl(l2ChainId)), 22 | }); 23 | 24 | const status = await crossChainMessenger.getMessageStatus(sealTxHash); 25 | 26 | if (MessageStatus.READY_TO_PROVE === status) { 27 | const tx = await crossChainMessenger.proveMessage(sealTxHash); 28 | await tx.wait(); 29 | console.log("Message proved", tx.hash); 30 | } else if (MessageStatus.READY_FOR_RELAY === status) { 31 | const tx = await crossChainMessenger.finalizeMessage(sealTxHash); 32 | await tx.wait(); 33 | console.log("Message finalized", tx.hash); 34 | } else if (MessageStatus.RELAYED === status) { 35 | console.log("Message relayed"); 36 | } else { 37 | console.log(`Message is in ${status} status`); 38 | } 39 | }; 40 | 41 | // npx ts-node scripts/native-bridge-helpers/optimism/l2tol1Relay.ts 42 | main() 43 | .then(() => process.exit(0)) 44 | .catch((error: Error) => { 45 | console.error(error); 46 | process.exit(1); 47 | }); 48 | -------------------------------------------------------------------------------- /scripts/native-bridge-helpers/optimism/op-stack-native-withdrawals.ts: -------------------------------------------------------------------------------- 1 | import { config as dotenvConfig } from "dotenv"; 2 | 3 | import { constants, providers, Wallet } from "ethers"; 4 | import { CrossChainMessenger, MessageStatus } from "@eth-optimism/sdk"; 5 | import { getJsonRpcUrl } from "../../constants"; 6 | import { ChainId } from "../../../src"; 7 | import { resolve } from "path"; 8 | import axios from "axios"; 9 | 10 | const dotenvConfigPath: string = 11 | process.env.DOTENV_CONFIG_PATH || "../../../.env"; 12 | dotenvConfig({ path: resolve(__dirname, dotenvConfigPath) }); 13 | 14 | // get providers for source and destination 15 | const l1Chain = ChainId.SEPOLIA; 16 | const l2Chain = ChainId.LYRA_TESTNET; 17 | const configLink = 18 | "https://api.conduit.xyz/file/getOptimismContractsJSON?network=fc538f39-aed2-48aa-a4ff-d733dd3be1e6&organization=9353f461-a1a4-4fb4-80de-90587a32f4b1"; 19 | const initTxHash = 20 | "0x373611163c75ca063aae79fc7a8ef4a9d8e66603cc92997cbbcd2a18cbbcde37"; 21 | 22 | const walletPrivateKey = process.env.SOCKET_SIGNER_KEY!; 23 | const l1Provider = new providers.JsonRpcProvider(getJsonRpcUrl(l1Chain)); 24 | const l2Provider = new providers.JsonRpcProvider(getJsonRpcUrl(l2Chain)); 25 | 26 | const l1Wallet = new Wallet(walletPrivateKey, l1Provider); 27 | 28 | export const main = async () => { 29 | const { data } = await axios.get(configLink); 30 | const crossChainMessenger = new CrossChainMessenger({ 31 | contracts: { 32 | l1: { 33 | StateCommitmentChain: constants.AddressZero, 34 | CanonicalTransactionChain: constants.AddressZero, 35 | BondManager: constants.AddressZero, 36 | AddressManager: data["AddressManager"], 37 | L1CrossDomainMessenger: data["L1CrossDomainMessengerProxy"], 38 | L1StandardBridge: data["L1StandardBridgeProxy"], 39 | OptimismPortal: data["OptimismPortalProxy"], 40 | L2OutputOracle: data["L2OutputOracleProxy"], 41 | }, 42 | }, 43 | l1ChainId: l1Chain, 44 | l2ChainId: l2Chain, 45 | l1SignerOrProvider: l1Wallet, 46 | l2SignerOrProvider: l2Provider, 47 | bedrock: true, 48 | }); 49 | 50 | const status = await crossChainMessenger.getMessageStatus(initTxHash); 51 | 52 | if (MessageStatus.READY_TO_PROVE === status) { 53 | console.log(`Message is ready to prove`); 54 | const tx = await crossChainMessenger.proveMessage(initTxHash); 55 | await tx.wait(); 56 | console.log("Message proved", tx.hash); 57 | } else if (MessageStatus.READY_FOR_RELAY === status) { 58 | console.log(`Message is ready for relay`); 59 | const tx = await crossChainMessenger.finalizeMessage(initTxHash); 60 | await tx.wait(); 61 | console.log("Message finalized", tx.hash); 62 | } else if (MessageStatus.RELAYED === status) { 63 | console.log("Message relayed"); 64 | } else { 65 | console.log(`status: ${status}`); 66 | } 67 | }; 68 | 69 | main() 70 | .then(() => process.exit(0)) 71 | .catch((error: Error) => { 72 | console.error(error); 73 | process.exit(1); 74 | }); 75 | -------------------------------------------------------------------------------- /scripts/rpcConfig/constants/batcherSupportedChainSlug.ts: -------------------------------------------------------------------------------- 1 | import { ChainSlug } from "../../../src"; 2 | 3 | export const batcherSupportedChainSlugs = [ 4 | ChainSlug.AEVO, 5 | ChainSlug.ARBITRUM, 6 | ChainSlug.OPTIMISM, 7 | ChainSlug.BSC, 8 | ChainSlug.POLYGON_MAINNET, 9 | ChainSlug.LYRA, 10 | ChainSlug.MAINNET, 11 | ChainSlug.MANTLE, 12 | ChainSlug.REYA, 13 | // ChainSlug.SX_NETWORK, 14 | // ChainSlug.AEVO_TESTNET, 15 | ChainSlug.SEPOLIA, 16 | ChainSlug.LYRA_TESTNET, 17 | // ChainSlug.SX_NETWORK_TESTNET, 18 | ChainSlug.ARBITRUM_SEPOLIA, 19 | ChainSlug.OPTIMISM_SEPOLIA, 20 | // ChainSlug.MODE_TESTNET, 21 | ChainSlug.BASE, 22 | ChainSlug.MODE, 23 | ChainSlug.REYA_CRONOS, 24 | ChainSlug.SYNDR_SEPOLIA_L3, 25 | ChainSlug.POLYNOMIAL_TESTNET, 26 | // ChainSlug.BOB, 27 | ChainSlug.KINTO, 28 | // ChainSlug.KINTO_DEVNET, 29 | // ChainSlug.SIPHER_FUNKI_TESTNET, 30 | ChainSlug.WINR, 31 | ChainSlug.BLAST, 32 | // ChainSlug.BSC_TESTNET, 33 | ChainSlug.POLYNOMIAL, 34 | ChainSlug.SYNDR, 35 | // ChainSlug.NEOX_TESTNET, 36 | // ChainSlug.NEOX_T4_TESTNET, 37 | ChainSlug.NEOX, 38 | ChainSlug.GNOSIS, 39 | ChainSlug.LINEA, 40 | ChainSlug.ZKEVM, 41 | ChainSlug.AVALANCHE, 42 | // ChainSlug.XLAYER, 43 | // ChainSlug.MANTA_PACIFIC, 44 | // ChainSlug.POLTER_TESTNET, 45 | // ChainSlug.POLYGON_AMOY, 46 | // ChainSlug.OPBNB, 47 | // ChainSlug.GEIST, 48 | // ChainSlug.ZERO_SEPOLIA, 49 | ChainSlug.ZERO, 50 | ChainSlug.ZKSYNC, 51 | // ChainSlug.ARENA_Z, 52 | ChainSlug.INK, 53 | ChainSlug.SONIC, 54 | // ChainSlug.BASE_SEPOLIA, 55 | ChainSlug.BERA, 56 | ChainSlug.B3, 57 | ChainSlug.UNICHAIN, 58 | // ChainSlug.MONAD_TESTNET, 59 | ChainSlug.SCROLL, 60 | ChainSlug.SONEIUM, 61 | ChainSlug.SWELLCHAIN, 62 | ChainSlug.WORLD_CHAIN, 63 | ChainSlug.PLUME, 64 | ChainSlug.KATANA, 65 | ]; 66 | -------------------------------------------------------------------------------- /scripts/rpcConfig/constants/defaultFinalityBucket.ts: -------------------------------------------------------------------------------- 1 | import { ChainSlug } from "../../../src/enums/chainSlug"; 2 | 3 | import { FinalityBucket } from "../../../src/socket-types"; 4 | 5 | export const getDefaultFinalityBucket = ( 6 | chainSlug: ChainSlug 7 | ): FinalityBucket => { 8 | return defaultFinalityBucket[chainSlug] ?? FinalityBucket.low; 9 | }; 10 | 11 | export const defaultFinalityBucket = { 12 | [ChainSlug.POLYGON_MAINNET]: FinalityBucket.medium, 13 | }; 14 | -------------------------------------------------------------------------------- /scripts/rpcConfig/constants/disabledDFFeeChains.ts: -------------------------------------------------------------------------------- 1 | import { ChainSlug } from "../../../src"; 2 | 3 | export const disabledDFFeeChains = [ 4 | // ChainSlug.AEVO, 5 | // ChainSlug.ARBITRUM, 6 | // ChainSlug.OPTIMISM, 7 | // ChainSlug.BSC, 8 | // ChainSlug.POLYGON_MAINNET, 9 | // ChainSlug.LYRA, 10 | // ChainSlug.MAINNET, 11 | // ChainSlug.MANTLE, 12 | // ChainSlug.REYA, 13 | // ChainSlug.BASE, 14 | // ChainSlug.KINTO, 15 | // ChainSlug.WINR, 16 | // ChainSlug.BLAST, 17 | // ChainSlug.POLYNOMIAL, 18 | // ChainSlug.SYNDR, 19 | ]; 20 | -------------------------------------------------------------------------------- /scripts/rpcConfig/constants/explorers.ts: -------------------------------------------------------------------------------- 1 | import { ChainSlug } from "../../../src"; 2 | 3 | export const explorers = { 4 | [ChainSlug.AEVO]: "https://explorer.aevo.xyz", 5 | [ChainSlug.LYRA]: "https://explorer.lyra.finance", 6 | [ChainSlug.MANTLE]: "https://explorer.mantle.xyz", 7 | [ChainSlug.REYA]: "https://explorer.reya.network", 8 | [ChainSlug.SIPHER_FUNKI_TESTNET]: "https://sepolia-sandbox.funkichain.com", 9 | [ChainSlug.WINR]: "https://explorerl2new-winr-mainnet-0.t.conduit.xyz", 10 | [ChainSlug.BLAST]: "https://blastscan.io", 11 | [ChainSlug.BSC_TESTNET]: "https://testnet.bscscan.com/", 12 | [ChainSlug.POLYNOMIAL]: "https://explorer.polynomial.fi", 13 | [ChainSlug.SYNDR]: "https://explorer.syndr.com/", 14 | [ChainSlug.NEOX_TESTNET]: "https://xt3scan.ngd.network/", 15 | [ChainSlug.NEOX_T4_TESTNET]: "https://xt4scan.ngd.network/", 16 | [ChainSlug.NEOX]: "https://xexplorer.neo.org", 17 | [ChainSlug.GNOSIS]: "https://gnosisscan.io/", 18 | [ChainSlug.LINEA]: "https://lineascan.build/", 19 | [ChainSlug.ZKEVM]: "https://zkevm.polygonscan.com/", 20 | [ChainSlug.AVALANCHE]: "https://snowtrace.io/", 21 | [ChainSlug.XLAYER]: "https://www.okx.com/web3/explorer/xlayer", 22 | [ChainSlug.MANTA_PACIFIC]: "https://pacific-explorer.manta.network/", 23 | [ChainSlug.POLTER_TESTNET]: "https://polter-testnet.explorer.alchemy.com/", 24 | [ChainSlug.POLYGON_AMOY]: "https://amoy.polygonscan.com/", 25 | [ChainSlug.OPBNB]: "https://opbnb.bscscan.com/", 26 | [ChainSlug.GEIST]: "https://geist-mainnet.explorer.alchemy.com/", 27 | [ChainSlug.ZERO_SEPOLIA]: "https://explorer.zero.network/", 28 | [ChainSlug.ZERO]: "https://zerion-explorer.vercel.app/", 29 | [ChainSlug.ZKSYNC]: "https://explorer.zksync.io/", 30 | [ChainSlug.ARENA_Z]: "https://explorer.arena-z.gg/", 31 | [ChainSlug.INK]: "https://explorer.inkonchain.com/", 32 | [ChainSlug.SONIC]: "https://sonicscan.org/", 33 | [ChainSlug.BASE_SEPOLIA]: "https://sepolia.basescan.org/", 34 | [ChainSlug.BERA]: "https://berascan.com/", 35 | [ChainSlug.B3]: "https://explorer.b3.fun/", 36 | [ChainSlug.UNICHAIN]: "https://unichain.blockscout.com/", 37 | [ChainSlug.MONAD_TESTNET]: "https://monad-testnet.socialscan.io/", 38 | [ChainSlug.SCROLL]: "https://scrollscan.com/", 39 | [ChainSlug.SONEIUM]: "https://soneium.blockscout.com/", 40 | [ChainSlug.SWELLCHAIN]: "https://explorer.swellnetwork.io/", 41 | [ChainSlug.WORLD_CHAIN]: "https://worldscan.org/", 42 | [ChainSlug.PLUME]: "https://explorer.plume.org/", 43 | [ChainSlug.KATANA]: "https://explorer.katanarpc.com", 44 | }; 45 | -------------------------------------------------------------------------------- /scripts/rpcConfig/constants/feesUpdaterChainSlugs.ts: -------------------------------------------------------------------------------- 1 | import { batcherSupportedChainSlugs } from "./batcherSupportedChainSlug"; 2 | import { 3 | ChainSlug, 4 | DeploymentMode, 5 | MainnetIds, 6 | TestnetIds, 7 | } from "../../../src"; 8 | import { mode } from "../../deploy/config/config"; 9 | 10 | export const feesUpdaterSupportedChainSlugs = (): ChainSlug[] => { 11 | if (mode === DeploymentMode.PROD) { 12 | const feesUpdaterSupportedChainSlugs = []; 13 | [...MainnetIds].forEach((m) => { 14 | if (batcherSupportedChainSlugs.includes(m)) { 15 | feesUpdaterSupportedChainSlugs.push(m); 16 | } 17 | }); 18 | 19 | return [ 20 | ...feesUpdaterSupportedChainSlugs, 21 | // ChainSlug.POLYNOMIAL_TESTNET, 22 | // ChainSlug.KINTO_DEVNET, 23 | // ChainSlug.ARBITRUM_SEPOLIA, 24 | ]; 25 | } else { 26 | return [ 27 | ChainSlug.ARBITRUM_SEPOLIA, 28 | ChainSlug.OPTIMISM_SEPOLIA, 29 | ChainSlug.SEPOLIA, 30 | ]; 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /scripts/rpcConfig/constants/finality.ts: -------------------------------------------------------------------------------- 1 | import { ChainSlug } from "../../../src/enums/chainSlug"; 2 | 3 | import { ChainFinalityInfo, FinalityBucket } from "../../../src/socket-types"; 4 | 5 | export const getFinality = ( 6 | chainSlug: ChainSlug 7 | ): ChainFinalityInfo | undefined => { 8 | return finalityOverrides[chainSlug]; 9 | }; 10 | 11 | export const finalityOverrides: { 12 | [chainSlug in ChainSlug]?: ChainFinalityInfo; 13 | } = { 14 | [ChainSlug.POLYGON_MAINNET]: { 15 | [FinalityBucket.low]: 64, 16 | [FinalityBucket.medium]: 256, 17 | [FinalityBucket.high]: 1000, 18 | }, 19 | [ChainSlug.NEOX_TESTNET]: { 20 | [FinalityBucket.low]: 1, 21 | [FinalityBucket.medium]: 10, 22 | [FinalityBucket.high]: 100, 23 | }, 24 | [ChainSlug.NEOX_T4_TESTNET]: { 25 | [FinalityBucket.low]: 1, 26 | [FinalityBucket.medium]: 10, 27 | [FinalityBucket.high]: 100, 28 | }, 29 | [ChainSlug.NEOX]: { 30 | [FinalityBucket.low]: 1, 31 | [FinalityBucket.medium]: 10, 32 | [FinalityBucket.high]: 100, 33 | }, 34 | [ChainSlug.LINEA]: { 35 | [FinalityBucket.low]: 1, 36 | [FinalityBucket.medium]: 10, 37 | [FinalityBucket.high]: 100, 38 | }, 39 | [ChainSlug.ZERO]: { 40 | [FinalityBucket.low]: 1, 41 | [FinalityBucket.medium]: 2000, 42 | [FinalityBucket.high]: 3000, 43 | }, 44 | [ChainSlug.ZKSYNC]: { 45 | [FinalityBucket.low]: 1, 46 | [FinalityBucket.medium]: 2000, 47 | [FinalityBucket.high]: 3000, 48 | }, 49 | [ChainSlug.SCROLL]: { 50 | [FinalityBucket.low]: 1, 51 | [FinalityBucket.medium]: 100, 52 | [FinalityBucket.high]: 1024, 53 | }, 54 | }; 55 | -------------------------------------------------------------------------------- /scripts/rpcConfig/constants/icons.ts: -------------------------------------------------------------------------------- 1 | import { ChainSlug } from "../../../src"; 2 | 3 | export const icons = { 4 | [ChainSlug.AEVO]: "https://media.socket.tech/aevo.png", 5 | [ChainSlug.LYRA]: "https://media.socket.tech/lyra.png", 6 | [ChainSlug.MANTLE]: "https://media.socket.tech/mantle.png", 7 | [ChainSlug.REYA]: "https://media.socket.tech/reya.png", 8 | [ChainSlug.BSC_TESTNET]: 9 | "https://testnet.bscscan.com/assets/bsc/images/svg/logos/logo-light.svg?v=24.5.5.0", 10 | [ChainSlug.POLYNOMIAL]: "", 11 | [ChainSlug.SYNDR]: "", 12 | [ChainSlug.NEOX_TESTNET]: "", 13 | [ChainSlug.NEOX_T4_TESTNET]: "", 14 | [ChainSlug.NEOX]: "", 15 | [ChainSlug.GNOSIS]: "", 16 | [ChainSlug.LINEA]: "", 17 | [ChainSlug.ZKEVM]: "", 18 | [ChainSlug.AVALANCHE]: "", 19 | [ChainSlug.XLAYER]: "", 20 | [ChainSlug.MANTA_PACIFIC]: "", 21 | [ChainSlug.POLTER_TESTNET]: "", 22 | [ChainSlug.POLYGON_AMOY]: "", 23 | [ChainSlug.OPBNB]: "", 24 | [ChainSlug.GEIST]: "", 25 | [ChainSlug.ZERO_SEPOLIA]: "", 26 | [ChainSlug.ZERO]: "", 27 | [ChainSlug.ZKSYNC]: "", 28 | [ChainSlug.ARENA_Z]: "", 29 | [ChainSlug.INK]: "", 30 | [ChainSlug.SONIC]: "", 31 | [ChainSlug.BASE_SEPOLIA]: "", 32 | [ChainSlug.BERA]: "", 33 | [ChainSlug.B3]: "", 34 | [ChainSlug.UNICHAIN]: "", 35 | [ChainSlug.MONAD_TESTNET]: "", 36 | [ChainSlug.SCROLL]: "", 37 | [ChainSlug.SONEIUM]: "", 38 | [ChainSlug.SWELLCHAIN]: "", 39 | [ChainSlug.WORLD_CHAIN]: "", 40 | [ChainSlug.PLUME]: "", 41 | [ChainSlug.KATANA]: "", 42 | }; 43 | -------------------------------------------------------------------------------- /scripts/rpcConfig/constants/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./batcherSupportedChainSlug"; 2 | export * from "./reSyncInterval"; 3 | export * from "./defaultFinalityBucket"; 4 | export * from "./explorers"; 5 | export * from "./icons"; 6 | export * from "./rpc"; 7 | export * from "./version"; 8 | export * from "./finality"; 9 | export * from "./disabledDFFeeChains"; 10 | -------------------------------------------------------------------------------- /scripts/rpcConfig/constants/reSyncInterval.ts: -------------------------------------------------------------------------------- 1 | import { ChainSlug } from "../../../src/enums/chainSlug"; 2 | 3 | export const getReSyncInterval = (chainSlug: ChainSlug) => { 4 | return reSyncInterval[chainSlug] ?? 0; 5 | }; 6 | 7 | export const reSyncInterval = { 8 | [ChainSlug.POLYGON_MAINNET]: 256, 9 | [ChainSlug.MAINNET]: 6, 10 | }; 11 | -------------------------------------------------------------------------------- /scripts/rpcConfig/constants/version.ts: -------------------------------------------------------------------------------- 1 | import { DeploymentMode } from "../../../src"; 2 | 3 | export const version = { 4 | [DeploymentMode.DEV]: "1.0.5", 5 | [DeploymentMode.PROD]: "1.0.95", 6 | }; 7 | -------------------------------------------------------------------------------- /scripts/rpcConfig/txdata-builder/util.ts: -------------------------------------------------------------------------------- 1 | import { BigNumber, Contract, ethers, utils } from "ethers"; 2 | 3 | import { packPacketId } from "@socket.tech/dl-common"; 4 | 5 | import capacitorAbiInterface from "@socket.tech/dl-core/artifacts/abi/SingleCapacitor.json"; 6 | import SocketSimulatorABI from "@socket.tech/dl-core/artifacts/abi/SocketSimulator.json"; 7 | import SwitchboardSimulatorABI from "@socket.tech/dl-core/artifacts/abi/SwitchboardSimulator.json"; 8 | import { getProviderFromChainSlug } from "../../constants"; 9 | import { version, ChainSlug } from "../../../src"; 10 | import { hexZeroPad } from "@ethersproject/bytes"; 11 | 12 | export const simulatorAbiInterface = new ethers.utils.Interface( 13 | SocketSimulatorABI 14 | ); 15 | export const switchboardSimulatorAbiInterface = new ethers.utils.Interface( 16 | SwitchboardSimulatorABI 17 | ); 18 | export const VERSION_HASH = utils.keccak256( 19 | utils.defaultAbiCoder.encode(["string"], [version]) 20 | ); 21 | 22 | export interface PacketInfo { 23 | root: string; 24 | packetId: string; 25 | capacitor: string; 26 | } 27 | 28 | export async function getPacketInfo( 29 | srcChainSlug: ChainSlug, 30 | capacitorAddress: string 31 | ): Promise { 32 | const capacitorContract = new Contract( 33 | capacitorAddress, 34 | capacitorAbiInterface, 35 | getProviderFromChainSlug(srcChainSlug) 36 | ); 37 | const packetDetails = await capacitorContract.getNextPacketToBeSealed(); 38 | const packetId = packPacketId( 39 | srcChainSlug, 40 | capacitorAddress, 41 | packetDetails[1].toString() 42 | ); 43 | return { 44 | root: packetDetails[0], 45 | packetId, 46 | capacitor: capacitorAddress, 47 | }; 48 | } 49 | 50 | export const packMessageId = ( 51 | chainSlug: number, 52 | plugAddr: string, 53 | msgCount: string 54 | ): string => { 55 | const nonce = BigNumber.from(msgCount).toHexString(); 56 | const nonceHex = 57 | nonce.length <= 16 ? hexZeroPad(nonce, 8).substring(2) : nonce.substring(2); 58 | 59 | const slug = BigNumber.from(chainSlug).toHexString(); 60 | const slugHex = slug.length <= 10 ? hexZeroPad(slug, 4) : slug; 61 | const id = slugHex + plugAddr.substring(2) + nonceHex; 62 | return id.toLowerCase(); 63 | }; 64 | -------------------------------------------------------------------------------- /scripts/rpcConfig/updateConstants.ts: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | import fs from "fs"; 3 | import dotenv from "dotenv"; 4 | dotenv.config(); 5 | 6 | import { ChainId, DeploymentMode } from "../../src"; 7 | import { version, rpcs } from "./constants"; 8 | 9 | const constantFolderPath = path.join(__dirname, `/constants/`); 10 | export const deploymentMode = process.env.DEPLOYMENT_MODE as DeploymentMode; 11 | 12 | export const updateConstants = async ( 13 | chainName: string, 14 | explorer?: string, 15 | icon?: string 16 | ) => { 17 | if (!fs.existsSync(constantFolderPath)) { 18 | throw new Error(`Folder not found! ${constantFolderPath}`); 19 | } 20 | 21 | const filteredChain = Object.keys(rpcs).filter( 22 | (c) => c == ChainId[chainName] 23 | ); 24 | if (filteredChain.length > 0) { 25 | console.log("Chain already added!"); 26 | return; 27 | } 28 | 29 | await updateFile( 30 | "rpc.ts", 31 | `,\n [ChainSlug.${chainName.toUpperCase()}]: checkEnvValue("${chainName.toUpperCase()}_RPC"),\n};`, 32 | ",\n};" 33 | ); 34 | 35 | await updateFile( 36 | "batcherSupportedChainSlug.ts", 37 | `,\n ChainSlug.${chainName.toUpperCase()},\n];`, 38 | ",\n];" 39 | ); 40 | await updateFile( 41 | "icons.ts", 42 | `,\n [ChainSlug.${chainName.toUpperCase()}]: "${icon}",\n};`, 43 | ",\n};" 44 | ); 45 | await updateFile( 46 | "explorers.ts", 47 | `,\n [ChainSlug.${chainName.toUpperCase()}]: "${explorer}",\n};`, 48 | ",\n};" 49 | ); 50 | 51 | await updateVersion(); 52 | }; 53 | 54 | const updateFile = async (fileName, newChainDetails, replaceWith) => { 55 | try { 56 | const filePath = constantFolderPath + fileName; 57 | const outputExists = fs.existsSync(filePath); 58 | if (!outputExists) 59 | throw new Error(`${fileName} enum not found! ${filePath}`); 60 | 61 | const fileContent = fs.readFileSync(filePath, "utf-8"); 62 | 63 | // replace last bracket with new line 64 | const newFileContent = fileContent 65 | .trimEnd() 66 | .replace(replaceWith, newChainDetails); 67 | 68 | fs.writeFileSync(filePath, newFileContent); 69 | } catch (error) { 70 | console.log(error); 71 | } 72 | }; 73 | 74 | const updateVersion = () => { 75 | let serializedContent; 76 | const currentVersion = version[deploymentMode]; 77 | const versions = currentVersion.split("."); 78 | const newVersion = `${versions[0]}.${versions[1]}.${++versions[2]}`; 79 | if (deploymentMode === DeploymentMode.PROD) { 80 | serializedContent = ` [DeploymentMode.DEV]: "${ 81 | version[DeploymentMode.DEV] 82 | }", 83 | [DeploymentMode.PROD]: "${newVersion}",`; 84 | } else if (deploymentMode === DeploymentMode.DEV) { 85 | serializedContent = ` [DeploymentMode.DEV]: "${newVersion}", 86 | [DeploymentMode.PROD]: "${version[DeploymentMode.PROD]}",`; 87 | } 88 | 89 | const content = `import { DeploymentMode } from "../../../src"; 90 | 91 | export const version = { 92 | ${serializedContent} 93 | };`; 94 | 95 | fs.writeFileSync(constantFolderPath + "version.ts", content); 96 | }; 97 | -------------------------------------------------------------------------------- /scripts/rpcConfig/uploadS3Config.ts: -------------------------------------------------------------------------------- 1 | import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3"; 2 | import * as fs from "fs"; 3 | import { DeploymentMode, TxData } from "../../src"; 4 | import dotenv from "dotenv"; 5 | import { generateDevConfig, generateProdConfig } from "./rpcConfig"; 6 | import { getTxData } from "./txdata-builder/generate-calldata"; 7 | dotenv.config(); 8 | 9 | const deploymentMode = process.env.DEPLOYMENT_MODE as DeploymentMode; 10 | const s3Client = new S3Client({ 11 | region: "us-east-1", 12 | }); 13 | 14 | // File path for the JSON file 15 | const fileName = deploymentMode + "RpcConfig.json"; 16 | const localFilePath = fileName; 17 | 18 | const bucketName = "socket-ll-" + deploymentMode; 19 | const s3FileKey = fileName; // File key in S3 20 | 21 | const createConfig = async () => { 22 | console.log("getting tx data"); 23 | const txData: TxData = await getTxData(); 24 | 25 | console.log("generating config"); 26 | const config = 27 | deploymentMode === "prod" 28 | ? await generateProdConfig(txData) 29 | : await generateDevConfig(txData); 30 | const jsonString = JSON.stringify(config, null, 2); // Use null and 2 for pretty formatting 31 | 32 | // Write the JSON string to the local file 33 | fs.writeFileSync(localFilePath, jsonString); 34 | }; 35 | 36 | const uploadToS3 = async () => { 37 | try { 38 | await createConfig(); 39 | const fileBuffer = fs.readFileSync(localFilePath); 40 | 41 | // Create an S3 PUT operation command 42 | const putObjectCommand = new PutObjectCommand({ 43 | Bucket: bucketName, 44 | Key: s3FileKey, 45 | Body: fileBuffer, 46 | ContentType: "application/json", 47 | }); 48 | 49 | // Execute the command and get the response 50 | const s3Response = await s3Client.send(putObjectCommand); 51 | 52 | console.log( 53 | `File uploaded to S3. ETag: ${s3Response.ETag} mode : ${deploymentMode}` 54 | ); 55 | } catch (error) { 56 | console.error("Error uploading data to S3:", error); 57 | } 58 | }; 59 | 60 | // npx ts-node scripts/rpcConfig/uploadS3Config.ts 61 | uploadToS3(); 62 | -------------------------------------------------------------------------------- /scripts/socket-helpers/arb-estimate.ts: -------------------------------------------------------------------------------- 1 | import { utils, BigNumber } from "ethers"; 2 | import { ArbGasInfo__factory } from "@arbitrum/sdk/dist/lib/abi/factories/ArbGasInfo__factory"; 3 | import { NodeInterface__factory } from "@arbitrum/sdk/dist/lib/abi/factories/NodeInterface__factory"; 4 | import { 5 | ARB_GAS_INFO, 6 | NODE_INTERFACE_ADDRESS, 7 | } from "@arbitrum/sdk/dist/lib/dataEntities/constants"; 8 | import { TxData } from "./utils"; 9 | import { StaticJsonRpcProvider } from "@ethersproject/providers"; 10 | 11 | export const getArbitrumGasLimitEstimate = async ( 12 | provider: StaticJsonRpcProvider, 13 | txData: TxData 14 | ): Promise => { 15 | const arbGasInfo = ArbGasInfo__factory.connect(ARB_GAS_INFO, provider); 16 | const nodeInterface = NodeInterface__factory.connect( 17 | NODE_INTERFACE_ADDRESS, 18 | provider 19 | ); 20 | // Getting the gas prices from ArbGasInfo.getPricesInWei() 21 | const gasComponents = await arbGasInfo.callStatic.getPricesInWei(); 22 | const gasEstimateComponents = 23 | await nodeInterface.callStatic.gasEstimateComponents( 24 | txData.to, 25 | false, 26 | txData.data, 27 | { from: txData.from } 28 | ); 29 | 30 | const l2GasUsed = gasEstimateComponents.gasEstimate.sub( 31 | gasEstimateComponents.gasEstimateForL1 32 | ); 33 | 34 | // Size in bytes of the calldata to post on L1 35 | const L1S = 140 + utils.hexDataLength(txData.data); 36 | 37 | // Estimated L1 gas cost 38 | const L1C = gasComponents[1].mul(L1S); 39 | 40 | // Extra buffer 41 | const B = L1C.div(gasComponents[5]); 42 | 43 | // G (Gas Limit) = l2GasUsed + B 44 | const gasLimit = l2GasUsed.add(B); 45 | return gasLimit; 46 | }; 47 | -------------------------------------------------------------------------------- /scripts/socket-helpers/main.ts: -------------------------------------------------------------------------------- 1 | require("dotenv").config(); 2 | import { BigNumber, providers, utils } from "ethers"; 3 | import { DeploymentMode } from "@socket.tech/dl-core"; 4 | import PlugABI from "@socket.tech/dl-core/artifacts/abi/IPlug.json"; 5 | 6 | import { ChainDetails, Inputs, getPayload } from "./utils"; 7 | import { getJsonRpcUrl } from "../constants"; 8 | import { arbChains, arbL3Chains, getAddresses } from "../../src"; 9 | import { getArbitrumGasLimitEstimate } from "./arb-estimate"; 10 | import { getOpAndEthGasLimitEstimate } from "./op-n-eth-estimate"; 11 | 12 | export const main = async ( 13 | chainDetails: ChainDetails, 14 | inputs: Inputs, 15 | withoutHook?: boolean 16 | ): Promise => { 17 | const srcChainSlug = chainDetails.srcChainSlug; 18 | const dstChainSlug = chainDetails.dstChainSlug; 19 | 20 | const provider = new providers.StaticJsonRpcProvider( 21 | getJsonRpcUrl(dstChainSlug) 22 | ); 23 | const payload = await getPayload(inputs, provider, withoutHook); 24 | 25 | const abiInterface = new utils.Interface(PlugABI); 26 | const data = abiInterface.encodeFunctionData("inbound", [ 27 | srcChainSlug, 28 | payload, 29 | ]); 30 | 31 | const txData = { 32 | from: getAddresses(dstChainSlug, DeploymentMode.PROD).Socket, 33 | to: inputs.connectorPlug, 34 | data, 35 | }; 36 | 37 | if ( 38 | arbChains.includes(chainDetails.dstChainSlug) || 39 | arbL3Chains.includes(chainDetails.dstChainSlug) 40 | ) { 41 | return await getArbitrumGasLimitEstimate(provider, txData); 42 | } else { 43 | // works for opt and eth like chains 44 | return await getOpAndEthGasLimitEstimate(provider, txData); 45 | } 46 | }; 47 | 48 | main( 49 | { 50 | srcChainSlug: 42161, 51 | dstChainSlug: 1324967486, 52 | }, 53 | { 54 | amount: "2000000000", 55 | connectorPlug: "0x663dc7e91157c58079f55c1bf5ee1bdb6401ca7a", 56 | executionData: "0x", 57 | receiver: "0x663dc7e91157c58079f55c1bf5ee1bdb6401ca7a", 58 | }, 59 | false 60 | ); 61 | -------------------------------------------------------------------------------- /scripts/socket-helpers/op-n-eth-estimate.ts: -------------------------------------------------------------------------------- 1 | import { BigNumber } from "ethers"; 2 | import { StaticJsonRpcProvider } from "@ethersproject/providers"; 3 | import { asL2Provider } from "@eth-optimism/sdk"; 4 | import { TxData } from "./utils"; 5 | 6 | // Get optimism gas limit from the SDK 7 | export const getOpAndEthGasLimitEstimate = async ( 8 | provider: StaticJsonRpcProvider, 9 | txData: TxData 10 | ): Promise => { 11 | const l2Provider = asL2Provider(provider); 12 | const gasLimit = await l2Provider.estimateGas(txData); 13 | return gasLimit; 14 | }; 15 | -------------------------------------------------------------------------------- /scripts/socket-helpers/utils.ts: -------------------------------------------------------------------------------- 1 | import { Contract, utils } from "ethers"; 2 | import { defaultAbiCoder } from "ethers/lib/utils"; 3 | import { StaticJsonRpcProvider } from "@ethersproject/providers"; 4 | import PlugABI from "@socket.tech/dl-core/artifacts/abi/IPlug.json"; 5 | import { ChainSlug } from "../../src"; 6 | 7 | export type TxData = { 8 | from: string; 9 | to: string; 10 | data: string; 11 | }; 12 | 13 | export type Inputs = { 14 | amount: string; 15 | receiver: string; 16 | executionData: string; 17 | connectorPlug: string; 18 | }; 19 | 20 | export type ChainDetails = { 21 | srcChainSlug: ChainSlug; 22 | dstChainSlug: ChainSlug; 23 | }; 24 | 25 | export const abiInterface = new utils.Interface(PlugABI); 26 | 27 | const ConnectorABI = [ 28 | { 29 | inputs: [], 30 | name: "getMessageId", 31 | outputs: [ 32 | { 33 | internalType: "bytes32", 34 | name: "", 35 | type: "bytes32", 36 | }, 37 | ], 38 | stateMutability: "view", 39 | type: "function", 40 | }, 41 | ]; 42 | 43 | export const getPayload = async ( 44 | inputs: Inputs, 45 | provider: StaticJsonRpcProvider, 46 | withoutHook?: boolean 47 | ) => { 48 | let payload; 49 | if (withoutHook) { 50 | payload = defaultAbiCoder.encode( 51 | ["address", "uint256"], 52 | [inputs.receiver, inputs.amount] 53 | ); 54 | } else { 55 | const connectorContract = new Contract( 56 | inputs.connectorPlug, 57 | ConnectorABI, 58 | provider 59 | ); 60 | const msgId = await connectorContract.getMessageId(); 61 | payload = defaultAbiCoder.encode( 62 | ["address", "uint256", "bytes32", "bytes"], 63 | [inputs.receiver, inputs.amount, msgId, inputs.executionData] 64 | ); 65 | } 66 | 67 | return payload; 68 | }; 69 | -------------------------------------------------------------------------------- /scripts/transmitter/propose.ts: -------------------------------------------------------------------------------- 1 | import { config as dotenvConfig } from "dotenv"; 2 | dotenvConfig(); 3 | 4 | import { arrayify } from "@ethersproject/bytes"; 5 | import { defaultAbiCoder, keccak256 } from "ethers/lib/utils"; 6 | import { Contract, Wallet, utils } from "ethers"; 7 | import { version, getAddresses, ChainSlug } from "../../src/index"; 8 | import { getProviderFromChainSlug } from "../constants/networks"; 9 | 10 | import { CORE_CONTRACTS } from "@socket.tech/dl-core"; 11 | import { getInstance } from "../deploy/utils"; 12 | import { mode, overrides } from "../deploy/config/config"; 13 | 14 | export const VERSION_HASH = utils.id(version[mode]); 15 | 16 | const chainSlug: ChainSlug = ChainSlug.OPTIMISM_SEPOLIA; 17 | const packetId = 18 | "0x000138815c83e326c0b4380127dccf01c3b69ff4dd5c16ae0000000000000001"; 19 | const root = 20 | "0x20b91edb1b25a3ea4403f9296edaff84d689c08b249406fdc6e248ada2919ef7"; 21 | 22 | export const main = async () => { 23 | try { 24 | if (!chainSlug) throw new Error("No chain found!"); 25 | const signer = new Wallet( 26 | process.env.SOCKET_SIGNER_KEY!, 27 | getProviderFromChainSlug(chainSlug) 28 | ); 29 | 30 | if (!process.env.TRANSMITTER_PK) 31 | throw new Error("No transmitter PK found!"); 32 | 33 | const transmitterSigner = new Wallet( 34 | process.env.TRANSMITTER_PK!, 35 | getProviderFromChainSlug(chainSlug) 36 | ); 37 | 38 | const proposeDigest = keccak256( 39 | defaultAbiCoder.encode( 40 | ["bytes32", "uint32", "bytes32", "bytes32"], 41 | [VERSION_HASH, chainSlug, packetId, root] 42 | ) 43 | ); 44 | const signature = await transmitterSigner.signMessage( 45 | arrayify(proposeDigest) 46 | ); 47 | 48 | console.log(`${signature} here`); 49 | 50 | const socketAddr = (await getAddresses(chainSlug, mode)).Socket; 51 | 52 | const socket: Contract = ( 53 | await getInstance(CORE_CONTRACTS.Socket, socketAddr) 54 | ).connect(signer); 55 | 56 | const tx = await socket.propose(packetId, root, signature, { 57 | ...(await overrides(chainSlug)), 58 | }); 59 | 60 | console.log(`Proposing at tx hash: ${tx.hash}`); 61 | await tx.wait(); 62 | } catch (error) { 63 | console.log("Error while sending transaction", error); 64 | throw error; 65 | } 66 | }; 67 | 68 | main() 69 | .then(() => process.exit(0)) 70 | .catch((error: Error) => { 71 | console.error(error); 72 | process.exit(1); 73 | }); 74 | -------------------------------------------------------------------------------- /src/currency-util.ts: -------------------------------------------------------------------------------- 1 | import { ChainSlug, Currency, NativeTokens } from "./enums"; 2 | 3 | export const getCurrency = (chainSlug: ChainSlug) => { 4 | if (Currency[chainSlug]) return Currency[chainSlug]; 5 | return NativeTokens.ethereum; 6 | }; 7 | -------------------------------------------------------------------------------- /src/enums/arbChains.ts: -------------------------------------------------------------------------------- 1 | import { ChainSlug } from "./chainSlug"; 2 | 3 | export const arbChains = [ 4 | ChainSlug.ARBITRUM, 5 | ChainSlug.ARBITRUM_GOERLI, 6 | ChainSlug.ARBITRUM_SEPOLIA, 7 | ChainSlug.PARALLEL, 8 | ChainSlug.REYA_CRONOS, 9 | ChainSlug.REYA, 10 | ChainSlug.GEIST, 11 | ChainSlug.PLUME, 12 | ]; 13 | -------------------------------------------------------------------------------- /src/enums/arbL3Chains.ts: -------------------------------------------------------------------------------- 1 | import { ChainSlug } from "./chainSlug"; 2 | 3 | export const arbL3Chains = [ 4 | ChainSlug.SYNDR_SEPOLIA_L3, 5 | ChainSlug.KINTO, 6 | ChainSlug.KINTO_DEVNET, 7 | ChainSlug.WINR, 8 | ChainSlug.SYNDR, 9 | ]; 10 | -------------------------------------------------------------------------------- /src/enums/chainId.ts: -------------------------------------------------------------------------------- 1 | export enum ChainId { 2 | ARBITRUM = 42161, 3 | ARBITRUM_GOERLI = 421613, 4 | ARBITRUM_SEPOLIA = 421614, 5 | OPTIMISM = 10, 6 | OPTIMISM_GOERLI = 420, 7 | OPTIMISM_SEPOLIA = 11155420, 8 | BSC = 56, 9 | MAINNET = 1, 10 | GOERLI = 5, 11 | SEPOLIA = 11155111, 12 | POLYGON_MAINNET = 137, 13 | AEVO_TESTNET = 11155112, 14 | AEVO = 2999, 15 | HARDHAT = 31337, 16 | LYRA_TESTNET = 901, 17 | LYRA = 957, 18 | XAI_TESTNET = 47279324479, 19 | CDK_TESTNET = 686669576, 20 | SX_NETWORK_TESTNET = 647, 21 | SX_NETWORK = 416, 22 | MODE_TESTNET = 919, 23 | VICTION_TESTNET = 89, 24 | BASE = 8453, 25 | MODE = 34443, 26 | ANCIENT8_TESTNET = 2863311531, 27 | ANCIENT8_TESTNET2 = 28122024, 28 | PARALLEL = 1024, 29 | MANTLE = 5000, 30 | REYA_CRONOS = 89346162, 31 | REYA = 1729, 32 | SYNDR_SEPOLIA_L3 = 444444, 33 | POLYNOMIAL_TESTNET = 80008, 34 | BOB = 60808, 35 | KINTO = 7887, 36 | KINTO_DEVNET = 412346, 37 | SIPHER_FUNKI_TESTNET = 3397901, 38 | WINR = 777777, 39 | BLAST = 81457, 40 | BSC_TESTNET = 97, 41 | POLYNOMIAL = 8008, 42 | SYNDR = 404, 43 | NEOX_TESTNET = 12227331, 44 | NEOX_T4_TESTNET = 12227332, 45 | NEOX = 47763, 46 | GNOSIS = 100, 47 | LINEA = 59144, 48 | ZKEVM = 1101, 49 | AVALANCHE = 43114, 50 | XLAYER = 196, 51 | MANTA_PACIFIC = 169, 52 | POLTER_TESTNET = 631571, 53 | POLYGON_AMOY = 80002, 54 | OPBNB = 204, 55 | GEIST = 63157, 56 | ZERO_SEPOLIA = 43210, 57 | ZERO = 543210, 58 | ZKSYNC = 324, 59 | ARENA_Z = 7897, 60 | INK = 57073, 61 | SONIC = 146, 62 | BASE_SEPOLIA = 84532, 63 | BERA = 80094, 64 | B3 = 8333, 65 | UNICHAIN = 130, 66 | MONAD_TESTNET = 10143, 67 | SCROLL = 534352, 68 | SONEIUM = 1868, 69 | SWELLCHAIN = 1923, 70 | WORLD_CHAIN = 480, 71 | PLUME = 98866, 72 | KATANA = 747474, 73 | } 74 | -------------------------------------------------------------------------------- /src/enums/chainSlug.ts: -------------------------------------------------------------------------------- 1 | import { ChainId } from "./chainId"; 2 | 3 | export enum ChainSlug { 4 | ARBITRUM = ChainId.ARBITRUM, 5 | ARBITRUM_GOERLI = ChainId.ARBITRUM_GOERLI, 6 | ARBITRUM_SEPOLIA = ChainId.ARBITRUM_SEPOLIA, 7 | OPTIMISM = ChainId.OPTIMISM, 8 | OPTIMISM_GOERLI = ChainId.OPTIMISM_GOERLI, 9 | OPTIMISM_SEPOLIA = ChainId.OPTIMISM_SEPOLIA, 10 | BSC = ChainId.BSC, 11 | MAINNET = ChainId.MAINNET, 12 | GOERLI = ChainId.GOERLI, 13 | SEPOLIA = ChainId.SEPOLIA, 14 | POLYGON_MAINNET = ChainId.POLYGON_MAINNET, 15 | AEVO_TESTNET = ChainId.AEVO_TESTNET, 16 | AEVO = ChainId.AEVO, 17 | HARDHAT = ChainId.HARDHAT, 18 | LYRA_TESTNET = ChainId.LYRA_TESTNET, 19 | LYRA = ChainId.LYRA, 20 | XAI_TESTNET = 1399904803, 21 | SX_NETWORK_TESTNET = ChainId.SX_NETWORK_TESTNET, 22 | SX_NETWORK = ChainId.SX_NETWORK, 23 | MODE_TESTNET = ChainId.MODE_TESTNET, 24 | VICTION_TESTNET = ChainId.VICTION_TESTNET, 25 | CDK_TESTNET = ChainId.CDK_TESTNET, 26 | BASE = ChainId.BASE, 27 | MODE = ChainId.MODE, 28 | ANCIENT8_TESTNET = ChainId.ANCIENT8_TESTNET, 29 | ANCIENT8_TESTNET2 = ChainId.ANCIENT8_TESTNET2, 30 | PARALLEL = ChainId.PARALLEL, 31 | MANTLE = ChainId.MANTLE, 32 | REYA_CRONOS = ChainId.REYA_CRONOS, 33 | REYA = 1324967486, 34 | SYNDR_SEPOLIA_L3 = ChainId.SYNDR_SEPOLIA_L3, 35 | POLYNOMIAL_TESTNET = ChainId.POLYNOMIAL_TESTNET, 36 | BOB = ChainId.BOB, 37 | KINTO = ChainId.KINTO, 38 | KINTO_DEVNET = ChainId.KINTO_DEVNET, 39 | SIPHER_FUNKI_TESTNET = ChainId.SIPHER_FUNKI_TESTNET, 40 | WINR = ChainId.WINR, 41 | BLAST = ChainId.BLAST, 42 | BSC_TESTNET = ChainId.BSC_TESTNET, 43 | POLYNOMIAL = ChainId.POLYNOMIAL, 44 | SYNDR = ChainId.SYNDR, 45 | NEOX_TESTNET = ChainId.NEOX_TESTNET, 46 | NEOX_T4_TESTNET = ChainId.NEOX_T4_TESTNET, 47 | NEOX = ChainId.NEOX, 48 | GNOSIS = ChainId.GNOSIS, 49 | LINEA = ChainId.LINEA, 50 | ZKEVM = ChainId.ZKEVM, 51 | AVALANCHE = ChainId.AVALANCHE, 52 | XLAYER = ChainId.XLAYER, 53 | MANTA_PACIFIC = ChainId.MANTA_PACIFIC, 54 | POLTER_TESTNET = ChainId.POLTER_TESTNET, 55 | POLYGON_AMOY = ChainId.POLYGON_AMOY, 56 | OPBNB = ChainId.OPBNB, 57 | GEIST = ChainId.GEIST, 58 | ZERO_SEPOLIA = ChainId.ZERO_SEPOLIA, 59 | ZERO = ChainId.ZERO, 60 | ZKSYNC = ChainId.ZKSYNC, 61 | ARENA_Z = ChainId.ARENA_Z, 62 | INK = ChainId.INK, 63 | SONIC = ChainId.SONIC, 64 | BASE_SEPOLIA = ChainId.BASE_SEPOLIA, 65 | BERA = ChainId.BERA, 66 | B3 = ChainId.B3, 67 | UNICHAIN = ChainId.UNICHAIN, 68 | MONAD_TESTNET = ChainId.MONAD_TESTNET, 69 | SCROLL = ChainId.SCROLL, 70 | SONEIUM = ChainId.SONEIUM, 71 | SWELLCHAIN = ChainId.SWELLCHAIN, 72 | WORLD_CHAIN = ChainId.WORLD_CHAIN, 73 | PLUME = ChainId.PLUME, 74 | KATANA = ChainId.KATANA, 75 | } 76 | -------------------------------------------------------------------------------- /src/enums/chainSlugToId.ts: -------------------------------------------------------------------------------- 1 | import { ChainId } from "./chainId"; 2 | import { ChainSlug } from "./chainSlug"; 3 | 4 | export const ChainSlugToId = { 5 | [ChainSlug.ARBITRUM]: ChainId.ARBITRUM, 6 | [ChainSlug.ARBITRUM_GOERLI]: ChainId.ARBITRUM_GOERLI, 7 | [ChainSlug.ARBITRUM_SEPOLIA]: ChainId.ARBITRUM_SEPOLIA, 8 | [ChainSlug.OPTIMISM]: ChainId.OPTIMISM, 9 | [ChainSlug.OPTIMISM_GOERLI]: ChainId.OPTIMISM_GOERLI, 10 | [ChainSlug.OPTIMISM_SEPOLIA]: ChainId.OPTIMISM_SEPOLIA, 11 | [ChainSlug.BSC]: ChainId.BSC, 12 | [ChainSlug.MAINNET]: ChainId.MAINNET, 13 | [ChainSlug.GOERLI]: ChainId.GOERLI, 14 | [ChainSlug.SEPOLIA]: ChainId.SEPOLIA, 15 | [ChainSlug.POLYGON_MAINNET]: ChainId.POLYGON_MAINNET, 16 | [ChainSlug.AEVO_TESTNET]: ChainId.AEVO_TESTNET, 17 | [ChainSlug.AEVO]: ChainId.AEVO, 18 | [ChainSlug.HARDHAT]: ChainId.HARDHAT, 19 | [ChainSlug.LYRA_TESTNET]: ChainId.LYRA_TESTNET, 20 | [ChainSlug.LYRA]: ChainId.LYRA, 21 | [ChainSlug.XAI_TESTNET]: ChainId.XAI_TESTNET, 22 | [ChainSlug.SX_NETWORK_TESTNET]: ChainId.SX_NETWORK_TESTNET, 23 | [ChainSlug.SX_NETWORK]: ChainId.SX_NETWORK, 24 | [ChainSlug.MODE_TESTNET]: ChainId.MODE_TESTNET, 25 | [ChainSlug.VICTION_TESTNET]: ChainId.VICTION_TESTNET, 26 | [ChainSlug.CDK_TESTNET]: ChainId.CDK_TESTNET, 27 | [ChainSlug.BASE]: ChainId.BASE, 28 | [ChainSlug.MODE]: ChainId.MODE, 29 | [ChainSlug.ANCIENT8_TESTNET]: ChainId.ANCIENT8_TESTNET, 30 | [ChainSlug.ANCIENT8_TESTNET2]: ChainId.ANCIENT8_TESTNET2, 31 | [ChainSlug.PARALLEL]: ChainId.PARALLEL, 32 | [ChainSlug.MANTLE]: ChainId.MANTLE, 33 | [ChainSlug.REYA_CRONOS]: ChainId.REYA_CRONOS, 34 | [ChainSlug.REYA]: ChainId.REYA, 35 | [ChainSlug.SYNDR_SEPOLIA_L3]: ChainId.SYNDR_SEPOLIA_L3, 36 | [ChainSlug.POLYNOMIAL_TESTNET]: ChainId.POLYNOMIAL_TESTNET, 37 | [ChainSlug.BOB]: ChainId.BOB, 38 | [ChainSlug.KINTO]: ChainId.KINTO, 39 | [ChainSlug.KINTO_DEVNET]: ChainId.KINTO_DEVNET, 40 | [ChainSlug.SIPHER_FUNKI_TESTNET]: ChainId.SIPHER_FUNKI_TESTNET, 41 | [ChainSlug.WINR]: ChainId.WINR, 42 | [ChainSlug.BLAST]: ChainId.BLAST, 43 | [ChainSlug.BSC_TESTNET]: ChainId.BSC_TESTNET, 44 | [ChainSlug.POLYNOMIAL]: ChainId.POLYNOMIAL, 45 | [ChainSlug.SYNDR]: ChainId.SYNDR, 46 | [ChainSlug.NEOX_TESTNET]: ChainId.NEOX_TESTNET, 47 | [ChainSlug.NEOX_T4_TESTNET]: ChainId.NEOX_T4_TESTNET, 48 | [ChainSlug.NEOX]: ChainId.NEOX, 49 | [ChainSlug.GNOSIS]: ChainId.GNOSIS, 50 | [ChainSlug.LINEA]: ChainId.LINEA, 51 | [ChainSlug.ZKEVM]: ChainId.ZKEVM, 52 | [ChainSlug.AVALANCHE]: ChainId.AVALANCHE, 53 | [ChainSlug.XLAYER]: ChainId.XLAYER, 54 | [ChainSlug.MANTA_PACIFIC]: ChainId.MANTA_PACIFIC, 55 | [ChainSlug.POLTER_TESTNET]: ChainId.POLTER_TESTNET, 56 | [ChainSlug.POLYGON_AMOY]: ChainId.POLYGON_AMOY, 57 | [ChainSlug.OPBNB]: ChainId.OPBNB, 58 | [ChainSlug.GEIST]: ChainId.GEIST, 59 | [ChainSlug.ZERO_SEPOLIA]: ChainId.ZERO_SEPOLIA, 60 | [ChainSlug.ZERO]: ChainId.ZERO, 61 | [ChainSlug.ZKSYNC]: ChainId.ZKSYNC, 62 | [ChainSlug.ARENA_Z]: ChainId.ARENA_Z, 63 | [ChainSlug.INK]: ChainId.INK, 64 | [ChainSlug.SONIC]: ChainId.SONIC, 65 | [ChainSlug.BASE_SEPOLIA]: ChainId.BASE_SEPOLIA, 66 | [ChainSlug.BERA]: ChainId.BERA, 67 | [ChainSlug.B3]: ChainId.B3, 68 | [ChainSlug.UNICHAIN]: ChainId.UNICHAIN, 69 | [ChainSlug.MONAD_TESTNET]: ChainId.MONAD_TESTNET, 70 | [ChainSlug.SCROLL]: ChainId.SCROLL, 71 | [ChainSlug.SONEIUM]: ChainId.SONEIUM, 72 | [ChainSlug.SWELLCHAIN]: ChainId.SWELLCHAIN, 73 | [ChainSlug.WORLD_CHAIN]: ChainId.WORLD_CHAIN, 74 | [ChainSlug.PLUME]: ChainId.PLUME, 75 | [ChainSlug.KATANA]: ChainId.KATANA, 76 | }; 77 | -------------------------------------------------------------------------------- /src/enums/currency.ts: -------------------------------------------------------------------------------- 1 | import { ChainSlug } from "./chainSlug"; 2 | import { NativeTokens } from "./native-tokens"; 3 | 4 | export const Currency = { 5 | [ChainSlug.BSC]: NativeTokens.binancecoin, 6 | [ChainSlug.POLYGON_MAINNET]: NativeTokens["matic-network"], 7 | [ChainSlug.SX_NETWORK_TESTNET]: NativeTokens["sx-network-2"], 8 | [ChainSlug.SX_NETWORK]: NativeTokens["sx-network-2"], 9 | [ChainSlug.MANTLE]: NativeTokens.mantle, 10 | [ChainSlug.BSC_TESTNET]: NativeTokens["binancecoin"], 11 | [ChainSlug.WINR]: NativeTokens["winr"], 12 | [ChainSlug.NEOX_TESTNET]: NativeTokens["gas"], 13 | [ChainSlug.NEOX_T4_TESTNET]: NativeTokens["gas"], 14 | [ChainSlug.NEOX]: NativeTokens["gas"], 15 | [ChainSlug.GNOSIS]: NativeTokens["dai"], 16 | [ChainSlug.AVALANCHE]: NativeTokens["avalanche-2"], 17 | [ChainSlug.XLAYER]: NativeTokens["okb"], 18 | [ChainSlug.POLTER_TESTNET]: NativeTokens["aavegotchi"], 19 | [ChainSlug.POLYGON_AMOY]: NativeTokens["matic-network"], 20 | [ChainSlug.OPBNB]: NativeTokens["binancecoin"], 21 | [ChainSlug.GEIST]: NativeTokens["aavegotchi"], 22 | [ChainSlug.SONIC]: NativeTokens["fantom"], 23 | [ChainSlug.BERA]: NativeTokens["berachain-bera"], 24 | [ChainSlug.MONAD_TESTNET]: NativeTokens["monad"], 25 | [ChainSlug.PLUME]: NativeTokens["plume"], 26 | }; 27 | -------------------------------------------------------------------------------- /src/enums/ethLikeChains.ts: -------------------------------------------------------------------------------- 1 | import { ChainSlug } from "./chainSlug"; 2 | 3 | // chains having constant gas limits 4 | export const ethLikeChains = [ 5 | ChainSlug.MAINNET, 6 | ChainSlug.BSC, 7 | ChainSlug.POLYGON_MAINNET, 8 | ChainSlug.SEPOLIA, 9 | ChainSlug.SX_NETWORK, 10 | ChainSlug.SX_NETWORK_TESTNET, 11 | ChainSlug.ANCIENT8_TESTNET, 12 | ChainSlug.ANCIENT8_TESTNET2, 13 | ChainSlug.REYA_CRONOS, 14 | ChainSlug.REYA, 15 | ChainSlug.GOERLI, 16 | ChainSlug.VICTION_TESTNET, 17 | ChainSlug.SYNDR_SEPOLIA_L3, 18 | ChainSlug.BSC_TESTNET, 19 | ChainSlug.NEOX_TESTNET, 20 | ChainSlug.NEOX_T4_TESTNET, 21 | ChainSlug.NEOX, 22 | ChainSlug.GNOSIS, 23 | ChainSlug.LINEA, 24 | ChainSlug.ZKEVM, 25 | ChainSlug.AVALANCHE, 26 | ChainSlug.POLYGON_AMOY, 27 | ChainSlug.SONIC, 28 | ChainSlug.BERA, 29 | ChainSlug.MONAD_TESTNET, 30 | ChainSlug.SCROLL, 31 | ]; 32 | -------------------------------------------------------------------------------- /src/enums/hardhatChainName.ts: -------------------------------------------------------------------------------- 1 | export enum HardhatChainName { 2 | ARBITRUM = "arbitrum", 3 | ARBITRUM_GOERLI = "arbitrum_goerli", 4 | ARBITRUM_SEPOLIA = "arbitrum_sepolia", 5 | OPTIMISM = "optimism", 6 | OPTIMISM_GOERLI = "optimism_goerli", 7 | OPTIMISM_SEPOLIA = "optimism_sepolia", 8 | BSC = "bsc", 9 | MAINNET = "mainnet", 10 | GOERLI = "goerli", 11 | SEPOLIA = "sepolia", 12 | POLYGON_MAINNET = "polygon_mainnet", 13 | AEVO_TESTNET = "aevo_testnet", 14 | AEVO = "aevo", 15 | LYRA_TESTNET = "lyra_testnet", 16 | LYRA = "lyra", 17 | XAI_TESTNET = "xai_testnet", 18 | SX_NETWORK_TESTNET = "sxn_testnet", 19 | SX_NETWORK = "sxn", 20 | MODE_TESTNET = "mode_testnet", 21 | VICTION_TESTNET = "viction_testnet", 22 | CDK_TESTNET = "cdk_testnet", 23 | HARDHAT = "hardhat", 24 | BASE = "base", 25 | MODE = "mode", 26 | ANCIENT8_TESTNET = "ancient8_testnet", 27 | ANCIENT8_TESTNET2 = "ancient8_testnet2", 28 | PARALLEL = "parallel", 29 | MANTLE = "mantle", 30 | REYA_CRONOS = "reya_cronos", 31 | REYA = "reya", 32 | SYNDR_SEPOLIA_L3 = "syndr_sepolia_l3", 33 | POLYNOMIAL_TESTNET = "polynomial_testnet", 34 | BOB = "bob", 35 | KINTO = "kinto", 36 | KINTO_DEVNET = "kinto_devnet", 37 | SIPHER_FUNKI_TESTNET = "sipher_funki_testnet", 38 | WINR = "winr", 39 | BLAST = "blast", 40 | BSC_TESTNET = "bsc_testnet", 41 | POLYNOMIAL = "polynomial", 42 | SYNDR = "syndr", 43 | NEOX_TESTNET = "neox_testnet", 44 | NEOX_T4_TESTNET = "neox_t4_testnet", 45 | NEOX = "neox", 46 | GNOSIS = "gnosis", 47 | LINEA = "linea", 48 | ZKEVM = "zkevm", 49 | AVALANCHE = "avalanche", 50 | XLAYER = "xlayer", 51 | MANTA_PACIFIC = "manta_pacific", 52 | POLTER_TESTNET = "polter_testnet", 53 | POLYGON_AMOY = "polygon_amoy", 54 | OPBNB = "opbnb", 55 | GEIST = "geist", 56 | ZERO_SEPOLIA = "zero_sepolia", 57 | ZERO = "zero", 58 | ZKSYNC = "zksync", 59 | ARENA_Z = "arena_z", 60 | INK = "ink", 61 | SONIC = "sonic", 62 | BASE_SEPOLIA = "base_sepolia", 63 | BERA = "bera", 64 | B3 = "b3", 65 | UNICHAIN = "unichain", 66 | MONAD_TESTNET = "monad_testnet", 67 | SCROLL = "scroll", 68 | SONEIUM = "soneium", 69 | SWELLCHAIN = "swellchain", 70 | WORLD_CHAIN = "world_chain", 71 | PLUME = "plume", 72 | KATANA = "katana", 73 | } 74 | -------------------------------------------------------------------------------- /src/enums/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./arbChains"; 2 | export * from "./arbL3Chains"; 3 | export * from "./chainId"; 4 | export * from "./chainSlug"; 5 | export * from "./chainSlugToHardhatChainName"; 6 | export * from "./chainSlugToId"; 7 | export * from "./chainSlugToKey"; 8 | export * from "./currency"; 9 | export * from "./ethLikeChains"; 10 | export * from "./hardhatChainName"; 11 | export * from "./hardhatChainNameToSlug"; 12 | export * from "./mainnetIds"; 13 | export * from "./native-tokens"; 14 | export * from "./opStackChains"; 15 | export * from "./polygonCDKChains"; 16 | export * from "./zkStackChain"; 17 | export * from "./testnetIds"; 18 | -------------------------------------------------------------------------------- /src/enums/mainnetIds.ts: -------------------------------------------------------------------------------- 1 | import { ChainSlug } from "./chainSlug"; 2 | 3 | export const MainnetIds: ChainSlug[] = [ 4 | ChainSlug.MAINNET, 5 | ChainSlug.POLYGON_MAINNET, 6 | ChainSlug.ARBITRUM, 7 | ChainSlug.OPTIMISM, 8 | ChainSlug.BSC, 9 | ChainSlug.AEVO, 10 | ChainSlug.LYRA, 11 | ChainSlug.BASE, 12 | ChainSlug.MODE, 13 | // // ChainSlug.PARALLEL, 14 | ChainSlug.MANTLE, 15 | ChainSlug.REYA, 16 | // // ChainSlug.SX_NETWORK, 17 | // // ChainSlug.BOB, 18 | ChainSlug.KINTO, 19 | ChainSlug.WINR, 20 | ChainSlug.BLAST, 21 | ChainSlug.POLYNOMIAL, 22 | ChainSlug.SYNDR, 23 | ChainSlug.NEOX, 24 | ChainSlug.GNOSIS, 25 | ChainSlug.LINEA, 26 | ChainSlug.ZKEVM, 27 | ChainSlug.AVALANCHE, 28 | ChainSlug.XLAYER, 29 | ChainSlug.MANTA_PACIFIC, 30 | ChainSlug.OPBNB, 31 | ChainSlug.GEIST, 32 | // // ChainSlug.ZERO, 33 | // // ChainSlug.ZKSYNC, 34 | ChainSlug.ARENA_Z, 35 | ChainSlug.INK, 36 | ChainSlug.SONIC, 37 | ChainSlug.BERA, 38 | ChainSlug.B3, 39 | ChainSlug.UNICHAIN, 40 | ChainSlug.SCROLL, 41 | ChainSlug.SONEIUM, 42 | ChainSlug.SWELLCHAIN, 43 | ChainSlug.WORLD_CHAIN, 44 | ChainSlug.PLUME, 45 | ChainSlug.KATANA, 46 | ]; 47 | -------------------------------------------------------------------------------- /src/enums/native-tokens.ts: -------------------------------------------------------------------------------- 1 | // add coingecko token id here 2 | export enum NativeTokens { 3 | "ethereum" = "ethereum", 4 | "matic-network" = "matic-network", 5 | "binancecoin" = "binancecoin", 6 | "sx-network-2" = "sx-network-2", 7 | "mantle" = "mantle", 8 | "winr" = "winr-protocol", 9 | "no-token" = "no-token", 10 | "gas" = "gas", 11 | "dai" = "dai", 12 | "avalanche-2" = "avalanche-2", 13 | "okb" = "okb", 14 | "aavegotchi" = "aavegotchi", 15 | "fantom" = "fantom", 16 | "berachain-bera" = "berachain-bera", 17 | "monad" = "monad", 18 | "plume" = "plume", 19 | } 20 | -------------------------------------------------------------------------------- /src/enums/opStackChains.ts: -------------------------------------------------------------------------------- 1 | import { ChainSlug } from "./chainSlug"; 2 | 3 | export const opStackL2Chain = [ 4 | ChainSlug.AEVO, 5 | ChainSlug.AEVO_TESTNET, 6 | ChainSlug.LYRA, 7 | ChainSlug.MODE_TESTNET, 8 | ChainSlug.LYRA_TESTNET, 9 | ChainSlug.MODE, 10 | ChainSlug.OPTIMISM, 11 | ChainSlug.OPTIMISM_SEPOLIA, 12 | ChainSlug.OPTIMISM_GOERLI, 13 | ChainSlug.BASE, 14 | ChainSlug.MANTLE, 15 | ChainSlug.POLYNOMIAL_TESTNET, 16 | ChainSlug.BOB, 17 | ChainSlug.SIPHER_FUNKI_TESTNET, 18 | ChainSlug.BLAST, 19 | ChainSlug.POLYNOMIAL, 20 | ChainSlug.MANTA_PACIFIC, 21 | ChainSlug.POLTER_TESTNET, 22 | ChainSlug.OPBNB, 23 | ChainSlug.ARENA_Z, 24 | ChainSlug.INK, 25 | ChainSlug.BASE_SEPOLIA, 26 | ChainSlug.B3, 27 | ChainSlug.UNICHAIN, 28 | ChainSlug.SONEIUM, 29 | ChainSlug.SWELLCHAIN, 30 | ChainSlug.WORLD_CHAIN, 31 | ChainSlug.KATANA, 32 | ]; 33 | -------------------------------------------------------------------------------- /src/enums/polygonCDKChains.ts: -------------------------------------------------------------------------------- 1 | import { ChainSlug } from "./chainSlug"; 2 | 3 | export const polygonCDKChains = [ 4 | ChainSlug.CDK_TESTNET, 5 | ChainSlug.ANCIENT8_TESTNET2, 6 | ChainSlug.SX_NETWORK_TESTNET, 7 | ChainSlug.SX_NETWORK, 8 | ChainSlug.XAI_TESTNET, 9 | ChainSlug.XLAYER, 10 | ]; 11 | -------------------------------------------------------------------------------- /src/enums/testnetIds.ts: -------------------------------------------------------------------------------- 1 | import { ChainSlug } from "./chainSlug"; 2 | 3 | export const TestnetIds: ChainSlug[] = [ 4 | ChainSlug.GOERLI, 5 | ChainSlug.SEPOLIA, 6 | ChainSlug.ARBITRUM_GOERLI, 7 | ChainSlug.ARBITRUM_SEPOLIA, 8 | ChainSlug.OPTIMISM_GOERLI, 9 | ChainSlug.OPTIMISM_SEPOLIA, 10 | ChainSlug.AEVO_TESTNET, 11 | ChainSlug.LYRA_TESTNET, 12 | ChainSlug.XAI_TESTNET, 13 | ChainSlug.SX_NETWORK_TESTNET, 14 | ChainSlug.MODE_TESTNET, 15 | ChainSlug.VICTION_TESTNET, 16 | ChainSlug.CDK_TESTNET, 17 | ChainSlug.ANCIENT8_TESTNET, 18 | ChainSlug.ANCIENT8_TESTNET2, 19 | ChainSlug.REYA_CRONOS, 20 | ChainSlug.SYNDR_SEPOLIA_L3, 21 | ChainSlug.POLYNOMIAL_TESTNET, 22 | ChainSlug.KINTO_DEVNET, 23 | ChainSlug.SIPHER_FUNKI_TESTNET, 24 | ChainSlug.BSC_TESTNET, 25 | ChainSlug.NEOX_TESTNET, 26 | ChainSlug.NEOX_T4_TESTNET, 27 | ChainSlug.POLTER_TESTNET, 28 | ChainSlug.POLYGON_AMOY, 29 | ChainSlug.ZERO_SEPOLIA, 30 | ChainSlug.BASE_SEPOLIA, 31 | ChainSlug.MONAD_TESTNET, 32 | ]; 33 | -------------------------------------------------------------------------------- /src/enums/zkStackChain.ts: -------------------------------------------------------------------------------- 1 | import { ChainSlug } from "./chainSlug"; 2 | 3 | export const zkStackChain = [ 4 | ChainSlug.ZERO_SEPOLIA, 5 | ChainSlug.ZERO, 6 | ChainSlug.ZKSYNC, 7 | ]; 8 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { DeploymentMode } from "./socket-types"; 2 | export { getFinality } from "../scripts/rpcConfig/constants/finality"; 3 | export { getDefaultFinalityBucket } from "../scripts/rpcConfig/constants/defaultFinalityBucket"; 4 | export { getReSyncInterval } from "../scripts/rpcConfig/constants/reSyncInterval"; 5 | export { getOverrides } from "../scripts/constants/overrides"; 6 | 7 | export * from "./socket-types"; 8 | export * from "./enums"; 9 | export * from "./addresses"; 10 | export * from "./currency-util"; 11 | export * from "./transmission-utils"; 12 | 13 | export const version = { 14 | [DeploymentMode.DEV]: "IMLI", 15 | [DeploymentMode.SURGE]: "IMLI", 16 | [DeploymentMode.PROD]: "IMLI", 17 | }; 18 | -------------------------------------------------------------------------------- /src/transmission-utils.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Transmission param format: 3 | - first byte - version - current version is 1 4 | - 2nd byte - finalityType (1: bucket) 5 | - next 4 bytes - value - bucket (1:low, 2:medium, 3:high) 6 | 7 | eg : want to transmit message with high finality - 8 | transmissionParam = 0x0101000000030000000000000000000000000000000000000000000000000000 9 | 10 | eg : want to transmit message with low finality - 11 | transmissionParam = 0x0101000000010000000000000000000000000000000000000000000000000000 12 | 13 | if version is 0, or invalid finality type, or invalid value is mentioned, it will use the default Bucket for that chain 14 | */ 15 | 16 | export const decodeTransmissionParams = (transmissionParam: string) => { 17 | if (transmissionParam.length !== 64 && transmissionParam.length !== 66) { 18 | throw new Error("Invalid transmission param length"); 19 | } 20 | transmissionParam = transmissionParam.replace("0x", ""); 21 | const version = parseInt("0x" + transmissionParam.slice(0, 2)); 22 | const finalityType = parseInt("0x" + transmissionParam.slice(2, 4)); 23 | const value = parseInt("0x" + transmissionParam.slice(4, 12)); 24 | 25 | return { version, finalityType, value }; 26 | }; 27 | 28 | export const encodeTransmissionParams = ( 29 | version: number, 30 | finalityType: number, 31 | value: number 32 | ) => { 33 | let transmissionParam = "0x"; 34 | transmissionParam += version.toString(16).padStart(2, "0"); 35 | transmissionParam += finalityType.toString(16).padStart(2, "0"); 36 | transmissionParam += value.toString(16).padStart(8, "0"); 37 | transmissionParam = transmissionParam.padEnd(66, "0"); 38 | return transmissionParam; 39 | }; 40 | 41 | export const isTxFinalized = ( 42 | currentBlock: number, 43 | eventBlock: number, 44 | finalityBlockDiff: number 45 | ) => { 46 | if ( 47 | currentBlock == null || 48 | currentBlock == undefined || 49 | eventBlock == null || 50 | eventBlock == undefined || 51 | finalityBlockDiff == null || 52 | finalityBlockDiff == undefined 53 | ) { 54 | throw new Error("Invalid data for block finality check"); 55 | } 56 | return currentBlock - eventBlock >= finalityBlockDiff; 57 | }; 58 | -------------------------------------------------------------------------------- /tasks/accounts.ts: -------------------------------------------------------------------------------- 1 | import { HardhatRuntimeEnvironment } from "hardhat/types/runtime"; 2 | 3 | export default async function accounts( 4 | params: any, 5 | hre: HardhatRuntimeEnvironment 6 | ): Promise { 7 | const [account] = await hre.ethers.getSigners(); 8 | 9 | console.log( 10 | `Balance for 1st account ${await account.getAddress()}: ${await account.getBalance()}` 11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /test/capacitors/CapacitorFactory.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | pragma solidity 0.8.19; 3 | 4 | import "../Setup.t.sol"; 5 | import {ERC20PresetFixedSupply} from "lib/openzeppelin-contracts/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol"; 6 | 7 | contract CapacitorFactoryTest is Setup { 8 | uint256 tokenSupply = 10000; 9 | uint32 siblingChainSlug = 80001; 10 | 11 | CapacitorFactory _cf; 12 | ERC20PresetFixedSupply _token; 13 | error NoPermit(bytes32 role); 14 | 15 | function setUp() external { 16 | initialize(); 17 | _cf = new CapacitorFactory(_socketOwner, maxAllowedPacketLength); 18 | _token = new ERC20PresetFixedSupply( 19 | "TEST", 20 | "T", 21 | tokenSupply, 22 | _socketOwner 23 | ); 24 | } 25 | 26 | function testDeploySingleCapacitor() external { 27 | (ICapacitor singleCapacitor, IDecapacitor singleDecapacitor) = _cf 28 | .deploy(1, siblingChainSlug, DEFAULT_BATCH_LENGTH); 29 | 30 | assertEq( 31 | address(singleCapacitor), 32 | 0x104fBc016F4bb334D775a19E8A6510109AC63E00 33 | ); 34 | assertEq( 35 | address(singleDecapacitor), 36 | 0x037eDa3aDB1198021A9b2e88C22B464fD38db3f3 37 | ); 38 | } 39 | 40 | function testDeployForInvalidCapacitorType(uint256 capacitorType) external { 41 | if (capacitorType != 1) { 42 | vm.expectRevert(ICapacitorFactory.InvalidCapacitorType.selector); 43 | } 44 | 45 | _cf.deploy(capacitorType, siblingChainSlug, DEFAULT_BATCH_LENGTH); 46 | } 47 | 48 | function testRescueFunds() external { 49 | uint256 amount = 1000; 50 | 51 | vm.startPrank(_socketOwner); 52 | _cf.grantRole(RESCUE_ROLE, _socketOwner); 53 | 54 | _token.transfer(address(_cf), amount); 55 | vm.stopPrank(); 56 | 57 | uint256 initialBalOfOwner = _token.balanceOf(_raju); 58 | 59 | hoax(_raju); 60 | bytes4 selector = bytes4(keccak256("NoPermit(bytes32)")); 61 | vm.expectRevert(abi.encodeWithSelector(selector, RESCUE_ROLE)); 62 | 63 | _cf.rescueFunds(address(_token), _raju, amount); 64 | 65 | hoax(_socketOwner); 66 | _cf.rescueFunds(address(_token), _raju, amount); 67 | 68 | uint256 finalBalOfOwner = _token.balanceOf(_raju); 69 | assertEq(finalBalOfOwner - initialBalOfOwner, amount); 70 | } 71 | 72 | function testRescueNativeFunds() external { 73 | uint256 amount = 1e18; 74 | 75 | hoax(_socketOwner); 76 | _rescueNative(address(_cf), NATIVE_TOKEN_ADDRESS, _fundRescuer, amount); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /test/managers/OpenExecutionManager.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | pragma solidity 0.8.19; 3 | 4 | import "../Setup.t.sol"; 5 | 6 | contract OpenExecutionManagerTest is Setup { 7 | OpenExecutionManager internal executionManager; 8 | 9 | error InsufficientExecutionFees(); 10 | event FeesWithdrawn(address account_, uint256 value_); 11 | error MsgValueTooLow(); 12 | error MsgValueTooHigh(); 13 | error InsufficientMsgValue(); 14 | 15 | function setUp() public { 16 | initialize(); 17 | _a.chainSlug = uint32(uint256(aChainSlug)); 18 | uint256[] memory transmitterPrivateKeys = new uint256[](1); 19 | transmitterPrivateKeys[0] = _transmitterPrivateKey; 20 | _deployContractsOnSingleChain( 21 | _a, 22 | bChainSlug, 23 | true, 24 | transmitterPrivateKeys 25 | ); 26 | 27 | executionManager = OpenExecutionManager(address(_a.executionManager__)); 28 | } 29 | 30 | function testIsExecutor() public { 31 | bytes32 packedMessage = bytes32("RANDOM_ROOT"); 32 | bytes memory sig = _createSignature(packedMessage, _executorPrivateKey); 33 | (, bool isValidExecutor) = executionManager.isExecutor( 34 | packedMessage, 35 | sig 36 | ); 37 | assertTrue(isValidExecutor); 38 | 39 | sig = _createSignature(packedMessage, _nonExecutorPrivateKey); 40 | (, isValidExecutor) = executionManager.isExecutor(packedMessage, sig); 41 | assertTrue(isValidExecutor); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /test/socket/SocketAdmin.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | pragma solidity 0.8.19; 3 | 4 | import "../Setup.t.sol"; 5 | 6 | contract SocketSrcTest is Setup { 7 | Socket internal socket__; 8 | 9 | address newHasher = address(uint160(c++)); 10 | address newTransmitManager = address(uint160(c++)); 11 | address newExecutionManager = address(uint160(c++)); 12 | address newCapacitorFactory = address(uint160(c++)); 13 | 14 | function setUp() external { 15 | initialize(); 16 | _a.chainSlug = uint32(uint256(aChainSlug)); 17 | uint256[] memory transmitterPrivateKeys = new uint256[](1); 18 | transmitterPrivateKeys[0] = _transmitterPrivateKey; 19 | _deployContractsOnSingleChain( 20 | _a, 21 | bChainSlug, 22 | isExecutionOpen, 23 | transmitterPrivateKeys 24 | ); 25 | 26 | socket__ = _a.socket__; 27 | } 28 | 29 | function testSetHasher() public { 30 | assertEq(address(socket__.hasher__()), address(_a.hasher__)); 31 | 32 | hoax(_raju); 33 | vm.expectRevert( 34 | abi.encodeWithSelector( 35 | AccessControl.NoPermit.selector, 36 | GOVERNANCE_ROLE 37 | ) 38 | ); 39 | socket__.setHasher(newHasher); 40 | 41 | hoax(_socketOwner); 42 | socket__.setHasher(newHasher); 43 | 44 | assertEq(address(socket__.hasher__()), newHasher); 45 | } 46 | 47 | function testSetTransmitManager() public { 48 | assertEq( 49 | address(socket__.transmitManager__()), 50 | address(_a.transmitManager__) 51 | ); 52 | 53 | hoax(_raju); 54 | vm.expectRevert( 55 | abi.encodeWithSelector( 56 | AccessControl.NoPermit.selector, 57 | GOVERNANCE_ROLE 58 | ) 59 | ); 60 | socket__.setTransmitManager(newTransmitManager); 61 | 62 | hoax(_socketOwner); 63 | socket__.setTransmitManager(newTransmitManager); 64 | 65 | assertEq(address(socket__.transmitManager__()), newTransmitManager); 66 | } 67 | 68 | function testSetExecutionManager() public { 69 | assertEq( 70 | address(socket__.executionManager__()), 71 | address(_a.executionManager__) 72 | ); 73 | 74 | hoax(_raju); 75 | vm.expectRevert( 76 | abi.encodeWithSelector( 77 | AccessControl.NoPermit.selector, 78 | GOVERNANCE_ROLE 79 | ) 80 | ); 81 | socket__.setExecutionManager(newExecutionManager); 82 | 83 | hoax(_socketOwner); 84 | socket__.setExecutionManager(newExecutionManager); 85 | 86 | assertEq(address(socket__.executionManager__()), newExecutionManager); 87 | } 88 | 89 | function testSetCapacitorFactory() public { 90 | assertEq( 91 | address(socket__.capacitorFactory__()), 92 | address(_a.capacitorFactory__) 93 | ); 94 | 95 | hoax(_raju); 96 | vm.expectRevert( 97 | abi.encodeWithSelector( 98 | AccessControl.NoPermit.selector, 99 | GOVERNANCE_ROLE 100 | ) 101 | ); 102 | socket__.setCapacitorFactory(newCapacitorFactory); 103 | 104 | hoax(_socketOwner); 105 | socket__.setCapacitorFactory(newCapacitorFactory); 106 | 107 | assertEq(address(socket__.capacitorFactory__()), newCapacitorFactory); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /test/socket/SocketBatcher.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | pragma solidity 0.8.19; 3 | 4 | import "../Setup.t.sol"; 5 | import "../../contracts/socket/SocketBatcher.sol"; 6 | import "../../contracts/examples/Counter.sol"; 7 | 8 | contract SocketBatcherTest is Setup { 9 | Counter srcCounter__; 10 | Counter dstCounter__; 11 | SocketBatcher batcher__; 12 | 13 | uint256 addAmount = 100; 14 | uint256 subAmount = 40; 15 | bool isFast = true; 16 | uint256 index = isFast ? 0 : 1; 17 | 18 | bytes32[] roots; 19 | 20 | event ExecutionSuccess(bytes32 msgId); 21 | event ExecutionFailed(bytes32 msgId, string result); 22 | event ExecutionFailedBytes(bytes32 msgId, bytes result); 23 | event PacketVerifiedAndSealed( 24 | address indexed transmitter, 25 | bytes32 indexed packetId, 26 | bytes32 root, 27 | bytes signature 28 | ); 29 | 30 | function setUp() external { 31 | uint256[] memory transmitterPrivateKeys = new uint256[](1); 32 | transmitterPrivateKeys[0] = _transmitterPrivateKey; 33 | 34 | _dualChainSetup(transmitterPrivateKeys); 35 | _deployPlugContracts(); 36 | 37 | _configPlugContracts(index); 38 | batcher__ = new SocketBatcher(address(this)); 39 | } 40 | 41 | function _deployPlugContracts() internal { 42 | vm.startPrank(_plugOwner); 43 | 44 | // deploy counters 45 | srcCounter__ = new Counter(address(_a.socket__)); 46 | dstCounter__ = new Counter(address(_b.socket__)); 47 | 48 | vm.stopPrank(); 49 | } 50 | 51 | function _configPlugContracts(uint256 socketConfigIndex) internal { 52 | hoax(_plugOwner); 53 | srcCounter__.setSocketConfig( 54 | _b.chainSlug, 55 | address(dstCounter__), 56 | address(_a.configs__[socketConfigIndex].switchboard__) 57 | ); 58 | 59 | hoax(_plugOwner); 60 | dstCounter__.setSocketConfig( 61 | _a.chainSlug, 62 | address(srcCounter__), 63 | address(_b.configs__[socketConfigIndex].switchboard__) 64 | ); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /test/utils/Ownable.t.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-only 2 | pragma solidity 0.8.19; 3 | 4 | import "forge-std/Test.sol"; 5 | import "../../contracts/mocks/MockOwnable.sol"; 6 | 7 | contract OwnableTest is Test { 8 | uint256 internal c = 1000; 9 | address immutable _bob = address(uint160(c++)); 10 | address immutable _owner = address(uint160(c++)); 11 | address immutable _newOwner = address(uint160(c++)); 12 | MockOwnable _mo; 13 | 14 | function setUp() external { 15 | _mo = new MockOwnable(_owner); 16 | } 17 | 18 | function testOwnerSet() external { 19 | address owner = _mo.owner(); 20 | assertEq(owner, _owner); 21 | } 22 | 23 | function testOwnableFunction() external { 24 | hoax(_owner); 25 | _mo.ownerFunction(); 26 | 27 | hoax(_bob); 28 | vm.expectRevert(Ownable.OnlyOwner.selector); 29 | _mo.ownerFunction(); 30 | } 31 | 32 | function testPublicFunction() external { 33 | hoax(_owner); 34 | _mo.publicFunction(); 35 | 36 | hoax(_bob); 37 | _mo.publicFunction(); 38 | } 39 | 40 | function testNominate() external { 41 | hoax(_bob); 42 | vm.expectRevert(Ownable.OnlyOwner.selector); 43 | _mo.nominateOwner(_newOwner); 44 | 45 | hoax(_owner); 46 | _mo.nominateOwner(_newOwner); 47 | } 48 | 49 | function testClaimOwner() external { 50 | hoax(_owner); 51 | _mo.nominateOwner(_newOwner); 52 | 53 | assertEq(_mo.nominee(), _newOwner); 54 | hoax(_bob); 55 | vm.expectRevert(Ownable.OnlyNominee.selector); 56 | _mo.claimOwner(); 57 | 58 | hoax(_newOwner); 59 | _mo.claimOwner(); 60 | } 61 | 62 | function testOwnableFunctionAfterChange() external { 63 | hoax(_owner); 64 | _mo.nominateOwner(_newOwner); 65 | 66 | hoax(_newOwner); 67 | _mo.claimOwner(); 68 | 69 | hoax(_newOwner); 70 | _mo.ownerFunction(); 71 | 72 | hoax(_owner); 73 | vm.expectRevert(Ownable.OnlyOwner.selector); 74 | _mo.ownerFunction(); 75 | 76 | hoax(_bob); 77 | vm.expectRevert(Ownable.OnlyOwner.selector); 78 | _mo.ownerFunction(); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2018", 4 | "module": "commonjs", 5 | "strict": false, 6 | "esModuleInterop": true, 7 | "outDir": "dist", 8 | "declaration": true, 9 | "resolveJsonModule": true 10 | }, 11 | "include": [ 12 | "./hardhat.config.ts", 13 | "./src", 14 | "./tasks", 15 | "./test", 16 | "./typechain-types", 17 | "./scripts" 18 | ], 19 | "files": ["./hardhat.config.ts"] 20 | } 21 | --------------------------------------------------------------------------------