Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 949 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
Value | ||||
---|---|---|---|---|---|---|---|---|---|
Process Message ... | 17133722 | 437 days ago | IN | 0 ETH | 0.03675365 | ||||
Process Message ... | 17133432 | 438 days ago | IN | 0 ETH | 0.04412318 | ||||
Process Message ... | 17130170 | 438 days ago | IN | 0 ETH | 0.03616633 | ||||
Process Message ... | 17130155 | 438 days ago | IN | 0 ETH | 0.03583023 | ||||
Process Message ... | 17129869 | 438 days ago | IN | 0 ETH | 0.03884047 | ||||
Process Message ... | 17129736 | 438 days ago | IN | 0 ETH | 0.03131968 | ||||
Process Message ... | 17129726 | 438 days ago | IN | 0 ETH | 0.03753183 | ||||
Process Message ... | 17128988 | 438 days ago | IN | 0 ETH | 0.0395677 | ||||
Process Message ... | 17128707 | 438 days ago | IN | 0 ETH | 0.0417432 | ||||
Process Message ... | 16769524 | 489 days ago | IN | 0 ETH | 0.02687624 | ||||
Process Message ... | 16756473 | 491 days ago | IN | 0 ETH | 0.025217 | ||||
Process Message ... | 16719290 | 496 days ago | IN | 0 ETH | 0.01680756 | ||||
Propose New Owne... | 16672892 | 503 days ago | IN | 0 ETH | 0.00209938 | ||||
Process Message ... | 16528452 | 523 days ago | IN | 0 ETH | 0.02241644 | ||||
Process Message ... | 16528445 | 523 days ago | IN | 0 ETH | 0.02261465 | ||||
Process Message ... | 16528438 | 523 days ago | IN | 0 ETH | 0.02198441 | ||||
Process Message ... | 16528430 | 523 days ago | IN | 0 ETH | 0.02343334 | ||||
Process Message ... | 16528422 | 523 days ago | IN | 0 ETH | 0.02405418 | ||||
Process Message ... | 16528414 | 523 days ago | IN | 0 ETH | 0.02477009 | ||||
Process Message ... | 16528405 | 523 days ago | IN | 0 ETH | 0.0214442 | ||||
Process Message ... | 16528398 | 523 days ago | IN | 0 ETH | 0.02705499 | ||||
Process Message ... | 16528391 | 523 days ago | IN | 0 ETH | 0.02665562 | ||||
Process Message ... | 16528383 | 523 days ago | IN | 0 ETH | 0.02795718 | ||||
Process Message ... | 16528375 | 523 days ago | IN | 0 ETH | 0.02654707 | ||||
Process Message ... | 16528365 | 523 days ago | IN | 0 ETH | 0.02438831 |
Advanced mode: Intended for advanced users or developers and will display all Internal Transactions including zero value transfers. Name tag integration is not available in advanced view.
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Block | From | To | Value | |||
---|---|---|---|---|---|---|---|
17422378 | 397 days ago | 0 ETH | |||||
17422378 | 397 days ago | 0 ETH | |||||
17422227 | 397 days ago | 0 ETH | |||||
17422227 | 397 days ago | 0 ETH | |||||
17422076 | 397 days ago | 0 ETH | |||||
17422076 | 397 days ago | 0 ETH | |||||
17421925 | 397 days ago | 0 ETH | |||||
17421925 | 397 days ago | 0 ETH | |||||
17421881 | 397 days ago | 0 ETH | |||||
17421881 | 397 days ago | 0 ETH | |||||
17421881 | 397 days ago | 0 ETH | |||||
17421776 | 397 days ago | 0 ETH | |||||
17421776 | 397 days ago | 0 ETH | |||||
17421750 | 397 days ago | 0 ETH | |||||
17421750 | 397 days ago | 0 ETH | |||||
17421750 | 397 days ago | 0 ETH | |||||
17421626 | 397 days ago | 0 ETH | |||||
17421626 | 397 days ago | 0 ETH | |||||
17421603 | 397 days ago | 0 ETH | |||||
17421603 | 397 days ago | 0 ETH | |||||
17421603 | 397 days ago | 0 ETH | |||||
17421580 | 397 days ago | 0 ETH | |||||
17421580 | 397 days ago | 0 ETH | |||||
17421580 | 397 days ago | 0 ETH | |||||
17421477 | 397 days ago | 0 ETH |
Loading...
Loading
Similar Match Source Code This contract matches the deployed Bytecode of the Source Code for Contract 0x3BCB9b4b...7432cF6D8 The constructor portion of the code might be different and could alter the actual behaviour of the contract
Contract Name:
OptimismHubConnector
Compiler Version
v0.8.17+commit.8df45f5f
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity 0.8.17; import {IRootManager} from "../../interfaces/IRootManager.sol"; import {OptimismAmb} from "../../interfaces/ambs/optimism/OptimismAmb.sol"; import {IStateCommitmentChain, L2MessageInclusionProof} from "../../interfaces/ambs/optimism/IStateCommitmentChain.sol"; import {TypedMemView} from "../../../shared/libraries/TypedMemView.sol"; import {HubConnector} from "../HubConnector.sol"; import {Connector} from "../Connector.sol"; import {PredeployAddresses} from "./lib/PredeployAddresses.sol"; import {OVMCodec} from "./lib/OVMCodec.sol"; import {SecureMerkleTrie} from "./lib/SecureMerkleTrie.sol"; import {BaseOptimism} from "./BaseOptimism.sol"; contract OptimismHubConnector is HubConnector, BaseOptimism { // ============ Libraries ============ using TypedMemView for bytes; using TypedMemView for bytes29; // ============ Storage ============ IStateCommitmentChain public immutable stateCommitmentChain; // NOTE: This is needed because we need to track the roots we've // already sent across chains. When sending an optimism message, we send calldata // for Connector.processMessage. At any point these messages could be processed // before the timeout using `processFromRoot` or after the timeout using `process` // we track the roots sent here to ensure we process each root once mapping(bytes32 => bool) public processed; // ============ Constructor ============ constructor( uint32 _domain, uint32 _mirrorDomain, address _amb, address _rootManager, address _mirrorConnector, address _stateCommitmentChain, uint256 _gasCap ) HubConnector(_domain, _mirrorDomain, _amb, _rootManager, _mirrorConnector) BaseOptimism(_gasCap) { stateCommitmentChain = IStateCommitmentChain(_stateCommitmentChain); } // ============ Override Fns ============ function _verifySender(address _expected) internal view override returns (bool) { return _verifySender(AMB, _expected); } /** * @dev Sends `aggregateRoot` to messaging on l2 */ function _sendMessage(bytes memory _data, bytes memory _encodedData) internal override { // Should always be dispatching the aggregate root require(_data.length == 32, "!length"); // Get the calldata bytes memory _calldata = abi.encodeWithSelector(Connector.processMessage.selector, _data); // Dispatch message OptimismAmb(AMB).sendMessage(mirrorConnector, _calldata, uint32(gasCap)); } // DO NOT override _processMessage, should revert from `Connector` class. All messages must use the // `processMessageFromRoot` flow. /** * @dev modified from: https://github.com/ethereum-optimism/optimism/blob/9973c1da3211e094a180a8a96ba9f8bb1ab1b389/packages/contracts/contracts/L1/messaging/L1CrossDomainMessenger.sol#L165 */ function processMessageFromRoot( address _target, address _sender, bytes memory _message, uint256 _messageNonce, L2MessageInclusionProof memory _proof ) external { // verify the sender is the l2 contract require(_sender == mirrorConnector, "!mirrorConnector"); // verify the target is this contract require(_target == address(this), "!this"); // Get the encoded data bytes memory xDomainData = _encodeXDomainCalldata(_target, _sender, _message, _messageNonce); require(_verifyXDomainMessage(xDomainData, _proof), "!proof"); // NOTE: optimism seems to pad the calldata sent in to include more than the expected // 36 bytes, i.e. in this transaction: // https://blockscout.com/optimism/goerli/tx/0x440fda036d28eb547394a8689af90c5342a00a8ca2ab5117f2b85f54d1416ddd/logs // the corresponding _message is: // 0x4ff746f60000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002027ae5ba08d7291c96c8cbddcc148bf48a6d68c7974b94356f53754ef6171d757 // // this means the length check and byte parsing used in the `ArbitrumHubConnector` would // not work here. Instead, take the back 32 bytes of the string // NOTE: TypedMemView only loads 32-byte chunks onto stack, which is fine in this case bytes29 _view = _message.ref(0); bytes32 root = _view.index(_view.len() - 32, 32); if (!processed[root]) { // set root to processed processed[root] = true; // update the root on the root manager IRootManager(ROOT_MANAGER).aggregate(MIRROR_DOMAIN, root); emit MessageProcessed(abi.encode(root), msg.sender); } // otherwise root was already sent to root manager } /** * Verifies that the given message is valid. * @dev modified from: https://github.com/ethereum-optimism/optimism/blob/9973c1da3211e094a180a8a96ba9f8bb1ab1b389/packages/contracts/contracts/L1/messaging/L1CrossDomainMessenger.sol#L283-L288 * @param _xDomainCalldata Calldata to verify. * @param _proof Inclusion proof for the message. * @return Whether or not the provided message is valid. */ function _verifyXDomainMessage(bytes memory _xDomainCalldata, L2MessageInclusionProof memory _proof) internal view returns (bool) { return (_verifyStateRootProof(_proof) && _verifyStorageProof(_xDomainCalldata, _proof)); } /** * Verifies that the state root within an inclusion proof is valid. * @dev modified from: https://github.com/ethereum-optimism/optimism/blob/9973c1da3211e094a180a8a96ba9f8bb1ab1b389/packages/contracts/contracts/L1/messaging/L1CrossDomainMessenger.sol#L295-L311 * @param _proof Message inclusion proof. * @return Whether or not the provided proof is valid. */ function _verifyStateRootProof(L2MessageInclusionProof memory _proof) internal view returns (bool) { return stateCommitmentChain.verifyStateCommitment(_proof.stateRoot, _proof.stateRootBatchHeader, _proof.stateRootProof); } /** * Verifies that the storage proof within an inclusion proof is valid. * @dev modified from: https://github.com/ethereum-optimism/optimism/blob/9973c1da3211e094a180a8a96ba9f8bb1ab1b389/packages/contracts/contracts/L1/messaging/L1CrossDomainMessenger.sol#L313-L357 * @param _xDomainCalldata Encoded message calldata. * @param _proof Message inclusion proof. * @return Whether or not the provided proof is valid. */ function _verifyStorageProof(bytes memory _xDomainCalldata, L2MessageInclusionProof memory _proof) internal pure returns (bool) { bytes32 storageKey = keccak256( abi.encodePacked( keccak256(abi.encodePacked(_xDomainCalldata, PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER)), uint256(0) ) ); (bool exists, bytes memory encodedMessagePassingAccount) = SecureMerkleTrie.get( abi.encodePacked(PredeployAddresses.L2_TO_L1_MESSAGE_PASSER), _proof.stateTrieWitness, _proof.stateRoot ); require(exists == true, "Message passing predeploy has not been initialized or invalid proof provided."); OVMCodec.EVMAccount memory account = OVMCodec.decodeEVMAccount(encodedMessagePassingAccount); return SecureMerkleTrie.verifyInclusionProof( abi.encodePacked(storageKey), abi.encodePacked(uint8(1)), _proof.storageTrieWitness, account.storageRoot ); } /** * Generates the correct cross domain calldata for a message. * @dev taken from: https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/libraries/bridge/Lib_CrossDomainUtils.sol * @param _target Target contract address. * @param _sender Message sender address. * @param _message Message to send to the target. * @param _messageNonce Nonce for the provided message. * @return ABI encoded cross domain calldata. */ function _encodeXDomainCalldata( address _target, address _sender, bytes memory _message, uint256 _messageNonce ) internal pure returns (bytes memory) { return abi.encodeWithSignature("relayMessage(address,address,bytes,uint256)", _target, _sender, _message, _messageNonce); } }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity 0.8.17; import {ProposedOwnable} from "../../shared/ProposedOwnable.sol"; import {IConnector} from "../interfaces/IConnector.sol"; /** * @title Connector * @author Connext Labs, Inc. * @notice This contract has the messaging interface functions used by all connectors. * * @dev This contract stores information about mirror connectors, but can be used as a * base for contracts that do not have a mirror (i.e. the connector handling messaging on * mainnet). In this case, the `mirrorConnector` and `MIRROR_DOMAIN` * will be empty * * @dev If ownership is renounced, this contract will be unable to update its `mirrorConnector` * or `mirrorGas` */ abstract contract Connector is ProposedOwnable, IConnector { // ========== Custom Errors =========== error Connector__processMessage_notUsed(); // ============ Events ============ event NewConnector( uint32 indexed domain, uint32 indexed mirrorDomain, address amb, address rootManager, address mirrorConnector ); event MirrorConnectorUpdated(address previous, address current); // ============ Public Storage ============ /** * @notice The domain of this Messaging (i.e. Connector) contract. */ uint32 public immutable DOMAIN; /** * @notice Address of the AMB on this domain. */ address public immutable AMB; /** * @notice RootManager contract address. */ address public immutable ROOT_MANAGER; /** * @notice The domain of the corresponding messaging (i.e. Connector) contract. */ uint32 public immutable MIRROR_DOMAIN; /** * @notice Connector on L2 for L1 connectors, and vice versa. */ address public mirrorConnector; // ============ Modifiers ============ /** * @notice Errors if the msg.sender is not the registered AMB */ modifier onlyAMB() { require(msg.sender == AMB, "!AMB"); _; } /** * @notice Errors if the msg.sender is not the registered ROOT_MANAGER */ modifier onlyRootManager() { // NOTE: RootManager will be zero address for spoke connectors. // Only root manager can dispatch a message to spokes/L2s via the hub connector. require(msg.sender == ROOT_MANAGER, "!rootManager"); _; } // ============ Constructor ============ /** * @notice Creates a new HubConnector instance * @dev The connectors are deployed such that there is one on each side of an AMB (i.e. * for optimism, there is one connector on optimism and one connector on mainnet) * @param _domain The domain this connector lives on * @param _mirrorDomain The spoke domain * @param _amb The address of the amb on the domain this connector lives on * @param _rootManager The address of the RootManager on mainnet * @param _mirrorConnector The address of the spoke connector */ constructor( uint32 _domain, uint32 _mirrorDomain, address _amb, address _rootManager, address _mirrorConnector ) ProposedOwnable() { // set the owner _setOwner(msg.sender); // sanity checks on values require(_domain != 0, "empty domain"); require(_rootManager != address(0), "empty rootManager"); // see note at top of contract on why the mirror values are not sanity checked // set immutables DOMAIN = _domain; AMB = _amb; ROOT_MANAGER = _rootManager; MIRROR_DOMAIN = _mirrorDomain; // set mutables if defined if (_mirrorConnector != address(0)) { _setMirrorConnector(_mirrorConnector); } emit NewConnector(_domain, _mirrorDomain, _amb, _rootManager, _mirrorConnector); } // ============ Receivable ============ /** * @notice Connectors may need to receive native asset to handle fees when sending a * message */ receive() external payable {} // ============ Admin Functions ============ /** * @notice Sets the address of the l2Connector for this domain */ function setMirrorConnector(address _mirrorConnector) public onlyOwner { _setMirrorConnector(_mirrorConnector); } // ============ Public Functions ============ /** * @notice Processes a message received by an AMB * @dev This is called by AMBs to process messages originating from mirror connector */ function processMessage(bytes memory _data) external virtual onlyAMB { _processMessage(_data); emit MessageProcessed(_data, msg.sender); } /** * @notice Checks the cross domain sender for a given address */ function verifySender(address _expected) external returns (bool) { return _verifySender(_expected); } // ============ Virtual Functions ============ /** * @notice This function is used by the Connext contract on the l2 domain to send a message to the * l1 domain (i.e. called by Connext on optimism to send a message to mainnet with roots) * @param _data The contents of the message * @param _encodedData Data used to send the message; specific to connector */ function _sendMessage(bytes memory _data, bytes memory _encodedData) internal virtual; /** * @notice This function is used by the AMBs to handle incoming messages. Should store the latest * root generated on the l2 domain. */ function _processMessage( bytes memory /* _data */ ) internal virtual { // By default, reverts. This is to ensure the call path is not used unless this function is // overridden by the inheriting class revert Connector__processMessage_notUsed(); } /** * @notice Verify that the msg.sender is the correct AMB contract, and that the message's origin sender * is the expected address. * @dev Should be overridden by the implementing Connector contract. */ function _verifySender(address _expected) internal virtual returns (bool); // ============ Private Functions ============ function _setMirrorConnector(address _mirrorConnector) internal virtual { emit MirrorConnectorUpdated(mirrorConnector, _mirrorConnector); mirrorConnector = _mirrorConnector; } }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity 0.8.17; import {ProposedOwnable} from "../../shared/ProposedOwnable.sol"; abstract contract GasCap is ProposedOwnable { // ============ Storage ============ /** * @notice The gnosis amb requires destination gas to be specified on the origin. * The gas used will be passed in by the relayer to allow for real-time estimates, * but will be capped at the admin-set cap. */ uint256 gasCap; // ============ Events ============ /** * @notice Emitted when admin updates the gas cap * @param _previous The starting value * @param _updated The final value */ event GasCapUpdated(uint256 _previous, uint256 _updated); // ============ Constructor ============ constructor(uint256 _gasCap) { _setGasCap(_gasCap); } // ============ Admin Fns ============ function setGasCap(uint256 _gasCap) public onlyOwner { _setGasCap(_gasCap); } // ============ Internal Fns ============ /** * @notice Used (by admin) to update the gas cap * @param _gasCap The new value */ function _setGasCap(uint256 _gasCap) internal { emit GasCapUpdated(gasCap, _gasCap); gasCap = _gasCap; } /** * @notice Used to get the gas to use. Will be the original value IFF it * is less than the cap * @param _gas The proposed gas value */ function _getGas(uint256 _gas) internal view returns (uint256) { if (_gas > gasCap) { _gas = gasCap; } return _gas; } }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity 0.8.17; import {Connector} from "./Connector.sol"; /** * @title HubConnector * @author Connext Labs, Inc. * @notice This contract implements the messaging functions needed on the hub-side of a given AMB. * The HubConnector has a limited set of functionality compared to the SpokeConnector, namely that * it contains no logic to store or prove messages. * * @dev This contract should be deployed on the hub-side of an AMB (i.e. on L1), and contracts * which extend this should implement the virtual functions defined in the BaseConnector class */ abstract contract HubConnector is Connector { /** * @notice Creates a new HubConnector instance * @dev The connectors are deployed such that there is one on each side of an AMB (i.e. * for optimism, there is one connector on optimism and one connector on mainnet) * @param _domain The domain this connector lives on * @param _mirrorDomain The spoke domain * @param _amb The address of the amb on the domain this connector lives on * @param _rootManager The address of the RootManager on mainnet * @param _mirrorConnector The address of the spoke connector */ constructor( uint32 _domain, uint32 _mirrorDomain, address _amb, address _rootManager, address _mirrorConnector ) Connector(_domain, _mirrorDomain, _amb, _rootManager, _mirrorConnector) {} // ============ Public fns ============ /** * @notice Sends a message over the amb * @dev This is called by the root manager *only* on mainnet to propagate the aggregate root */ function sendMessage(bytes memory _data, bytes memory _encodedData) external payable onlyRootManager { _sendMessage(_data, _encodedData); emit MessageSent(_data, _encodedData, msg.sender); } }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity 0.8.17; import {OptimismAmb} from "../../interfaces/ambs/optimism/OptimismAmb.sol"; import {GasCap} from "../GasCap.sol"; abstract contract BaseOptimism is GasCap { // ============ Constructor ============ constructor(uint256 _gasCap) GasCap(_gasCap) {} // ============ Override Fns ============ function _verifySender(address _amb, address _expected) internal view returns (bool) { require(msg.sender == _amb, "!bridge"); return OptimismAmb(_amb).xDomainMessageSender() == _expected; } /** * @notice Using Optimism AMB, the gas is provided to `sendMessage` as an encoded uint */ function _getGasFromEncoded(bytes memory _encodedData) internal view returns (uint256 _gas) { // Should include gas info in specialized calldata require(_encodedData.length == 32, "!data length"); // Get the gas, if it is more than the cap use the cap _gas = _getGas(abi.decode(_encodedData, (uint256))); } }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity 0.8.17; /** * @title BytesUtils * * @dev modified from: https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/libraries/utils/Lib_BytesUtils.sol */ library BytesUtils { /********************** * Internal Functions * **********************/ function slice( bytes memory _bytes, uint256 _start, uint256 _length ) internal pure returns (bytes memory) { require(_length + 31 >= _length, "slice_overflow"); require(_start + _length >= _start, "slice_overflow"); require(_bytes.length >= _start + _length, "slice_outOfBounds"); bytes memory tempBytes; assembly { switch iszero(_length) case 0 { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // The first word of the slice result is potentially a partial // word read from the original array. To read it, we calculate // the length of that partial word and start copying that many // bytes into the array. The first word we copy will start with // data we don't care about, but the last `lengthmod` bytes will // land at the beginning of the contents of the new array. When // we're done copying, we overwrite the full first word with // the actual length of the slice. let lengthmod := and(_length, 31) // The multiplication in the next line is necessary // because when slicing multiples of 32 bytes (lengthmod == 0) // the following copy loop was copying the origin's length // and then ending prematurely not copying everything it should. let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod))) let end := add(mc, _length) for { // The multiplication in the next line has the same exact purpose // as the one above. let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } mstore(tempBytes, _length) //update free-memory pointer //allocating the array padded to 32 bytes like the compiler does now mstore(0x40, and(add(mc, 31), not(31))) } //if we want a zero-length slice let's just return a zero-length array default { tempBytes := mload(0x40) //zero out the 32 bytes slice we are about to return //we need to do it because Solidity does not garbage collect mstore(tempBytes, 0) mstore(0x40, add(tempBytes, 0x20)) } } return tempBytes; } function slice(bytes memory _bytes, uint256 _start) internal pure returns (bytes memory) { if (_start >= _bytes.length) { return bytes(""); } return slice(_bytes, _start, _bytes.length - _start); } function toBytes32(bytes memory _bytes) internal pure returns (bytes32) { if (_bytes.length < 32) { bytes32 ret; assembly { ret := mload(add(_bytes, 32)) } return ret; } return abi.decode(_bytes, (bytes32)); // will truncate if input length > 32 bytes } function toUint256(bytes memory _bytes) internal pure returns (uint256) { return uint256(toBytes32(_bytes)); } function toNibbles(bytes memory _bytes) internal pure returns (bytes memory) { bytes memory nibbles = new bytes(_bytes.length * 2); uint256 len = _bytes.length; for (uint256 i = 0; i < len; ) { nibbles[i * 2] = _bytes[i] >> 4; nibbles[i * 2 + 1] = bytes1(uint8(_bytes[i]) % 16); unchecked { ++i; } } return nibbles; } function fromNibbles(bytes memory _bytes) internal pure returns (bytes memory) { bytes memory ret = new bytes(_bytes.length / 2); uint256 len = ret.length; for (uint256 i = 0; i < len; ) { ret[i] = (_bytes[i * 2] << 4) | (_bytes[i * 2 + 1]); unchecked { ++i; } } return ret; } function equal(bytes memory _bytes, bytes memory _other) internal pure returns (bool) { return keccak256(_bytes) == keccak256(_other); } }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity 0.8.17; /* Library Imports */ import {BytesUtils} from "./BytesUtils.sol"; import {RLPReader} from "./RLPReader.sol"; /** * @title MerkleTrie * * @dev modified from: https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/libraries/trie/Lib_MerkleTrie.sol */ library MerkleTrie { /******************* * Data Structures * *******************/ enum NodeType { BranchNode, ExtensionNode, LeafNode } struct TrieNode { bytes encoded; RLPReader.RLPItem[] decoded; } /********************** * Contract Constants * **********************/ // TREE_RADIX determines the number of elements per branch node. uint256 constant TREE_RADIX = 16; // Branch nodes have TREE_RADIX elements plus an additional `value` slot. uint256 constant BRANCH_NODE_LENGTH = TREE_RADIX + 1; // Leaf nodes and extension nodes always have two elements, a `path` and a `value`. uint256 constant LEAF_OR_EXTENSION_NODE_LENGTH = 2; // Prefixes are prepended to the `path` within a leaf or extension node and // allow us to differentiate between the two node types. `ODD` or `EVEN` is // determined by the number of nibbles within the unprefixed `path`. If the // number of nibbles if even, we need to insert an extra padding nibble so // the resulting prefixed `path` has an even number of nibbles. uint8 constant PREFIX_EXTENSION_EVEN = 0; uint8 constant PREFIX_EXTENSION_ODD = 1; uint8 constant PREFIX_LEAF_EVEN = 2; uint8 constant PREFIX_LEAF_ODD = 3; // Just a utility constant. RLP represents `NULL` as 0x80. bytes1 constant RLP_NULL = bytes1(0x80); /********************** * Internal Functions * **********************/ /** * @notice Verifies a proof that a given key/value pair is present in the * Merkle trie. * @param _key Key of the node to search for, as a hex string. * @param _value Value of the node to search for, as a hex string. * @param _proof Merkle trie inclusion proof for the desired node. Unlike * traditional Merkle trees, this proof is executed top-down and consists * of a list of RLP-encoded nodes that make a path down to the target node. * @param _root Known root of the Merkle trie. Used to verify that the * included proof is correctly constructed. * @return _verified `true` if the k/v pair exists in the trie, `false` otherwise. */ function verifyInclusionProof( bytes memory _key, bytes memory _value, bytes memory _proof, bytes32 _root ) internal pure returns (bool _verified) { (bool exists, bytes memory value) = get(_key, _proof, _root); return (exists && BytesUtils.equal(_value, value)); } /** * @notice Retrieves the value associated with a given key. * @param _key Key to search for, as hex bytes. * @param _proof Merkle trie inclusion proof for the key. * @param _root Known root of the Merkle trie. * @return _exists Whether or not the key exists. * @return _value Value of the key if it exists. */ function get( bytes memory _key, bytes memory _proof, bytes32 _root ) internal pure returns (bool _exists, bytes memory _value) { TrieNode[] memory proof = _parseProof(_proof); (uint256 pathLength, bytes memory keyRemainder, bool isFinalNode) = _walkNodePath(proof, _key, _root); bool exists = keyRemainder.length == 0; require(exists || isFinalNode, "Provided proof is invalid."); bytes memory value = exists ? _getNodeValue(proof[pathLength - 1]) : bytes(""); return (exists, value); } /********************* * Private Functions * *********************/ /** * @notice Walks through a proof using a provided key. * @param _proof Inclusion proof to walk through. * @param _key Key to use for the walk. * @param _root Known root of the trie. * @return _pathLength Length of the final path * @return _keyRemainder Portion of the key remaining after the walk. * @return _isFinalNode Whether or not we've hit a dead end. */ function _walkNodePath( TrieNode[] memory _proof, bytes memory _key, bytes32 _root ) private pure returns ( uint256 _pathLength, bytes memory _keyRemainder, bool _isFinalNode ) { uint256 pathLength = 0; bytes memory key = BytesUtils.toNibbles(_key); bytes32 currentNodeID = _root; uint256 currentKeyIndex = 0; uint256 currentKeyIncrement = 0; TrieNode memory currentNode; // Proof is top-down, so we start at the first element (root). uint256 len = _proof.length; for (uint256 i = 0; i < len; ) { currentNode = _proof[i]; currentKeyIndex += currentKeyIncrement; // Keep track of the proof elements we actually need. // It's expensive to resize arrays, so this simply reduces gas costs. pathLength += 1; if (currentKeyIndex == 0) { // First proof element is always the root node. require(keccak256(currentNode.encoded) == currentNodeID, "Invalid root hash"); } else if (currentNode.encoded.length > 32 - 1) { // Nodes 32 bytes or larger are hashed inside branch nodes. require(keccak256(currentNode.encoded) == currentNodeID, "Invalid large internal hash"); } else { // Nodes smaller than 31 bytes aren't hashed. require(BytesUtils.toBytes32(currentNode.encoded) == currentNodeID, "Invalid internal node hash"); } // unreachable code if it's below the if statement under this unchecked { ++i; } if (currentNode.decoded.length == BRANCH_NODE_LENGTH) { if (currentKeyIndex == key.length) { // We've hit the end of the key // meaning the value should be within this branch node. break; } else { // We're not at the end of the key yet. // Figure out what the next node ID should be and continue. uint8 branchKey = uint8(key[currentKeyIndex]); RLPReader.RLPItem memory nextNode = currentNode.decoded[branchKey]; currentNodeID = _getNodeID(nextNode); currentKeyIncrement = 1; continue; } } else if (currentNode.decoded.length == LEAF_OR_EXTENSION_NODE_LENGTH) { bytes memory path = _getNodePath(currentNode); uint8 prefix = uint8(path[0]); uint8 offset = 2 - (prefix % 2); bytes memory pathRemainder = BytesUtils.slice(path, offset); bytes memory keyRemainder = BytesUtils.slice(key, currentKeyIndex); uint256 sharedNibbleLength = _getSharedNibbleLength(pathRemainder, keyRemainder); if (prefix == PREFIX_LEAF_EVEN || prefix == PREFIX_LEAF_ODD) { if (pathRemainder.length == sharedNibbleLength && keyRemainder.length == sharedNibbleLength) { // The key within this leaf matches our key exactly. // Increment the key index to reflect that we have no remainder. currentKeyIndex += sharedNibbleLength; } // We've hit a leaf node, so our next node should be NULL. currentNodeID = bytes32(RLP_NULL); break; } else if (prefix == PREFIX_EXTENSION_EVEN || prefix == PREFIX_EXTENSION_ODD) { if (sharedNibbleLength != pathRemainder.length) { // Our extension node is not identical to the remainder. // We've hit the end of this path // updates will need to modify this extension. currentNodeID = bytes32(RLP_NULL); break; } else { // Our extension shares some nibbles. // Carry on to the next node. currentNodeID = _getNodeID(currentNode.decoded[1]); currentKeyIncrement = sharedNibbleLength; continue; } } else { revert("Received a node with an unknown prefix"); } } else { revert("Received an unparseable node."); } } // If our node ID is NULL, then we're at a dead end. bool isFinalNode = currentNodeID == bytes32(RLP_NULL); return (pathLength, BytesUtils.slice(key, currentKeyIndex), isFinalNode); } /** * @notice Parses an RLP-encoded proof into something more useful. * @param _proof RLP-encoded proof to parse. * @return _parsed Proof parsed into easily accessible structs. */ function _parseProof(bytes memory _proof) private pure returns (TrieNode[] memory _parsed) { RLPReader.RLPItem[] memory nodes = RLPReader.readList(_proof); TrieNode[] memory proof = new TrieNode[](nodes.length); uint256 len = nodes.length; for (uint256 i = 0; i < len; ) { bytes memory encoded = RLPReader.readBytes(nodes[i]); proof[i] = TrieNode({encoded: encoded, decoded: RLPReader.readList(encoded)}); unchecked { ++i; } } return proof; } /** * @notice Picks out the ID for a node. Node ID is referred to as the * "hash" within the specification, but nodes < 32 bytes are not actually * hashed. * @param _node Node to pull an ID for. * @return _nodeID ID for the node, depending on the size of its contents. */ function _getNodeID(RLPReader.RLPItem memory _node) private pure returns (bytes32 _nodeID) { bytes memory nodeID; if (_node.length < 32) { // Nodes smaller than 32 bytes are RLP encoded. nodeID = RLPReader.readRawBytes(_node); } else { // Nodes 32 bytes or larger are hashed. nodeID = RLPReader.readBytes(_node); } return BytesUtils.toBytes32(nodeID); } /** * @notice Gets the path for a leaf or extension node. * @param _node Node to get a path for. * @return _path Node path, converted to an array of nibbles. */ function _getNodePath(TrieNode memory _node) private pure returns (bytes memory _path) { return BytesUtils.toNibbles(RLPReader.readBytes(_node.decoded[0])); } /** * @notice Gets the path for a node. * @param _node Node to get a value for. * @return _value Node value, as hex bytes. */ function _getNodeValue(TrieNode memory _node) private pure returns (bytes memory _value) { return RLPReader.readBytes(_node.decoded[_node.decoded.length - 1]); } /** * @notice Utility; determines the number of nibbles shared between two * nibble arrays. * @param _a First nibble array. * @param _b Second nibble array. * @return _shared Number of shared nibbles. */ function _getSharedNibbleLength(bytes memory _a, bytes memory _b) private pure returns (uint256 _shared) { uint256 i = 0; while (_a.length > i && _b.length > i && _a[i] == _b[i]) { i++; } return i; } }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity 0.8.17; /* Library Imports */ import {RLPReader} from "./RLPReader.sol"; /** * @title OVMCodec * * @dev modified from: https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/libraries/codec/Lib_OVMCodec.sol */ library OVMCodec { /*********** * Structs * ***********/ struct EVMAccount { uint256 nonce; uint256 balance; bytes32 storageRoot; bytes32 codeHash; } /** * @notice Decodes an RLP-encoded account state into a useful struct. * @param _encoded RLP-encoded account state. * @return Account state struct. */ function decodeEVMAccount(bytes memory _encoded) internal pure returns (EVMAccount memory) { RLPReader.RLPItem[] memory accountState = RLPReader.readList(_encoded); return EVMAccount({ nonce: RLPReader.readUint256(accountState[0]), balance: RLPReader.readUint256(accountState[1]), storageRoot: RLPReader.readBytes32(accountState[2]), codeHash: RLPReader.readBytes32(accountState[3]) }); } }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity 0.8.17; /** * @title PredeployAddresses * * @dev modified from: https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/libraries/constants/Lib_PredeployAddresses.sol */ library PredeployAddresses { address internal constant L2_TO_L1_MESSAGE_PASSER = 0x4200000000000000000000000000000000000000; address internal constant L1_MESSAGE_SENDER = 0x4200000000000000000000000000000000000001; address internal constant DEPLOYER_WHITELIST = 0x4200000000000000000000000000000000000002; address payable internal constant OVM_ETH = payable(0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000); address internal constant L2_CROSS_DOMAIN_MESSENGER = 0x4200000000000000000000000000000000000007; address internal constant LIB_ADDRESS_MANAGER = 0x4200000000000000000000000000000000000008; address internal constant PROXY_EOA = 0x4200000000000000000000000000000000000009; address internal constant L2_STANDARD_BRIDGE = 0x4200000000000000000000000000000000000010; address internal constant SEQUENCER_FEE_WALLET = 0x4200000000000000000000000000000000000011; address internal constant L2_STANDARD_TOKEN_FACTORY = 0x4200000000000000000000000000000000000012; address internal constant L1_BLOCK_NUMBER = 0x4200000000000000000000000000000000000013; }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity 0.8.17; /** * @title RLPReader * @dev modified from: https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/libraries/rlp/Lib_RLPReader.sol */ library RLPReader { /************* * Constants * *************/ uint256 internal constant MAX_LIST_LENGTH = 32; /********* * Enums * *********/ enum RLPItemType { DATA_ITEM, LIST_ITEM } /*********** * Structs * ***********/ struct RLPItem { uint256 length; uint256 ptr; } /********************** * Internal Functions * **********************/ /** * Converts bytes to a reference to memory position and length. * @param _in Input bytes to convert. * @return Output memory reference. */ function toRLPItem(bytes memory _in) internal pure returns (RLPItem memory) { uint256 ptr; assembly { ptr := add(_in, 32) } return RLPItem({length: _in.length, ptr: ptr}); } /** * Reads an RLP list value into a list of RLP items. * @param _in RLP list value. * @return Decoded RLP list items. */ function readList(RLPItem memory _in) internal pure returns (RLPItem[] memory) { (uint256 listOffset, , RLPItemType itemType) = _decodeLength(_in); require(itemType == RLPItemType.LIST_ITEM, "Invalid RLP list value."); // Solidity in-memory arrays can't be increased in size, but *can* be decreased in size by // writing to the length. Since we can't know the number of RLP items without looping over // the entire input, we'd have to loop twice to accurately size this array. It's easier to // simply set a reasonable maximum list length and decrease the size before we finish. RLPItem[] memory out = new RLPItem[](MAX_LIST_LENGTH); uint256 itemCount = 0; uint256 offset = listOffset; while (offset < _in.length) { require(itemCount < MAX_LIST_LENGTH, "Provided RLP list exceeds max list length."); (uint256 itemOffset, uint256 itemLength, ) = _decodeLength( RLPItem({length: _in.length - offset, ptr: _in.ptr + offset}) ); out[itemCount] = RLPItem({length: itemLength + itemOffset, ptr: _in.ptr + offset}); itemCount += 1; offset += itemOffset + itemLength; } // Decrease the array size to match the actual item count. assembly { mstore(out, itemCount) } return out; } /** * Reads an RLP list value into a list of RLP items. * @param _in RLP list value. * @return Decoded RLP list items. */ function readList(bytes memory _in) internal pure returns (RLPItem[] memory) { return readList(toRLPItem(_in)); } /** * Reads an RLP bytes value into bytes. * @param _in RLP bytes value. * @return Decoded bytes. */ function readBytes(RLPItem memory _in) internal pure returns (bytes memory) { (uint256 itemOffset, uint256 itemLength, RLPItemType itemType) = _decodeLength(_in); require(itemType == RLPItemType.DATA_ITEM, "Invalid RLP bytes value."); return _copy(_in.ptr, itemOffset, itemLength); } /** * Reads an RLP bytes value into bytes. * @param _in RLP bytes value. * @return Decoded bytes. */ function readBytes(bytes memory _in) internal pure returns (bytes memory) { return readBytes(toRLPItem(_in)); } /** * Reads an RLP string value into a string. * @param _in RLP string value. * @return Decoded string. */ function readString(RLPItem memory _in) internal pure returns (string memory) { return string(readBytes(_in)); } /** * Reads an RLP string value into a string. * @param _in RLP string value. * @return Decoded string. */ function readString(bytes memory _in) internal pure returns (string memory) { return readString(toRLPItem(_in)); } /** * Reads an RLP bytes32 value into a bytes32. * @param _in RLP bytes32 value. * @return Decoded bytes32. */ function readBytes32(RLPItem memory _in) internal pure returns (bytes32) { // instead of <= 33 require(_in.length < 33 + 1, "Invalid RLP bytes32 value."); (uint256 itemOffset, uint256 itemLength, RLPItemType itemType) = _decodeLength(_in); require(itemType == RLPItemType.DATA_ITEM, "Invalid RLP bytes32 value."); uint256 ptr = _in.ptr + itemOffset; bytes32 out; assembly { out := mload(ptr) // Shift the bytes over to match the item size. if lt(itemLength, 32) { out := div(out, exp(256, sub(32, itemLength))) } } return out; } /** * Reads an RLP bytes32 value into a bytes32. * @param _in RLP bytes32 value. * @return Decoded bytes32. */ function readBytes32(bytes memory _in) internal pure returns (bytes32) { return readBytes32(toRLPItem(_in)); } /** * Reads an RLP uint256 value into a uint256. * @param _in RLP uint256 value. * @return Decoded uint256. */ function readUint256(RLPItem memory _in) internal pure returns (uint256) { return uint256(readBytes32(_in)); } /** * Reads an RLP uint256 value into a uint256. * @param _in RLP uint256 value. * @return Decoded uint256. */ function readUint256(bytes memory _in) internal pure returns (uint256) { return readUint256(toRLPItem(_in)); } /** * Reads an RLP bool value into a bool. * @param _in RLP bool value. * @return Decoded bool. */ function readBool(RLPItem memory _in) internal pure returns (bool) { require(_in.length == 1, "Invalid RLP boolean value."); uint256 ptr = _in.ptr; uint256 out; assembly { out := byte(0, mload(ptr)) } require(out == 0 || out == 1, "Lib_RLPReader: Invalid RLP boolean value, must be 0 or 1"); return out != 0; } /** * Reads an RLP bool value into a bool. * @param _in RLP bool value. * @return Decoded bool. */ function readBool(bytes memory _in) internal pure returns (bool) { return readBool(toRLPItem(_in)); } /** * Reads an RLP address value into a address. * @param _in RLP address value. * @return Decoded address. */ function readAddress(RLPItem memory _in) internal pure returns (address) { if (_in.length == 1) { return address(0); } require(_in.length == 21, "Invalid RLP address value."); return address(uint160(readUint256(_in))); } /** * Reads an RLP address value into a address. * @param _in RLP address value. * @return Decoded address. */ function readAddress(bytes memory _in) internal pure returns (address) { return readAddress(toRLPItem(_in)); } /** * Reads the raw bytes of an RLP item. * @param _in RLP item to read. * @return Raw RLP bytes. */ function readRawBytes(RLPItem memory _in) internal pure returns (bytes memory) { return _copy(_in); } /********************* * Private Functions * *********************/ /** * Decodes the length of an RLP item. * @param _in RLP item to decode. * @return Offset of the encoded data. * @return Length of the encoded data. * @return RLP item type (LIST_ITEM or DATA_ITEM). */ function _decodeLength(RLPItem memory _in) private pure returns ( uint256, uint256, RLPItemType ) { require(_in.length > 0, "RLP item cannot be null."); uint256 ptr = _in.ptr; uint256 prefix; assembly { prefix := byte(0, mload(ptr)) } if (prefix < 0x7f + 1) { // Single byte. return (0, 1, RLPItemType.DATA_ITEM); } else if (prefix < 0xb7 + 1) { // Short string. // slither-disable-next-line variable-scope uint256 strLen = prefix - 0x80; require(_in.length > strLen, "Invalid RLP short string."); return (1, strLen, RLPItemType.DATA_ITEM); } else if (prefix < 0xbf + 1) { // Long string. uint256 lenOfStrLen = prefix - 0xb7; require(_in.length > lenOfStrLen, "Invalid RLP long string length."); uint256 strLen; assembly { // Pick out the string length. strLen := div(mload(add(ptr, 1)), exp(256, sub(32, lenOfStrLen))) } require(_in.length > lenOfStrLen + strLen, "Invalid RLP long string."); return (1 + lenOfStrLen, strLen, RLPItemType.DATA_ITEM); } else if (prefix < 0xf7 + 1) { // Short list. // slither-disable-next-line variable-scope uint256 listLen = prefix - 0xc0; require(_in.length > listLen, "Invalid RLP short list."); return (1, listLen, RLPItemType.LIST_ITEM); } else { // Long list. uint256 lenOfListLen = prefix - 0xf7; require(_in.length > lenOfListLen, "Invalid RLP long list length."); uint256 listLen; assembly { // Pick out the list length. listLen := div(mload(add(ptr, 1)), exp(256, sub(32, lenOfListLen))) } require(_in.length > lenOfListLen + listLen, "Invalid RLP long list."); return (1 + lenOfListLen, listLen, RLPItemType.LIST_ITEM); } } /** * Copies the bytes from a memory location. * @param _src Pointer to the location to read from. * @param _offset Offset to start reading from. * @param _length Number of bytes to read. * @return Copied bytes. */ function _copy( uint256 _src, uint256 _offset, uint256 _length ) private pure returns (bytes memory) { bytes memory out = new bytes(_length); if (out.length == 0) { return out; } uint256 src = _src + _offset; uint256 dest; assembly { dest := add(out, 32) } // Copy over as many complete words as we can. for (uint256 i = 0; i < _length / 32; ) { assembly { mstore(dest, mload(src)) } src += 32; dest += 32; unchecked { ++i; } } // Pick out the remaining bytes. uint256 mask; unchecked { mask = 256**(32 - (_length % 32)) - 1; } assembly { mstore(dest, or(and(mload(src), not(mask)), and(mload(dest), mask))) } return out; } /** * Copies an RLP item into bytes. * @param _in RLP item to copy. * @return Copied bytes. */ function _copy(RLPItem memory _in) private pure returns (bytes memory) { return _copy(_in.ptr, 0, _in.length); } }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity 0.8.17; /* Library Imports */ import {MerkleTrie} from "./MerkleTrie.sol"; /** * @title SecureMerkleTrie * * @dev modified from: https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/libraries/trie/Lib_SecureMerkleTrie.sol */ library SecureMerkleTrie { /********************** * Internal Functions * **********************/ /** * @notice Verifies a proof that a given key/value pair is present in the * Merkle trie. * @param _key Key of the node to search for, as a hex string. * @param _value Value of the node to search for, as a hex string. * @param _proof Merkle trie inclusion proof for the desired node. Unlike * traditional Merkle trees, this proof is executed top-down and consists * of a list of RLP-encoded nodes that make a path down to the target node. * @param _root Known root of the Merkle trie. Used to verify that the * included proof is correctly constructed. * @return _verified `true` if the k/v pair exists in the trie, `false` otherwise. */ function verifyInclusionProof( bytes memory _key, bytes memory _value, bytes memory _proof, bytes32 _root ) internal pure returns (bool _verified) { bytes memory key = _getSecureKey(_key); return MerkleTrie.verifyInclusionProof(key, _value, _proof, _root); } /** * @notice Retrieves the value associated with a given key. * @param _key Key to search for, as hex bytes. * @param _proof Merkle trie inclusion proof for the key. * @param _root Known root of the Merkle trie. * @return _exists Whether or not the key exists. * @return _value Value of the key if it exists. */ function get( bytes memory _key, bytes memory _proof, bytes32 _root ) internal pure returns (bool _exists, bytes memory _value) { bytes memory key = _getSecureKey(_key); return MerkleTrie.get(key, _proof, _root); } /********************* * Private Functions * *********************/ /** * Computes the secure counterpart to a key. * @param _key Key to get a secure key from. * @return _secureKey Secure version of the key. */ function _getSecureKey(bytes memory _key) private pure returns (bytes memory _secureKey) { return abi.encodePacked(keccak256(_key)); } }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity 0.8.17; import {IProposedOwnable} from "../../shared/interfaces/IProposedOwnable.sol"; /** * @notice This interface is what the Connext contract will send and receive messages through. * The messaging layer should conform to this interface, and should be interchangeable (i.e. * could be Nomad or a generic AMB under the hood). * * @dev This uses the nomad format to ensure nomad can be added in as it comes back online. * * Flow from transfer from polygon to optimism: * 1. User calls `xcall` with destination specified * 2. This will swap in to the bridge assets * 3. The swapped assets will get burned * 4. The Connext contract will call `dispatch` on the messaging contract to add the transfer * to the root * 5. [At some time interval] Relayers call `send` to send the current root from polygon to * mainnet. This is done on all "spoke" domains. * 6. [At some time interval] Relayers call `propagate` [better name] on mainnet, this generates a new merkle * root from all of the AMBs * - This function must be able to read root data from all AMBs and aggregate them into a single merkle * tree root * - Will send the mixed root from all chains back through the respective AMBs to all other chains * 7. AMB will call `update` to update the latest root on the messaging contract on spoke domains * 8. [At any point] Relayers can call `proveAndProcess` to prove inclusion of dispatched message, and call * process on the `Connext` contract * 9. Takes minted bridge tokens and credits the LP * * AMB requirements: * - Access `msg.sender` both from mainnet -> spoke and vice versa * - Ability to read *our root* from the AMB * * AMBs: * - PoS bridge from polygon * - arbitrum bridge * - optimism bridge * - gnosis chain * - bsc (use multichain for messaging) */ interface IConnector is IProposedOwnable { // ============ Events ============ /** * @notice Emitted whenever a message is successfully sent over an AMB * @param data The contents of the message * @param encodedData Data used to send the message; specific to connector * @param caller Who called the function (sent the message) */ event MessageSent(bytes data, bytes encodedData, address caller); /** * @notice Emitted whenever a message is successfully received over an AMB * @param data The contents of the message * @param caller Who called the function */ event MessageProcessed(bytes data, address caller); // ============ Public fns ============ function processMessage(bytes memory _data) external; function verifySender(address _expected) external returns (bool); }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity 0.8.17; interface IRootManager { /** * @notice This is called by relayers to generate + send the mixed root from mainnet via AMB to * spoke domains. * @dev This must read information for the root from the registered AMBs. */ function propagate( address[] calldata _connectors, uint256[] calldata _fees, bytes[] memory _encodedData ) external payable; /** * @notice Called by the connectors for various domains on the hub to aggregate their latest * inbound root. * @dev This must read information for the root from the registered AMBs */ function aggregate(uint32 _domain, bytes32 _outbound) external; }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity 0.8.17; // modified from: https://github.com/ethereum-optimism/optimism/blob/fcfcf6e7e69801e63904ec53815db01a8d45dcac/packages/contracts/contracts/libraries/codec/Lib_OVMCodec.sol#L34-L40 struct ChainBatchHeader { uint256 batchIndex; bytes32 batchRoot; uint256 batchSize; uint256 prevTotalElements; bytes extraData; } // modified from: https://github.com/ethereum-optimism/optimism/blob/fcfcf6e7e69801e63904ec53815db01a8d45dcac/packages/contracts/contracts/libraries/codec/Lib_OVMCodec.sol#L42-L45 struct ChainInclusionProof { uint256 index; bytes32[] siblings; } // modified from: https://github.com/ethereum-optimism/optimism/blob/fcfcf6e7e69801e63904ec53815db01a8d45dcac/packages/contracts/contracts/L1/messaging/IL1CrossDomainMessenger.sol#L18-L24 struct L2MessageInclusionProof { bytes32 stateRoot; ChainBatchHeader stateRootBatchHeader; ChainInclusionProof stateRootProof; bytes stateTrieWitness; bytes storageTrieWitness; } /** * @title IStateCommitmentChain * * @dev modified from: https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/L1/rollup/IStateCommitmentChain.sol */ interface IStateCommitmentChain { /********** * Events * **********/ event StateBatchAppended( uint256 indexed _batchIndex, bytes32 _batchRoot, uint256 _batchSize, uint256 _prevTotalElements, bytes _extraData ); event StateBatchDeleted(uint256 indexed _batchIndex, bytes32 _batchRoot); /******************** * Public Functions * ********************/ /** * Retrieves the total number of elements submitted. * @return _totalElements Total submitted elements. */ function getTotalElements() external view returns (uint256 _totalElements); /** * Retrieves the total number of batches submitted. * @return _totalBatches Total submitted batches. */ function getTotalBatches() external view returns (uint256 _totalBatches); /** * Retrieves the timestamp of the last batch submitted by the sequencer. * @return _lastSequencerTimestamp Last sequencer batch timestamp. */ function getLastSequencerTimestamp() external view returns (uint256 _lastSequencerTimestamp); /** * Appends a batch of state roots to the chain. * @param _batch Batch of state roots. * @param _shouldStartAtElement Index of the element at which this batch should start. */ function appendStateBatch(bytes32[] calldata _batch, uint256 _shouldStartAtElement) external; /** * Deletes all state roots after (and including) a given batch. * @param _batchHeader Header of the batch to start deleting from. */ function deleteStateBatch(ChainBatchHeader memory _batchHeader) external; /** * Verifies a batch inclusion proof. * @param _element Hash of the element to verify a proof for. * @param _batchHeader Header of the batch in which the element was included. * @param _proof Merkle inclusion proof for the element. */ function verifyStateCommitment( bytes32 _element, ChainBatchHeader memory _batchHeader, ChainInclusionProof memory _proof ) external view returns (bool _verified); /** * Checks whether a given batch is still inside its fraud proof window. * @param _batchHeader Header of the batch to check. * @return _inside Whether or not the batch is inside the fraud proof window. */ function insideFraudProofWindow(ChainBatchHeader memory _batchHeader) external view returns (bool _inside); }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity 0.8.17; /** * @dev The optimism bridge shares both of these functions, but it is important * to note that when going from L2 -> L1, the message cannot be processed by the * AMB until the challenge period elapses. * * HOWEVER, before the challenge elapses, you can read the state of the L2 as it is * placed on mainnet. By processing data from the L2 state, we are able to "circumvent" * this delay to a reasonable degree. * * This means that for messages going L1 -> L2, you can call "processMessage" and expect * the call to be executed to pass up the aggregate root. When going from L2 -> L1, you * must read the root from the L2 state * * L2 messenger: https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/L2/messaging/L2CrossDomainMessenger.sol * L1 messenger: https://github.com/ethereum-optimism/optimism/blob/develop/packages/contracts/contracts/L1/messaging/L1CrossDomainMessenger.sol */ interface OptimismAmb { function sendMessage( address _target, bytes memory _message, uint32 _gasLimit ) external; function xDomainMessageSender() external view returns (address); }
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.17; import {IProposedOwnable} from "./interfaces/IProposedOwnable.sol"; /** * @title ProposedOwnable * @notice Contract module which provides a basic access control mechanism, * where there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed via a two step process: * 1. Call `proposeOwner` * 2. Wait out the delay period * 3. Call `acceptOwner` * * @dev This module is used through inheritance. It will make available the * modifier `onlyOwner`, which can be applied to your functions to restrict * their use to the owner. * * @dev The majority of this code was taken from the openzeppelin Ownable * contract * */ abstract contract ProposedOwnable is IProposedOwnable { // ========== Custom Errors =========== error ProposedOwnable__onlyOwner_notOwner(); error ProposedOwnable__onlyProposed_notProposedOwner(); error ProposedOwnable__ownershipDelayElapsed_delayNotElapsed(); error ProposedOwnable__proposeNewOwner_invalidProposal(); error ProposedOwnable__proposeNewOwner_noOwnershipChange(); error ProposedOwnable__renounceOwnership_noProposal(); error ProposedOwnable__renounceOwnership_invalidProposal(); // ============ Properties ============ address private _owner; address private _proposed; uint256 private _proposedOwnershipTimestamp; uint256 private constant _delay = 7 days; // ======== Getters ========= /** * @notice Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @notice Returns the address of the proposed owner. */ function proposed() public view virtual returns (address) { return _proposed; } /** * @notice Returns the address of the proposed owner. */ function proposedTimestamp() public view virtual returns (uint256) { return _proposedOwnershipTimestamp; } /** * @notice Returns the delay period before a new owner can be accepted. */ function delay() public view virtual returns (uint256) { return _delay; } /** * @notice Throws if called by any account other than the owner. */ modifier onlyOwner() { if (_owner != msg.sender) revert ProposedOwnable__onlyOwner_notOwner(); _; } /** * @notice Throws if called by any account other than the proposed owner. */ modifier onlyProposed() { if (_proposed != msg.sender) revert ProposedOwnable__onlyProposed_notProposedOwner(); _; } /** * @notice Throws if the ownership delay has not elapsed */ modifier ownershipDelayElapsed() { // Ensure delay has elapsed if ((block.timestamp - _proposedOwnershipTimestamp) <= _delay) revert ProposedOwnable__ownershipDelayElapsed_delayNotElapsed(); _; } /** * @notice Indicates if the ownership has been renounced() by * checking if current owner is address(0) */ function renounced() public view returns (bool) { return _owner == address(0); } // ======== External ========= /** * @notice Sets the timestamp for an owner to be proposed, and sets the * newly proposed owner as step 1 in a 2-step process */ function proposeNewOwner(address newlyProposed) public virtual onlyOwner { // Contract as source of truth if (_proposed == newlyProposed && _proposedOwnershipTimestamp != 0) revert ProposedOwnable__proposeNewOwner_invalidProposal(); // Sanity check: reasonable proposal if (_owner == newlyProposed) revert ProposedOwnable__proposeNewOwner_noOwnershipChange(); _setProposed(newlyProposed); } /** * @notice Renounces ownership of the contract after a delay */ function renounceOwnership() public virtual onlyOwner ownershipDelayElapsed { // Ensure there has been a proposal cycle started if (_proposedOwnershipTimestamp == 0) revert ProposedOwnable__renounceOwnership_noProposal(); // Require proposed is set to 0 if (_proposed != address(0)) revert ProposedOwnable__renounceOwnership_invalidProposal(); // Emit event, set new owner, reset timestamp _setOwner(address(0)); } /** * @notice Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function acceptProposedOwner() public virtual onlyProposed ownershipDelayElapsed { // NOTE: no need to check if _owner == _proposed, because the _proposed // is 0-d out and this check is implicitly enforced by modifier // NOTE: no need to check if _proposedOwnershipTimestamp > 0 because // the only time this would happen is if the _proposed was never // set (will fail from modifier) or if the owner == _proposed (checked // above) // Emit event, set new owner, reset timestamp _setOwner(_proposed); } // ======== Internal ========= function _setOwner(address newOwner) internal { emit OwnershipTransferred(_owner, newOwner); _owner = newOwner; delete _proposedOwnershipTimestamp; delete _proposed; } function _setProposed(address newlyProposed) private { _proposedOwnershipTimestamp = block.timestamp; _proposed = newlyProposed; emit OwnershipProposed(newlyProposed); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; /** * @title IProposedOwnable * @notice Defines a minimal interface for ownership with a two step proposal and acceptance * process */ interface IProposedOwnable { /** * @dev This emits when change in ownership of a contract is proposed. */ event OwnershipProposed(address indexed proposedOwner); /** * @dev This emits when ownership of a contract changes. */ event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @notice Get the address of the owner * @return owner_ The address of the owner. */ function owner() external view returns (address owner_); /** * @notice Get the address of the proposed owner * @return proposed_ The address of the proposed. */ function proposed() external view returns (address proposed_); /** * @notice Set the address of the proposed owner of the contract * @param newlyProposed The proposed new owner of the contract */ function proposeNewOwner(address newlyProposed) external; /** * @notice Set the address of the proposed owner of the contract */ function acceptProposedOwner() external; }
// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity 0.8.17; library TypedMemView { // Why does this exist? // the solidity `bytes memory` type has a few weaknesses. // 1. You can't index ranges effectively // 2. You can't slice without copying // 3. The underlying data may represent any type // 4. Solidity never deallocates memory, and memory costs grow // superlinearly // By using a memory view instead of a `bytes memory` we get the following // advantages: // 1. Slices are done on the stack, by manipulating the pointer // 2. We can index arbitrary ranges and quickly convert them to stack types // 3. We can insert type info into the pointer, and typecheck at runtime // This makes `TypedMemView` a useful tool for efficient zero-copy // algorithms. // Why bytes29? // We want to avoid confusion between views, digests, and other common // types so we chose a large and uncommonly used odd number of bytes // // Note that while bytes are left-aligned in a word, integers and addresses // are right-aligned. This means when working in assembly we have to // account for the 3 unused bytes on the righthand side // // First 5 bytes are a type flag. // - ff_ffff_fffe is reserved for unknown type. // - ff_ffff_ffff is reserved for invalid types/errors. // next 12 are memory address // next 12 are len // bottom 3 bytes are empty // Assumptions: // - non-modification of memory. // - No Solidity updates // - - wrt free mem point // - - wrt bytes representation in memory // - - wrt memory addressing in general // Usage: // - create type constants // - use `assertType` for runtime type assertions // - - unfortunately we can't do this at compile time yet :( // - recommended: implement modifiers that perform type checking // - - e.g. // - - `uint40 constant MY_TYPE = 3;` // - - ` modifer onlyMyType(bytes29 myView) { myView.assertType(MY_TYPE); }` // - instantiate a typed view from a bytearray using `ref` // - use `index` to inspect the contents of the view // - use `slice` to create smaller views into the same memory // - - `slice` can increase the offset // - - `slice can decrease the length` // - - must specify the output type of `slice` // - - `slice` will return a null view if you try to overrun // - - make sure to explicitly check for this with `notNull` or `assertType` // - use `equal` for typed comparisons. // The null view bytes29 public constant NULL = hex"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; uint256 constant LOW_12_MASK = 0xffffffffffffffffffffffff; uint256 constant TWENTY_SEVEN_BYTES = 8 * 27; uint256 private constant _27_BYTES_IN_BITS = 8 * 27; // <--- also used this named constant where ever 216 is used. uint256 private constant LOW_27_BYTES_MASK = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffff; // (1 << _27_BYTES_IN_BITS) - 1; // ========== Custom Errors =========== error TypedMemView__assertType_typeAssertionFailed(uint256 actual, uint256 expected); error TypedMemView__index_overrun(uint256 loc, uint256 len, uint256 index, uint256 slice); error TypedMemView__index_indexMoreThan32Bytes(); error TypedMemView__unsafeCopyTo_nullPointer(); error TypedMemView__unsafeCopyTo_invalidPointer(); error TypedMemView__unsafeCopyTo_identityOOG(); error TypedMemView__assertValid_validityAssertionFailed(); /** * @notice Changes the endianness of a uint256. * @dev https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel * @param _b The unsigned integer to reverse * @return v - The reversed value */ function reverseUint256(uint256 _b) internal pure returns (uint256 v) { v = _b; // swap bytes v = ((v >> 8) & 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) | ((v & 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) << 8); // swap 2-byte long pairs v = ((v >> 16) & 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) | ((v & 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) << 16); // swap 4-byte long pairs v = ((v >> 32) & 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) | ((v & 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) << 32); // swap 8-byte long pairs v = ((v >> 64) & 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) | ((v & 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) << 64); // swap 16-byte long pairs v = (v >> 128) | (v << 128); } /** * @notice Create a mask with the highest `_len` bits set. * @param _len The length * @return mask - The mask */ function leftMask(uint8 _len) private pure returns (uint256 mask) { // ugly. redo without assembly? assembly { // solhint-disable-previous-line no-inline-assembly mask := sar(sub(_len, 1), 0x8000000000000000000000000000000000000000000000000000000000000000) } } /** * @notice Return the null view. * @return bytes29 - The null view */ function nullView() internal pure returns (bytes29) { return NULL; } /** * @notice Check if the view is null. * @return bool - True if the view is null */ function isNull(bytes29 memView) internal pure returns (bool) { return memView == NULL; } /** * @notice Check if the view is not null. * @return bool - True if the view is not null */ function notNull(bytes29 memView) internal pure returns (bool) { return !isNull(memView); } /** * @notice Check if the view is of a invalid type and points to a valid location * in memory. * @dev We perform this check by examining solidity's unallocated memory * pointer and ensuring that the view's upper bound is less than that. * @param memView The view * @return ret - True if the view is invalid */ function isNotValid(bytes29 memView) internal pure returns (bool ret) { if (typeOf(memView) == 0xffffffffff) { return true; } uint256 _end = end(memView); assembly { // solhint-disable-previous-line no-inline-assembly ret := gt(_end, mload(0x40)) } } /** * @notice Require that a typed memory view be valid. * @dev Returns the view for easy chaining. * @param memView The view * @return bytes29 - The validated view */ function assertValid(bytes29 memView) internal pure returns (bytes29) { if (isNotValid(memView)) revert TypedMemView__assertValid_validityAssertionFailed(); return memView; } /** * @notice Return true if the memview is of the expected type. Otherwise false. * @param memView The view * @param _expected The expected type * @return bool - True if the memview is of the expected type */ function isType(bytes29 memView, uint40 _expected) internal pure returns (bool) { return typeOf(memView) == _expected; } /** * @notice Require that a typed memory view has a specific type. * @dev Returns the view for easy chaining. * @param memView The view * @param _expected The expected type * @return bytes29 - The view with validated type */ function assertType(bytes29 memView, uint40 _expected) internal pure returns (bytes29) { if (!isType(memView, _expected)) { revert TypedMemView__assertType_typeAssertionFailed(uint256(typeOf(memView)), uint256(_expected)); } return memView; } /** * @notice Return an identical view with a different type. * @param memView The view * @param _newType The new type * @return newView - The new view with the specified type */ function castTo(bytes29 memView, uint40 _newType) internal pure returns (bytes29 newView) { // then | in the new type assembly { // solhint-disable-previous-line no-inline-assembly // shift off the top 5 bytes newView := or(and(memView, LOW_27_BYTES_MASK), shl(_27_BYTES_IN_BITS, _newType)) } } /** * @notice Unsafe raw pointer construction. This should generally not be called * directly. Prefer `ref` wherever possible. * @dev Unsafe raw pointer construction. This should generally not be called * directly. Prefer `ref` wherever possible. * @param _type The type * @param _loc The memory address * @param _len The length * @return newView - The new view with the specified type, location and length */ function unsafeBuildUnchecked( uint256 _type, uint256 _loc, uint256 _len ) private pure returns (bytes29 newView) { uint256 _uint96Bits = 96; uint256 _emptyBits = 24; // Cast params to ensure input is of correct length uint96 len_ = uint96(_len); uint96 loc_ = uint96(_loc); require(len_ == _len && loc_ == _loc, "!truncated"); assembly { // solium-disable-previous-line security/no-inline-assembly newView := shl(_uint96Bits, _type) // insert type newView := shl(_uint96Bits, or(newView, loc_)) // insert loc newView := shl(_emptyBits, or(newView, len_)) // empty bottom 3 bytes } } /** * @notice Instantiate a new memory view. This should generally not be called * directly. Prefer `ref` wherever possible. * @dev Instantiate a new memory view. This should generally not be called * directly. Prefer `ref` wherever possible. * @param _type The type * @param _loc The memory address * @param _len The length * @return newView - The new view with the specified type, location and length */ function build( uint256 _type, uint256 _loc, uint256 _len ) internal pure returns (bytes29 newView) { uint256 _end = _loc + _len; assembly { // solhint-disable-previous-line no-inline-assembly if gt(_end, mload(0x40)) { _end := 0 } } if (_end == 0) { return NULL; } newView = unsafeBuildUnchecked(_type, _loc, _len); } /** * @notice Instantiate a memory view from a byte array. * @dev Note that due to Solidity memory representation, it is not possible to * implement a deref, as the `bytes` type stores its len in memory. * @param arr The byte array * @param newType The type * @return bytes29 - The memory view */ function ref(bytes memory arr, uint40 newType) internal pure returns (bytes29) { uint256 _len = arr.length; uint256 _loc; assembly { // solhint-disable-previous-line no-inline-assembly _loc := add(arr, 0x20) // our view is of the data, not the struct } return build(newType, _loc, _len); } /** * @notice Return the associated type information. * @param memView The memory view * @return _type - The type associated with the view */ function typeOf(bytes29 memView) internal pure returns (uint40 _type) { assembly { // solhint-disable-previous-line no-inline-assembly // 216 == 256 - 40 _type := shr(_27_BYTES_IN_BITS, memView) // shift out lower 24 bytes } } /** * @notice Return the memory address of the underlying bytes. * @param memView The view * @return _loc - The memory address */ function loc(bytes29 memView) internal pure returns (uint96 _loc) { uint256 _mask = LOW_12_MASK; // assembly can't use globals assembly { // solhint-disable-previous-line no-inline-assembly // 120 bits = 12 bytes (the encoded loc) + 3 bytes (empty low space) _loc := and(shr(120, memView), _mask) } } /** * @notice The number of memory words this memory view occupies, rounded up. * @param memView The view * @return uint256 - The number of memory words */ function words(bytes29 memView) internal pure returns (uint256) { return (uint256(len(memView)) + 31) / 32; } /** * @notice The in-memory footprint of a fresh copy of the view. * @param memView The view * @return uint256 - The in-memory footprint of a fresh copy of the view. */ function footprint(bytes29 memView) internal pure returns (uint256) { return words(memView) * 32; } /** * @notice The number of bytes of the view. * @param memView The view * @return _len - The length of the view */ function len(bytes29 memView) internal pure returns (uint96 _len) { uint256 _mask = LOW_12_MASK; // assembly can't use globals assembly { // solhint-disable-previous-line no-inline-assembly _len := and(shr(24, memView), _mask) } } /** * @notice Returns the endpoint of `memView`. * @param memView The view * @return uint256 - The endpoint of `memView` */ function end(bytes29 memView) internal pure returns (uint256) { unchecked { return loc(memView) + len(memView); } } /** * @notice Safe slicing without memory modification. * @param memView The view * @param _index The start index * @param _len The length * @param newType The new type * @return bytes29 - The new view */ function slice( bytes29 memView, uint256 _index, uint256 _len, uint40 newType ) internal pure returns (bytes29) { uint256 _loc = loc(memView); // Ensure it doesn't overrun the view if (_loc + _index + _len > end(memView)) { return NULL; } _loc = _loc + _index; return build(newType, _loc, _len); } /** * @notice Shortcut to `slice`. Gets a view representing the first `_len` bytes. * @param memView The view * @param _len The length * @param newType The new type * @return bytes29 - The new view */ function prefix( bytes29 memView, uint256 _len, uint40 newType ) internal pure returns (bytes29) { return slice(memView, 0, _len, newType); } /** * @notice Shortcut to `slice`. Gets a view representing the last `_len` byte. * @param memView The view * @param _len The length * @param newType The new type * @return bytes29 - The new view */ function postfix( bytes29 memView, uint256 _len, uint40 newType ) internal pure returns (bytes29) { return slice(memView, uint256(len(memView)) - _len, _len, newType); } /** * @notice Load up to 32 bytes from the view onto the stack. * @dev Returns a bytes32 with only the `_bytes` highest bytes set. * This can be immediately cast to a smaller fixed-length byte array. * To automatically cast to an integer, use `indexUint`. * @param memView The view * @param _index The index * @param _bytes The bytes * @return result - The 32 byte result */ function index( bytes29 memView, uint256 _index, uint8 _bytes ) internal pure returns (bytes32 result) { if (_bytes == 0) { return bytes32(0); } if (_index + _bytes > len(memView)) { // "TypedMemView/index - Overran the view. Slice is at {loc} with length {len}. Attempted to index at offset {index} with length {slice}, revert TypedMemView__index_overrun(loc(memView), len(memView), _index, uint256(_bytes)); } if (_bytes > 32) revert TypedMemView__index_indexMoreThan32Bytes(); uint8 bitLength; unchecked { bitLength = _bytes * 8; } uint256 _loc = loc(memView); uint256 _mask = leftMask(bitLength); assembly { // solhint-disable-previous-line no-inline-assembly result := and(mload(add(_loc, _index)), _mask) } } /** * @notice Parse an unsigned integer from the view at `_index`. * @dev Requires that the view have >= `_bytes` bytes following that index. * @param memView The view * @param _index The index * @param _bytes The bytes * @return result - The unsigned integer */ function indexUint( bytes29 memView, uint256 _index, uint8 _bytes ) internal pure returns (uint256 result) { return uint256(index(memView, _index, _bytes)) >> ((32 - _bytes) * 8); } /** * @notice Parse an unsigned integer from LE bytes. * @param memView The view * @param _index The index * @param _bytes The bytes * @return result - The unsigned integer */ function indexLEUint( bytes29 memView, uint256 _index, uint8 _bytes ) internal pure returns (uint256 result) { return reverseUint256(uint256(index(memView, _index, _bytes))); } /** * @notice Parse an address from the view at `_index`. Requires that the view have >= 20 bytes * following that index. * @param memView The view * @param _index The index * @return address - The address */ function indexAddress(bytes29 memView, uint256 _index) internal pure returns (address) { return address(uint160(indexUint(memView, _index, 20))); } /** * @notice Return the keccak256 hash of the underlying memory * @param memView The view * @return digest - The keccak256 hash of the underlying memory */ function keccak(bytes29 memView) internal pure returns (bytes32 digest) { uint256 _loc = loc(memView); uint256 _len = len(memView); assembly { // solhint-disable-previous-line no-inline-assembly digest := keccak256(_loc, _len) } } /** * @notice Return true if the underlying memory is equal. Else false. * @param left The first view * @param right The second view * @return bool - True if the underlying memory is equal */ function untypedEqual(bytes29 left, bytes29 right) internal pure returns (bool) { return (loc(left) == loc(right) && len(left) == len(right)) || keccak(left) == keccak(right); } /** * @notice Return false if the underlying memory is equal. Else true. * @param left The first view * @param right The second view * @return bool - False if the underlying memory is equal */ function untypedNotEqual(bytes29 left, bytes29 right) internal pure returns (bool) { return !untypedEqual(left, right); } /** * @notice Compares type equality. * @dev Shortcuts if the pointers are identical, otherwise compares type and digest. * @param left The first view * @param right The second view * @return bool - True if the types are the same */ function equal(bytes29 left, bytes29 right) internal pure returns (bool) { return left == right || (typeOf(left) == typeOf(right) && keccak(left) == keccak(right)); } /** * @notice Compares type inequality. * @dev Shortcuts if the pointers are identical, otherwise compares type and digest. * @param left The first view * @param right The second view * @return bool - True if the types are not the same */ function notEqual(bytes29 left, bytes29 right) internal pure returns (bool) { return !equal(left, right); } /** * @notice Copy the view to a location, return an unsafe memory reference * @dev Super Dangerous direct memory access. * * This reference can be overwritten if anything else modifies memory (!!!). * As such it MUST be consumed IMMEDIATELY. * This function is private to prevent unsafe usage by callers. * @param memView The view * @param _newLoc The new location * @return written - the unsafe memory reference */ function unsafeCopyTo(bytes29 memView, uint256 _newLoc) private view returns (bytes29 written) { if (isNull(memView)) revert TypedMemView__unsafeCopyTo_nullPointer(); if (isNotValid(memView)) revert TypedMemView__unsafeCopyTo_invalidPointer(); uint256 _len = len(memView); uint256 _oldLoc = loc(memView); uint256 ptr; bool res; assembly { // solhint-disable-previous-line no-inline-assembly ptr := mload(0x40) // revert if we're writing in occupied memory if gt(ptr, _newLoc) { revert(0x60, 0x20) // empty revert message } // use the identity precompile to copy // guaranteed not to fail, so pop the success res := staticcall(gas(), 4, _oldLoc, _len, _newLoc, _len) } if (!res) revert TypedMemView__unsafeCopyTo_identityOOG(); written = unsafeBuildUnchecked(typeOf(memView), _newLoc, _len); } /** * @notice Copies the referenced memory to a new loc in memory, returning a `bytes` pointing to * the new memory * @dev Shortcuts if the pointers are identical, otherwise compares type and digest. * @param memView The view * @return ret - The view pointing to the new memory */ function clone(bytes29 memView) internal view returns (bytes memory ret) { uint256 ptr; uint256 _len = len(memView); assembly { // solhint-disable-previous-line no-inline-assembly ptr := mload(0x40) // load unused memory pointer ret := ptr } unchecked { unsafeCopyTo(memView, ptr + 0x20); } assembly { // solhint-disable-previous-line no-inline-assembly mstore(0x40, add(add(ptr, _len), 0x20)) // write new unused pointer mstore(ptr, _len) // write len of new array (in bytes) } } /** * @notice Join the views in memory, return an unsafe reference to the memory. * @dev Super Dangerous direct memory access. * * This reference can be overwritten if anything else modifies memory (!!!). * As such it MUST be consumed IMMEDIATELY. * This function is private to prevent unsafe usage by callers. * @param memViews The views * @return unsafeView - The conjoined view pointing to the new memory */ function unsafeJoin(bytes29[] memory memViews, uint256 _location) private view returns (bytes29 unsafeView) { assembly { // solhint-disable-previous-line no-inline-assembly let ptr := mload(0x40) // revert if we're writing in occupied memory if gt(ptr, _location) { revert(0x60, 0x20) // empty revert message } } uint256 _offset = 0; uint256 _len = memViews.length; for (uint256 i = 0; i < _len; ) { bytes29 memView = memViews[i]; unchecked { unsafeCopyTo(memView, _location + _offset); _offset += len(memView); ++i; } } unsafeView = unsafeBuildUnchecked(0, _location, _offset); } /** * @notice Produce the keccak256 digest of the concatenated contents of multiple views. * @param memViews The views * @return bytes32 - The keccak256 digest */ function joinKeccak(bytes29[] memory memViews) internal view returns (bytes32) { uint256 ptr; assembly { // solhint-disable-previous-line no-inline-assembly ptr := mload(0x40) // load unused memory pointer } return keccak(unsafeJoin(memViews, ptr)); } /** * @notice copies all views, joins them into a new bytearray. * @param memViews The views * @return ret - The new byte array */ function join(bytes29[] memory memViews) internal view returns (bytes memory ret) { uint256 ptr; assembly { // solhint-disable-previous-line no-inline-assembly ptr := mload(0x40) // load unused memory pointer } bytes29 _newView; unchecked { _newView = unsafeJoin(memViews, ptr + 0x20); } uint256 _written = len(_newView); uint256 _footprint = footprint(_newView); assembly { // solhint-disable-previous-line no-inline-assembly // store the legnth mstore(ptr, _written) // new pointer is old + 0x20 + the footprint of the body mstore(0x40, add(add(ptr, _footprint), 0x20)) ret := ptr } } }
{ "evmVersion": "london", "libraries": {}, "metadata": { "bytecodeHash": "ipfs", "useLiteralContent": true }, "optimizer": { "enabled": true, "runs": 200 }, "remappings": [], "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"uint32","name":"_domain","type":"uint32"},{"internalType":"uint32","name":"_mirrorDomain","type":"uint32"},{"internalType":"address","name":"_amb","type":"address"},{"internalType":"address","name":"_rootManager","type":"address"},{"internalType":"address","name":"_mirrorConnector","type":"address"},{"internalType":"address","name":"_stateCommitmentChain","type":"address"},{"internalType":"uint256","name":"_gasCap","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"Connector__processMessage_notUsed","type":"error"},{"inputs":[],"name":"ProposedOwnable__onlyOwner_notOwner","type":"error"},{"inputs":[],"name":"ProposedOwnable__onlyProposed_notProposedOwner","type":"error"},{"inputs":[],"name":"ProposedOwnable__ownershipDelayElapsed_delayNotElapsed","type":"error"},{"inputs":[],"name":"ProposedOwnable__proposeNewOwner_invalidProposal","type":"error"},{"inputs":[],"name":"ProposedOwnable__proposeNewOwner_noOwnershipChange","type":"error"},{"inputs":[],"name":"ProposedOwnable__renounceOwnership_invalidProposal","type":"error"},{"inputs":[],"name":"ProposedOwnable__renounceOwnership_noProposal","type":"error"},{"inputs":[],"name":"TypedMemView__index_indexMoreThan32Bytes","type":"error"},{"inputs":[{"internalType":"uint256","name":"loc","type":"uint256"},{"internalType":"uint256","name":"len","type":"uint256"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"uint256","name":"slice","type":"uint256"}],"name":"TypedMemView__index_overrun","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_previous","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_updated","type":"uint256"}],"name":"GasCapUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"},{"indexed":false,"internalType":"address","name":"caller","type":"address"}],"name":"MessageProcessed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"encodedData","type":"bytes"},{"indexed":false,"internalType":"address","name":"caller","type":"address"}],"name":"MessageSent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previous","type":"address"},{"indexed":false,"internalType":"address","name":"current","type":"address"}],"name":"MirrorConnectorUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint32","name":"domain","type":"uint32"},{"indexed":true,"internalType":"uint32","name":"mirrorDomain","type":"uint32"},{"indexed":false,"internalType":"address","name":"amb","type":"address"},{"indexed":false,"internalType":"address","name":"rootManager","type":"address"},{"indexed":false,"internalType":"address","name":"mirrorConnector","type":"address"}],"name":"NewConnector","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"proposedOwner","type":"address"}],"name":"OwnershipProposed","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":[],"name":"AMB","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIRROR_DOMAIN","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ROOT_MANAGER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptProposedOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"delay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mirrorConnector","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"processMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_target","type":"address"},{"internalType":"address","name":"_sender","type":"address"},{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"uint256","name":"_messageNonce","type":"uint256"},{"components":[{"internalType":"bytes32","name":"stateRoot","type":"bytes32"},{"components":[{"internalType":"uint256","name":"batchIndex","type":"uint256"},{"internalType":"bytes32","name":"batchRoot","type":"bytes32"},{"internalType":"uint256","name":"batchSize","type":"uint256"},{"internalType":"uint256","name":"prevTotalElements","type":"uint256"},{"internalType":"bytes","name":"extraData","type":"bytes"}],"internalType":"struct ChainBatchHeader","name":"stateRootBatchHeader","type":"tuple"},{"components":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"bytes32[]","name":"siblings","type":"bytes32[]"}],"internalType":"struct ChainInclusionProof","name":"stateRootProof","type":"tuple"},{"internalType":"bytes","name":"stateTrieWitness","type":"bytes"},{"internalType":"bytes","name":"storageTrieWitness","type":"bytes"}],"internalType":"struct L2MessageInclusionProof","name":"_proof","type":"tuple"}],"name":"processMessageFromRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"processed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newlyProposed","type":"address"}],"name":"proposeNewOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"proposed","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proposedTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounced","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_data","type":"bytes"},{"internalType":"bytes","name":"_encodedData","type":"bytes"}],"name":"sendMessage","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_gasCap","type":"uint256"}],"name":"setGasCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_mirrorConnector","type":"address"}],"name":"setMirrorConnector","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stateCommitmentChain","outputs":[{"internalType":"contract IStateCommitmentChain","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_expected","type":"address"}],"name":"verifySender","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Deployed Bytecode
0x60806040526004361061012e5760003560e01c8063715018a6116100ab578063c5b350df1161006f578063c5b350df14610399578063cc394283146103ae578063d1851c92146103ce578063d232c220146103ec578063d69f9d611461040b578063db1b76591461043f57600080fd5b8063715018a6146102e65780637850b020146102fb5780638da5cb5b1461031b578063b1f8100d14610339578063c1f0808a1461035957600080fd5b806352a9674b116100f257806352a9674b146102285780635bd11efc1461025c5780635f61e3ec1461027c5780636a42b8f8146102b05780636e2edb4e146102c657600080fd5b80630f329ef81461013a578063141684161461018b5780633cf52ffb146101d457806348e6fa23146101f35780634ff746f61461020857600080fd5b3661013557005b600080fd5b34801561014657600080fd5b5061016e7f000000000000000000000000be5dab4a2e9cd0f27300db4ab94bee3a233aeb1981565b6040516001600160a01b0390911681526020015b60405180910390f35b34801561019757600080fd5b506101bf7f000000000000000000000000000000000000000000000000000000006f70746981565b60405163ffffffff9091168152602001610182565b3480156101e057600080fd5b506002545b604051908152602001610182565b610206610201366004612687565b61045f565b005b34801561021457600080fd5b506102066102233660046126eb565b610514565b34801561023457600080fd5b506101bf7f000000000000000000000000000000000000000000000000000000000065746881565b34801561026857600080fd5b5061020661027736600461273d565b6105ba565b34801561028857600080fd5b5061016e7f000000000000000000000000d5d61e9dfb6680cba8353988ba0337802811c2e181565b3480156102bc57600080fd5b5062093a806101e5565b3480156102d257600080fd5b506102066102e13660046128a3565b6105f1565b3480156102f257600080fd5b5061020661084e565b34801561030757600080fd5b506102066103163660046129dc565b610902565b34801561032757600080fd5b506000546001600160a01b031661016e565b34801561034557600080fd5b5061020661035436600461273d565b610936565b34801561036557600080fd5b506103896103743660046129dc565b60056020526000908152604090205460ff1681565b6040519015158152602001610182565b3480156103a557600080fd5b506102066109d4565b3480156103ba57600080fd5b5060035461016e906001600160a01b031681565b3480156103da57600080fd5b506001546001600160a01b031661016e565b3480156103f857600080fd5b506000546001600160a01b031615610389565b34801561041757600080fd5b5061016e7f00000000000000000000000025ace71c97b33cc4729cf772ae268934f7ab5fa181565b34801561044b57600080fd5b5061038961045a36600461273d565b610a44565b336001600160a01b037f000000000000000000000000d5d61e9dfb6680cba8353988ba0337802811c2e116146104cb5760405162461bcd60e51b815260206004820152600c60248201526b10b937b7ba26b0b730b3b2b960a11b60448201526064015b60405180910390fd5b6104d58282610a55565b7fdcaa37a042a0087de79018c629bbd29cee82ca80bd9be394e1696bf9e935507782823360405161050893929190612a45565b60405180910390a15050565b336001600160a01b037f00000000000000000000000025ace71c97b33cc4729cf772ae268934f7ab5fa116146105755760405162461bcd60e51b81526004016104c29060208082526004908201526310a0a6a160e11b604082015260600190565b61057e81610b6c565b7fb3abc57bfeebd2cac918901db582f71972a8e628bccf19f5ae3e3482b98a5ced81336040516105af929190612a83565b60405180910390a150565b6000546001600160a01b031633146105e5576040516311a8a1bb60e31b815260040160405180910390fd5b6105ee81610b85565b50565b6003546001600160a01b038581169116146106415760405162461bcd60e51b815260206004820152601060248201526f10b6b4b93937b921b7b73732b1ba37b960811b60448201526064016104c2565b6001600160a01b03851630146106815760405162461bcd60e51b8152602060048201526005602482015264217468697360d81b60448201526064016104c2565b600061068f86868686610bee565b905061069b8183610c3b565b6106d05760405162461bcd60e51b815260206004820152600660248201526510b83937b7b360d11b60448201526064016104c2565b60006106dc8582610c5e565b905060006107136106fb6020601885901c6001600160601b0316612ac3565b62ffffff198416906001600160601b03166020610c82565b60008181526005602052604090205490915060ff166108445760008181526005602052604090819020805460ff191660011790555163473ec9fd60e11b81527f000000000000000000000000000000000000000000000000000000006f70746963ffffffff166004820152602481018290526001600160a01b037f000000000000000000000000d5d61e9dfb6680cba8353988ba0337802811c2e11690638e7d93fa90604401600060405180830381600087803b1580156107d357600080fd5b505af11580156107e7573d6000803e3d6000fd5b505050507fb3abc57bfeebd2cac918901db582f71972a8e628bccf19f5ae3e3482b98a5ced8160405160200161081f91815260200190565b60408051601f198184030181529082905261083b913390612a83565b60405180910390a15b5050505050505050565b6000546001600160a01b03163314610879576040516311a8a1bb60e31b815260040160405180910390fd5b62093a806002544261088b9190612aea565b116108a9576040516324e0285f60e21b815260040160405180910390fd5b6002546000036108cc57604051630e4b303f60e21b815260040160405180910390fd5b6001546001600160a01b0316156108f6576040516323295ef960e01b815260040160405180910390fd5b6109006000610d8d565b565b6000546001600160a01b0316331461092d576040516311a8a1bb60e31b815260040160405180910390fd5b6105ee81610df2565b6000546001600160a01b03163314610961576040516311a8a1bb60e31b815260040160405180910390fd5b6001546001600160a01b03828116911614801561097f575060025415155b1561099d576040516311bc066560e11b815260040160405180910390fd5b6000546001600160a01b038083169116036109cb57604051634a2fb73f60e11b815260040160405180910390fd5b6105ee81610e33565b6001546001600160a01b031633146109ff576040516311a7f27160e11b815260040160405180910390fd5b62093a8060025442610a119190612aea565b11610a2f576040516324e0285f60e21b815260040160405180910390fd5b600154610900906001600160a01b0316610d8d565b6000610a4f82610e81565b92915050565b8151602014610a905760405162461bcd60e51b8152602060048201526007602482015266042d8cadccee8d60cb1b60448201526064016104c2565b6000634ff746f660e01b83604051602401610aab9190612afd565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252600354600480549351633dbb202b60e01b81529294506001600160a01b037f00000000000000000000000025ace71c97b33cc4729cf772ae268934f7ab5fa1811694633dbb202b94610b359490921692879201612b10565b600060405180830381600087803b158015610b4f57600080fd5b505af1158015610b63573d6000803e3d6000fd5b50505050505050565b6040516316c2fdb560e21b815260040160405180910390fd5b600354604080516001600160a01b03928316815291831660208301527fc77bec288fc88f168427f2f7da682eadb26cac89d8d591af6e443da98dff2bbc910160405180910390a1600380546001600160a01b0319166001600160a01b0392909216919091179055565b606084848484604051602401610c079493929190612b4a565b60408051601f198184030181529190526020810180516001600160e01b031663cbd4ece960e01b1790529050949350505050565b6000610c4682610ead565b8015610c575750610c578383610f47565b9392505050565b815160009060208401610c7964ffffffffff851682846110d6565b95945050505050565b60008160ff16600003610c9757506000610c57565b610caa8460181c6001600160601b031690565b6001600160601b0316610cc060ff841685612b87565b1115610d2857610cd98460781c6001600160601b031690565b610cec8560181c6001600160601b031690565b6040516378218d2960e01b81526001600160601b039283166004820152911660248201526044810184905260ff831660648201526084016104c2565b60208260ff161115610d4d5760405163045df3f960e01b815260040160405180910390fd5b600882026000610d668660781c6001600160601b031690565b6001600160601b03169490940151600160ff1b600019929092019190911d16949350505050565b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b039092166001600160a01b0319928316178155600255600180549091169055565b60045460408051918252602082018390527f877a02cb809da0364d23adca3cd50c451b53f279d3df632e1fc11eb66335bce5910160405180910390a1600455565b42600255600180546001600160a01b0319166001600160a01b0383169081179091556040517f6ab4d119f23076e8ad491bc65ce85f017fb0591dce08755ba8591059cc51737a90600090a250565b6000610a4f7f00000000000000000000000025ace71c97b33cc4729cf772ae268934f7ab5fa183611113565b805160208201516040808401519051634d69ee5760e01b81526000936001600160a01b037f000000000000000000000000be5dab4a2e9cd0f27300db4ab94bee3a233aeb191693634d69ee5793610f0693600401612b9a565b602060405180830381865afa158015610f23573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a4f9190612c45565b600080836007602160991b01604051602001610f64929190612c67565b60408051601f1981840301815282825280516020918201209083015260009082015260600160408051601f19818403018152908290528051602091820120602160f91b9183019190915291506000908190610fd89060340160408051601f19818403018152919052606087015187516111d4565b909250905060018215151461106b5760405162461bcd60e51b815260206004820152604d60248201527f4d6573736167652070617373696e67207072656465706c6f7920686173206e6f60448201527f74206265656e20696e697469616c697a6564206f7220696e76616c696420707260648201526c37b7b310383937bb34b232b21760991b608482015260a4016104c2565b6000611076826111fd565b90506110cb8460405160200161108e91815260200190565b60408051601f1981840301815290829052600160f81b602083015290602101604051602081830303815290604052886080015184604001516112c1565b979650505050505050565b6000806110e38385612b87565b90506040518111156110f3575060005b806000036111085762ffffff19915050610c57565b610c798585856112e5565b6000336001600160a01b038416146111575760405162461bcd60e51b81526020600482015260076024820152662162726964676560c81b60448201526064016104c2565b816001600160a01b0316836001600160a01b0316636e296e456040518163ffffffff1660e01b8152600401602060405180830381865afa15801561119f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111c39190612c9e565b6001600160a01b0316149392505050565b6000606060006111e38661135c565b90506111f081868661138e565b9250925050935093915050565b60408051608081018252600080825260208201819052918101829052606081018290529061122a83611469565b9050604051806080016040528061125a8360008151811061124d5761124d612cbb565b602002602001015161149c565b81526020016112758360018151811061124d5761124d612cbb565b815260200161129d8360028151811061129057611290612cbb565b60200260200101516114a3565b81526020016112b88360038151811061129057611290612cbb565b90529392505050565b6000806112cd8661135c565b90506112db818686866115a4565b9695505050505050565b60006060601883856001600160601b0382168214801561130d575086816001600160601b0316145b6113465760405162461bcd60e51b815260206004820152600a602482015269085d1c9d5b98d85d195960b21b60448201526064016104c2565b96831b90961790911b90941790931b9392505050565b6060818051906020012060405160200161137891815260200190565b6040516020818303038152906040529050919050565b60006060600061139d856115da565b905060008060006113af848a896116ce565b815192955090935091501580806113c35750815b61140f5760405162461bcd60e51b815260206004820152601a60248201527f50726f76696465642070726f6f6620697320696e76616c69642e00000000000060448201526064016104c2565b60008161142b5760405180602001604052806000815250611457565b6114578661143a600188612aea565b8151811061144a5761144a612cbb565b6020026020010151611ae4565b919b919a509098505050505050505050565b604080518082018252600080825260209182015281518083019092528251825280830190820152606090610a4f90611b0e565b6000610a4f825b600060228260000151106114f95760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420524c5020627974657333322076616c75652e00000000000060448201526064016104c2565b600080600061150785611cfa565b91945092509050600081600181111561152257611522612cd1565b1461156f5760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420524c5020627974657333322076616c75652e00000000000060448201526064016104c2565b60008386602001516115819190612b87565b805190915060208410156112db5760208490036101000a90049695505050505050565b60008060006115b487868661138e565b915091508180156110cb57508051602080830191909120875191880191909120146110cb565b606060006115e783611469565b90506000815167ffffffffffffffff81111561160557611605612584565b60405190808252806020026020018201604052801561164a57816020015b60408051808201909152606080825260208201528152602001906001900390816116235790505b50825190915060005b818110156116c457600061167f85838151811061167257611672612cbb565b6020026020010151612048565b9050604051806040016040528082815260200161169b83611469565b8152508483815181106116b0576116b0612cbb565b602090810291909101015250600101611653565b5090949350505050565b600060608180806116de876120cf565b90506000869050600080611705604051806040016040528060608152602001606081525090565b8b5160005b81811015611abb578d818151811061172457611724612cbb565b60200260200101519250838561173a9190612b87565b9450611747600189612b87565b9750846000036117a25782518051602090910120861461179d5760405162461bcd60e51b8152602060048201526011602482015270092dcecc2d8d2c840e4dedee840d0c2e6d607b1b60448201526064016104c2565b611860565b825151601f10156118055782518051602090910120861461179d5760405162461bcd60e51b815260206004820152601b60248201527f496e76616c6964206c6172676520696e7465726e616c2068617368000000000060448201526064016104c2565b856118138460000151612204565b146118605760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420696e7465726e616c206e6f6465206861736800000000000060448201526064016104c2565b60019081019061187290601090612b87565b836020015151036118e45786518514611abb57600087868151811061189957611899612cbb565b602001015160f81c60f81b60f81c9050600084602001518260ff16815181106118c4576118c4612cbb565b602002602001015190506118d78161222c565b975060019550505061170a565b600283602001515103611a735760006118fc84612262565b905060008160008151811061191357611913612cbb565b016020015160f81c9050600061192a600283612cfd565b611935906002612d1f565b90506000611946848360ff16612286565b905060006119548c8b612286565b9050600061196283836122bc565b905060ff851660021480611979575060ff85166003145b156119b35780835114801561198e5750808251145b156119a05761199d818c612b87565b9a505b50600160ff1b9a50611abb945050505050565b60ff851615806119c6575060ff85166001145b15611a1c57825181146119e65750600160ff1b9a50611abb945050505050565b611a0d8960200151600181518110611a0057611a00612cbb565b602002602001015161222c565b9b50985061170a945050505050565b60405162461bcd60e51b815260206004820152602660248201527f52656365697665642061206e6f6465207769746820616e20756e6b6e6f776e206044820152650e0e4caccd2f60d31b60648201526084016104c2565b60405162461bcd60e51b815260206004820152601d60248201527f526563656976656420616e20756e706172736561626c65206e6f64652e00000060448201526064016104c2565b50600160ff1b851487611ace8887612286565b909f909e50909c509a5050505050505050505050565b60208101518051606091610a4f91611afe90600190612aea565b8151811061167257611672612cbb565b6060600080611b1c84611cfa565b91935090915060019050816001811115611b3857611b38612cd1565b14611b855760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420524c50206c6973742076616c75652e00000000000000000060448201526064016104c2565b6040805160208082526104208201909252600091816020015b6040805180820190915260008082526020820152815260200190600190039081611b9e5790505090506000835b8651811015611cef5760208210611c375760405162461bcd60e51b815260206004820152602a60248201527f50726f766964656420524c50206c6973742065786365656473206d6178206c6960448201526939ba103632b733ba341760b11b60648201526084016104c2565b600080611c746040518060400160405280858c60000151611c589190612aea565b8152602001858c60200151611c6d9190612b87565b9052611cfa565b509150915060405180604001604052808383611c909190612b87565b8152602001848b60200151611ca59190612b87565b815250858581518110611cba57611cba612cbb565b6020908102919091010152611cd0600185612b87565b9350611cdc8183612b87565b611ce69084612b87565b92505050611bcb565b508152949350505050565b600080600080846000015111611d525760405162461bcd60e51b815260206004820152601860248201527f524c50206974656d2063616e6e6f74206265206e756c6c2e000000000000000060448201526064016104c2565b6020840151805160001a6080811015611d78576000600160009450945094505050612041565b60b8811015611df5576000611d8e608083612aea565b905080876000015111611de35760405162461bcd60e51b815260206004820152601960248201527f496e76616c696420524c502073686f727420737472696e672e0000000000000060448201526064016104c2565b60019550935060009250612041915050565b60c0811015611ee5576000611e0b60b783612aea565b905080876000015111611e605760405162461bcd60e51b815260206004820152601f60248201527f496e76616c696420524c50206c6f6e6720737472696e67206c656e6774682e0060448201526064016104c2565b600183015160208290036101000a9004611e7a8183612b87565b885111611ec95760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420524c50206c6f6e6720737472696e672e000000000000000060448201526064016104c2565b611ed4826001612b87565b965094506000935061204192505050565b60f8811015611f61576000611efb60c083612aea565b905080876000015111611f505760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420524c502073686f7274206c6973742e00000000000000000060448201526064016104c2565b600195509350849250612041915050565b6000611f6e60f783612aea565b905080876000015111611fc35760405162461bcd60e51b815260206004820152601d60248201527f496e76616c696420524c50206c6f6e67206c697374206c656e6774682e00000060448201526064016104c2565b600183015160208290036101000a9004611fdd8183612b87565b8851116120255760405162461bcd60e51b815260206004820152601660248201527524b73b30b634b210292628103637b733903634b9ba1760511b60448201526064016104c2565b612030826001612b87565b965094506001935061204192505050565b9193909250565b6060600080600061205885611cfa565b91945092509050600081600181111561207357612073612cd1565b146120c05760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420524c502062797465732076616c75652e000000000000000060448201526064016104c2565b610c7985602001518484612338565b60606000825160026120e19190612d38565b67ffffffffffffffff8111156120f9576120f9612584565b6040519080825280601f01601f191660200182016040528015612123576020820181803683370190505b50835190915060005b818110156121fb57600485828151811061214857612148612cbb565b01602001516001600160f81b031916901c83612165836002612d38565b8151811061217557612175612cbb565b60200101906001600160f81b031916908160001a90535060108582815181106121a0576121a0612cbb565b01602001516121b2919060f81c612cfd565b60f81b836121c1836002612d38565b6121cc906001612b87565b815181106121dc576121dc612cbb565b60200101906001600160f81b031916908160001a90535060010161212c565b50909392505050565b600060208251101561221857506020015190565b81806020019051810190610a4f9190612d4f565b6000606060208360000151101561224d576122468361240c565b9050612259565b61225683612048565b90505b610c5781612204565b6060610a4f612281836020015160008151811061167257611672612cbb565b6120cf565b6060825182106122a55750604080516020810190915260008152610a4f565b610c5783838486516122b79190612aea565b612417565b6000805b8084511180156122d05750808351115b801561232157508281815181106122e9576122e9612cbb565b602001015160f81c60f81b6001600160f81b03191684828151811061231057612310612cbb565b01602001516001600160f81b031916145b15610c57578061233081612d68565b9150506122c0565b606060008267ffffffffffffffff81111561235557612355612584565b6040519080825280601f01601f19166020018201604052801561237f576020820181803683370190505b5090508051600003612392579050610c57565b600061239e8587612b87565b90506020820160005b6123b2602087612d81565b8110156123df57825182526123c8602084612b87565b92506123d5602083612b87565b91506001016123a7565b5060006001602087066020036101000a039050808251168119845116178252839450505050509392505050565b6060610a4f8261256e565b60608161242581601f612b87565b10156124645760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b60448201526064016104c2565b8261246f8382612b87565b10156124ae5760405162461bcd60e51b815260206004820152600e60248201526d736c6963655f6f766572666c6f7760901b60448201526064016104c2565b6124b88284612b87565b845110156124fc5760405162461bcd60e51b8152602060048201526011602482015270736c6963655f6f75744f66426f756e647360781b60448201526064016104c2565b60608215801561251b5760405191506000825260208201604052612565565b6040519150601f8416801560200281840101858101878315602002848b0101015b8183101561255457805183526020928301920161253c565b5050858452601f01601f1916604052505b50949350505050565b6060610a4f826020015160008460000151612338565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff811182821017156125bd576125bd612584565b60405290565b60405160a0810167ffffffffffffffff811182821017156125bd576125bd612584565b604051601f8201601f1916810167ffffffffffffffff8111828210171561260f5761260f612584565b604052919050565b600082601f83011261262857600080fd5b813567ffffffffffffffff81111561264257612642612584565b612655601f8201601f19166020016125e6565b81815284602083860101111561266a57600080fd5b816020850160208301376000918101602001919091529392505050565b6000806040838503121561269a57600080fd5b823567ffffffffffffffff808211156126b257600080fd5b6126be86838701612617565b935060208501359150808211156126d457600080fd5b506126e185828601612617565b9150509250929050565b6000602082840312156126fd57600080fd5b813567ffffffffffffffff81111561271457600080fd5b61272084828501612617565b949350505050565b6001600160a01b03811681146105ee57600080fd5b60006020828403121561274f57600080fd5b8135610c5781612728565b600060a0828403121561276c57600080fd5b60405160a0810167ffffffffffffffff828210818311171561279057612790612584565b816040528293508435835260208501356020840152604085013560408401526060850135606084015260808501359150808211156127cd57600080fd5b506127da85828601612617565b6080830152505092915050565b6000604082840312156127f957600080fd5b61280161259a565b90508135815260208083013567ffffffffffffffff8082111561282357600080fd5b818501915085601f83011261283757600080fd5b81358181111561284957612849612584565b8060051b915061285a8483016125e6565b818152918301840191848101908884111561287457600080fd5b938501935b8385101561289257843582529385019390850190612879565b808688015250505050505092915050565b600080600080600060a086880312156128bb57600080fd5b85356128c681612728565b945060208601356128d681612728565b9350604086013567ffffffffffffffff808211156128f357600080fd5b6128ff89838a01612617565b945060608801359350608088013591508082111561291c57600080fd5b9087019060a0828a03121561293057600080fd5b6129386125c3565b8235815260208301358281111561294e57600080fd5b61295a8b82860161275a565b60208301525060408301358281111561297257600080fd5b61297e8b8286016127e7565b60408301525060608301358281111561299657600080fd5b6129a28b828601612617565b6060830152506080830135828111156129ba57600080fd5b6129c68b828601612617565b6080830152508093505050509295509295909350565b6000602082840312156129ee57600080fd5b5035919050565b60005b83811015612a105781810151838201526020016129f8565b50506000910152565b60008151808452612a318160208601602086016129f5565b601f01601f19169290920160200192915050565b606081526000612a586060830186612a19565b8281036020840152612a6a8186612a19565b91505060018060a01b0383166040830152949350505050565b604081526000612a966040830185612a19565b905060018060a01b03831660208301529392505050565b634e487b7160e01b600052601160045260246000fd5b6001600160601b03828116828216039080821115612ae357612ae3612aad565b5092915050565b81810381811115610a4f57610a4f612aad565b602081526000610c576020830184612a19565b6001600160a01b0384168152606060208201819052600090612b3490830185612a19565b905063ffffffff83166040830152949350505050565b6001600160a01b03858116825284166020820152608060408201819052600090612b7690830185612a19565b905082606083015295945050505050565b80820180821115610a4f57610a4f612aad565b8381526000602060608184015284516060840152808501516080840152604085015160a0840152606085015160c0840152608085015160a060e0850152612be5610100850182612a19565b905083810360408501526040810185518252828601516040848401528181518084526060850191508583019450600093505b80841015612c375784518252938501936001939093019290850190612c17565b509998505050505050505050565b600060208284031215612c5757600080fd5b81518015158114610c5757600080fd5b60008351612c798184602088016129f5565b60609390931b6bffffffffffffffffffffffff19169190920190815260140192915050565b600060208284031215612cb057600080fd5b8151610c5781612728565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b634e487b7160e01b600052601260045260246000fd5b600060ff831680612d1057612d10612ce7565b8060ff84160691505092915050565b60ff8281168282160390811115610a4f57610a4f612aad565b8082028115828204841417610a4f57610a4f612aad565b600060208284031215612d6157600080fd5b5051919050565b600060018201612d7a57612d7a612aad565b5060010190565b600082612d9057612d90612ce7565b50049056fea264697066735822122049488d98f454e5e1097bffbc409bd2ed7b797216444b82845a44d82d3af4fe4b64736f6c63430008110033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 26 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.