├── .github └── workflows │ └── release.yml ├── .gitignore ├── LICENSE ├── README.md ├── funding.json ├── optimism ├── __init__.py ├── assets │ ├── dispute_game_factory.json │ ├── erc20.json │ ├── fault_dispute_game.json │ ├── l1_cross_messenger.json │ ├── l1_standard_bridge.json │ ├── l2_cross_messenger.json │ ├── l2_output_oracle.json │ ├── l2_standard_bridge.json │ ├── l2_to_l1_message_passer.json │ ├── optimism_erc20.json │ └── optimism_portal.json ├── config.json ├── constants.py ├── contracts.py ├── cross_chain_messenger.py ├── types.py └── utils.py ├── pyproject.toml ├── requirements.txt └── test ├── README.md ├── __init__.py ├── extract_addresses.py ├── test_deposit.py ├── test_withdrawl.py └── utils.py /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | release: 5 | types: [created] 6 | 7 | jobs: 8 | publish-pypi: 9 | name: Publish to PyPi 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/checkout@v4 14 | - name: Set up Python 15 | uses: actions/setup-python@v4 16 | with: 17 | python-version: '3.11.0' 18 | - name: Install dependencies 19 | run: | 20 | python -m pip install --upgrade pip 21 | pip install poetry 22 | - name: Build and publish 23 | env: 24 | PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} 25 | run: | 26 | # set pyproject.toml version to github.ref_name (without v prefix) 27 | VERSION=$(echo "${{ github.ref_name }}" | sed 's/^v//') 28 | sed -i 's/^version = ".*"$/version = "'"$VERSION"'"/' pyproject.toml 29 | poetry publish --build --username=__token__ --password=$PYPI_TOKEN -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | __pycache__ 3 | 4 | dist -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2023 rafalum 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Optimism-Python: Unofficial Python Client for the OP-Stack 2 | 3 | > [!WARNING] 4 | > Reference SDK is still under active development so the repository might be temporarily out of date. 5 | 6 |
7 | 8 |
9 | 10 | 11 | This library is a Python implementation of the [OP-Stack SDK](https://sdk.optimism.io/). It tries to mirror some of the core functionalities such as: 12 | 13 | - providing easy access to the OP-Stack contracts 14 | - bridging of assets from L1 to L2 (deposits) and vice-versa (withdrawls) 15 | - creating withdrawl proofs 16 | 17 | ## Getting started 18 | 19 | ### Installation 20 | 21 | ```bash 22 | pip install optimism-python 23 | ``` 24 | 25 | ### Deposit ETH to L2 26 | 27 | ```python 28 | from web3 import Web3 29 | from optimism import CrossChainMessenger 30 | from optimism.types import Chains 31 | 32 | # Create a node provider for each chain 33 | provider_l1 = Web3(Web3.HTTPProvider("https://eth-mainnet.g.alchemy.com/v2/")) 34 | provider_l2 = Web3(Web3.HTTPProvider("https://optimism-mainnet.g.alchemy.com/v2/")) 35 | 36 | # Specify an account for each chain (can be the same) 37 | account_l1 = provider_l1.eth.account.from_key("") 38 | account_l2 = provider_l2.eth.account.from_key("") 39 | 40 | # Create a messenger instance 41 | messenger = CrossChainMessenger(chain_l1=Chains.ETHEREUM_MAINNET, 42 | chain_l2=Chains.OPTIMISM_MAINNET, 43 | account_l1=account_l1, 44 | account_l2=account_l2, 45 | provider_l1=provider_l1, 46 | provider_l2=provider_l2) 47 | 48 | # Deposit 1 ETH to L2 49 | messenger.deposit_eth(10**18) 50 | ``` 51 | -------------------------------------------------------------------------------- /funding.json: -------------------------------------------------------------------------------- 1 | { 2 | "opRetro": { 3 | "projectId": "0x0b723463dee5c51f19dec738932260e89c9641f7342b8021551123605dee2dd6" 4 | } 5 | } -------------------------------------------------------------------------------- /optimism/__init__.py: -------------------------------------------------------------------------------- 1 | from .cross_chain_messenger import CrossChainMessenger 2 | from .contracts import OptimismPortal, StandardBridge, L2ToL1MessagePasser, L2OutputOracle, DisputeGameFactory, FaultDisputeGame, CrossChainMessengerContract 3 | from .types import Chains 4 | 5 | __all__ = ["CrossChainMessenger", "OptimismPortal", "StandardBridge", "CrossChainMessengerContract", "L2OutputOracle", "DisputeGameFactory", "FaultDisputeGame", "L2ToL1MessagePasser", "Chains"] -------------------------------------------------------------------------------- /optimism/assets/dispute_game_factory.json: -------------------------------------------------------------------------------- 1 | [{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"Hash","name":"uuid","type":"bytes32"}],"name":"GameAlreadyExists","type":"error"},{"inputs":[],"name":"IncorrectBondAmount","type":"error"},{"inputs":[{"internalType":"GameType","name":"gameType","type":"uint32"}],"name":"NoImplementation","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"disputeProxy","type":"address"},{"indexed":true,"internalType":"GameType","name":"gameType","type":"uint32"},{"indexed":true,"internalType":"Claim","name":"rootClaim","type":"bytes32"}],"name":"DisputeGameCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"impl","type":"address"},{"indexed":true,"internalType":"GameType","name":"gameType","type":"uint32"}],"name":"ImplementationSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"GameType","name":"gameType","type":"uint32"},{"indexed":true,"internalType":"uint256","name":"newBond","type":"uint256"}],"name":"InitBondUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"internalType":"GameType","name":"_gameType","type":"uint32"},{"internalType":"Claim","name":"_rootClaim","type":"bytes32"},{"internalType":"bytes","name":"_extraData","type":"bytes"}],"name":"create","outputs":[{"internalType":"contract IDisputeGame","name":"proxy_","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"GameType","name":"_gameType","type":"uint32"},{"internalType":"uint256","name":"_start","type":"uint256"},{"internalType":"uint256","name":"_n","type":"uint256"}],"name":"findLatestGames","outputs":[{"components":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"GameId","name":"metadata","type":"bytes32"},{"internalType":"Timestamp","name":"timestamp","type":"uint64"},{"internalType":"Claim","name":"rootClaim","type":"bytes32"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct IDisputeGameFactory.GameSearchResult[]","name":"games_","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"gameAtIndex","outputs":[{"internalType":"GameType","name":"gameType_","type":"uint32"},{"internalType":"Timestamp","name":"timestamp_","type":"uint64"},{"internalType":"contract IDisputeGame","name":"proxy_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gameCount","outputs":[{"internalType":"uint256","name":"gameCount_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"GameType","name":"","type":"uint32"}],"name":"gameImpls","outputs":[{"internalType":"contract IDisputeGame","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"GameType","name":"_gameType","type":"uint32"},{"internalType":"Claim","name":"_rootClaim","type":"bytes32"},{"internalType":"bytes","name":"_extraData","type":"bytes"}],"name":"games","outputs":[{"internalType":"contract IDisputeGame","name":"proxy_","type":"address"},{"internalType":"Timestamp","name":"timestamp_","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"GameType","name":"_gameType","type":"uint32"},{"internalType":"Claim","name":"_rootClaim","type":"bytes32"},{"internalType":"bytes","name":"_extraData","type":"bytes"}],"name":"getGameUUID","outputs":[{"internalType":"Hash","name":"uuid_","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"GameType","name":"","type":"uint32"}],"name":"initBonds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"GameType","name":"_gameType","type":"uint32"},{"internalType":"contract IDisputeGame","name":"_impl","type":"address"}],"name":"setImplementation","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"GameType","name":"_gameType","type":"uint32"},{"internalType":"uint256","name":"_initBond","type":"uint256"}],"name":"setInitBond","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}] -------------------------------------------------------------------------------- /optimism/assets/erc20.json: -------------------------------------------------------------------------------- 1 | [{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"authorizer","type":"address"},{"indexed":true,"internalType":"bytes32","name":"nonce","type":"bytes32"}],"name":"AuthorizationCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"authorizer","type":"address"},{"indexed":true,"internalType":"bytes32","name":"nonce","type":"bytes32"}],"name":"AuthorizationUsed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_account","type":"address"}],"name":"Blacklisted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newBlacklister","type":"address"}],"name":"BlacklisterChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"burner","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newMasterMinter","type":"address"}],"name":"MasterMinterChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"minter","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"minter","type":"address"},{"indexed":false,"internalType":"uint256","name":"minterAllowedAmount","type":"uint256"}],"name":"MinterConfigured","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldMinter","type":"address"}],"name":"MinterRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[],"name":"Pause","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newAddress","type":"address"}],"name":"PauserChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newRescuer","type":"address"}],"name":"RescuerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_account","type":"address"}],"name":"UnBlacklisted","type":"event"},{"anonymous":false,"inputs":[],"name":"Unpause","type":"event"},{"inputs":[],"name":"CANCEL_AUTHORIZATION_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERMIT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RECEIVE_WITH_AUTHORIZATION_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TRANSFER_WITH_AUTHORIZATION_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"authorizer","type":"address"},{"internalType":"bytes32","name":"nonce","type":"bytes32"}],"name":"authorizationState","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"blacklist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"blacklister","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"authorizer","type":"address"},{"internalType":"bytes32","name":"nonce","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"cancelAuthorization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"minter","type":"address"},{"internalType":"uint256","name":"minterAllowedAmount","type":"uint256"}],"name":"configureMinter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"currency","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"decrement","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"increment","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"tokenName","type":"string"},{"internalType":"string","name":"tokenSymbol","type":"string"},{"internalType":"string","name":"tokenCurrency","type":"string"},{"internalType":"uint8","name":"tokenDecimals","type":"uint8"},{"internalType":"address","name":"newMasterMinter","type":"address"},{"internalType":"address","name":"newPauser","type":"address"},{"internalType":"address","name":"newBlacklister","type":"address"},{"internalType":"address","name":"newOwner","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"newName","type":"string"}],"name":"initializeV2","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"lostAndFound","type":"address"}],"name":"initializeV2_1","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"isBlacklisted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isMinter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"masterMinter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"mint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"minter","type":"address"}],"name":"minterAllowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pauser","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"validAfter","type":"uint256"},{"internalType":"uint256","name":"validBefore","type":"uint256"},{"internalType":"bytes32","name":"nonce","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"receiveWithAuthorization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"minter","type":"address"}],"name":"removeMinter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"tokenContract","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"rescueERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rescuer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"validAfter","type":"uint256"},{"internalType":"uint256","name":"validBefore","type":"uint256"},{"internalType":"bytes32","name":"nonce","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"transferWithAuthorization","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"unBlacklist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newBlacklister","type":"address"}],"name":"updateBlacklister","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newMasterMinter","type":"address"}],"name":"updateMasterMinter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newPauser","type":"address"}],"name":"updatePauser","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newRescuer","type":"address"}],"name":"updateRescuer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}] -------------------------------------------------------------------------------- /optimism/assets/fault_dispute_game.json: -------------------------------------------------------------------------------- 1 | [{"inputs":[{"internalType":"GameType","name":"_gameType","type":"uint32"},{"internalType":"Claim","name":"_absolutePrestate","type":"bytes32"},{"internalType":"uint256","name":"_maxGameDepth","type":"uint256"},{"internalType":"uint256","name":"_splitDepth","type":"uint256"},{"internalType":"Duration","name":"_clockExtension","type":"uint64"},{"internalType":"Duration","name":"_maxClockDuration","type":"uint64"},{"internalType":"contract IBigStepper","name":"_vm","type":"address"},{"internalType":"contract IDelayedWETH","name":"_weth","type":"address"},{"internalType":"contract IAnchorStateRegistry","name":"_anchorStateRegistry","type":"address"},{"internalType":"uint256","name":"_l2ChainId","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"AnchorRootNotFound","type":"error"},{"inputs":[],"name":"BlockNumberMatches","type":"error"},{"inputs":[],"name":"BondTransferFailed","type":"error"},{"inputs":[],"name":"CannotDefendRootClaim","type":"error"},{"inputs":[],"name":"ClaimAboveSplit","type":"error"},{"inputs":[],"name":"ClaimAlreadyExists","type":"error"},{"inputs":[],"name":"ClaimAlreadyResolved","type":"error"},{"inputs":[],"name":"ClockNotExpired","type":"error"},{"inputs":[],"name":"ClockTimeExceeded","type":"error"},{"inputs":[],"name":"ContentLengthMismatch","type":"error"},{"inputs":[],"name":"DuplicateStep","type":"error"},{"inputs":[],"name":"EmptyItem","type":"error"},{"inputs":[],"name":"GameDepthExceeded","type":"error"},{"inputs":[],"name":"GameNotInProgress","type":"error"},{"inputs":[],"name":"IncorrectBondAmount","type":"error"},{"inputs":[],"name":"InvalidClockExtension","type":"error"},{"inputs":[],"name":"InvalidDataRemainder","type":"error"},{"inputs":[],"name":"InvalidDisputedClaimIndex","type":"error"},{"inputs":[],"name":"InvalidHeader","type":"error"},{"inputs":[],"name":"InvalidHeaderRLP","type":"error"},{"inputs":[],"name":"InvalidLocalIdent","type":"error"},{"inputs":[],"name":"InvalidOutputRootProof","type":"error"},{"inputs":[],"name":"InvalidParent","type":"error"},{"inputs":[],"name":"InvalidPrestate","type":"error"},{"inputs":[],"name":"InvalidSplitDepth","type":"error"},{"inputs":[],"name":"L2BlockNumberChallenged","type":"error"},{"inputs":[],"name":"MaxDepthTooLarge","type":"error"},{"inputs":[],"name":"NoCreditToClaim","type":"error"},{"inputs":[],"name":"OutOfOrderResolution","type":"error"},{"inputs":[],"name":"UnexpectedList","type":"error"},{"inputs":[{"internalType":"Claim","name":"rootClaim","type":"bytes32"}],"name":"UnexpectedRootClaim","type":"error"},{"inputs":[],"name":"UnexpectedString","type":"error"},{"inputs":[],"name":"ValidStep","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"parentIndex","type":"uint256"},{"indexed":true,"internalType":"Claim","name":"claim","type":"bytes32"},{"indexed":true,"internalType":"address","name":"claimant","type":"address"}],"name":"Move","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"enum GameStatus","name":"status","type":"uint8"}],"name":"Resolved","type":"event"},{"inputs":[],"name":"absolutePrestate","outputs":[{"internalType":"Claim","name":"absolutePrestate_","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_ident","type":"uint256"},{"internalType":"uint256","name":"_execLeafIdx","type":"uint256"},{"internalType":"uint256","name":"_partOffset","type":"uint256"}],"name":"addLocalData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"anchorStateRegistry","outputs":[{"internalType":"contract IAnchorStateRegistry","name":"registry_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"Claim","name":"_disputed","type":"bytes32"},{"internalType":"uint256","name":"_parentIndex","type":"uint256"},{"internalType":"Claim","name":"_claim","type":"bytes32"}],"name":"attack","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"version","type":"bytes32"},{"internalType":"bytes32","name":"stateRoot","type":"bytes32"},{"internalType":"bytes32","name":"messagePasserStorageRoot","type":"bytes32"},{"internalType":"bytes32","name":"latestBlockhash","type":"bytes32"}],"internalType":"struct Types.OutputRootProof","name":"_outputRootProof","type":"tuple"},{"internalType":"bytes","name":"_headerRLP","type":"bytes"}],"name":"challengeRootL2Block","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"}],"name":"claimCredit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"claimData","outputs":[{"internalType":"uint32","name":"parentIndex","type":"uint32"},{"internalType":"address","name":"counteredBy","type":"address"},{"internalType":"address","name":"claimant","type":"address"},{"internalType":"uint128","name":"bond","type":"uint128"},{"internalType":"Claim","name":"claim","type":"bytes32"},{"internalType":"Position","name":"position","type":"uint128"},{"internalType":"Clock","name":"clock","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimDataLen","outputs":[{"internalType":"uint256","name":"len_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"Hash","name":"","type":"bytes32"}],"name":"claims","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"clockExtension","outputs":[{"internalType":"Duration","name":"clockExtension_","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"createdAt","outputs":[{"internalType":"Timestamp","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"credit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"Claim","name":"_disputed","type":"bytes32"},{"internalType":"uint256","name":"_parentIndex","type":"uint256"},{"internalType":"Claim","name":"_claim","type":"bytes32"}],"name":"defend","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"extraData","outputs":[{"internalType":"bytes","name":"extraData_","type":"bytes"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"gameCreator","outputs":[{"internalType":"address","name":"creator_","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"gameData","outputs":[{"internalType":"GameType","name":"gameType_","type":"uint32"},{"internalType":"Claim","name":"rootClaim_","type":"bytes32"},{"internalType":"bytes","name":"extraData_","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gameType","outputs":[{"internalType":"GameType","name":"gameType_","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_claimIndex","type":"uint256"}],"name":"getChallengerDuration","outputs":[{"internalType":"Duration","name":"duration_","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_claimIndex","type":"uint256"}],"name":"getNumToResolve","outputs":[{"internalType":"uint256","name":"numRemainingChildren_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"Position","name":"_position","type":"uint128"}],"name":"getRequiredBond","outputs":[{"internalType":"uint256","name":"requiredBond_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"l1Head","outputs":[{"internalType":"Hash","name":"l1Head_","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"l2BlockNumber","outputs":[{"internalType":"uint256","name":"l2BlockNumber_","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"l2BlockNumberChallenged","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"l2BlockNumberChallenger","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"l2ChainId","outputs":[{"internalType":"uint256","name":"l2ChainId_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxClockDuration","outputs":[{"internalType":"Duration","name":"maxClockDuration_","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxGameDepth","outputs":[{"internalType":"uint256","name":"maxGameDepth_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"Claim","name":"_disputed","type":"bytes32"},{"internalType":"uint256","name":"_challengeIndex","type":"uint256"},{"internalType":"Claim","name":"_claim","type":"bytes32"},{"internalType":"bool","name":"_isAttack","type":"bool"}],"name":"move","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"resolutionCheckpoints","outputs":[{"internalType":"bool","name":"initialCheckpointComplete","type":"bool"},{"internalType":"uint32","name":"subgameIndex","type":"uint32"},{"internalType":"Position","name":"leftmostPosition","type":"uint128"},{"internalType":"address","name":"counteredBy","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"resolve","outputs":[{"internalType":"enum GameStatus","name":"status_","type":"uint8"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_claimIndex","type":"uint256"},{"internalType":"uint256","name":"_numToResolve","type":"uint256"}],"name":"resolveClaim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"resolvedAt","outputs":[{"internalType":"Timestamp","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"resolvedSubgames","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rootClaim","outputs":[{"internalType":"Claim","name":"rootClaim_","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"splitDepth","outputs":[{"internalType":"uint256","name":"splitDepth_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"startingBlockNumber","outputs":[{"internalType":"uint256","name":"startingBlockNumber_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"startingOutputRoot","outputs":[{"internalType":"Hash","name":"root","type":"bytes32"},{"internalType":"uint256","name":"l2BlockNumber","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"startingRootHash","outputs":[{"internalType":"Hash","name":"startingRootHash_","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"status","outputs":[{"internalType":"enum GameStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_claimIndex","type":"uint256"},{"internalType":"bool","name":"_isAttack","type":"bool"},{"internalType":"bytes","name":"_stateData","type":"bytes"},{"internalType":"bytes","name":"_proof","type":"bytes"}],"name":"step","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"subgames","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vm","outputs":[{"internalType":"contract IBigStepper","name":"vm_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"contract IDelayedWETH","name":"weth_","type":"address"}],"stateMutability":"view","type":"function"}] -------------------------------------------------------------------------------- /optimism/assets/l1_cross_messenger.json: -------------------------------------------------------------------------------- 1 | [{"inputs":[{"internalType":"contract OptimismPortal","name":"_portal","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"msgHash","type":"bytes32"}],"name":"FailedRelayedMessage","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"msgHash","type":"bytes32"}],"name":"RelayedMessage","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"message","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"messageNonce","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"gasLimit","type":"uint256"}],"name":"SentMessage","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"SentMessageExtension1","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"MESSAGE_VERSION","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_GAS_CALLDATA_OVERHEAD","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_GAS_CONSTANT_OVERHEAD","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_GAS_DYNAMIC_OVERHEAD_DENOMINATOR","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_GAS_DYNAMIC_OVERHEAD_NUMERATOR","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OTHER_MESSENGER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PORTAL","outputs":[{"internalType":"contract OptimismPortal","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"uint32","name":"_minGasLimit","type":"uint32"}],"name":"baseGas","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"failedMessages","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"messageNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nonce","type":"uint256"},{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_target","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"uint256","name":"_minGasLimit","type":"uint256"},{"internalType":"bytes","name":"_message","type":"bytes"}],"name":"relayMessage","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_target","type":"address"},{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"uint32","name":"_minGasLimit","type":"uint32"}],"name":"sendMessage","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"successfulMessages","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"xDomainMessageSender","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}] -------------------------------------------------------------------------------- /optimism/assets/l1_standard_bridge.json: -------------------------------------------------------------------------------- 1 | [{"inputs":[{"internalType":"address payable","name":"_messenger","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"localToken","type":"address"},{"indexed":true,"internalType":"address","name":"remoteToken","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"extraData","type":"bytes"}],"name":"ERC20BridgeFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"localToken","type":"address"},{"indexed":true,"internalType":"address","name":"remoteToken","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"extraData","type":"bytes"}],"name":"ERC20BridgeInitiated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"l1Token","type":"address"},{"indexed":true,"internalType":"address","name":"l2Token","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"extraData","type":"bytes"}],"name":"ERC20DepositInitiated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"l1Token","type":"address"},{"indexed":true,"internalType":"address","name":"l2Token","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"extraData","type":"bytes"}],"name":"ERC20WithdrawalFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"extraData","type":"bytes"}],"name":"ETHBridgeFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"extraData","type":"bytes"}],"name":"ETHBridgeInitiated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"extraData","type":"bytes"}],"name":"ETHDepositInitiated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"extraData","type":"bytes"}],"name":"ETHWithdrawalFinalized","type":"event"},{"inputs":[],"name":"MESSENGER","outputs":[{"internalType":"contract CrossDomainMessenger","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OTHER_BRIDGE","outputs":[{"internalType":"contract StandardBridge","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_localToken","type":"address"},{"internalType":"address","name":"_remoteToken","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint32","name":"_minGasLimit","type":"uint32"},{"internalType":"bytes","name":"_extraData","type":"bytes"}],"name":"bridgeERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_localToken","type":"address"},{"internalType":"address","name":"_remoteToken","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint32","name":"_minGasLimit","type":"uint32"},{"internalType":"bytes","name":"_extraData","type":"bytes"}],"name":"bridgeERC20To","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_minGasLimit","type":"uint32"},{"internalType":"bytes","name":"_extraData","type":"bytes"}],"name":"bridgeETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint32","name":"_minGasLimit","type":"uint32"},{"internalType":"bytes","name":"_extraData","type":"bytes"}],"name":"bridgeETHTo","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_l1Token","type":"address"},{"internalType":"address","name":"_l2Token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint32","name":"_minGasLimit","type":"uint32"},{"internalType":"bytes","name":"_extraData","type":"bytes"}],"name":"depositERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_l1Token","type":"address"},{"internalType":"address","name":"_l2Token","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint32","name":"_minGasLimit","type":"uint32"},{"internalType":"bytes","name":"_extraData","type":"bytes"}],"name":"depositERC20To","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_minGasLimit","type":"uint32"},{"internalType":"bytes","name":"_extraData","type":"bytes"}],"name":"depositETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint32","name":"_minGasLimit","type":"uint32"},{"internalType":"bytes","name":"_extraData","type":"bytes"}],"name":"depositETHTo","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"deposits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_localToken","type":"address"},{"internalType":"address","name":"_remoteToken","type":"address"},{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes","name":"_extraData","type":"bytes"}],"name":"finalizeBridgeERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes","name":"_extraData","type":"bytes"}],"name":"finalizeBridgeETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_l1Token","type":"address"},{"internalType":"address","name":"_l2Token","type":"address"},{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes","name":"_extraData","type":"bytes"}],"name":"finalizeERC20Withdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes","name":"_extraData","type":"bytes"}],"name":"finalizeETHWithdrawal","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"l2TokenBridge","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"messenger","outputs":[{"internalType":"contract CrossDomainMessenger","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}] -------------------------------------------------------------------------------- /optimism/assets/l2_cross_messenger.json: -------------------------------------------------------------------------------- 1 | [{"inputs":[{"internalType":"address","name":"_l1CrossDomainMessenger","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"msgHash","type":"bytes32"}],"name":"FailedRelayedMessage","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"msgHash","type":"bytes32"}],"name":"RelayedMessage","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"message","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"messageNonce","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"gasLimit","type":"uint256"}],"name":"SentMessage","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"SentMessageExtension1","type":"event"},{"inputs":[],"name":"MESSAGE_VERSION","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_GAS_CALLDATA_OVERHEAD","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_GAS_DYNAMIC_OVERHEAD_DENOMINATOR","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_GAS_DYNAMIC_OVERHEAD_NUMERATOR","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OTHER_MESSENGER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RELAY_CALL_OVERHEAD","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RELAY_CONSTANT_OVERHEAD","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RELAY_GAS_CHECK_BUFFER","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RELAY_RESERVED_GAS","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"uint32","name":"_minGasLimit","type":"uint32"}],"name":"baseGas","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"failedMessages","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"l1CrossDomainMessenger","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"messageNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_nonce","type":"uint256"},{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_target","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"uint256","name":"_minGasLimit","type":"uint256"},{"internalType":"bytes","name":"_message","type":"bytes"}],"name":"relayMessage","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_target","type":"address"},{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"uint32","name":"_minGasLimit","type":"uint32"}],"name":"sendMessage","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"successfulMessages","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"xDomainMessageSender","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}] -------------------------------------------------------------------------------- /optimism/assets/l2_output_oracle.json: -------------------------------------------------------------------------------- 1 | [{"inputs":[{"internalType":"uint256","name":"_submissionInterval","type":"uint256"},{"internalType":"uint256","name":"_l2BlockTime","type":"uint256"},{"internalType":"uint256","name":"_startingBlockNumber","type":"uint256"},{"internalType":"uint256","name":"_startingTimestamp","type":"uint256"},{"internalType":"address","name":"_proposer","type":"address"},{"internalType":"address","name":"_challenger","type":"address"},{"internalType":"uint256","name":"_finalizationPeriodSeconds","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"outputRoot","type":"bytes32"},{"indexed":true,"internalType":"uint256","name":"l2OutputIndex","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"l2BlockNumber","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"l1Timestamp","type":"uint256"}],"name":"OutputProposed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"prevNextOutputIndex","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"newNextOutputIndex","type":"uint256"}],"name":"OutputsDeleted","type":"event"},{"inputs":[],"name":"CHALLENGER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FINALIZATION_PERIOD_SECONDS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"L2_BLOCK_TIME","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PROPOSER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SUBMISSION_INTERVAL","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_l2BlockNumber","type":"uint256"}],"name":"computeL2Timestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_l2OutputIndex","type":"uint256"}],"name":"deleteL2Outputs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_l2OutputIndex","type":"uint256"}],"name":"getL2Output","outputs":[{"components":[{"internalType":"bytes32","name":"outputRoot","type":"bytes32"},{"internalType":"uint128","name":"timestamp","type":"uint128"},{"internalType":"uint128","name":"l2BlockNumber","type":"uint128"}],"internalType":"struct Types.OutputProposal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_l2BlockNumber","type":"uint256"}],"name":"getL2OutputAfter","outputs":[{"components":[{"internalType":"bytes32","name":"outputRoot","type":"bytes32"},{"internalType":"uint128","name":"timestamp","type":"uint128"},{"internalType":"uint128","name":"l2BlockNumber","type":"uint128"}],"internalType":"struct Types.OutputProposal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_l2BlockNumber","type":"uint256"}],"name":"getL2OutputIndexAfter","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_startingBlockNumber","type":"uint256"},{"internalType":"uint256","name":"_startingTimestamp","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"latestBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestOutputIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextOutputIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_outputRoot","type":"bytes32"},{"internalType":"uint256","name":"_l2BlockNumber","type":"uint256"},{"internalType":"bytes32","name":"_l1BlockHash","type":"bytes32"},{"internalType":"uint256","name":"_l1BlockNumber","type":"uint256"}],"name":"proposeL2Output","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"startingBlockNumber","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"startingTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}] -------------------------------------------------------------------------------- /optimism/assets/l2_standard_bridge.json: -------------------------------------------------------------------------------- 1 | [{"inputs":[{"internalType":"addresspayable","name":"_otherBridge","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"l1Token","type":"address"},{"indexed":true,"internalType":"address","name":"l2Token","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"extraData","type":"bytes"}],"name":"DepositFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"localToken","type":"address"},{"indexed":true,"internalType":"address","name":"remoteToken","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"extraData","type":"bytes"}],"name":"ERC20BridgeFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"localToken","type":"address"},{"indexed":true,"internalType":"address","name":"remoteToken","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"extraData","type":"bytes"}],"name":"ERC20BridgeInitiated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"extraData","type":"bytes"}],"name":"ETHBridgeFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"extraData","type":"bytes"}],"name":"ETHBridgeInitiated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"l1Token","type":"address"},{"indexed":true,"internalType":"address","name":"l2Token","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"extraData","type":"bytes"}],"name":"WithdrawalInitiated","type":"event"},{"inputs":[],"name":"MESSENGER","outputs":[{"internalType":"contractCrossDomainMessenger","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OTHER_BRIDGE","outputs":[{"internalType":"contractStandardBridge","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_localToken","type":"address"},{"internalType":"address","name":"_remoteToken","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint32","name":"_minGasLimit","type":"uint32"},{"internalType":"bytes","name":"_extraData","type":"bytes"}],"name":"bridgeERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_localToken","type":"address"},{"internalType":"address","name":"_remoteToken","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint32","name":"_minGasLimit","type":"uint32"},{"internalType":"bytes","name":"_extraData","type":"bytes"}],"name":"bridgeERC20To","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"_minGasLimit","type":"uint32"},{"internalType":"bytes","name":"_extraData","type":"bytes"}],"name":"bridgeETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint32","name":"_minGasLimit","type":"uint32"},{"internalType":"bytes","name":"_extraData","type":"bytes"}],"name":"bridgeETHTo","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"deposits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_localToken","type":"address"},{"internalType":"address","name":"_remoteToken","type":"address"},{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes","name":"_extraData","type":"bytes"}],"name":"finalizeBridgeERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes","name":"_extraData","type":"bytes"}],"name":"finalizeBridgeETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_l1Token","type":"address"},{"internalType":"address","name":"_l2Token","type":"address"},{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes","name":"_extraData","type":"bytes"}],"name":"finalizeDeposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"l1TokenBridge","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"messenger","outputs":[{"internalType":"contractCrossDomainMessenger","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_l2Token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint32","name":"_minGasLimit","type":"uint32"},{"internalType":"bytes","name":"_extraData","type":"bytes"}],"name":"withdraw","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_l2Token","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint32","name":"_minGasLimit","type":"uint32"},{"internalType":"bytes","name":"_extraData","type":"bytes"}],"name":"withdrawTo","outputs":[],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}] -------------------------------------------------------------------------------- /optimism/assets/l2_to_l1_message_passer.json: -------------------------------------------------------------------------------- 1 | [{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":true,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"gasLimit","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"},{"indexed":false,"internalType":"bytes32","name":"withdrawalHash","type":"bytes32"}],"name":"MessagePassed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"WithdrawerBalanceBurnt","type":"event"},{"inputs":[],"name":"MESSAGE_VERSION","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_target","type":"address"},{"internalType":"uint256","name":"_gasLimit","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"initiateWithdrawal","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"messageNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"sentMessages","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}] -------------------------------------------------------------------------------- /optimism/assets/optimism_erc20.json: -------------------------------------------------------------------------------- 1 | [{"inputs":[{"internalType":"address","name":"_bridge","type":"address"},{"internalType":"address","name":"_remoteToken","type":"address"},{"internalType":"uint8","name":"_decimals","type":"uint8"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Burn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Mint","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"BRIDGE","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REMOTE_TOKEN","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bridge","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"l1Token","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"l2Bridge","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"remoteToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"_interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}] -------------------------------------------------------------------------------- /optimism/assets/optimism_portal.json: -------------------------------------------------------------------------------- 1 | [{"inputs":[{"internalType":"uint256","name":"_proofMaturityDelaySeconds","type":"uint256"},{"internalType":"uint256","name":"_disputeGameFinalityDelaySeconds","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"BadTarget","type":"error"},{"inputs":[],"name":"CallPaused","type":"error"},{"inputs":[],"name":"ContentLengthMismatch","type":"error"},{"inputs":[],"name":"EmptyItem","type":"error"},{"inputs":[],"name":"GasEstimation","type":"error"},{"inputs":[],"name":"InvalidDataRemainder","type":"error"},{"inputs":[],"name":"InvalidHeader","type":"error"},{"inputs":[],"name":"LargeCalldata","type":"error"},{"inputs":[],"name":"OutOfGas","type":"error"},{"inputs":[],"name":"SmallGasLimit","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"UnexpectedList","type":"error"},{"inputs":[],"name":"UnexpectedString","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IDisputeGame","name":"disputeGame","type":"address"}],"name":"DisputeGameBlacklisted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"version","type":"uint8"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"GameType","name":"newGameType","type":"uint32"},{"indexed":true,"internalType":"Timestamp","name":"updatedAt","type":"uint64"}],"name":"RespectedGameTypeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"version","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"opaqueData","type":"bytes"}],"name":"TransactionDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"withdrawalHash","type":"bytes32"},{"indexed":false,"internalType":"bool","name":"success","type":"bool"}],"name":"WithdrawalFinalized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"withdrawalHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"WithdrawalProven","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"withdrawalHash","type":"bytes32"},{"indexed":true,"internalType":"address","name":"proofSubmitter","type":"address"}],"name":"WithdrawalProvenExtension1","type":"event"},{"inputs":[{"internalType":"contract IDisputeGame","name":"_disputeGame","type":"address"}],"name":"blacklistDisputeGame","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_withdrawalHash","type":"bytes32"},{"internalType":"address","name":"_proofSubmitter","type":"address"}],"name":"checkWithdrawal","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"},{"internalType":"uint64","name":"_gasLimit","type":"uint64"},{"internalType":"bool","name":"_isCreation","type":"bool"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"depositTransaction","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IDisputeGame","name":"","type":"address"}],"name":"disputeGameBlacklist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"disputeGameFactory","outputs":[{"internalType":"contract DisputeGameFactory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"disputeGameFinalityDelaySeconds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"donateETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct Types.WithdrawalTransaction","name":"_tx","type":"tuple"}],"name":"finalizeWithdrawalTransaction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct Types.WithdrawalTransaction","name":"_tx","type":"tuple"},{"internalType":"address","name":"_proofSubmitter","type":"address"}],"name":"finalizeWithdrawalTransactionExternalProof","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"finalizedWithdrawals","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"guardian","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract DisputeGameFactory","name":"_disputeGameFactory","type":"address"},{"internalType":"contract SystemConfig","name":"_systemConfig","type":"address"},{"internalType":"contract SuperchainConfig","name":"_superchainConfig","type":"address"},{"internalType":"GameType","name":"_initialRespectedGameType","type":"uint32"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"l2Sender","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"_byteCount","type":"uint64"}],"name":"minimumGasLimit","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_withdrawalHash","type":"bytes32"}],"name":"numProofSubmitters","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"params","outputs":[{"internalType":"uint128","name":"prevBaseFee","type":"uint128"},{"internalType":"uint64","name":"prevBoughtGas","type":"uint64"},{"internalType":"uint64","name":"prevBlockNum","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proofMaturityDelaySeconds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"proofSubmitters","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct Types.WithdrawalTransaction","name":"_tx","type":"tuple"},{"internalType":"uint256","name":"_disputeGameIndex","type":"uint256"},{"components":[{"internalType":"bytes32","name":"version","type":"bytes32"},{"internalType":"bytes32","name":"stateRoot","type":"bytes32"},{"internalType":"bytes32","name":"messagePasserStorageRoot","type":"bytes32"},{"internalType":"bytes32","name":"latestBlockhash","type":"bytes32"}],"internalType":"struct Types.OutputRootProof","name":"_outputRootProof","type":"tuple"},{"internalType":"bytes[]","name":"_withdrawalProof","type":"bytes[]"}],"name":"proveWithdrawalTransaction","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"address","name":"","type":"address"}],"name":"provenWithdrawals","outputs":[{"internalType":"contract IDisputeGame","name":"disputeGameProxy","type":"address"},{"internalType":"uint64","name":"timestamp","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"respectedGameType","outputs":[{"internalType":"GameType","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"respectedGameTypeUpdatedAt","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"GameType","name":"_gameType","type":"uint32"}],"name":"setRespectedGameType","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"superchainConfig","outputs":[{"internalType":"contract SuperchainConfig","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"systemConfig","outputs":[{"internalType":"contract SystemConfig","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}] -------------------------------------------------------------------------------- /optimism/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "1": { 3 | "10": { 4 | "l1_addresses": { 5 | "OPTIMISM_PORTAL": "0xbEb5Fc579115071764c7423A4f12eDde41f106Ed", 6 | "L1_STANDARD_BRIDGE": "0x99C9fc46f92E8a1c0deC1b1747d010903E884bE1", 7 | "L1_CROSS_CHAIN_MESSENGER": "0x25ace71c97B33Cc4729CF772ae268934F7ab5fA1", 8 | "DISPUTE_GAME_FACTORY": "0xe5965Ab5962eDc7477C8520243A95517CD252fA9" 9 | }, 10 | "l2_addresses": { 11 | "L2_STANDARD_BRIDGE": "0x4200000000000000000000000000000000000010", 12 | "L2_CROSS_CHAIN_MESSENGER": "0x4200000000000000000000000000000000000007", 13 | "L2_TO_L1_MESSAGE_PASSER": "0x4200000000000000000000000000000000000016" 14 | }, 15 | "name": "OPTIMISM ETHEREUM MAINNET" 16 | }, 17 | "8453": { 18 | "l1_addresses": { 19 | "OPTIMISM_PORTAL": "0x49048044D57e1C92A77f79988d21Fa8fAF74E97e", 20 | "L1_STANDARD_BRIDGE": "0x3154Cf16ccdb4C6d922629664174b904d80F2C35", 21 | "L1_CROSS_CHAIN_MESSENGER": "0x866E82a600A1414e583f7F13623F1aC5d58b0Afa", 22 | "DISPUTE_GAME_FACTORY": "0x43edB88C4B80fDD2AdFF2412A7BebF9dF42cB40e" 23 | }, 24 | "l2_addresses": { 25 | "L2_STANDARD_BRIDGE": "0x4200000000000000000000000000000000000010", 26 | "L2_CROSS_CHAIN_MESSENGER": "0x4200000000000000000000000000000000000007", 27 | "L2_TO_L1_MESSAGE_PASSER": "0x4200000000000000000000000000000000000016" 28 | }, 29 | "name": "BASE ETHEREUM MAINNET" 30 | } 31 | }, 32 | "11155111": { 33 | "11155420": { 34 | "l1_addresses": { 35 | "OPTIMISM_PORTAL": "0x16Fc5058F25648194471939df75CF27A2fdC48BC", 36 | "L1_STANDARD_BRIDGE": "0xFBb0621E0B23b5478B630BD55a5f21f67730B0F1", 37 | "L1_CROSS_CHAIN_MESSENGER": "0x58Cc85b8D04EA49cC6DBd3CbFFd00B4B8D6cb3ef", 38 | "DISPUTE_GAME_FACTORY": "0x05F9613aDB30026FFd634f38e5C4dFd30a197Fa1" 39 | }, 40 | "l2_addresses": { 41 | "L2_STANDARD_BRIDGE": "0x4200000000000000000000000000000000000010", 42 | "L2_CROSS_CHAIN_MESSENGER": "0x4200000000000000000000000000000000000007", 43 | "L2_TO_L1_MESSAGE_PASSER": "0x4200000000000000000000000000000000000016" 44 | }, 45 | "name": "OPTIMISM ETHEREUM SEPOLIA" 46 | }, 47 | "84532": { 48 | "l1_addresses": { 49 | "OPTIMISM_PORTAL": "0x49f53e41452C74589E85cA1677426Ba426459e85", 50 | "L1_STANDARD_BRIDGE": "0xfd0Bf71F60660E2f608ed56e1659C450eB113120", 51 | "L1_CROSS_CHAIN_MESSENGER": "0xC34855F4De64F1840e5686e64278da901e261f20", 52 | "DISPUTE_GAME_FACTORY": "0xd6E6dBf4F7EA0ac412fD8b65ED297e64BB7a06E1" 53 | }, 54 | "l2_addresses": { 55 | "L2_STANDARD_BRIDGE": "0x4200000000000000000000000000000000000010", 56 | "L2_CROSS_CHAIN_MESSENGER": "0x4200000000000000000000000000000000000007", 57 | "L2_TO_L1_MESSAGE_PASSER": "0x4200000000000000000000000000000000000016" 58 | }, 59 | "name": "BASE ETHEREUM SEPOLIA" 60 | } 61 | }, 62 | "900": { 63 | "901": { 64 | "l1_addresses": { 65 | "OPTIMISM_PORTAL": "0xB8D51FB7CA777D93aC7BdEAAE09a68A55D5DA2CE", 66 | "L1_STANDARD_BRIDGE": "0xf1a49dC6AA8DB645362E367c07312bC2eb175B6b", 67 | "L1_CROSS_CHAIN_MESSENGER": "0x448AD78a66aCA245F059bE7b8e6e3a29d5Cc9306", 68 | "L2_OUTPUT_ORACLE": "0xfA661Ac734F86AAF427a3ED1858031A5516E917b" 69 | }, 70 | "l2_addresses": { 71 | "L2_STANDARD_BRIDGE": "0x4200000000000000000000000000000000000010", 72 | "L2_CROSS_CHAIN_MESSENGER": "0x4200000000000000000000000000000000000007", 73 | "L2_TO_L1_MESSAGE_PASSER": "0x4200000000000000000000000000000000000016" 74 | }, 75 | "name": "OPTIMISM ETHEREUM DEVNET" 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /optimism/constants.py: -------------------------------------------------------------------------------- 1 | OUTPUT_ROOT_PROOF_VERSION = "0x0000000000000000000000000000000000000000000000000000000000000000" 2 | MESSAGE_PASSED_ID = "0x02a52367d10742d8032712c1bb8e0144ff1ec5ffda1ed7d70bb05a2744955054" 3 | CHALLENGE_PERIOD_MAINNET = 604800 4 | CHALLENGE_PERIOD_TESTNET = 100 -------------------------------------------------------------------------------- /optimism/contracts.py: -------------------------------------------------------------------------------- 1 | from web3 import Web3 2 | 3 | from .types import MessageStatus 4 | from .utils import load_abi, is_l1_to_l2, is_chain_supported, read_addresses 5 | 6 | class Contract(): 7 | 8 | def __int__(): 9 | pass 10 | 11 | def sign_and_broadcast(self, transaction): 12 | signed_txn = self.provider.eth.account.sign_transaction(transaction, self.account.key) 13 | txn_hash = self.provider.eth.send_raw_transaction(signed_txn.rawTransaction) 14 | txn_receipt = self.provider.eth.wait_for_transaction_receipt(txn_hash) 15 | 16 | return txn_hash.hex(), txn_receipt 17 | 18 | class OptimismPortal(Contract): 19 | 20 | def __init__(self, chain_id_l1, chain_id_l2, account, provider): 21 | 22 | self.provider = provider 23 | 24 | if is_chain_supported(chain_id_l1) is False: 25 | raise Exception(f"Chain ID {chain_id_l1} not supported: add it to the config.json file or open a request to add it.") 26 | if is_chain_supported(chain_id_l2) is False: 27 | raise Exception(f"Chain ID {chain_id_l2} not supported: add it to the config.json file or open a request to add it.") 28 | 29 | self.address = read_addresses(chain_id_l1, chain_id_l2, layer="l1")["OPTIMISM_PORTAL"] 30 | 31 | self.account = account 32 | self.contract = self.provider.eth.contract(address=self.address, abi=load_abi("OPTIMISM_PORTAL")) 33 | 34 | def deposit_transaction(self, to, value, gas_limit, is_creation, data): 35 | 36 | deposit_transaction_tx = self.contract.functions.depositTransaction(to, value, gas_limit, is_creation, data).build_transaction({ 37 | "from": self.account.address, 38 | "gas": 500000, 39 | "value": value, 40 | "nonce": self.provider.eth.get_transaction_count(self.account.address) 41 | }) 42 | 43 | return self.sign_and_broadcast(deposit_transaction_tx) 44 | 45 | def prove_withdrawl_transaction(self, tx, l2_output_index, output_root_proof, withdrawl_proof): 46 | 47 | prove_withdrawl_transaction_tx = self.contract.functions.proveWithdrawalTransaction(tx, l2_output_index, output_root_proof, withdrawl_proof).build_transaction({ 48 | "from": self.account.address, 49 | "gas": 1000000, 50 | "nonce": self.provider.eth.get_transaction_count(self.account.address) 51 | }) 52 | 53 | return self.sign_and_broadcast(prove_withdrawl_transaction_tx) 54 | 55 | def finalize_withdrawl_transaction(self, tx): 56 | 57 | finalize_withdrawl_transaction_tx = self.contract.functions.finalizeWithdrawalTransaction(tx).build_transaction({ 58 | "from": self.account.address, 59 | "gas": 100000, 60 | "nonce": self.provider.eth.get_transaction_count(self.account.address) 61 | }) 62 | 63 | return self.sign_and_broadcast(finalize_withdrawl_transaction_tx) 64 | 65 | def is_output_finalized(): 66 | pass 67 | 68 | def proof_maturity_delay_seconds(self): 69 | 70 | return self.contract.functions.proofMaturityDelaySeconds().call() 71 | 72 | def proven_withdrawls(self, withdrawl_hash, proof_submitter): 73 | 74 | return self.contract.functions.provenWithdrawals(withdrawl_hash, proof_submitter).call() 75 | 76 | class StandardBridge(Contract): 77 | 78 | def __init__(self, account, from_chain_id, to_chain_id, provider): 79 | 80 | self.l1_to_l2 = is_l1_to_l2(from_chain_id, to_chain_id) 81 | 82 | self.provider = provider 83 | 84 | if is_chain_supported(from_chain_id) is False: 85 | raise Exception(f"Origin Chain ID {from_chain_id} not supported: add it to the config.json file or open a request to add it.") 86 | if is_chain_supported(to_chain_id) is False: 87 | raise Exception(f"Destination Chain ID {to_chain_id} not supported: add it to the config.json file or open a request to add it.") 88 | 89 | if self.l1_to_l2: 90 | self.address = read_addresses(from_chain_id, to_chain_id, layer="l1")["L1_STANDARD_BRIDGE"] 91 | else: 92 | self.address = read_addresses(to_chain_id, from_chain_id, layer="l2")["L2_STANDARD_BRIDGE"] 93 | 94 | self.from_chain_id = from_chain_id 95 | self.to_chain_id = to_chain_id 96 | 97 | self.account = account 98 | 99 | if self.l1_to_l2: 100 | self.contract = self.provider.eth.contract(address=self.address, abi=load_abi("L1_STANDARD_BRIDGE")) 101 | else: 102 | self.contract = self.provider.eth.contract(address=self.address, abi=load_abi("L2_STANDARD_BRIDGE")) 103 | 104 | def deposit_eth_to(self, to, value, gas_limit, extra_data): 105 | 106 | if not self.l1_to_l2: 107 | raise Exception("This method can only be called on a L1 to L2 Bridge") 108 | 109 | deposit_eth_to_tx = self.contract.functions.depositETHTo(to, gas_limit, extra_data).build_transaction({ 110 | "from": self.account.address, 111 | "gas": 500000, 112 | "nonce": self.provider.eth.get_transaction_count(self.account.address), 113 | "value": value 114 | }) 115 | 116 | return self.sign_and_broadcast(deposit_eth_to_tx) 117 | 118 | def deposit_erc20(self, l1_token_address, l2_token_address, value, gas_limit, extra_data): 119 | 120 | if not self.l1_to_l2: 121 | raise Exception("This method can only be called on a L1 to L2 Bridge") 122 | 123 | deposit_erc20_tx = self.contract.functions.depositERC20(l1_token_address, l2_token_address, value, gas_limit, extra_data).build_transaction({ 124 | "from": self.account.address, 125 | "gas": 700000, 126 | "nonce": self.provider.eth.get_transaction_count(self.account.address) 127 | }) 128 | 129 | return self.sign_and_broadcast(deposit_erc20_tx) 130 | 131 | def deposit_erc20_to(self, l1_token_address, l2_token_address, to, value, gas_limit, extra_data): 132 | 133 | if not self.l1_to_l2: 134 | raise Exception("This method can only be called on a L1 to L2 Bridge") 135 | 136 | deposit_erc20_to_tx = self.contract.functions.depositERC20To(l1_token_address, l2_token_address, to, value, gas_limit, extra_data).build_transaction({ 137 | "from": self.account.address, 138 | "gas": 700000, 139 | "nonce": self.provider.eth.get_transaction_count(self.account.address) 140 | }) 141 | 142 | return self.sign_and_broadcast(deposit_erc20_to_tx) 143 | 144 | 145 | def withdraw_eth_to(self, to, value, gas_limit, extra_data): 146 | 147 | if self.l1_to_l2: 148 | raise Exception("This method can only be called on a L2 to L1 Bridge") 149 | 150 | withdraw_eth_to_tx = self.contract.functions.withdrawTo("0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000", to, value, gas_limit, extra_data).build_transaction({ 151 | "from": self.account.address, 152 | "gas": 500000, 153 | "nonce": self.provider.eth.get_transaction_count(self.account.address), 154 | "value": value 155 | }) 156 | 157 | return self.sign_and_broadcast(withdraw_eth_to_tx) 158 | 159 | def bridge_erc20(self, l1_token_address, l2_token_address, value, gas_limit, extra_data): 160 | 161 | if self.l1_to_l2: 162 | raise Exception("This method can only be called on a L2 to L1 Bridge") 163 | 164 | withdraw_erc20_tx = self.contract.functions.bridgeERC20(l2_token_address, l1_token_address, value, gas_limit, extra_data).build_transaction({ 165 | "from": self.account.address, 166 | "gas": 500000, 167 | "nonce": self.provider.eth.get_transaction_count(self.account.address) 168 | }) 169 | 170 | return self.sign_and_broadcast(withdraw_erc20_tx) 171 | 172 | def bridge_erc20_to(self, l1_token_address, l2_token_address, to, value, gas_limit, extra_data): 173 | 174 | if self.l1_to_l2: 175 | raise Exception("This method can only be called on a L2 to L1 Bridge") 176 | 177 | withdraw_erc20_to_tx = self.contract.functions.bridgeERC20To(l2_token_address, l1_token_address, to, value, gas_limit, extra_data).build_transaction({ 178 | "from": self.account.address, 179 | "gas": 500000, 180 | "nonce": self.provider.eth.get_transaction_count(self.account.address) 181 | }) 182 | 183 | class CrossChainMessengerContract(Contract): 184 | 185 | def __init__(self, account, from_chain_id, to_chain_id, provider): 186 | 187 | self.l1_to_l2 = is_l1_to_l2(from_chain_id, to_chain_id) 188 | 189 | self.provider = provider 190 | 191 | if is_chain_supported(from_chain_id) is False: 192 | raise Exception(f"Origin Chain ID {from_chain_id} not supported: add it to the config.json file or open a request to add it.") 193 | if is_chain_supported(to_chain_id) is False: 194 | raise Exception(f"Destination Chain ID {to_chain_id} not supported: add it to the config.json file or open a request to add it.") 195 | 196 | if self.l1_to_l2: 197 | self.address = read_addresses(from_chain_id, to_chain_id, layer="l1")["L1_CROSS_CHAIN_MESSENGER"] 198 | else: 199 | self.address = read_addresses(to_chain_id, from_chain_id, layer="l2")["L2_CROSS_CHAIN_MESSENGER"] 200 | 201 | self.from_chain_id = from_chain_id 202 | self.to_chain_id = to_chain_id 203 | 204 | self.account = account 205 | 206 | if self.l1_to_l2: 207 | self.contract = self.provider.eth.contract(address=self.address, abi=load_abi("L1_CROSS_MESSENGER")) 208 | else: 209 | self.contract = self.provider.eth.contract(address=self.address, abi=load_abi("L2_CROSS_MESSENGER")) 210 | 211 | 212 | def send_message(self, target, message, min_gas_limit, value=None): 213 | 214 | send_message_tx = self.contract.functions.sendMessage(target, message, min_gas_limit).build_transaction({ 215 | "from": self.account.address, 216 | "gas": 500000, 217 | "nonce": self.provider.eth.get_transaction_count(self.account.address), 218 | "value": 0 if value is None else value 219 | }) 220 | 221 | return self.sign_and_broadcast(send_message_tx) 222 | 223 | def message_nonce(self): 224 | 225 | return self.contract.functions.messageNonce().call() 226 | 227 | 228 | class L2OutputOracle(): 229 | 230 | def __init__(self, chain_id_l1, chain_id_l2, account, provider): 231 | 232 | self.provider = provider 233 | 234 | if is_chain_supported(chain_id_l1) is False: 235 | raise Exception(f"Chain ID {chain_id_l1} not supported: add it to the config.json file or open a request to add it.") 236 | if is_chain_supported(chain_id_l2) is False: 237 | raise Exception(f"Chain ID {chain_id_l2} not supported: add it to the config.json file or open a request to add it.") 238 | 239 | self.address = read_addresses(chain_id_l1, chain_id_l2, layer="l1")["L2_OUTPUT_ORACLE"] 240 | 241 | self.account = account 242 | 243 | self.contract = self.provider.eth.contract(address=self.address, abi=load_abi("L2_OUTPUT_ORACLE")) 244 | 245 | def latest_output_index(self): 246 | 247 | return self.contract.functions.latestOutputIndex().call() 248 | 249 | def latest_block_number(self): 250 | 251 | return self.contract.functions.latestBlockNumber().call() 252 | 253 | def next_output_index(self): 254 | 255 | return self.contract.functions.nextOutputIndex().call() 256 | 257 | def get_l2_output_index_after(self, l2_block_nummer): 258 | 259 | return self.contract.functions.getL2OutputIndexAfter(l2_block_nummer).call() 260 | 261 | def get_l2_output_after(self, l2_block_number): 262 | 263 | output_root, timestamp, l2_block_number = self.contract.functions.getL2OutputAfter(l2_block_number).call() 264 | 265 | return output_root.hex(), timestamp, l2_block_number 266 | 267 | def get_l2_output(self, l2_output_index): 268 | 269 | output_root, timestamp, l2_block_number = self.contract.functions.getL2Output(l2_output_index).call() 270 | 271 | return output_root.hex(), timestamp, l2_block_number 272 | 273 | class DisputeGameFactory(Contract): 274 | 275 | def __init__(self, chain_id_l1, chain_id_l2, provider): 276 | 277 | self.provider = provider 278 | 279 | if is_chain_supported(chain_id_l1) is False: 280 | raise Exception(f"Chain ID {chain_id_l1} not supported: add it to the config.json file or open a request to add it.") 281 | if is_chain_supported(chain_id_l2) is False: 282 | raise Exception(f"Chain ID {chain_id_l2} not supported: add it to the config.json file or open a request to add it.") 283 | 284 | self.address = read_addresses(chain_id_l1, chain_id_l2, layer="l1")["DISPUTE_GAME_FACTORY"] 285 | 286 | self.contract = self.provider.eth.contract(address=self.address, abi=load_abi("DISPUTE_GAME_FACTORY")) 287 | 288 | def game_count(self): 289 | 290 | return self.contract.functions.gameCount().call() 291 | 292 | def game_at_index(self, index): 293 | 294 | return self.contract.functions.gameAtIndex(index).call() 295 | 296 | 297 | class FaultDisputeGame(Contract): 298 | 299 | def __init__(self, address, provider): 300 | 301 | self.provider = provider 302 | 303 | self.address = address 304 | 305 | self.contract = self.provider.eth.contract(address=self.address, abi=load_abi("FAULT_DISPUTE_GAME")) 306 | 307 | def root_claim(self): 308 | 309 | return self.contract.functions.rootClaim().call() 310 | 311 | def l2_block_number(self): 312 | 313 | return self.contract.functions.l2BlockNumber().call() 314 | 315 | class L2ToL1MessagePasser(Contract): 316 | 317 | def __init__(self, chain_id_l1, chain_id_l2, account, provider): 318 | 319 | self.provider = provider 320 | 321 | self.address = read_addresses(chain_id_l1, chain_id_l2, layer="l2")["L2_TO_L1_MESSAGE_PASSER"] 322 | 323 | self.account = account 324 | 325 | self.contract = self.provider.eth.contract(address=self.address, abi=load_abi("L2_TO_L1_MESSAGE_PASSER")) 326 | 327 | def initiate_withdrawl(self, to, gas_limit, data, value): 328 | 329 | initiate_withdrawl_tx = self.contract.functions.initiateWithdrawal(to, gas_limit, data).build_transaction({ 330 | "from": self.account.address, 331 | "gas": 100000, 332 | "nonce": self.provider.eth.get_transaction_count(self.account.address), 333 | "value": value 334 | }) 335 | 336 | return self.sign_and_broadcast(initiate_withdrawl_tx) -------------------------------------------------------------------------------- /optimism/cross_chain_messenger.py: -------------------------------------------------------------------------------- 1 | from .constants import OUTPUT_ROOT_PROOF_VERSION 2 | 3 | from .types import MessageStatus, OutputRootProof, BedrockMessageProof, Chains 4 | from .utils import to_low_level_message, make_state_trie_proof, hash_message_hash, read_addresses, load_abi 5 | from .contracts import L2ToL1MessagePasser, DisputeGameFactory, FaultDisputeGame, OptimismPortal, CrossChainMessengerContract, StandardBridge 6 | 7 | class CrossChainMessenger(): 8 | 9 | def __init__(self, chain_l1, chain_l2, account_l1, account_l2, provider_l1, provider_l2): 10 | 11 | if isinstance(chain_l1, Chains) and isinstance(chain_l2, Chains): 12 | self.chain_id_l1 = chain_l1.chain_id() 13 | self.chain_id_l2 = chain_l2.chain_id() 14 | else: 15 | self.chain_id_l1 = chain_l1 16 | self.chain_id_l2 = chain_l2 17 | 18 | self.provider_l1 = provider_l1 19 | self.provider_l2 = provider_l2 20 | 21 | self.account_l1 = account_l1 22 | self.account_l2 = account_l2 23 | 24 | self.l1_cross_chain_messenger = CrossChainMessengerContract(account_l1, self.chain_id_l1, self.chain_id_l2, provider=provider_l1) 25 | self.l2_cross_chain_messenger = CrossChainMessengerContract(account_l2, self.chain_id_l2, self.chain_id_l1, provider=provider_l2) 26 | 27 | self.l1_bridge = StandardBridge(account_l1, from_chain_id=self.chain_id_l1, to_chain_id=self.chain_id_l2, provider=provider_l1) 28 | self.l2_bridge = StandardBridge(account_l2, from_chain_id=self.chain_id_l2, to_chain_id=self.chain_id_l1, provider=provider_l2) 29 | 30 | def deposit_eth(self, value): 31 | 32 | return self.l1_cross_chain_messenger.send_message(self.account_l1.address, b"", 0, value) 33 | 34 | def deposit_eth_to(self, to, value): 35 | 36 | return self.l1_cross_chain_messenger.send_message(to, b"", 0, value) 37 | 38 | def deposit_erc20(self, token_address_l1, token_address_l2, value): 39 | 40 | if not self._supports_token_pair(token_address_l1, token_address_l2): 41 | raise Exception("Token pair not supported") 42 | 43 | return self.l1_bridge.deposit_erc20(token_address_l1, token_address_l2, value, 0, b"") 44 | 45 | def deposit_erc20_to(self, token_address_l1, token_address_l2, to, value): 46 | 47 | if not self._supports_token_pair(token_address_l1, token_address_l2): 48 | raise Exception("Token pair not supported") 49 | 50 | return self.l1_bridge.deposit_erc20_to(token_address_l1, token_address_l2, to, value, 0, b"") 51 | 52 | def approve_erc20(self, token_address_l1, token_address_l2, value): 53 | 54 | if not self._supports_token_pair(token_address_l1, token_address_l2): 55 | raise Exception("Token pair not supported") 56 | 57 | token_contract_l1 = self.provider_l1.eth.contract(address=token_address_l1, abi=load_abi("ERC20")) 58 | 59 | approve_tx = token_contract_l1.functions.approve(self.l1_bridge.address, value).build_transaction({ 60 | "from": self.account_l1.address, 61 | "nonce": self.provider_l1.eth.get_transaction_count(self.account_l1.address) 62 | }) 63 | 64 | signed_txn = self.provider_l1.eth.account.sign_transaction(approve_tx, self.account_l1.key) 65 | txn_hash = self.provider_l1.eth.send_raw_transaction(signed_txn.rawTransaction) 66 | txn_receipt = self.provider_l1.eth.wait_for_transaction_receipt(txn_hash) 67 | 68 | return txn_hash.hex(), txn_receipt 69 | 70 | 71 | def withdraw_eth(self, value): 72 | 73 | l2_to_l1_message_passer = L2ToL1MessagePasser(self.chain_id_l1, self.chain_id_l2, self.account_l2, provider=self.provider_l2) 74 | 75 | return l2_to_l1_message_passer.initiate_withdrawl(self.account_l2.address, 0, b"", value) 76 | 77 | def withdraw_eth_to(self, to, value): 78 | 79 | l2_to_l1_message_passer = L2ToL1MessagePasser(self.chain_id_l1, self.chain_id_l2, self.account_l2, provider=self.provider_l2) 80 | 81 | return l2_to_l1_message_passer.initiate_withdrawl(to, 0, b"", value) 82 | 83 | def withdraw_erc20(self, token_address_l1, token_address_l2, value): 84 | 85 | if not self._supports_token_pair(token_address_l1, token_address_l2): 86 | raise Exception("Token pair not supported") 87 | 88 | return self.l2_bridge.bridge_erc20(token_address_l1, token_address_l2, value, 0, b"") 89 | 90 | def withdraw_erc20_to(self, token_address_l1, token_address_l2, to, value): 91 | 92 | if not self._supports_token_pair(token_address_l1, token_address_l2): 93 | raise Exception("Token pair not supported") 94 | 95 | return self.l2_bridge.bridge_erc20_to(token_address_l1, token_address_l2, to, value, 0, b"") 96 | 97 | def prove_message(self, l2_txn_hash): 98 | 99 | l2_txn = self.provider_l2.eth.get_transaction(l2_txn_hash) 100 | l2_txn_receipt = self.provider_l2.eth.get_transaction_receipt(l2_txn_hash) 101 | 102 | withdrawl_message, withrawl_message_hash = to_low_level_message(l2_txn, l2_txn_receipt) 103 | message_proof = self.get_bedrock_message_proof(l2_txn, withrawl_message_hash) 104 | 105 | optimism_portal = OptimismPortal(self.chain_id_l1, self.chain_id_l2, self.account_l1, provider=self.provider_l1) 106 | return optimism_portal.prove_withdrawl_transaction(withdrawl_message.values(), message_proof.get_dispute_game_index(), message_proof.get_output_root_proof(), message_proof.get_withdrawl_proof()) 107 | 108 | def finalize_message(self, l2_txn_hash): 109 | 110 | l2_txn = self.provider_l2.eth.get_transaction(l2_txn_hash) 111 | l2_txn_receipt = self.provider_l2.eth.get_transaction_receipt(l2_txn_hash) 112 | 113 | withdrawl_message, withrawl_message_hash = to_low_level_message(l2_txn, l2_txn_receipt) 114 | 115 | optimism_portal = OptimismPortal(self.chain_id_l1, self.chain_id_l2, self.account_l1, provider=self.provider_l1) 116 | return optimism_portal.finalize_withdrawl_transaction(tuple(withdrawl_message.values())) 117 | 118 | 119 | def get_bedrock_message_proof(self, txn, withdrawl_hash): 120 | 121 | l2_block_number = txn.blockNumber 122 | 123 | dispute_game_factory = DisputeGameFactory(self.chain_id_l1, self.chain_id_l2, provider=self.provider_l1) 124 | game_count = dispute_game_factory.game_count() 125 | 126 | game_index = game_count - 1 127 | 128 | latest_game_type, latest_game_timestamp, latest_game_address = dispute_game_factory.game_at_index(game_index) 129 | 130 | fault_dispute_game = FaultDisputeGame(latest_game_address, self.provider_l1) 131 | l2_block_number = fault_dispute_game.l2_block_number() 132 | 133 | message_slot = hash_message_hash(withdrawl_hash) 134 | 135 | state_trie_proof = make_state_trie_proof(self.provider_l2, l2_block_number, read_addresses(self.chain_id_l1, self.chain_id_l2, layer="l2")["L2_TO_L1_MESSAGE_PASSER"], message_slot) 136 | block = self.provider_l2.eth.get_block(l2_block_number) 137 | 138 | output_root_proof = OutputRootProof(version=OUTPUT_ROOT_PROOF_VERSION, 139 | state_root=block.stateRoot.hex(), 140 | message_passer_storage_root=state_trie_proof.storage_root.hex(), 141 | latest_blockhash=block.hash.hex()) 142 | 143 | bedrock_message_proof = BedrockMessageProof(output_root_proof=output_root_proof, 144 | withdrawl_proof=[el.hex() for el in state_trie_proof.storage_proof], 145 | dispute_game_index=game_index) 146 | 147 | return bedrock_message_proof 148 | 149 | def get_message_status(self, txn_hash): 150 | 151 | l1_to_l2 = True 152 | 153 | try: 154 | txn = self.provider_l1.eth.get_transaction(txn_hash) 155 | txn_receipt = self.provider_l1.eth.get_transaction_receipt(txn_hash) 156 | except: 157 | txn = self.provider_l2.eth.get_transaction(txn_hash) 158 | txn_receipt = self.provider_l2.eth.get_transaction_receipt(txn_hash) 159 | l1_to_l2 = False 160 | 161 | if l1_to_l2: 162 | if txn_receipt is None: 163 | return MessageStatus.UNCONFIRMED_L1_TO_L2_MESSAGE 164 | else: 165 | if txn_receipt.status == 1: 166 | return MessageStatus.RELAYED 167 | else: 168 | return MessageStatus.FAILED_L1_TO_L2_MESSAGE 169 | else: 170 | if txn_receipt is None: 171 | return MessageStatus.UNCONFIRMED_L2_TO_L1_MESSAGE 172 | else: 173 | if txn_receipt.status == 1: 174 | 175 | dispute_game_factory = DisputeGameFactory(self.chain_id_l1, self.chain_id_l2, provider=self.provider_l1) 176 | game_count = dispute_game_factory.game_count() 177 | 178 | game_index = game_count - 1 179 | 180 | latest_game_type, latest_game_timestamp, latest_game_address = dispute_game_factory.game_at_index(game_index) 181 | 182 | fault_dispute_game = FaultDisputeGame(latest_game_address, self.provider_l1) 183 | latest_block_number = fault_dispute_game.l2_block_number() 184 | 185 | try: 186 | _, message_hash = to_low_level_message(txn, txn_receipt) 187 | except: 188 | raise Exception("Transaction is not a valid L2 to L1 message") 189 | 190 | if int(latest_block_number) < int(txn.blockNumber): 191 | return MessageStatus.STATE_ROOT_NOT_PUBLISHED 192 | else: 193 | optimism_portal = OptimismPortal(self.chain_id_l1, self.chain_id_l2, self.account_l1, provider=self.provider_l1) 194 | proven = optimism_portal.proven_withdrawls(message_hash, txn["from"]) 195 | if proven[-1] == 0: 196 | return MessageStatus.READY_TO_PROVE 197 | else: 198 | current_timestamp = self.provider_l2.eth.get_block(self.provider_l2.eth.block_number).timestamp 199 | if current_timestamp > proven[1] + optimism_portal.proof_maturity_delay_seconds(): 200 | return MessageStatus.READY_FOR_RELAY 201 | else: 202 | return MessageStatus.IN_CHALLENGE_PERIOD 203 | else: 204 | return MessageStatus.FAILED_L2_TO_L1_MESSAGE 205 | 206 | def get_erc20_deposits_by_address(self, address, from_block=0, to_block="latest"): 207 | 208 | """ 209 | Returns a list of ERC20 deposits initiated by the given address 210 | """ 211 | 212 | events = self.l1_bridge.contract.events.ERC20DepositInitiated.create_filter( 213 | fromBlock=from_block, 214 | toBlock=to_block, 215 | argument_filters={'from': address} 216 | ).get_all_entries() 217 | 218 | token_bridge_messages = [] 219 | 220 | for event in events: 221 | 222 | message = { 223 | 'direction': 'L1_TO_L2', 224 | 'from': event.args['from'], 225 | 'to': event.args['to'], 226 | 'l1Token': event.args['l1Token'], 227 | 'l2Token': event.args['l2Token'], 228 | 'amount': event.args['amount'], 229 | 'data': event.args['extraData'], 230 | 'logIndex': event.logIndex, 231 | 'blockNumber': event.blockNumber, 232 | 'transactionHash': event.transactionHash.hex() 233 | } 234 | token_bridge_messages.append(message) 235 | 236 | token_bridge_messages.sort(key=lambda x: x['blockNumber'], reverse=True) 237 | 238 | return token_bridge_messages 239 | 240 | def get_eth_deposits_by_address(self, address, from_block=0, to_block="latest"): 241 | 242 | """ 243 | Returns a list of ETH deposits initiated by the given address 244 | """ 245 | 246 | events = self.l1_bridge.contract.events.ETHDepositInitiated.create_filter( 247 | fromBlock=from_block, 248 | toBlock=to_block, 249 | argument_filters={'from': address} 250 | ).get_all_entries() 251 | 252 | eth_bridge_messages = [] 253 | 254 | for event in events: 255 | 256 | message = { 257 | 'direction': 'L1_TO_L2', 258 | 'from': event.args['from'], 259 | 'to': event.args['to'], 260 | 'amount': event.args['amount'], 261 | 'data': event.args['extraData'], 262 | 'logIndex': event.logIndex, 263 | 'blockNumber': event.blockNumber, 264 | 'transactionHash': event.transactionHash.hex() 265 | } 266 | eth_bridge_messages.append(message) 267 | 268 | eth_bridge_messages.sort(key=lambda x: x['blockNumber'], reverse=True) 269 | 270 | return eth_bridge_messages 271 | 272 | def get_erc20_withdrawals_by_address(self, address, from_block=0, to_block='latest'): 273 | 274 | """ 275 | Returns a list of ERC20 withdrawals initiated by the given address 276 | """ 277 | 278 | events = self.l2_bridge.contract.events.ERC20BridgeInitiated.create_filter( 279 | fromBlock=from_block, 280 | toBlock=to_block, 281 | argument_filters={'from': address} 282 | ).get_all_entries() 283 | 284 | token_bridge_messages = [] 285 | 286 | for event in events: 287 | 288 | message = { 289 | 'direction': 'L2_TO_L1', 290 | 'from': event.args['from'], 291 | 'to': event.args['to'], 292 | 'l1Token': event.args['remoteToken'], 293 | 'l2Token': event.args['localToken'], 294 | 'amount': event.args['amount'], 295 | 'data': event.args['extraData'], 296 | 'logIndex': event.logIndex, 297 | 'blockNumber': event.blockNumber, 298 | 'transactionHash': event.transactionHash.hex() 299 | } 300 | token_bridge_messages.append(message) 301 | 302 | token_bridge_messages.sort(key=lambda x: x['blockNumber'], reverse=True) 303 | 304 | return token_bridge_messages 305 | 306 | def get_eth_withdrawals_by_address(self, address, from_block=0, to_block='latest'): 307 | 308 | """ 309 | Returns a list of ETH withdrawals initiated by the given address 310 | """ 311 | 312 | events = self.l2_bridge.contract.events.ETHBridgeInitiated.create_filter( 313 | fromBlock=from_block, 314 | toBlock=to_block, 315 | argument_filters={'from': address} 316 | ).get_all_entries() 317 | 318 | eth_bridge_messages = [] 319 | 320 | for event in events: 321 | 322 | message = { 323 | 'direction': 'L2_TO_L1', 324 | 'from': event.args['from'], 325 | 'to': event.args['to'], 326 | 'amount': event.args['amount'], 327 | 'data': event.args['extraData'], 328 | 'logIndex': event.logIndex, 329 | 'blockNumber': event.blockNumber, 330 | 'transactionHash': event.transactionHash.hex() 331 | } 332 | eth_bridge_messages.append(message) 333 | 334 | eth_bridge_messages.sort(key=lambda x: x['blockNumber'], reverse=True) 335 | 336 | return eth_bridge_messages 337 | 338 | def estimate_l2_gas_limit(self, message): 339 | raise NotImplementedError 340 | 341 | def estimate_message_wait_time_seconds(self, message): 342 | raise NotImplementedError 343 | 344 | def get_challenge_period_seconds(self): 345 | raise NotImplementedError 346 | 347 | def get_proven_withdrawl(self): 348 | raise NotImplementedError 349 | 350 | def get_message_state_root(self): 351 | raise NotImplementedError 352 | 353 | def get_state_batch_appended_event_by_batch_index(self): 354 | raise NotImplementedError 355 | 356 | def get_state_batch_appended_event_by_transaction_index(self): 357 | raise NotImplementedError 358 | 359 | def get_state_root_batch_by_transaction_index(self): 360 | raise NotImplementedError 361 | 362 | def _supports_token_pair(self, token_address_l1, token_address_l2): 363 | 364 | token_contract_l2 = self.provider_l2.eth.contract(address=token_address_l2, abi=load_abi("OPTIMISM_ERC20")) 365 | try: 366 | l1_token = token_contract_l2.functions.l1Token().call() 367 | except: 368 | raise Exception(f"Token Contract {token_address_l2} is not an Optimism ERC20") 369 | 370 | return l1_token == token_address_l1 -------------------------------------------------------------------------------- /optimism/types.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | 3 | class MessageStatus(Enum): 4 | UNCONFIRMED_L1_TO_L2_MESSAGE = 0 5 | UNCONFIRMED_L2_TO_L1_MESSAGE = 1 6 | FAILED_L1_TO_L2_MESSAGE = 2 7 | FAILED_L2_TO_L1_MESSAGE = 3 8 | STATE_ROOT_NOT_PUBLISHED = 4 9 | READY_TO_PROVE = 5 10 | IN_CHALLENGE_PERIOD = 6 11 | READY_FOR_RELAY = 7 12 | RELAYED = 8 13 | 14 | class ChainInfo: 15 | def __init__(self, chain_id, layer): 16 | self.chain_id = chain_id 17 | self.layer = layer 18 | 19 | class Chains(Enum): 20 | ETHEREUM_MAINNET = ChainInfo(1, 'L1') 21 | OPTIMISM_MAINNET = ChainInfo(10, 'L2') 22 | BASE_MAINNET = ChainInfo(8453, 'L2') 23 | 24 | ETHEREUM_SEPOLIA = ChainInfo(11155111, 'L1') 25 | OPTIMISM_SEPOLIA = ChainInfo(11155420, 'L2') 26 | BASE_SEPOLIA = ChainInfo(84532, 'L2') 27 | 28 | def chain_id(self): 29 | return self.value.chain_id 30 | 31 | def layer(self): 32 | return self.value.layer 33 | 34 | class StateTrieProof(): 35 | 36 | def __init__(self, account_proof, storage_proof, storage_value, storage_root): 37 | 38 | self.account_proof = account_proof 39 | self.storage_proof = storage_proof 40 | self.storage_value = storage_value 41 | self.storage_root = storage_root 42 | 43 | def __str__(self): 44 | 45 | return f"StateTrieProof(account_proof={self.account_proof}, storage_proof={self.storage_proof}, storage_value={self.storage_value}, storage_root={self.storage_root})" 46 | 47 | class MessagePassedEvent(): 48 | 49 | def __init__(self, message_nonce, sender, target, value, min_gas_limit, message): 50 | 51 | self.message_nonce = message_nonce 52 | self.sender = sender 53 | self.target = target 54 | self.value = value 55 | self.min_gas_limit = min_gas_limit 56 | self.message = message 57 | 58 | def __str__(self): 59 | 60 | return f"MessagePassedEvent(message_nonce={self.message_nonce}, sender={self.sender}, target={self.target}, value={self.value}, min_gas_limit={self.min_gas_limit}, message={self.message})" 61 | 62 | def values(self): 63 | 64 | return (self.message_nonce, self.sender, self.target, self.value, self.min_gas_limit, self.message) 65 | 66 | class OutputRootProof(): 67 | 68 | def __init__(self, version, state_root, message_passer_storage_root, latest_blockhash): 69 | 70 | self.version = version 71 | self.state_root = state_root 72 | self.message_passer_storage_root = message_passer_storage_root 73 | self.latest_blockhash = latest_blockhash 74 | 75 | def __str__(self): 76 | 77 | return f"OutputRootProof(version={self.version}, state_root={self.state_root}, message_passer_storage_root={self.message_passer_storage_root}, latest_blockhash={self.latest_blockhash})" 78 | 79 | def values(self): 80 | 81 | return (self.version, self.state_root, self.message_passer_storage_root, self.latest_blockhash) 82 | 83 | 84 | class BedrockMessageProof(): 85 | 86 | def __init__(self, output_root_proof, withdrawl_proof, dispute_game_index): 87 | 88 | self.output_root_proof = output_root_proof 89 | self.withdrawl_proof = withdrawl_proof 90 | self.dispute_game_index = dispute_game_index 91 | 92 | def __str__(self): 93 | 94 | return f"BedrockMessageProof(output_root_proof={self.output_root_proof}, withdrawl_proof={self.withdrawl_proof}, dispute_game_index={self.dispute_game_index})" 95 | 96 | def get_dispute_game_index(self): 97 | 98 | return self.dispute_game_index 99 | 100 | def get_output_root_proof(self): 101 | 102 | return self.output_root_proof.values() 103 | 104 | def get_withdrawl_proof(self): 105 | 106 | return tuple(self.withdrawl_proof) 107 | -------------------------------------------------------------------------------- /optimism/utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | 4 | from web3 import Web3 5 | 6 | from .constants import MESSAGE_PASSED_ID 7 | from .types import MessagePassedEvent, StateTrieProof, Chains 8 | 9 | def get_env_variable(var_name): 10 | return os.environ.get(var_name) 11 | 12 | def load_abi(name: str) -> str: 13 | 14 | abi = name.lower() 15 | 16 | path = f"{os.path.dirname(os.path.abspath(__file__))}/assets/" 17 | with open(os.path.abspath(path + f"{abi}.json")) as f: 18 | abi: str = json.load(f) 19 | return abi 20 | 21 | def is_l1_to_l2(from_chain_id, to_chain_id): 22 | 23 | chain_id_to_info = {chain.value.chain_id: chain.value.layer for chain in Chains} 24 | 25 | if chain_id_to_info.get(from_chain_id) == "L1" and chain_id_to_info.get(to_chain_id) == "L2": 26 | return True 27 | elif chain_id_to_info.get(from_chain_id) == "L2" and chain_id_to_info.get(to_chain_id) == "L1": 28 | return False 29 | else: 30 | raise ValueError("Invalid chain ids") 31 | 32 | def hash_message_hash(message_hash: str) -> str: 33 | # Web3 provides utility functions similar to ethers 34 | w3 = Web3() 35 | 36 | # These are equivalent constants in web3.py for ethers.constants.HashZero 37 | HASH_ZERO = int('0x0000000000000000000000000000000000000000000000000000000000000000', 16) 38 | 39 | # Use solidityKeccak for both encoding and hashing 40 | return w3.solidity_keccak(['bytes32', 'uint256'], [message_hash, HASH_ZERO]).hex() 41 | 42 | def log_to_address(log): 43 | 44 | return Web3.to_checksum_address("0x" + log[-40:]) 45 | 46 | def to_low_level_message(txn, txn_receipt): 47 | 48 | logs = txn_receipt.logs 49 | 50 | for log in logs: 51 | if log.topics[0].hex() == MESSAGE_PASSED_ID: 52 | message_passed_log = log 53 | break 54 | 55 | message_length = int(message_passed_log.data[128:160].hex(), 16) 56 | 57 | return MessagePassedEvent( 58 | message_nonce=int(message_passed_log.topics[1].hex(), 16), 59 | sender=log_to_address(message_passed_log.topics[2].hex()), 60 | target=log_to_address(message_passed_log.topics[3].hex()), 61 | value=int(message_passed_log.data[:32].hex(), 16), 62 | min_gas_limit=int(message_passed_log.data[32:64].hex(), 16), 63 | message=message_passed_log.data[160:160 + message_length].hex() 64 | ), message_passed_log.data[96:128].hex() 65 | 66 | def make_state_trie_proof(provider, block_number, address, slot): 67 | 68 | proof = provider.eth.get_proof(address, [slot], block_identifier=block_number) 69 | 70 | return StateTrieProof( 71 | account_proof=proof.accountProof, 72 | storage_proof=proof.storageProof[0].proof, 73 | storage_value=proof.storageProof[0].value, 74 | storage_root=proof.storageHash 75 | ) 76 | 77 | def is_chain_supported(chain_id): 78 | 79 | l1_chain_ids = get_l1_chain_ids() 80 | l2_chain_ids = get_l2_chain_ids() 81 | 82 | return str(chain_id) in l1_chain_ids or str(chain_id) in l2_chain_ids 83 | 84 | def read_addresses(chain_id_l1, chain_id_l2, layer="l1"): 85 | 86 | path = f"{os.path.dirname(os.path.abspath(__file__))}" 87 | with open(os.path.abspath(path + f"/config.json")) as f: 88 | addresses: dict = json.load(f) 89 | 90 | return addresses[str(chain_id_l1)][str(chain_id_l2)][layer + "_addresses"] 91 | 92 | 93 | def get_l1_chain_ids(): 94 | path = f"{os.path.dirname(os.path.abspath(__file__))}" 95 | with open(os.path.abspath(path + f"/config.json")) as f: 96 | addresses: dict = json.load(f) 97 | 98 | return addresses.keys() 99 | 100 | def get_l2_chain_ids(): 101 | path = f"{os.path.dirname(os.path.abspath(__file__))}" 102 | with open(os.path.abspath(path + f"/config.json")) as f: 103 | addresses: dict = json.load(f) 104 | 105 | l1_chain_ids = addresses.keys() 106 | l2_chain_ids = [] 107 | for id in l1_chain_ids: 108 | l2_chain_ids += addresses[id].keys() 109 | 110 | return l2_chain_ids 111 | 112 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "optimism-python" 3 | version = "0.3.1" 4 | description = "Unofficial Python Client for the OP-Stack" 5 | authors = ["rafalum "] 6 | license = "MIT" 7 | repository = "https://github.com/rafalum/optimism-python" 8 | readme = "README.md" 9 | packages = [ 10 | { include = "optimism" }, 11 | ] 12 | include = ["optimism/assets/*.abi", "optimism/assets/*.json", "op.png"] 13 | 14 | [tool.poetry.dependencies] 15 | python = "^3.11" 16 | web3 = "6.11.1" 17 | python-dotenv = "1.0.0" 18 | 19 | 20 | [build-system] 21 | requires = ["poetry-core"] 22 | build-backend = "poetry.core.masonry.api" 23 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | web3=="6.11.1" 2 | python-dotenv=="1.0.0" -------------------------------------------------------------------------------- /test/README.md: -------------------------------------------------------------------------------- 1 | # Testing 2 | 3 | Testing is done by spinning up a local dev node in a QEMU VM and running the tests against it. Follow [this guide](https://github.com/rafalum/optimism-local-devnet) to setup your local dev net and place the .qcow2 file in the root of this directory. Further make the binaries `start_devnet` and `stop_devnet` available in your path. 4 | 5 | Then, run the tests with: 6 | ```bash 7 | python -m unittest discover -s test -p 'test_*.py' 8 | ``` 9 | 10 | -------------------------------------------------------------------------------- /test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rafalum/optimism-python/48a25b021c5b7c16cfca8f96a09553765acd1c0c/test/__init__.py -------------------------------------------------------------------------------- /test/extract_addresses.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | # Load the JSON data from the new file 4 | with open('/home/sandbox/optimism/packages/contracts-bedrock/deployments/31337-deploy.json') as f: 5 | data = json.load(f) 6 | 7 | # Extract the addresses based on the keys provided in the new JSON file 8 | addresses = { 9 | "OPTIMISM_PORTAL": data.get("OptimismPortal2"), 10 | "L1_STANDARD_BRIDGE": data.get("L1StandardBridgeProxy"), 11 | "L1_CROSS_CHAIN_MESSENGER": data.get("L1CrossDomainMessengerProxy"), 12 | "L2_OUTPUT_ORACLE": data.get("L2OutputOracleProxy"), 13 | "DISPUTE_GAME_FACTORY": data.get("DisputeGameFactoryProxy") 14 | } 15 | 16 | # Print the addresses 17 | print(addresses) 18 | -------------------------------------------------------------------------------- /test/test_deposit.py: -------------------------------------------------------------------------------- 1 | import os 2 | import time 3 | import json 4 | import signal 5 | import psutil 6 | import unittest 7 | import subprocess 8 | 9 | from web3 import Web3 10 | from web3.middleware import geth_poa_middleware 11 | 12 | from optimism import CrossChainMessenger 13 | 14 | from test.utils import TestUtil 15 | 16 | class TestDeposit(unittest.TestCase, TestUtil): 17 | 18 | def setUp(self) -> None: 19 | 20 | self.node_process = subprocess.Popen(["start_devnet", "devnode"]) 21 | 22 | if self.node_process.returncode == None: 23 | print("Local dev net started successfully") 24 | else: 25 | print(f"Error starting local dev net. Exit code: {self.node_process.returncode}") 26 | 27 | time.sleep(40) 28 | 29 | subprocess.Popen(["sshpass", "-p", "sandbox", "ssh", "-o", "IdentitiesOnly=yes", "-t", "sandbox@127.0.0.1", "-p", "10022", "cd ~/optimism && make devnet-up"]) 30 | 31 | time.sleep(40) 32 | 33 | vm_process = subprocess.Popen(["sshpass", "-p", "sandbox", "ssh", "-o", "IdentitiesOnly=yes", "-t", "sandbox@127.0.0.1", "-p", "10022", "python3 extract_addresses.py"], stdout=subprocess.PIPE) 34 | 35 | output, error = vm_process.communicate() 36 | if error: 37 | print(f"Error: {error}") 38 | else: 39 | l1_addresses_devnet = json.loads(output.decode().split("\r\n")[-2].strip("\r\n").replace("'", "\"")) 40 | 41 | with open("optimism/config.json", 'r') as file: 42 | addresses = json.load(file) 43 | 44 | addresses["900"]["901"]["l1_addresses"] = l1_addresses_devnet 45 | 46 | with open("optimism/config.json", 'w') as json_file: 47 | json.dump(addresses, json_file, indent=4) 48 | 49 | subprocess.Popen(["sshpass", "-p", "sandbox", "ssh", "-o", "IdentitiesOnly=yes", "-t", "sandbox@127.0.0.1", "-p", "10022", f"echo 'export L2OO_ADDRESS={l1_addresses_devnet['L2_OUTPUT_ORACLE']}' >> '/home/sandbox/.bashrc'"]) 50 | subprocess.Popen(["sshpass", "-p", "sandbox", "ssh", "-o", "IdentitiesOnly=yes", "-t", "sandbox@127.0.0.1", "-p", "10022", f"echo 'export DGF_ADDRESS={l1_addresses_devnet['DISPUTE_GAME_FACTORY']}' >> '/home/sandbox/.bashrc'"]) 51 | subprocess.Popen(["sshpass", "-p", "sandbox", "ssh", "-o", "IdentitiesOnly=yes", "-t", "sandbox@127.0.0.1", "-p", "10022", f"echo 'export DG_TYPE=0' >> '/home/sandbox/.bashrc'"]) 52 | subprocess.Popen(["sshpass", "-p", "sandbox", "ssh", "-o", "IdentitiesOnly=yes", "-t", "sandbox@127.0.0.1", "-p", "10022", f"cd ~/optimism && python3 bedrock-devnet/main.py"]) 53 | 54 | time.sleep(20) 55 | 56 | self.l1_provider = Web3(Web3.HTTPProvider("http://127.0.0.1:8545")) 57 | self.l2_provider = Web3(Web3.HTTPProvider("http://127.0.0.1:9545")) 58 | 59 | self.l1_provider.middleware_onion.inject(geth_poa_middleware, layer=0) 60 | self.l2_provider.middleware_onion.inject(geth_poa_middleware, layer=0) 61 | 62 | self.faucet = self.l1_provider.eth.account.from_key("0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80") 63 | 64 | self.account = self.l1_provider.eth.account.from_key("0x" + "1" * 64) 65 | 66 | self.fund_account(self.account, 10**18, layer="l1") 67 | 68 | 69 | 70 | def tearDown(self) -> None: 71 | print("Tearing down devnet") 72 | 73 | subprocess.Popen(["sshpass", "-p", "sandbox", "ssh", "-o", "IdentitiesOnly=yes", "-t", "sandbox@127.0.0.1", "-p", "10022", "cd ~/optimism && make devnet-down"]) 74 | time.sleep(30) 75 | subprocess.Popen(["sshpass", "-p", "sandbox", "ssh", "-o", "IdentitiesOnly=yes", "-t", "sandbox@127.0.0.1", "-p", "10022", "cd ~/optimism && make devnet-clean"]) 76 | time.sleep(30) 77 | subprocess.Popen(["sshpass", "-p", "sandbox", "ssh", "-o", "IdentitiesOnly=yes", "-t", "sandbox@127.0.0.1", "-p", "10022", "sudo poweroff"]) 78 | time.sleep(10) 79 | 80 | node_process_pid = self.node_process.pid 81 | 82 | parent_process = psutil.Process(node_process_pid) 83 | child_processes = parent_process.children(recursive=True) 84 | 85 | self.node_process.terminate() 86 | 87 | # kill all child processes 88 | for child in child_processes: 89 | if parent_process.pid != child.pid: 90 | os.kill(child.pid, signal.SIGTERM) 91 | 92 | 93 | def testDepositETH(self): 94 | 95 | l1_chain_id = 900 96 | l2_chain_id = 901 97 | 98 | cross_chain_messenger = CrossChainMessenger(l1_chain_id, l2_chain_id, account_l1=self.account, account_l2=self.account, provider_l1=self.l1_provider, provider_l2=self.l2_provider) 99 | 100 | balance_l1 = self.l1_provider.eth.get_balance(self.account.address) 101 | balance_l2 = self.l2_provider.eth.get_balance(self.account.address) 102 | 103 | self.assertEqual(balance_l1, 10**18) 104 | self.assertEqual(balance_l2, 0) 105 | 106 | deposit_txn_hash, deposit_txn_receipt = cross_chain_messenger.deposit_eth(5*10**17) 107 | 108 | time.sleep(30) 109 | 110 | balance_l1 = self.l1_provider.eth.get_balance(self.account.address) 111 | balance_l2 = self.l2_provider.eth.get_balance(self.account.address) 112 | 113 | self.assertGreater(balance_l1, 0.498*10**18) 114 | self.assertLess(balance_l1, 0.5*10**18) 115 | 116 | self.assertEqual(balance_l2, 0.5*10**18) 117 | 118 | 119 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /test/test_withdrawl.py: -------------------------------------------------------------------------------- 1 | import os 2 | import time 3 | import json 4 | import signal 5 | import psutil 6 | import unittest 7 | import subprocess 8 | 9 | from web3 import Web3 10 | from web3.middleware import geth_poa_middleware 11 | 12 | from optimism import CrossChainMessenger 13 | from optimism.types import MessageStatus 14 | 15 | from test.utils import TestUtil 16 | 17 | class TestWithdrawl(unittest.TestCase, TestUtil): 18 | 19 | def setUp(self) -> None: 20 | 21 | self.node_process = subprocess.Popen(["start_devnet", "devnode"]) 22 | 23 | if self.node_process.returncode == None: 24 | print("Local dev net started successfully") 25 | else: 26 | print(f"Error starting local dev net. Exit code: {self.node_process.returncode}") 27 | 28 | time.sleep(40) 29 | 30 | subprocess.Popen(["sshpass", "-p", "sandbox", "ssh", "-o", "IdentitiesOnly=yes", "-t", "sandbox@127.0.0.1", "-p", "10022", "cd ~/optimism && make devnet-up"]) 31 | 32 | time.sleep(40) 33 | 34 | vm_process = subprocess.Popen(["sshpass", "-p", "sandbox", "ssh", "-o", "IdentitiesOnly=yes", "-t", "sandbox@127.0.0.1", "-p", "10022", "python3 extract_addresses.py"], stdout=subprocess.PIPE) 35 | 36 | output, error = vm_process.communicate() 37 | if error: 38 | print(f"Error: {error}") 39 | else: 40 | l1_addresses_devnet = json.loads(output.decode().split("\r\n")[-2].strip("\r\n").replace("'", "\"")) 41 | 42 | with open("optimism/config.json", 'r') as file: 43 | addresses = json.load(file) 44 | 45 | addresses["900"]["901"]["l1_addresses"] = l1_addresses_devnet 46 | 47 | with open("optimism/config.json", 'w') as json_file: 48 | json.dump(addresses, json_file, indent=4) 49 | 50 | 51 | subprocess.Popen(["sshpass", "-p", "sandbox", "ssh", "-o", "IdentitiesOnly=yes", "-t", "sandbox@127.0.0.1", "-p", "10022", f"echo 'export L2OO_ADDRESS={l1_addresses_devnet['L2_OUTPUT_ORACLE']}' >> '/home/sandbox/.bashrc'"]) 52 | subprocess.Popen(["sshpass", "-p", "sandbox", "ssh", "-o", "IdentitiesOnly=yes", "-t", "sandbox@127.0.0.1", "-p", "10022", f"echo 'export DGF_ADDRESS={l1_addresses_devnet['DISPUTE_GAME_FACTORY']}' >> '/home/sandbox/.bashrc'"]) 53 | subprocess.Popen(["sshpass", "-p", "sandbox", "ssh", "-o", "IdentitiesOnly=yes", "-t", "sandbox@127.0.0.1", "-p", "10022", f"echo 'export DG_TYPE=0' >> '/home/sandbox/.bashrc'"]) 54 | subprocess.Popen(["sshpass", "-p", "sandbox", "ssh", "-o", "IdentitiesOnly=yes", "-t", "sandbox@127.0.0.1", "-p", "10022", f"cd ~/optimism && python3 bedrock-devnet/main.py"]) 55 | 56 | time.sleep(20) 57 | 58 | self.l1_provider = Web3(Web3.HTTPProvider("http://127.0.0.1:8545")) 59 | self.l2_provider = Web3(Web3.HTTPProvider("http://127.0.0.1:9545")) 60 | 61 | self.l1_provider.middleware_onion.inject(geth_poa_middleware, layer=0) 62 | self.l2_provider.middleware_onion.inject(geth_poa_middleware, layer=0) 63 | 64 | self.faucet = self.l1_provider.eth.account.from_key("0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80") 65 | 66 | self.account = self.l1_provider.eth.account.from_key("0x" + "1" * 64) 67 | 68 | self.fund_account(self.account, 10**18, "l1") 69 | self.fund_account(self.account, 10**18, "l2") 70 | 71 | 72 | 73 | def tearDown(self) -> None: 74 | print("Tearing down devnet") 75 | 76 | subprocess.Popen(["sshpass", "-p", "sandbox", "ssh", "-o", "IdentitiesOnly=yes", "-t", "sandbox@127.0.0.1, -p", "10022", "sed -i '$d' '/home/sandbox/.bashrc'"]) 77 | subprocess.Popen(["sshpass", "-p", "sandbox", "ssh", "-o", "IdentitiesOnly=yes", "-t", "sandbox@127.0.0.1", "-p", "10022", "cd ~/optimism && make devnet-down"]) 78 | time.sleep(30) 79 | subprocess.Popen(["sshpass", "-p", "sandbox", "ssh", "-o", "IdentitiesOnly=yes", "-t", "sandbox@127.0.0.1", "-p", "10022", "cd ~/optimism && make devnet-clean"]) 80 | time.sleep(30) 81 | subprocess.Popen(["sshpass", "-p", "sandbox", "ssh", "-o", "IdentitiesOnly=yes", "-t", "sandbox@127.0.0.1", "-p", "10022", "sudo poweroff"]) 82 | time.sleep(10) 83 | 84 | node_process_pid = self.node_process.pid 85 | 86 | parent_process = psutil.Process(node_process_pid) 87 | child_processes = parent_process.children(recursive=True) 88 | 89 | self.node_process.terminate() 90 | 91 | # kill all child processes 92 | for child in child_processes: 93 | if parent_process.pid != child.pid: 94 | os.kill(child.pid, signal.SIGTERM) 95 | 96 | 97 | def testWithdrawETH(self): 98 | 99 | l1_chain_id = 900 100 | l2_chain_id = 901 101 | 102 | cross_chain_messenger = CrossChainMessenger(l1_chain_id, l2_chain_id, account_l1=self.account, account_l2=self.account, provider_l1=self.l1_provider, provider_l2=self.l2_provider) 103 | 104 | balance_l1 = self.l1_provider.eth.get_balance(self.account.address) 105 | balance_l2 = self.l2_provider.eth.get_balance(self.account.address) 106 | 107 | self.assertEqual(balance_l1, 10**18) 108 | self.assertEqual(balance_l2, 10**18) 109 | 110 | withdrawl_txn_hash, withdrawl_txn_receipt = cross_chain_messenger.withdraw_eth(5*10**17) 111 | 112 | self.assertEqual(withdrawl_txn_receipt.status, 1) 113 | 114 | print(withdrawl_txn_hash) 115 | 116 | while True: 117 | status = cross_chain_messenger.get_message_status(withdrawl_txn_hash) 118 | print(status) 119 | if status == MessageStatus.READY_TO_PROVE: 120 | break 121 | else: 122 | time.sleep(10) 123 | 124 | prove_message_txn, prove_message_receipt = cross_chain_messenger.prove_message(withdrawl_txn_hash) 125 | 126 | self.assertEqual(prove_message_receipt.status, 1) 127 | 128 | while True: 129 | status = cross_chain_messenger.get_message_status(withdrawl_txn_hash) 130 | print(status) 131 | if status == MessageStatus.READY_FOR_RELAY: 132 | break 133 | else: 134 | time.sleep(10) 135 | 136 | finalize_message_tx, finalize_message_receipt = cross_chain_messenger.finalize_message(withdrawl_txn_hash) 137 | 138 | self.assertEqual(finalize_message_receipt.status, 1) 139 | 140 | print(finalize_message_receipt) 141 | 142 | time.sleep(30) 143 | 144 | balance_l1 = self.l1_provider.eth.get_balance(self.account.address) 145 | balance_l2 = self.l2_provider.eth.get_balance(self.account.address) 146 | 147 | # TODO: Balance should be 0.5 ETH for L2 and 1.5 ETH for L1. This is not the case. Fix. 148 | print(balance_l1) 149 | print(balance_l2) 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | -------------------------------------------------------------------------------- /test/utils.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | class TestUtil(): 4 | 5 | def __init__(self) -> None: 6 | pass 7 | 8 | def fund_account(self, account, value, layer="l1"): 9 | 10 | if layer == "l1": 11 | provider = self.l1_provider 12 | elif layer == "l2": 13 | provider = self.l2_provider 14 | else: 15 | raise Exception(f"Invalid layer: {layer}") 16 | 17 | tx = { 18 | 'nonce': provider.eth.get_transaction_count(self.faucet.address), 19 | 'to': account.address, 20 | 'value': value, 21 | 'gas': 50000, 22 | 'gasPrice': provider.eth.gas_price 23 | } 24 | 25 | # Sign and broadcast the transaction 26 | signed_tx = provider.eth.account.sign_transaction(tx, self.faucet.key) 27 | tx_hash = provider.eth.send_raw_transaction(signed_tx.rawTransaction) 28 | receipt = provider.eth.wait_for_transaction_receipt(tx_hash) 29 | 30 | return tx_hash.hex(), receipt --------------------------------------------------------------------------------