Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00Latest 1 from a total of 1 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Initialize | 13596492 | 1563 days ago | IN | 0 ETH | 0.02413425 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
L1CrossDomainMessenger
Compiler Version
v0.8.9+commit.e5eed63a
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
/* Library Imports */
import { AddressAliasHelper } from "../../standards/AddressAliasHelper.sol";
import { Lib_AddressResolver } from "../../libraries/resolver/Lib_AddressResolver.sol";
import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol";
import { Lib_AddressManager } from "../../libraries/resolver/Lib_AddressManager.sol";
import { Lib_SecureMerkleTrie } from "../../libraries/trie/Lib_SecureMerkleTrie.sol";
import { Lib_DefaultValues } from "../../libraries/constants/Lib_DefaultValues.sol";
import { Lib_PredeployAddresses } from "../../libraries/constants/Lib_PredeployAddresses.sol";
import { Lib_CrossDomainUtils } from "../../libraries/bridge/Lib_CrossDomainUtils.sol";
/* Interface Imports */
import { IL1CrossDomainMessenger } from "./IL1CrossDomainMessenger.sol";
import { ICanonicalTransactionChain } from "../rollup/ICanonicalTransactionChain.sol";
import { IStateCommitmentChain } from "../rollup/IStateCommitmentChain.sol";
/* External Imports */
import {
OwnableUpgradeable
} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import {
PausableUpgradeable
} from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
import {
ReentrancyGuardUpgradeable
} from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
/**
* @title L1CrossDomainMessenger
* @dev The L1 Cross Domain Messenger contract sends messages from L1 to L2, and relays messages
* from L2 onto L1. In the event that a message sent from L1 to L2 is rejected for exceeding the L2
* epoch gas limit, it can be resubmitted via this contract's replay function.
*
* Runtime target: EVM
*/
contract L1CrossDomainMessenger is
IL1CrossDomainMessenger,
Lib_AddressResolver,
OwnableUpgradeable,
PausableUpgradeable,
ReentrancyGuardUpgradeable
{
/**********
* Events *
**********/
event MessageBlocked(bytes32 indexed _xDomainCalldataHash);
event MessageAllowed(bytes32 indexed _xDomainCalldataHash);
/**********************
* Contract Variables *
**********************/
mapping(bytes32 => bool) public blockedMessages;
mapping(bytes32 => bool) public relayedMessages;
mapping(bytes32 => bool) public successfulMessages;
address internal xDomainMsgSender = Lib_DefaultValues.DEFAULT_XDOMAIN_SENDER;
/***************
* Constructor *
***************/
/**
* This contract is intended to be behind a delegate proxy.
* We pass the zero address to the address resolver just to satisfy the constructor.
* We still need to set this value in initialize().
*/
constructor() Lib_AddressResolver(address(0)) {}
/********************
* Public Functions *
********************/
/**
* @param _libAddressManager Address of the Address Manager.
*/
function initialize(address _libAddressManager) public initializer {
require(
address(libAddressManager) == address(0),
"L1CrossDomainMessenger already intialized."
);
libAddressManager = Lib_AddressManager(_libAddressManager);
xDomainMsgSender = Lib_DefaultValues.DEFAULT_XDOMAIN_SENDER;
// Initialize upgradable OZ contracts
__Context_init_unchained(); // Context is a dependency for both Ownable and Pausable
__Ownable_init_unchained();
__Pausable_init_unchained();
__ReentrancyGuard_init_unchained();
}
/**
* Pause relaying.
*/
function pause() external onlyOwner {
_pause();
}
/**
* Block a message.
* @param _xDomainCalldataHash Hash of the message to block.
*/
function blockMessage(bytes32 _xDomainCalldataHash) external onlyOwner {
blockedMessages[_xDomainCalldataHash] = true;
emit MessageBlocked(_xDomainCalldataHash);
}
/**
* Allow a message.
* @param _xDomainCalldataHash Hash of the message to block.
*/
function allowMessage(bytes32 _xDomainCalldataHash) external onlyOwner {
blockedMessages[_xDomainCalldataHash] = false;
emit MessageAllowed(_xDomainCalldataHash);
}
function xDomainMessageSender() public view returns (address) {
require(
xDomainMsgSender != Lib_DefaultValues.DEFAULT_XDOMAIN_SENDER,
"xDomainMessageSender is not set"
);
return xDomainMsgSender;
}
/**
* Sends a cross domain message to the target messenger.
* @param _target Target contract address.
* @param _message Message to send to the target.
* @param _gasLimit Gas limit for the provided message.
*/
function sendMessage(
address _target,
bytes memory _message,
uint32 _gasLimit
) public {
address ovmCanonicalTransactionChain = resolve("CanonicalTransactionChain");
// Use the CTC queue length as nonce
uint40 nonce = ICanonicalTransactionChain(ovmCanonicalTransactionChain).getQueueLength();
bytes memory xDomainCalldata = Lib_CrossDomainUtils.encodeXDomainCalldata(
_target,
msg.sender,
_message,
nonce
);
_sendXDomainMessage(ovmCanonicalTransactionChain, xDomainCalldata, _gasLimit);
emit SentMessage(_target, msg.sender, _message, nonce, _gasLimit);
}
/**
* Relays a cross domain message to a contract.
* @inheritdoc IL1CrossDomainMessenger
*/
function relayMessage(
address _target,
address _sender,
bytes memory _message,
uint256 _messageNonce,
L2MessageInclusionProof memory _proof
) public nonReentrant whenNotPaused {
bytes memory xDomainCalldata = Lib_CrossDomainUtils.encodeXDomainCalldata(
_target,
_sender,
_message,
_messageNonce
);
require(
_verifyXDomainMessage(xDomainCalldata, _proof) == true,
"Provided message could not be verified."
);
bytes32 xDomainCalldataHash = keccak256(xDomainCalldata);
require(
successfulMessages[xDomainCalldataHash] == false,
"Provided message has already been received."
);
require(
blockedMessages[xDomainCalldataHash] == false,
"Provided message has been blocked."
);
require(
_target != resolve("CanonicalTransactionChain"),
"Cannot send L2->L1 messages to L1 system contracts."
);
xDomainMsgSender = _sender;
(bool success, ) = _target.call(_message);
xDomainMsgSender = Lib_DefaultValues.DEFAULT_XDOMAIN_SENDER;
// Mark the message as received if the call was successful. Ensures that a message can be
// relayed multiple times in the case that the call reverted.
if (success == true) {
successfulMessages[xDomainCalldataHash] = true;
emit RelayedMessage(xDomainCalldataHash);
} else {
emit FailedRelayedMessage(xDomainCalldataHash);
}
// Store an identifier that can be used to prove that the given message was relayed by some
// user. Gives us an easy way to pay relayers for their work.
bytes32 relayId = keccak256(abi.encodePacked(xDomainCalldata, msg.sender, block.number));
relayedMessages[relayId] = true;
}
/**
* Replays a cross domain message to the target messenger.
* @inheritdoc IL1CrossDomainMessenger
*/
function replayMessage(
address _target,
address _sender,
bytes memory _message,
uint256 _queueIndex,
uint32 _oldGasLimit,
uint32 _newGasLimit
) public {
// Verify that the message is in the queue:
address canonicalTransactionChain = resolve("CanonicalTransactionChain");
Lib_OVMCodec.QueueElement memory element = ICanonicalTransactionChain(
canonicalTransactionChain
).getQueueElement(_queueIndex);
// Compute the calldata that was originally used to send the message.
bytes memory xDomainCalldata = Lib_CrossDomainUtils.encodeXDomainCalldata(
_target,
_sender,
_message,
_queueIndex
);
// Compute the transactionHash
bytes32 transactionHash = keccak256(
abi.encode(
AddressAliasHelper.applyL1ToL2Alias(address(this)),
Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER,
_oldGasLimit,
xDomainCalldata
)
);
// Now check that the provided message data matches the one in the queue element.
require(
transactionHash == element.transactionHash,
"Provided message has not been enqueued."
);
// Send the same message but with the new gas limit.
_sendXDomainMessage(canonicalTransactionChain, xDomainCalldata, _newGasLimit);
}
/**********************
* Internal Functions *
**********************/
/**
* Verifies that the given message is valid.
* @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.
* @param _proof Message inclusion proof.
* @return Whether or not the provided proof is valid.
*/
function _verifyStateRootProof(L2MessageInclusionProof memory _proof)
internal
view
returns (bool)
{
IStateCommitmentChain ovmStateCommitmentChain = IStateCommitmentChain(
resolve("StateCommitmentChain")
);
return (ovmStateCommitmentChain.insideFraudProofWindow(_proof.stateRootBatchHeader) ==
false &&
ovmStateCommitmentChain.verifyStateCommitment(
_proof.stateRoot,
_proof.stateRootBatchHeader,
_proof.stateRootProof
));
}
/**
* Verifies that the storage proof within an inclusion proof is valid.
* @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 view returns (bool) {
bytes32 storageKey = keccak256(
abi.encodePacked(
keccak256(
abi.encodePacked(
_xDomainCalldata,
Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER
)
),
uint256(0)
)
);
(bool exists, bytes memory encodedMessagePassingAccount) = Lib_SecureMerkleTrie.get(
abi.encodePacked(Lib_PredeployAddresses.L2_TO_L1_MESSAGE_PASSER),
_proof.stateTrieWitness,
_proof.stateRoot
);
require(
exists == true,
"Message passing predeploy has not been initialized or invalid proof provided."
);
Lib_OVMCodec.EVMAccount memory account = Lib_OVMCodec.decodeEVMAccount(
encodedMessagePassingAccount
);
return
Lib_SecureMerkleTrie.verifyInclusionProof(
abi.encodePacked(storageKey),
abi.encodePacked(uint8(1)),
_proof.storageTrieWitness,
account.storageRoot
);
}
/**
* Sends a cross domain message.
* @param _canonicalTransactionChain Address of the CanonicalTransactionChain instance.
* @param _message Message to send.
* @param _gasLimit OVM gas limit for the message.
*/
function _sendXDomainMessage(
address _canonicalTransactionChain,
bytes memory _message,
uint256 _gasLimit
) internal {
ICanonicalTransactionChain(_canonicalTransactionChain).enqueue(
Lib_PredeployAddresses.L2_CROSS_DOMAIN_MESSENGER,
_gasLimit,
_message
);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";
/**
* @dev 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 with {transferOwnership}.
*
* 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.
*/
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
function __Ownable_init() internal initializer {
__Context_init_unchained();
__Ownable_init_unchained();
}
function __Ownable_init_unchained() internal initializer {
_setOwner(_msgSender());
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_setOwner(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_setOwner(newOwner);
}
function _setOwner(address newOwner) private {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
*/
bool private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Modifier to protect an initializer function from being invoked twice.
*/
modifier initializer() {
require(_initializing || !_initialized, "Initializable: contract is already initialized");
bool isTopLevelCall = !_initializing;
if (isTopLevelCall) {
_initializing = true;
_initialized = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../utils/ContextUpgradeable.sol";
import "../proxy/utils/Initializable.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract PausableUpgradeable is Initializable, ContextUpgradeable {
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
bool private _paused;
/**
* @dev Initializes the contract in unpaused state.
*/
function __Pausable_init() internal initializer {
__Context_init_unchained();
__Pausable_init_unchained();
}
function __Pausable_init_unchained() internal initializer {
_paused = false;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
require(!paused(), "Pausable: paused");
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
require(paused(), "Pausable: not paused");
_;
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuardUpgradeable is Initializable {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
function __ReentrancyGuard_init() internal initializer {
__ReentrancyGuard_init_unchained();
}
function __ReentrancyGuard_init_unchained() internal initializer {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and make it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
// On the first call to nonReentrant, _notEntered will be true
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
_;
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = _NOT_ENTERED;
}
uint256[49] private __gap;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../proxy/utils/Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal initializer {
__Context_init_unchained();
}
function __Context_init_unchained() internal initializer {
}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
uint256[50] private __gap;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev 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 with {transferOwnership}.
*
* 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.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_setOwner(_msgSender());
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_setOwner(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_setOwner(newOwner);
}
function _setOwner(address newOwner) private {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
/* Library Imports */
import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol";
/* Interface Imports */
import { ICrossDomainMessenger } from "../../libraries/bridge/ICrossDomainMessenger.sol";
/**
* @title IL1CrossDomainMessenger
*/
interface IL1CrossDomainMessenger is ICrossDomainMessenger {
/*******************
* Data Structures *
*******************/
struct L2MessageInclusionProof {
bytes32 stateRoot;
Lib_OVMCodec.ChainBatchHeader stateRootBatchHeader;
Lib_OVMCodec.ChainInclusionProof stateRootProof;
bytes stateTrieWitness;
bytes storageTrieWitness;
}
/********************
* Public Functions *
********************/
/**
* Relays a cross domain message to a contract.
* @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.
* @param _proof Inclusion proof for the given message.
*/
function relayMessage(
address _target,
address _sender,
bytes memory _message,
uint256 _messageNonce,
L2MessageInclusionProof memory _proof
) external;
/**
* Replays a cross domain message to the target messenger.
* @param _target Target contract address.
* @param _sender Original sender address.
* @param _message Message to send to the target.
* @param _queueIndex CTC Queue index for the message to replay.
* @param _oldGasLimit Original gas limit used to send the message.
* @param _newGasLimit New gas limit to be used for this message.
*/
function replayMessage(
address _target,
address _sender,
bytes memory _message,
uint256 _queueIndex,
uint32 _oldGasLimit,
uint32 _newGasLimit
) external;
}// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.9.0;
/* Library Imports */
import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol";
/* Interface Imports */
import { IChainStorageContainer } from "./IChainStorageContainer.sol";
/**
* @title ICanonicalTransactionChain
*/
interface ICanonicalTransactionChain {
/**********
* Events *
**********/
event L2GasParamsUpdated(
uint256 l2GasDiscountDivisor,
uint256 enqueueGasCost,
uint256 enqueueL2GasPrepaid
);
event TransactionEnqueued(
address indexed _l1TxOrigin,
address indexed _target,
uint256 _gasLimit,
bytes _data,
uint256 indexed _queueIndex,
uint256 _timestamp
);
event QueueBatchAppended(
uint256 _startingQueueIndex,
uint256 _numQueueElements,
uint256 _totalElements
);
event SequencerBatchAppended(
uint256 _startingQueueIndex,
uint256 _numQueueElements,
uint256 _totalElements
);
event TransactionBatchAppended(
uint256 indexed _batchIndex,
bytes32 _batchRoot,
uint256 _batchSize,
uint256 _prevTotalElements,
bytes _extraData
);
/***********
* Structs *
***********/
struct BatchContext {
uint256 numSequencedTransactions;
uint256 numSubsequentQueueTransactions;
uint256 timestamp;
uint256 blockNumber;
}
/*******************************
* Authorized Setter Functions *
*******************************/
/**
* Allows the Burn Admin to update the parameters which determine the amount of gas to burn.
* The value of enqueueL2GasPrepaid is immediately updated as well.
*/
function setGasParams(uint256 _l2GasDiscountDivisor, uint256 _enqueueGasCost) external;
/********************
* Public Functions *
********************/
/**
* Accesses the batch storage container.
* @return Reference to the batch storage container.
*/
function batches() external view returns (IChainStorageContainer);
/**
* 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);
/**
* Returns the index of the next element to be enqueued.
* @return Index for the next queue element.
*/
function getNextQueueIndex() external view returns (uint40);
/**
* Gets the queue element at a particular index.
* @param _index Index of the queue element to access.
* @return _element Queue element at the given index.
*/
function getQueueElement(uint256 _index)
external
view
returns (Lib_OVMCodec.QueueElement memory _element);
/**
* Returns the timestamp of the last transaction.
* @return Timestamp for the last transaction.
*/
function getLastTimestamp() external view returns (uint40);
/**
* Returns the blocknumber of the last transaction.
* @return Blocknumber for the last transaction.
*/
function getLastBlockNumber() external view returns (uint40);
/**
* Get the number of queue elements which have not yet been included.
* @return Number of pending queue elements.
*/
function getNumPendingQueueElements() external view returns (uint40);
/**
* Retrieves the length of the queue, including
* both pending and canonical transactions.
* @return Length of the queue.
*/
function getQueueLength() external view returns (uint40);
/**
* Adds a transaction to the queue.
* @param _target Target contract to send the transaction to.
* @param _gasLimit Gas limit for the given transaction.
* @param _data Transaction data.
*/
function enqueue(
address _target,
uint256 _gasLimit,
bytes memory _data
) external;
/**
* Allows the sequencer to append a batch of transactions.
* @dev This function uses a custom encoding scheme for efficiency reasons.
* .param _shouldStartAtElement Specific batch we expect to start appending to.
* .param _totalElementsToAppend Total number of batch elements we expect to append.
* .param _contexts Array of batch contexts.
* .param _transactionDataFields Array of raw transaction data.
*/
function appendSequencerBatch(
// uint40 _shouldStartAtElement,
// uint24 _totalElementsToAppend,
// BatchContext[] _contexts,
// bytes[] _transactionDataFields
) external;
}// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.9.0;
/**
* @title IChainStorageContainer
*/
interface IChainStorageContainer {
/********************
* Public Functions *
********************/
/**
* Sets the container's global metadata field. We're using `bytes27` here because we use five
* bytes to maintain the length of the underlying data structure, meaning we have an extra
* 27 bytes to store arbitrary data.
* @param _globalMetadata New global metadata to set.
*/
function setGlobalMetadata(bytes27 _globalMetadata) external;
/**
* Retrieves the container's global metadata field.
* @return Container global metadata field.
*/
function getGlobalMetadata() external view returns (bytes27);
/**
* Retrieves the number of objects stored in the container.
* @return Number of objects in the container.
*/
function length() external view returns (uint256);
/**
* Pushes an object into the container.
* @param _object A 32 byte value to insert into the container.
*/
function push(bytes32 _object) external;
/**
* Pushes an object into the container. Function allows setting the global metadata since
* we'll need to touch the "length" storage slot anyway, which also contains the global
* metadata (it's an optimization).
* @param _object A 32 byte value to insert into the container.
* @param _globalMetadata New global metadata for the container.
*/
function push(bytes32 _object, bytes27 _globalMetadata) external;
/**
* Retrieves an object from the container.
* @param _index Index of the particular object to access.
* @return 32 byte object value.
*/
function get(uint256 _index) external view returns (bytes32);
/**
* Removes all objects after and including a given index.
* @param _index Object index to delete from.
*/
function deleteElementsAfterInclusive(uint256 _index) external;
/**
* Removes all objects after and including a given index. Also allows setting the global
* metadata field.
* @param _index Object index to delete from.
* @param _globalMetadata New global metadata for the container.
*/
function deleteElementsAfterInclusive(uint256 _index, bytes27 _globalMetadata) external;
}// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.9.0;
/* Library Imports */
import { Lib_OVMCodec } from "../../libraries/codec/Lib_OVMCodec.sol";
/**
* @title IStateCommitmentChain
*/
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(Lib_OVMCodec.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,
Lib_OVMCodec.ChainBatchHeader memory _batchHeader,
Lib_OVMCodec.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(Lib_OVMCodec.ChainBatchHeader memory _batchHeader)
external
view
returns (bool _inside);
}// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.9.0;
/**
* @title ICrossDomainMessenger
*/
interface ICrossDomainMessenger {
/**********
* Events *
**********/
event SentMessage(
address indexed target,
address sender,
bytes message,
uint256 messageNonce,
uint256 gasLimit
);
event RelayedMessage(bytes32 indexed msgHash);
event FailedRelayedMessage(bytes32 indexed msgHash);
/*************
* Variables *
*************/
function xDomainMessageSender() external view returns (address);
/********************
* Public Functions *
********************/
/**
* Sends a cross domain message to the target messenger.
* @param _target Target contract address.
* @param _message Message to send to the target.
* @param _gasLimit Gas limit for the provided message.
*/
function sendMessage(
address _target,
bytes calldata _message,
uint32 _gasLimit
) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
/* Library Imports */
import { Lib_RLPReader } from "../rlp/Lib_RLPReader.sol";
/**
* @title Lib_CrossDomainUtils
*/
library Lib_CrossDomainUtils {
/**
* Generates the correct cross domain calldata for a message.
* @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
pragma solidity ^0.8.9;
/* Library Imports */
import { Lib_RLPReader } from "../rlp/Lib_RLPReader.sol";
import { Lib_RLPWriter } from "../rlp/Lib_RLPWriter.sol";
import { Lib_BytesUtils } from "../utils/Lib_BytesUtils.sol";
import { Lib_Bytes32Utils } from "../utils/Lib_Bytes32Utils.sol";
/**
* @title Lib_OVMCodec
*/
library Lib_OVMCodec {
/*********
* Enums *
*********/
enum QueueOrigin {
SEQUENCER_QUEUE,
L1TOL2_QUEUE
}
/***********
* Structs *
***********/
struct EVMAccount {
uint256 nonce;
uint256 balance;
bytes32 storageRoot;
bytes32 codeHash;
}
struct ChainBatchHeader {
uint256 batchIndex;
bytes32 batchRoot;
uint256 batchSize;
uint256 prevTotalElements;
bytes extraData;
}
struct ChainInclusionProof {
uint256 index;
bytes32[] siblings;
}
struct Transaction {
uint256 timestamp;
uint256 blockNumber;
QueueOrigin l1QueueOrigin;
address l1TxOrigin;
address entrypoint;
uint256 gasLimit;
bytes data;
}
struct TransactionChainElement {
bool isSequenced;
uint256 queueIndex; // QUEUED TX ONLY
uint256 timestamp; // SEQUENCER TX ONLY
uint256 blockNumber; // SEQUENCER TX ONLY
bytes txData; // SEQUENCER TX ONLY
}
struct QueueElement {
bytes32 transactionHash;
uint40 timestamp;
uint40 blockNumber;
}
/**********************
* Internal Functions *
**********************/
/**
* Encodes a standard OVM transaction.
* @param _transaction OVM transaction to encode.
* @return Encoded transaction bytes.
*/
function encodeTransaction(Transaction memory _transaction)
internal
pure
returns (bytes memory)
{
return
abi.encodePacked(
_transaction.timestamp,
_transaction.blockNumber,
_transaction.l1QueueOrigin,
_transaction.l1TxOrigin,
_transaction.entrypoint,
_transaction.gasLimit,
_transaction.data
);
}
/**
* Hashes a standard OVM transaction.
* @param _transaction OVM transaction to encode.
* @return Hashed transaction
*/
function hashTransaction(Transaction memory _transaction) internal pure returns (bytes32) {
return keccak256(encodeTransaction(_transaction));
}
/**
* @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) {
Lib_RLPReader.RLPItem[] memory accountState = Lib_RLPReader.readList(_encoded);
return
EVMAccount({
nonce: Lib_RLPReader.readUint256(accountState[0]),
balance: Lib_RLPReader.readUint256(accountState[1]),
storageRoot: Lib_RLPReader.readBytes32(accountState[2]),
codeHash: Lib_RLPReader.readBytes32(accountState[3])
});
}
/**
* Calculates a hash for a given batch header.
* @param _batchHeader Header to hash.
* @return Hash of the header.
*/
function hashBatchHeader(Lib_OVMCodec.ChainBatchHeader memory _batchHeader)
internal
pure
returns (bytes32)
{
return
keccak256(
abi.encode(
_batchHeader.batchRoot,
_batchHeader.batchSize,
_batchHeader.prevTotalElements,
_batchHeader.extraData
)
);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
/**
* @title Lib_DefaultValues
*/
library Lib_DefaultValues {
// The default x-domain message sender being set to a non-zero value makes
// deployment a bit more expensive, but in exchange the refund on every call to
// `relayMessage` by the L1 and L2 messengers will be higher.
address internal constant DEFAULT_XDOMAIN_SENDER = 0x000000000000000000000000000000000000dEaD;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
/**
* @title Lib_PredeployAddresses
*/
library Lib_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
pragma solidity ^0.8.9;
/* External Imports */
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
/**
* @title Lib_AddressManager
*/
contract Lib_AddressManager is Ownable {
/**********
* Events *
**********/
event AddressSet(string indexed _name, address _newAddress, address _oldAddress);
/*************
* Variables *
*************/
mapping(bytes32 => address) private addresses;
/********************
* Public Functions *
********************/
/**
* Changes the address associated with a particular name.
* @param _name String name to associate an address with.
* @param _address Address to associate with the name.
*/
function setAddress(string memory _name, address _address) external onlyOwner {
bytes32 nameHash = _getNameHash(_name);
address oldAddress = addresses[nameHash];
addresses[nameHash] = _address;
emit AddressSet(_name, _address, oldAddress);
}
/**
* Retrieves the address associated with a given name.
* @param _name Name to retrieve an address for.
* @return Address associated with the given name.
*/
function getAddress(string memory _name) external view returns (address) {
return addresses[_getNameHash(_name)];
}
/**********************
* Internal Functions *
**********************/
/**
* Computes the hash of a name.
* @param _name Name to compute a hash for.
* @return Hash of the given name.
*/
function _getNameHash(string memory _name) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(_name));
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
/* Library Imports */
import { Lib_AddressManager } from "./Lib_AddressManager.sol";
/**
* @title Lib_AddressResolver
*/
abstract contract Lib_AddressResolver {
/*************
* Variables *
*************/
Lib_AddressManager public libAddressManager;
/***************
* Constructor *
***************/
/**
* @param _libAddressManager Address of the Lib_AddressManager.
*/
constructor(address _libAddressManager) {
libAddressManager = Lib_AddressManager(_libAddressManager);
}
/********************
* Public Functions *
********************/
/**
* Resolves the address associated with a given name.
* @param _name Name to resolve an address for.
* @return Address associated with the given name.
*/
function resolve(string memory _name) public view returns (address) {
return libAddressManager.getAddress(_name);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
/**
* @title Lib_RLPReader
* @dev Adapted from "RLPReader" by Hamdi Allam (hamdi.allam97@gmail.com).
*/
library Lib_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) {
require(_in.length <= 33, "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) {
// Single byte.
return (0, 1, RLPItemType.DATA_ITEM);
} else if (prefix <= 0xb7) {
// Short string.
uint256 strLen = prefix - 0x80;
require(_in.length > strLen, "Invalid RLP short string.");
return (1, strLen, RLPItemType.DATA_ITEM);
} else if (prefix <= 0xbf) {
// 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) {
// Short list.
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; i++) {
assembly {
mstore(dest, mload(src))
}
src += 32;
dest += 32;
}
// 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
pragma solidity ^0.8.9;
/**
* @title Lib_RLPWriter
* @author Bakaoh (with modifications)
*/
library Lib_RLPWriter {
/**********************
* Internal Functions *
**********************/
/**
* RLP encodes a byte string.
* @param _in The byte string to encode.
* @return The RLP encoded string in bytes.
*/
function writeBytes(bytes memory _in) internal pure returns (bytes memory) {
bytes memory encoded;
if (_in.length == 1 && uint8(_in[0]) < 128) {
encoded = _in;
} else {
encoded = abi.encodePacked(_writeLength(_in.length, 128), _in);
}
return encoded;
}
/**
* RLP encodes a list of RLP encoded byte byte strings.
* @param _in The list of RLP encoded byte strings.
* @return The RLP encoded list of items in bytes.
*/
function writeList(bytes[] memory _in) internal pure returns (bytes memory) {
bytes memory list = _flatten(_in);
return abi.encodePacked(_writeLength(list.length, 192), list);
}
/**
* RLP encodes a string.
* @param _in The string to encode.
* @return The RLP encoded string in bytes.
*/
function writeString(string memory _in) internal pure returns (bytes memory) {
return writeBytes(bytes(_in));
}
/**
* RLP encodes an address.
* @param _in The address to encode.
* @return The RLP encoded address in bytes.
*/
function writeAddress(address _in) internal pure returns (bytes memory) {
return writeBytes(abi.encodePacked(_in));
}
/**
* RLP encodes a uint.
* @param _in The uint256 to encode.
* @return The RLP encoded uint256 in bytes.
*/
function writeUint(uint256 _in) internal pure returns (bytes memory) {
return writeBytes(_toBinary(_in));
}
/**
* RLP encodes a bool.
* @param _in The bool to encode.
* @return The RLP encoded bool in bytes.
*/
function writeBool(bool _in) internal pure returns (bytes memory) {
bytes memory encoded = new bytes(1);
encoded[0] = (_in ? bytes1(0x01) : bytes1(0x80));
return encoded;
}
/*********************
* Private Functions *
*********************/
/**
* Encode the first byte, followed by the `len` in binary form if `length` is more than 55.
* @param _len The length of the string or the payload.
* @param _offset 128 if item is string, 192 if item is list.
* @return RLP encoded bytes.
*/
function _writeLength(uint256 _len, uint256 _offset) private pure returns (bytes memory) {
bytes memory encoded;
if (_len < 56) {
encoded = new bytes(1);
encoded[0] = bytes1(uint8(_len) + uint8(_offset));
} else {
uint256 lenLen;
uint256 i = 1;
while (_len / i != 0) {
lenLen++;
i *= 256;
}
encoded = new bytes(lenLen + 1);
encoded[0] = bytes1(uint8(lenLen) + uint8(_offset) + 55);
for (i = 1; i <= lenLen; i++) {
encoded[i] = bytes1(uint8((_len / (256**(lenLen - i))) % 256));
}
}
return encoded;
}
/**
* Encode integer in big endian binary form with no leading zeroes.
* @notice TODO: This should be optimized with assembly to save gas costs.
* @param _x The integer to encode.
* @return RLP encoded bytes.
*/
function _toBinary(uint256 _x) private pure returns (bytes memory) {
bytes memory b = abi.encodePacked(_x);
uint256 i = 0;
for (; i < 32; i++) {
if (b[i] != 0) {
break;
}
}
bytes memory res = new bytes(32 - i);
for (uint256 j = 0; j < res.length; j++) {
res[j] = b[i++];
}
return res;
}
/**
* Copies a piece of memory to another location.
* @notice From: https://github.com/Arachnid/solidity-stringutils/blob/master/src/strings.sol.
* @param _dest Destination location.
* @param _src Source location.
* @param _len Length of memory to copy.
*/
function _memcpy(
uint256 _dest,
uint256 _src,
uint256 _len
) private pure {
uint256 dest = _dest;
uint256 src = _src;
uint256 len = _len;
for (; len >= 32; len -= 32) {
assembly {
mstore(dest, mload(src))
}
dest += 32;
src += 32;
}
uint256 mask;
unchecked {
mask = 256**(32 - len) - 1;
}
assembly {
let srcpart := and(mload(src), not(mask))
let destpart := and(mload(dest), mask)
mstore(dest, or(destpart, srcpart))
}
}
/**
* Flattens a list of byte strings into one byte string.
* @notice From: https://github.com/sammayo/solidity-rlp-encoder/blob/master/RLPEncode.sol.
* @param _list List of byte strings to flatten.
* @return The flattened byte string.
*/
function _flatten(bytes[] memory _list) private pure returns (bytes memory) {
if (_list.length == 0) {
return new bytes(0);
}
uint256 len;
uint256 i = 0;
for (; i < _list.length; i++) {
len += _list[i].length;
}
bytes memory flattened = new bytes(len);
uint256 flattenedPtr;
assembly {
flattenedPtr := add(flattened, 0x20)
}
for (i = 0; i < _list.length; i++) {
bytes memory item = _list[i];
uint256 listPtr;
assembly {
listPtr := add(item, 0x20)
}
_memcpy(flattenedPtr, listPtr, item.length);
flattenedPtr += _list[i].length;
}
return flattened;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
/* Library Imports */
import { Lib_BytesUtils } from "../utils/Lib_BytesUtils.sol";
import { Lib_RLPReader } from "../rlp/Lib_RLPReader.sol";
import { Lib_RLPWriter } from "../rlp/Lib_RLPWriter.sol";
/**
* @title Lib_MerkleTrie
*/
library Lib_MerkleTrie {
/*******************
* Data Structures *
*******************/
enum NodeType {
BranchNode,
ExtensionNode,
LeafNode
}
struct TrieNode {
bytes encoded;
Lib_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);
bytes constant RLP_NULL_BYTES = hex"80";
bytes32 internal constant KECCAK256_RLP_NULL_BYTES = keccak256(RLP_NULL_BYTES);
/**********************
* 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 && Lib_BytesUtils.equal(_value, value));
}
/**
* @notice Updates a Merkle trie and returns a new root hash.
* @param _key Key of the node to update, as a hex string.
* @param _value Value of the node to update, as a hex string.
* @param _proof Merkle trie inclusion proof for the node *nearest* the
* target node. If the key exists, we can simply update the value.
* Otherwise, we need to modify the trie to handle the new k/v pair.
* @param _root Known root of the Merkle trie. Used to verify that the
* included proof is correctly constructed.
* @return _updatedRoot Root hash of the newly constructed trie.
*/
function update(
bytes memory _key,
bytes memory _value,
bytes memory _proof,
bytes32 _root
) internal pure returns (bytes32 _updatedRoot) {
// Special case when inserting the very first node.
if (_root == KECCAK256_RLP_NULL_BYTES) {
return getSingleNodeRootHash(_key, _value);
}
TrieNode[] memory proof = _parseProof(_proof);
(uint256 pathLength, bytes memory keyRemainder, ) = _walkNodePath(proof, _key, _root);
TrieNode[] memory newPath = _getNewPath(proof, pathLength, _key, keyRemainder, _value);
return _getUpdatedTrieRoot(newPath, _key);
}
/**
* @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);
}
/**
* Computes the root hash for a trie with a single node.
* @param _key Key for the single node.
* @param _value Value for the single node.
* @return _updatedRoot Hash of the trie.
*/
function getSingleNodeRootHash(bytes memory _key, bytes memory _value)
internal
pure
returns (bytes32 _updatedRoot)
{
return keccak256(_makeLeafNode(Lib_BytesUtils.toNibbles(_key), _value).encoded);
}
/*********************
* 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 = Lib_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).
for (uint256 i = 0; i < _proof.length; i++) {
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) {
// 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(
Lib_BytesUtils.toBytes32(currentNode.encoded) == currentNodeID,
"Invalid internal node hash"
);
}
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]);
Lib_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 = Lib_BytesUtils.slice(path, offset);
bytes memory keyRemainder = Lib_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, Lib_BytesUtils.slice(key, currentKeyIndex), isFinalNode);
}
/**
* @notice Creates new nodes to support a k/v pair insertion into a given Merkle trie path.
* @param _path Path to the node nearest the k/v pair.
* @param _pathLength Length of the path. Necessary because the provided path may include
* additional nodes (e.g., it comes directly from a proof) and we can't resize in-memory
* arrays without costly duplication.
* @param _key Full original key.
* @param _keyRemainder Portion of the initial key that must be inserted into the trie.
* @param _value Value to insert at the given key.
* @return _newPath A new path with the inserted k/v pair and extra supporting nodes.
*/
function _getNewPath(
TrieNode[] memory _path,
uint256 _pathLength,
bytes memory _key,
bytes memory _keyRemainder,
bytes memory _value
) private pure returns (TrieNode[] memory _newPath) {
bytes memory keyRemainder = _keyRemainder;
// Most of our logic depends on the status of the last node in the path.
TrieNode memory lastNode = _path[_pathLength - 1];
NodeType lastNodeType = _getNodeType(lastNode);
// Create an array for newly created nodes.
// We need up to three new nodes, depending on the contents of the last node.
// Since array resizing is expensive, we'll keep track of the size manually.
// We're using an explicit `totalNewNodes += 1` after insertions for clarity.
TrieNode[] memory newNodes = new TrieNode[](3);
uint256 totalNewNodes = 0;
// solhint-disable-next-line max-line-length
// Reference: https://github.com/ethereumjs/merkle-patricia-tree/blob/c0a10395aab37d42c175a47114ebfcbd7efcf059/src/baseTrie.ts#L294-L313
bool matchLeaf = false;
if (lastNodeType == NodeType.LeafNode) {
uint256 l = 0;
if (_path.length > 0) {
for (uint256 i = 0; i < _path.length - 1; i++) {
if (_getNodeType(_path[i]) == NodeType.BranchNode) {
l++;
} else {
l += _getNodeKey(_path[i]).length;
}
}
}
if (
_getSharedNibbleLength(
_getNodeKey(lastNode),
Lib_BytesUtils.slice(Lib_BytesUtils.toNibbles(_key), l)
) ==
_getNodeKey(lastNode).length &&
keyRemainder.length == 0
) {
matchLeaf = true;
}
}
if (matchLeaf) {
// We've found a leaf node with the given key.
// Simply need to update the value of the node to match.
newNodes[totalNewNodes] = _makeLeafNode(_getNodeKey(lastNode), _value);
totalNewNodes += 1;
} else if (lastNodeType == NodeType.BranchNode) {
if (keyRemainder.length == 0) {
// We've found a branch node with the given key.
// Simply need to update the value of the node to match.
newNodes[totalNewNodes] = _editBranchValue(lastNode, _value);
totalNewNodes += 1;
} else {
// We've found a branch node, but it doesn't contain our key.
// Reinsert the old branch for now.
newNodes[totalNewNodes] = lastNode;
totalNewNodes += 1;
// Create a new leaf node, slicing our remainder since the first byte points
// to our branch node.
newNodes[totalNewNodes] = _makeLeafNode(
Lib_BytesUtils.slice(keyRemainder, 1),
_value
);
totalNewNodes += 1;
}
} else {
// Our last node is either an extension node or a leaf node with a different key.
bytes memory lastNodeKey = _getNodeKey(lastNode);
uint256 sharedNibbleLength = _getSharedNibbleLength(lastNodeKey, keyRemainder);
if (sharedNibbleLength != 0) {
// We've got some shared nibbles between the last node and our key remainder.
// We'll need to insert an extension node that covers these shared nibbles.
bytes memory nextNodeKey = Lib_BytesUtils.slice(lastNodeKey, 0, sharedNibbleLength);
newNodes[totalNewNodes] = _makeExtensionNode(nextNodeKey, _getNodeHash(_value));
totalNewNodes += 1;
// Cut down the keys since we've just covered these shared nibbles.
lastNodeKey = Lib_BytesUtils.slice(lastNodeKey, sharedNibbleLength);
keyRemainder = Lib_BytesUtils.slice(keyRemainder, sharedNibbleLength);
}
// Create an empty branch to fill in.
TrieNode memory newBranch = _makeEmptyBranchNode();
if (lastNodeKey.length == 0) {
// Key remainder was larger than the key for our last node.
// The value within our last node is therefore going to be shifted into
// a branch value slot.
newBranch = _editBranchValue(newBranch, _getNodeValue(lastNode));
} else {
// Last node key was larger than the key remainder.
// We're going to modify some index of our branch.
uint8 branchKey = uint8(lastNodeKey[0]);
// Move on to the next nibble.
lastNodeKey = Lib_BytesUtils.slice(lastNodeKey, 1);
if (lastNodeType == NodeType.LeafNode) {
// We're dealing with a leaf node.
// We'll modify the key and insert the old leaf node into the branch index.
TrieNode memory modifiedLastNode = _makeLeafNode(
lastNodeKey,
_getNodeValue(lastNode)
);
newBranch = _editBranchIndex(
newBranch,
branchKey,
_getNodeHash(modifiedLastNode.encoded)
);
} else if (lastNodeKey.length != 0) {
// We're dealing with a shrinking extension node.
// We need to modify the node to decrease the size of the key.
TrieNode memory modifiedLastNode = _makeExtensionNode(
lastNodeKey,
_getNodeValue(lastNode)
);
newBranch = _editBranchIndex(
newBranch,
branchKey,
_getNodeHash(modifiedLastNode.encoded)
);
} else {
// We're dealing with an unnecessary extension node.
// We're going to delete the node entirely.
// Simply insert its current value into the branch index.
newBranch = _editBranchIndex(newBranch, branchKey, _getNodeValue(lastNode));
}
}
if (keyRemainder.length == 0) {
// We've got nothing left in the key remainder.
// Simply insert the value into the branch value slot.
newBranch = _editBranchValue(newBranch, _value);
// Push the branch into the list of new nodes.
newNodes[totalNewNodes] = newBranch;
totalNewNodes += 1;
} else {
// We've got some key remainder to work with.
// We'll be inserting a leaf node into the trie.
// First, move on to the next nibble.
keyRemainder = Lib_BytesUtils.slice(keyRemainder, 1);
// Push the branch into the list of new nodes.
newNodes[totalNewNodes] = newBranch;
totalNewNodes += 1;
// Push a new leaf node for our k/v pair.
newNodes[totalNewNodes] = _makeLeafNode(keyRemainder, _value);
totalNewNodes += 1;
}
}
// Finally, join the old path with our newly created nodes.
// Since we're overwriting the last node in the path, we use `_pathLength - 1`.
return _joinNodeArrays(_path, _pathLength - 1, newNodes, totalNewNodes);
}
/**
* @notice Computes the trie root from a given path.
* @param _nodes Path to some k/v pair.
* @param _key Key for the k/v pair.
* @return _updatedRoot Root hash for the updated trie.
*/
function _getUpdatedTrieRoot(TrieNode[] memory _nodes, bytes memory _key)
private
pure
returns (bytes32 _updatedRoot)
{
bytes memory key = Lib_BytesUtils.toNibbles(_key);
// Some variables to keep track of during iteration.
TrieNode memory currentNode;
NodeType currentNodeType;
bytes memory previousNodeHash;
// Run through the path backwards to rebuild our root hash.
for (uint256 i = _nodes.length; i > 0; i--) {
// Pick out the current node.
currentNode = _nodes[i - 1];
currentNodeType = _getNodeType(currentNode);
if (currentNodeType == NodeType.LeafNode) {
// Leaf nodes are already correctly encoded.
// Shift the key over to account for the nodes key.
bytes memory nodeKey = _getNodeKey(currentNode);
key = Lib_BytesUtils.slice(key, 0, key.length - nodeKey.length);
} else if (currentNodeType == NodeType.ExtensionNode) {
// Shift the key over to account for the nodes key.
bytes memory nodeKey = _getNodeKey(currentNode);
key = Lib_BytesUtils.slice(key, 0, key.length - nodeKey.length);
// If this node is the last element in the path, it'll be correctly encoded
// and we can skip this part.
if (previousNodeHash.length > 0) {
// Re-encode the node based on the previous node.
currentNode = _editExtensionNodeValue(currentNode, previousNodeHash);
}
} else if (currentNodeType == NodeType.BranchNode) {
// If this node is the last element in the path, it'll be correctly encoded
// and we can skip this part.
if (previousNodeHash.length > 0) {
// Re-encode the node based on the previous node.
uint8 branchKey = uint8(key[key.length - 1]);
key = Lib_BytesUtils.slice(key, 0, key.length - 1);
currentNode = _editBranchIndex(currentNode, branchKey, previousNodeHash);
}
}
// Compute the node hash for the next iteration.
previousNodeHash = _getNodeHash(currentNode.encoded);
}
// Current node should be the root at this point.
// Simply return the hash of its encoding.
return keccak256(currentNode.encoded);
}
/**
* @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) {
Lib_RLPReader.RLPItem[] memory nodes = Lib_RLPReader.readList(_proof);
TrieNode[] memory proof = new TrieNode[](nodes.length);
for (uint256 i = 0; i < nodes.length; i++) {
bytes memory encoded = Lib_RLPReader.readBytes(nodes[i]);
proof[i] = TrieNode({ encoded: encoded, decoded: Lib_RLPReader.readList(encoded) });
}
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(Lib_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 = Lib_RLPReader.readRawBytes(_node);
} else {
// Nodes 32 bytes or larger are hashed.
nodeID = Lib_RLPReader.readBytes(_node);
}
return Lib_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 Lib_BytesUtils.toNibbles(Lib_RLPReader.readBytes(_node.decoded[0]));
}
/**
* @notice Gets the key for a leaf or extension node. Keys are essentially
* just paths without any prefix.
* @param _node Node to get a key for.
* @return _key Node key, converted to an array of nibbles.
*/
function _getNodeKey(TrieNode memory _node) private pure returns (bytes memory _key) {
return _removeHexPrefix(_getNodePath(_node));
}
/**
* @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 Lib_RLPReader.readBytes(_node.decoded[_node.decoded.length - 1]);
}
/**
* @notice Computes the node hash for an encoded node. Nodes < 32 bytes
* are not hashed, all others are keccak256 hashed.
* @param _encoded Encoded node to hash.
* @return _hash Hash of the encoded node. Simply the input if < 32 bytes.
*/
function _getNodeHash(bytes memory _encoded) private pure returns (bytes memory _hash) {
if (_encoded.length < 32) {
return _encoded;
} else {
return abi.encodePacked(keccak256(_encoded));
}
}
/**
* @notice Determines the type for a given node.
* @param _node Node to determine a type for.
* @return _type Type of the node; BranchNode/ExtensionNode/LeafNode.
*/
function _getNodeType(TrieNode memory _node) private pure returns (NodeType _type) {
if (_node.decoded.length == BRANCH_NODE_LENGTH) {
return NodeType.BranchNode;
} else if (_node.decoded.length == LEAF_OR_EXTENSION_NODE_LENGTH) {
bytes memory path = _getNodePath(_node);
uint8 prefix = uint8(path[0]);
if (prefix == PREFIX_LEAF_EVEN || prefix == PREFIX_LEAF_ODD) {
return NodeType.LeafNode;
} else if (prefix == PREFIX_EXTENSION_EVEN || prefix == PREFIX_EXTENSION_ODD) {
return NodeType.ExtensionNode;
}
}
revert("Invalid node type");
}
/**
* @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;
}
/**
* @notice Utility; converts an RLP-encoded node into our nice struct.
* @param _raw RLP-encoded node to convert.
* @return _node Node as a TrieNode struct.
*/
function _makeNode(bytes[] memory _raw) private pure returns (TrieNode memory _node) {
bytes memory encoded = Lib_RLPWriter.writeList(_raw);
return TrieNode({ encoded: encoded, decoded: Lib_RLPReader.readList(encoded) });
}
/**
* @notice Utility; converts an RLP-decoded node into our nice struct.
* @param _items RLP-decoded node to convert.
* @return _node Node as a TrieNode struct.
*/
function _makeNode(Lib_RLPReader.RLPItem[] memory _items)
private
pure
returns (TrieNode memory _node)
{
bytes[] memory raw = new bytes[](_items.length);
for (uint256 i = 0; i < _items.length; i++) {
raw[i] = Lib_RLPReader.readRawBytes(_items[i]);
}
return _makeNode(raw);
}
/**
* @notice Creates a new extension node.
* @param _key Key for the extension node, unprefixed.
* @param _value Value for the extension node.
* @return _node New extension node with the given k/v pair.
*/
function _makeExtensionNode(bytes memory _key, bytes memory _value)
private
pure
returns (TrieNode memory _node)
{
bytes[] memory raw = new bytes[](2);
bytes memory key = _addHexPrefix(_key, false);
raw[0] = Lib_RLPWriter.writeBytes(Lib_BytesUtils.fromNibbles(key));
raw[1] = Lib_RLPWriter.writeBytes(_value);
return _makeNode(raw);
}
/**
* Creates a new extension node with the same key but a different value.
* @param _node Extension node to copy and modify.
* @param _value New value for the extension node.
* @return New node with the same key and different value.
*/
function _editExtensionNodeValue(TrieNode memory _node, bytes memory _value)
private
pure
returns (TrieNode memory)
{
bytes[] memory raw = new bytes[](2);
bytes memory key = _addHexPrefix(_getNodeKey(_node), false);
raw[0] = Lib_RLPWriter.writeBytes(Lib_BytesUtils.fromNibbles(key));
if (_value.length < 32) {
raw[1] = _value;
} else {
raw[1] = Lib_RLPWriter.writeBytes(_value);
}
return _makeNode(raw);
}
/**
* @notice Creates a new leaf node.
* @dev This function is essentially identical to `_makeExtensionNode`.
* Although we could route both to a single method with a flag, it's
* more gas efficient to keep them separate and duplicate the logic.
* @param _key Key for the leaf node, unprefixed.
* @param _value Value for the leaf node.
* @return _node New leaf node with the given k/v pair.
*/
function _makeLeafNode(bytes memory _key, bytes memory _value)
private
pure
returns (TrieNode memory _node)
{
bytes[] memory raw = new bytes[](2);
bytes memory key = _addHexPrefix(_key, true);
raw[0] = Lib_RLPWriter.writeBytes(Lib_BytesUtils.fromNibbles(key));
raw[1] = Lib_RLPWriter.writeBytes(_value);
return _makeNode(raw);
}
/**
* @notice Creates an empty branch node.
* @return _node Empty branch node as a TrieNode struct.
*/
function _makeEmptyBranchNode() private pure returns (TrieNode memory _node) {
bytes[] memory raw = new bytes[](BRANCH_NODE_LENGTH);
for (uint256 i = 0; i < raw.length; i++) {
raw[i] = RLP_NULL_BYTES;
}
return _makeNode(raw);
}
/**
* @notice Modifies the value slot for a given branch.
* @param _branch Branch node to modify.
* @param _value Value to insert into the branch.
* @return _updatedNode Modified branch node.
*/
function _editBranchValue(TrieNode memory _branch, bytes memory _value)
private
pure
returns (TrieNode memory _updatedNode)
{
bytes memory encoded = Lib_RLPWriter.writeBytes(_value);
_branch.decoded[_branch.decoded.length - 1] = Lib_RLPReader.toRLPItem(encoded);
return _makeNode(_branch.decoded);
}
/**
* @notice Modifies a slot at an index for a given branch.
* @param _branch Branch node to modify.
* @param _index Slot index to modify.
* @param _value Value to insert into the slot.
* @return _updatedNode Modified branch node.
*/
function _editBranchIndex(
TrieNode memory _branch,
uint8 _index,
bytes memory _value
) private pure returns (TrieNode memory _updatedNode) {
bytes memory encoded = _value.length < 32 ? _value : Lib_RLPWriter.writeBytes(_value);
_branch.decoded[_index] = Lib_RLPReader.toRLPItem(encoded);
return _makeNode(_branch.decoded);
}
/**
* @notice Utility; adds a prefix to a key.
* @param _key Key to prefix.
* @param _isLeaf Whether or not the key belongs to a leaf.
* @return _prefixedKey Prefixed key.
*/
function _addHexPrefix(bytes memory _key, bool _isLeaf)
private
pure
returns (bytes memory _prefixedKey)
{
uint8 prefix = _isLeaf ? uint8(0x02) : uint8(0x00);
uint8 offset = uint8(_key.length % 2);
bytes memory prefixed = new bytes(2 - offset);
prefixed[0] = bytes1(prefix + offset);
return abi.encodePacked(prefixed, _key);
}
/**
* @notice Utility; removes a prefix from a path.
* @param _path Path to remove the prefix from.
* @return _unprefixedKey Unprefixed key.
*/
function _removeHexPrefix(bytes memory _path)
private
pure
returns (bytes memory _unprefixedKey)
{
if (uint8(_path[0]) % 2 == 0) {
return Lib_BytesUtils.slice(_path, 2);
} else {
return Lib_BytesUtils.slice(_path, 1);
}
}
/**
* @notice Utility; combines two node arrays. Array lengths are required
* because the actual lengths may be longer than the filled lengths.
* Array resizing is extremely costly and should be avoided.
* @param _a First array to join.
* @param _aLength Length of the first array.
* @param _b Second array to join.
* @param _bLength Length of the second array.
* @return _joined Combined node array.
*/
function _joinNodeArrays(
TrieNode[] memory _a,
uint256 _aLength,
TrieNode[] memory _b,
uint256 _bLength
) private pure returns (TrieNode[] memory _joined) {
TrieNode[] memory ret = new TrieNode[](_aLength + _bLength);
// Copy elements from the first array.
for (uint256 i = 0; i < _aLength; i++) {
ret[i] = _a[i];
}
// Copy elements from the second array.
for (uint256 i = 0; i < _bLength; i++) {
ret[i + _aLength] = _b[i];
}
return ret;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
/* Library Imports */
import { Lib_MerkleTrie } from "./Lib_MerkleTrie.sol";
/**
* @title Lib_SecureMerkleTrie
*/
library Lib_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 Lib_MerkleTrie.verifyInclusionProof(key, _value, _proof, _root);
}
/**
* @notice Updates a Merkle trie and returns a new root hash.
* @param _key Key of the node to update, as a hex string.
* @param _value Value of the node to update, as a hex string.
* @param _proof Merkle trie inclusion proof for the node *nearest* the
* target node. If the key exists, we can simply update the value.
* Otherwise, we need to modify the trie to handle the new k/v pair.
* @param _root Known root of the Merkle trie. Used to verify that the
* included proof is correctly constructed.
* @return _updatedRoot Root hash of the newly constructed trie.
*/
function update(
bytes memory _key,
bytes memory _value,
bytes memory _proof,
bytes32 _root
) internal pure returns (bytes32 _updatedRoot) {
bytes memory key = _getSecureKey(_key);
return Lib_MerkleTrie.update(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 Lib_MerkleTrie.get(key, _proof, _root);
}
/**
* Computes the root hash for a trie with a single node.
* @param _key Key for the single node.
* @param _value Value for the single node.
* @return _updatedRoot Hash of the trie.
*/
function getSingleNodeRootHash(bytes memory _key, bytes memory _value)
internal
pure
returns (bytes32 _updatedRoot)
{
bytes memory key = _getSecureKey(_key);
return Lib_MerkleTrie.getSingleNodeRootHash(key, _value);
}
/*********************
* 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
pragma solidity ^0.8.9;
/**
* @title Lib_Byte32Utils
*/
library Lib_Bytes32Utils {
/**********************
* Internal Functions *
**********************/
/**
* Converts a bytes32 value to a boolean. Anything non-zero will be converted to "true."
* @param _in Input bytes32 value.
* @return Bytes32 as a boolean.
*/
function toBool(bytes32 _in) internal pure returns (bool) {
return _in != 0;
}
/**
* Converts a boolean to a bytes32 value.
* @param _in Input boolean value.
* @return Boolean as a bytes32.
*/
function fromBool(bool _in) internal pure returns (bytes32) {
return bytes32(uint256(_in ? 1 : 0));
}
/**
* Converts a bytes32 value to an address. Takes the *last* 20 bytes.
* @param _in Input bytes32 value.
* @return Bytes32 as an address.
*/
function toAddress(bytes32 _in) internal pure returns (address) {
return address(uint160(uint256(_in)));
}
/**
* Converts an address to a bytes32.
* @param _in Input address value.
* @return Address as a bytes32.
*/
function fromAddress(address _in) internal pure returns (bytes32) {
return bytes32(uint256(uint160(_in)));
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
/**
* @title Lib_BytesUtils
*/
library Lib_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);
for (uint256 i = 0; i < _bytes.length; i++) {
nibbles[i * 2] = _bytes[i] >> 4;
nibbles[i * 2 + 1] = bytes1(uint8(_bytes[i]) % 16);
}
return nibbles;
}
function fromNibbles(bytes memory _bytes) internal pure returns (bytes memory) {
bytes memory ret = new bytes(_bytes.length / 2);
for (uint256 i = 0; i < ret.length; i++) {
ret[i] = (_bytes[i * 2] << 4) | (_bytes[i * 2 + 1]);
}
return ret;
}
function equal(bytes memory _bytes, bytes memory _other) internal pure returns (bool) {
return keccak256(_bytes) == keccak256(_other);
}
}// SPDX-License-Identifier: Apache-2.0
/*
* Copyright 2019-2021, Offchain Labs, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
pragma solidity ^0.8.7;
library AddressAliasHelper {
uint160 constant offset = uint160(0x1111000000000000000000000000000000001111);
/// @notice Utility function that converts the address in the L1 that submitted a tx to
/// the inbox to the msg.sender viewed in the L2
/// @param l1Address the address in the L1 that triggered the tx to L2
/// @return l2Address L2 address as viewed in msg.sender
function applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {
unchecked {
l2Address = address(uint160(l1Address) + offset);
}
}
/// @notice Utility function that converts the msg.sender viewed in the L2 to the
/// address in the L1 that submitted a tx to the inbox
/// @param l2Address L2 address as viewed in msg.sender
/// @return l1Address the address in the L1 that triggered the tx to L2
function undoL1ToL2Alias(address l2Address) internal pure returns (address l1Address) {
unchecked {
l1Address = address(uint160(l2Address) - offset);
}
}
}{
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 10000
},
"remappings": [],
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"msgHash","type":"bytes32"}],"name":"FailedRelayedMessage","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"_xDomainCalldataHash","type":"bytes32"}],"name":"MessageAllowed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"_xDomainCalldataHash","type":"bytes32"}],"name":"MessageBlocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"msgHash","type":"bytes32"}],"name":"RelayedMessage","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes","name":"message","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"messageNonce","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"gasLimit","type":"uint256"}],"name":"SentMessage","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[{"internalType":"bytes32","name":"_xDomainCalldataHash","type":"bytes32"}],"name":"allowMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_xDomainCalldataHash","type":"bytes32"}],"name":"blockMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"blockedMessages","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_libAddressManager","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"libAddressManager","outputs":[{"internalType":"contract Lib_AddressManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"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 Lib_OVMCodec.ChainBatchHeader","name":"stateRootBatchHeader","type":"tuple"},{"components":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"bytes32[]","name":"siblings","type":"bytes32[]"}],"internalType":"struct Lib_OVMCodec.ChainInclusionProof","name":"stateRootProof","type":"tuple"},{"internalType":"bytes","name":"stateTrieWitness","type":"bytes"},{"internalType":"bytes","name":"storageTrieWitness","type":"bytes"}],"internalType":"struct IL1CrossDomainMessenger.L2MessageInclusionProof","name":"_proof","type":"tuple"}],"name":"relayMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"relayedMessages","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","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":"_queueIndex","type":"uint256"},{"internalType":"uint32","name":"_oldGasLimit","type":"uint32"},{"internalType":"uint32","name":"_newGasLimit","type":"uint32"}],"name":"replayMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"}],"name":"resolve","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_target","type":"address"},{"internalType":"bytes","name":"_message","type":"bytes"},{"internalType":"uint32","name":"_gasLimit","type":"uint32"}],"name":"sendMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"successfulMessages","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"xDomainMessageSender","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]Contract Creation Code
608060405260cc80546001600160a01b03191661dead17905534801561002457600080fd5b50600080546001600160a01b0319169055613c54806100446000396000f3fe608060405234801561001057600080fd5b506004361061011b5760003560e01c8063715018a6116100b2578063b1b1b20911610081578063c6b94ab011610066578063c6b94ab014610275578063d7fd19dd14610298578063f2fde38b146102ab57600080fd5b8063b1b1b2091461023f578063c4d66de81461026257600080fd5b8063715018a6146101fe57806381ada46c146102065780638456cb59146102195780638da5cb5b1461022157600080fd5b8063461a4478116100ee578063461a4478146101c55780635c975abb146101d85780636e296e45146101e35780636f1c8d47146101eb57600080fd5b80630ecf2eea1461012057806321d800ec14610135578063299ca4781461016d5780633dbb202b146101b2575b600080fd5b61013361012e36600461311d565b6102be565b005b61015861014336600461311d565b60ca6020526000908152604090205460ff1681565b60405190151581526020015b60405180910390f35b60005461018d9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610164565b6101336101c0366004613295565b61036d565b61018d6101d33660046132f5565b6104b5565b60655460ff16610158565b61018d610562565b6101336101f9366004613346565b6105ec565b6101336107d3565b61013361021436600461311d565b610846565b6101336108ed565b60335473ffffffffffffffffffffffffffffffffffffffff1661018d565b61015861024d36600461311d565b60cb6020526000908152604090205460ff1681565b6101336102703660046133d2565b61095c565b61015861028336600461311d565b60c96020526000908152604090205460ff1681565b6101336102a6366004613538565b610ba9565b6101336102b93660046133d2565b611078565b60335473ffffffffffffffffffffffffffffffffffffffff16331461032a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b600081815260c96020526040808220805460ff191660011790555182917ff52508d5339edf0d7e5060a416df98db067af561bdc60872d29c0439eaa13a0291a250565b60006103ad6040518060400160405280601981526020017f43616e6f6e6963616c5472616e73616374696f6e436861696e000000000000008152506104b5565b905060008173ffffffffffffffffffffffffffffffffffffffff1663b8f770056040518163ffffffff1660e01b815260040160206040518083038186803b1580156103f757600080fd5b505afa15801561040b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061042f9190613686565b905060006104468633878564ffffffffff16611174565b905061045983828663ffffffff166111ef565b8573ffffffffffffffffffffffffffffffffffffffff167fcb0f7ffd78f9aee47a248fae8db181db6eee833039123e026dcbff529522e52a338785886040516104a594939291906136fd565b60405180910390a2505050505050565b600080546040517fbf40fac100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169063bf40fac19061050c908590600401613750565b60206040518083038186803b15801561052457600080fd5b505afa158015610538573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061055c9190613763565b92915050565b60cc5460009073ffffffffffffffffffffffffffffffffffffffff1661dead14156105cf5760405162461bcd60e51b815260206004820152601f60248201527f78446f6d61696e4d65737361676553656e646572206973206e6f7420736574006044820152606401610321565b5060cc5473ffffffffffffffffffffffffffffffffffffffff1690565b600061062c6040518060400160405280601981526020017f43616e6f6e6963616c5472616e73616374696f6e436861696e000000000000008152506104b5565b6040517f2a7f18be0000000000000000000000000000000000000000000000000000000081526004810186905290915060009073ffffffffffffffffffffffffffffffffffffffff831690632a7f18be9060240160606040518083038186803b15801561069857600080fd5b505afa1580156106ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106d09190613780565b905060006106e089898989611174565b905060007311110000000000000000000000000000000011113001734200000000000000000000000000000000000007878460405160200161072594939291906137e5565b604051602081830303815290604052805190602001209050826000015181146107b65760405162461bcd60e51b815260206004820152602760248201527f50726f7669646564206d65737361676520686173206e6f74206265656e20656e60448201527f7175657565642e000000000000000000000000000000000000000000000000006064820152608401610321565b6107c784838763ffffffff166111ef565b50505050505050505050565b60335473ffffffffffffffffffffffffffffffffffffffff16331461083a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610321565b6108446000611290565b565b60335473ffffffffffffffffffffffffffffffffffffffff1633146108ad5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610321565b600081815260c96020526040808220805460ff191690555182917f52c8a2680a9f4cc0ad0bf88f32096eadbebf0646ea611d93a0ce6a29a024040591a250565b60335473ffffffffffffffffffffffffffffffffffffffff1633146109545760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610321565b610844611307565b6000547501000000000000000000000000000000000000000000900460ff16806109a1575060005474010000000000000000000000000000000000000000900460ff16155b610a135760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610321565b6000547501000000000000000000000000000000000000000000900460ff16158015610a7a57600080547fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff1675010100000000000000000000000000000000000000001790555b60005473ffffffffffffffffffffffffffffffffffffffff1615610b065760405162461bcd60e51b815260206004820152602a60248201527f4c3143726f7373446f6d61696e4d657373656e67657220616c7265616479206960448201527f6e7469616c697a65642e000000000000000000000000000000000000000000006064820152608401610321565b6000805473ffffffffffffffffffffffffffffffffffffffff84167fffffffffffffffffffffffff00000000000000000000000000000000000000009182161790915560cc805490911661dead179055610b5e6113b9565b610b66611508565b610b6e61162f565b610b76611788565b8015610ba557600080547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff1690555b5050565b60026097541415610bfc5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610321565b600260975560655460ff1615610c545760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610321565b6000610c6286868686611174565b9050610c6e81836118dc565b1515600114610ce55760405162461bcd60e51b815260206004820152602760248201527f50726f7669646564206d65737361676520636f756c64206e6f7420626520766560448201527f7269666965642e000000000000000000000000000000000000000000000000006064820152608401610321565b8051602080830191909120600081815260cb90925260409091205460ff1615610d765760405162461bcd60e51b815260206004820152602b60248201527f50726f7669646564206d6573736167652068617320616c72656164792062656560448201527f6e2072656365697665642e0000000000000000000000000000000000000000006064820152608401610321565b600081815260c9602052604090205460ff1615610dfb5760405162461bcd60e51b815260206004820152602260248201527f50726f7669646564206d65737361676520686173206265656e20626c6f636b6560448201527f642e0000000000000000000000000000000000000000000000000000000000006064820152608401610321565b610e396040518060400160405280601981526020017f43616e6f6e6963616c5472616e73616374696f6e436861696e000000000000008152506104b5565b73ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff161415610eda5760405162461bcd60e51b815260206004820152603360248201527f43616e6e6f742073656e64204c322d3e4c31206d6573736167657320746f204c60448201527f312073797374656d20636f6e7472616374732e000000000000000000000000006064820152608401610321565b60cc80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff88811691909117909155604051600091891690610f3390889061382a565b6000604051808303816000865af19150503d8060008114610f70576040519150601f19603f3d011682016040523d82523d6000602084013e610f75565b606091505b505060cc80547fffffffffffffffffffffffff00000000000000000000000000000000000000001661dead179055905080151560011415610ff557600082815260cb6020526040808220805460ff191660011790555183917f4641df4a962071e12719d8c8c8e5ac7fc4d97b927346a3d7a335b1f7517e133c91a2611021565b60405182907f99d0e048484baa1b1540b1367cb128acd7ab2946d1ed91ec10e3c85e4bf51b8f90600090a25b600083334360405160200161103893929190613846565b60408051601f198184030181529181528151602092830120600090815260ca9092529020805460ff19166001908117909155609755505050505050505050565b60335473ffffffffffffffffffffffffffffffffffffffff1633146110df5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610321565b73ffffffffffffffffffffffffffffffffffffffff81166111685760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610321565b61117181611290565b50565b60608484848460405160240161118d9493929190613898565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fcbd4ece9000000000000000000000000000000000000000000000000000000001790529050949350505050565b6040517f6fee07e000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841690636fee07e0906112599073420000000000000000000000000000000000000790859087906004016138e2565b600060405180830381600087803b15801561127357600080fd5b505af1158015611287573d6000803e3d6000fd5b50505050505050565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60655460ff161561135a5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610321565b6065805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861138f3390565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b6000547501000000000000000000000000000000000000000000900460ff16806113fe575060005474010000000000000000000000000000000000000000900460ff16155b6114705760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610321565b6000547501000000000000000000000000000000000000000000900460ff161580156114d757600080547fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff1675010100000000000000000000000000000000000000001790555b801561117157600080547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff16905550565b6000547501000000000000000000000000000000000000000000900460ff168061154d575060005474010000000000000000000000000000000000000000900460ff16155b6115bf5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610321565b6000547501000000000000000000000000000000000000000000900460ff1615801561162657600080547fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff1675010100000000000000000000000000000000000000001790555b6114d733611290565b6000547501000000000000000000000000000000000000000000900460ff1680611674575060005474010000000000000000000000000000000000000000900460ff16155b6116e65760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610321565b6000547501000000000000000000000000000000000000000000900460ff1615801561174d57600080547fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff1675010100000000000000000000000000000000000000001790555b6065805460ff19169055801561117157600080547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff16905550565b6000547501000000000000000000000000000000000000000000900460ff16806117cd575060005474010000000000000000000000000000000000000000900460ff16155b61183f5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610321565b6000547501000000000000000000000000000000000000000000900460ff161580156118a657600080547fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff1675010100000000000000000000000000000000000000001790555b6001609755801561117157600080547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff16905550565b60006118e7826118ff565b80156118f857506118f88383611aa1565b9392505050565b6000806119406040518060400160405280601481526020017f5374617465436f6d6d69746d656e74436861696e0000000000000000000000008152506104b5565b60208401516040517f9418bddd00000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff831691639418bddd9161199891600401613954565b60206040518083038186803b1580156119b057600080fd5b505afa1580156119c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119e89190613967565b1580156118f857508251602084015160408086015190517f4d69ee5700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff851693634d69ee5793611a51939192909190600401613989565b60206040518083038186803b158015611a6957600080fd5b505afa158015611a7d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118f89190613967565b60008083734200000000000000000000000000000000000007604051602001611acb929190613a01565b60408051601f1981840301815282825280516020918201209083015260009082015260600160408051601f198184030181529082905280516020918201207f42000000000000000000000000000000000000000000000000000000000000009183019190915291506000908190611b5b9060340160408051601f1981840301815291905260608701518751611c85565b9092509050600182151514611bfe5760405162461bcd60e51b815260206004820152604d60248201527f4d6573736167652070617373696e67207072656465706c6f7920686173206e6f60448201527f74206265656e20696e697469616c697a6564206f7220696e76616c696420707260648201527f6f6f662070726f76696465642e00000000000000000000000000000000000000608482015260a401610321565b6000611c0982611cae565b9050611c7a84604051602001611c2191815260200190565b60408051601f19818403018152908290527f010000000000000000000000000000000000000000000000000000000000000060208301529060210160405160208183030381529060405288608001518460400151611d72565b979650505050505050565b600060606000611c9486611d96565b9050611ca1818686611dc8565b9250925050935093915050565b604080516080810182526000808252602082018190529181018290526060810182905290611cdb83611ea3565b90506040518060800160405280611d0b83600081518110611cfe57611cfe613a4b565b6020026020010151611ed6565b8152602001611d2683600181518110611cfe57611cfe613a4b565b8152602001611d4e83600281518110611d4157611d41613a4b565b6020026020010151611edd565b8152602001611d6983600381518110611d4157611d41613a4b565b90529392505050565b600080611d7e86611d96565b9050611d8c81868686611fdf565b9695505050505050565b60608180519060200120604051602001611db291815260200190565b6040516020818303038152906040529050919050565b600060606000611dd785612015565b90506000806000611de9848a89612110565b81519295509093509150158080611dfd5750815b611e495760405162461bcd60e51b815260206004820152601a60248201527f50726f76696465642070726f6f6620697320696e76616c69642e0000000000006044820152606401610321565b600081611e655760405180602001604052806000815250611e91565b611e9186611e74600188613aa9565b81518110611e8457611e84613a4b565b60200260200101516125ab565b919b919a509098505050505050505050565b60408051808201825260008082526020918201528151808301909252825182528083019082015260609061055c906125d5565b600061055c825b6000602182600001511115611f345760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420524c5020627974657333322076616c75652e0000000000006044820152606401610321565b6000806000611f42856127d4565b919450925090506000816001811115611f5d57611f5d613ac0565b14611faa5760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420524c5020627974657333322076616c75652e0000000000006044820152606401610321565b6000838660200151611fbc9190613aef565b80519091506020841015611d8c5760208490036101000a90049695505050505050565b6000806000611fef878686611dc8565b91509150818015611c7a5750805160208083019190912087519188019190912014611c7a565b6060600061202283611ea3565b90506000815167ffffffffffffffff81111561204057612040613158565b60405190808252806020026020018201604052801561208557816020015b604080518082019091526060808252602082015281526020019060019003908161205e5790505b50905060005b82518110156121085760006120b88483815181106120ab576120ab613a4b565b6020026020010151612b25565b905060405180604001604052808281526020016120d483611ea3565b8152508383815181106120e9576120e9613a4b565b602002602001018190525050808061210090613b07565b91505061208b565b509392505050565b6000606081808061212087612bb5565b90506000869050600080612147604051806040016040528060608152602001606081525090565b60005b8c51811015612567578c818151811061216557612165613a4b565b60200260200101519150828461217b9190613aef565b9350612188600188613aef565b9650836121ec578151805160209091012085146121e75760405162461bcd60e51b815260206004820152601160248201527f496e76616c696420726f6f7420686173680000000000000000000000000000006044820152606401610321565b6122a9565b81515160201161224e578151805160209091012085146121e75760405162461bcd60e51b815260206004820152601b60248201527f496e76616c6964206c6172676520696e7465726e616c206861736800000000006044820152606401610321565b8461225c8360000151612d38565b146122a95760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420696e7465726e616c206e6f646520686173680000000000006044820152606401610321565b6122b560106001613aef565b826020015151141561232e5785518414156122cf57612567565b60008685815181106122e3576122e3613a4b565b602001015160f81c60f81b60f81c9050600083602001518260ff168151811061230e5761230e613a4b565b6020026020010151905061232181612d60565b9650600194505050612555565b6002826020015151141561250d57600061234783612d96565b905060008160008151811061235e5761235e613a4b565b016020015160f81c90506000612375600283613b6f565b612380906002613b91565b90506000612391848360ff16612dba565b9050600061239f8b8a612dba565b905060006123ad8383612df0565b905060ff8516600214806123c4575060ff85166003145b1561241a578083511480156123d95750808251145b156123eb576123e8818b613aef565b99505b507f80000000000000000000000000000000000000000000000000000000000000009950612567945050505050565b60ff8516158061242d575060ff85166001145b1561249f578251811461246957507f80000000000000000000000000000000000000000000000000000000000000009950612567945050505050565b612490886020015160018151811061248357612483613a4b565b6020026020010151612d60565b9a509750612555945050505050565b60405162461bcd60e51b815260206004820152602660248201527f52656365697665642061206e6f6465207769746820616e20756e6b6e6f776e2060448201527f70726566697800000000000000000000000000000000000000000000000000006064820152608401610321565b60405162461bcd60e51b815260206004820152601d60248201527f526563656976656420616e20756e706172736561626c65206e6f64652e0000006044820152606401610321565b8061255f81613b07565b91505061214a565b507f80000000000000000000000000000000000000000000000000000000000000008414866125968786612dba565b909e909d50909b509950505050505050505050565b6020810151805160609161055c916125c590600190613aa9565b815181106120ab576120ab613a4b565b60606000806125e3846127d4565b919350909150600190508160018111156125ff576125ff613ac0565b1461264c5760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420524c50206c6973742076616c75652e0000000000000000006044820152606401610321565b6040805160208082526104208201909252600091816020015b60408051808201909152600080825260208201528152602001906001900390816126655790505090506000835b86518110156127c957602082106127115760405162461bcd60e51b815260206004820152602a60248201527f50726f766964656420524c50206c6973742065786365656473206d6178206c6960448201527f7374206c656e6774682e000000000000000000000000000000000000000000006064820152608401610321565b60008061274e6040518060400160405280858c600001516127329190613aa9565b8152602001858c602001516127479190613aef565b90526127d4565b50915091506040518060400160405280838361276a9190613aef565b8152602001848b6020015161277f9190613aef565b81525085858151811061279457612794613a4b565b60209081029190910101526127aa600185613aef565b93506127b68183613aef565b6127c09084613aef565b92505050612692565b508152949350505050565b60008060008084600001511161282c5760405162461bcd60e51b815260206004820152601860248201527f524c50206974656d2063616e6e6f74206265206e756c6c2e00000000000000006044820152606401610321565b6020840151805160001a607f8111612851576000600160009450945094505050612b1e565b60b781116128cd576000612866608083613aa9565b9050808760000151116128bb5760405162461bcd60e51b815260206004820152601960248201527f496e76616c696420524c502073686f727420737472696e672e000000000000006044820152606401610321565b60019550935060009250612b1e915050565b60bf81116129bc5760006128e260b783613aa9565b9050808760000151116129375760405162461bcd60e51b815260206004820152601f60248201527f496e76616c696420524c50206c6f6e6720737472696e67206c656e6774682e006044820152606401610321565b600183015160208290036101000a90046129518183613aef565b8851116129a05760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420524c50206c6f6e6720737472696e672e00000000000000006044820152606401610321565b6129ab826001613aef565b9650945060009350612b1e92505050565b60f78111612a375760006129d160c083613aa9565b905080876000015111612a265760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420524c502073686f7274206c6973742e0000000000000000006044820152606401610321565b600195509350849250612b1e915050565b6000612a4460f783613aa9565b905080876000015111612a995760405162461bcd60e51b815260206004820152601d60248201527f496e76616c696420524c50206c6f6e67206c697374206c656e6774682e0000006044820152606401610321565b600183015160208290036101000a9004612ab38183613aef565b885111612b025760405162461bcd60e51b815260206004820152601660248201527f496e76616c696420524c50206c6f6e67206c6973742e000000000000000000006044820152606401610321565b612b0d826001613aef565b9650945060019350612b1e92505050565b9193909250565b60606000806000612b35856127d4565b919450925090506000816001811115612b5057612b50613ac0565b14612b9d5760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420524c502062797465732076616c75652e00000000000000006044820152606401610321565b612bac85602001518484612e9c565b95945050505050565b6060600082516002612bc79190613bb4565b67ffffffffffffffff811115612bdf57612bdf613158565b6040519080825280601f01601f191660200182016040528015612c09576020820181803683370190505b50905060005b8351811015612d31576004848281518110612c2c57612c2c613a4b565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016901c82612c61836002613bb4565b81518110612c7157612c71613a4b565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506010848281518110612cb457612cb4613a4b565b0160200151612cc6919060f81c613b6f565b60f81b82612cd5836002613bb4565b612ce0906001613aef565b81518110612cf057612cf0613a4b565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535080612d2981613b07565b915050612c0f565b5092915050565b6000602082511015612d4c57506020015190565b8180602001905181019061055c9190613bf1565b60006060602083600001511015612d8157612d7a83612f7b565b9050612d8d565b612d8a83612b25565b90505b6118f881612d38565b606061055c612db583602001516000815181106120ab576120ab613a4b565b612bb5565b606082518210612dd9575060408051602081019091526000815261055c565b6118f88383848651612deb9190613aa9565b612f86565b6000805b808451118015612e045750808351115b8015612e855750828181518110612e1d57612e1d613a4b565b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916848281518110612e5c57612e5c613a4b565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016145b156118f85780612e9481613b07565b915050612df4565b606060008267ffffffffffffffff811115612eb957612eb9613158565b6040519080825280601f01601f191660200182016040528015612ee3576020820181803683370190505b509050805160001415612ef75790506118f8565b6000612f038587613aef565b90506020820160005b612f17602087613c0a565b811015612f4e5782518252612f2d602084613aef565b9250612f3a602083613aef565b915080612f4681613b07565b915050612f0c565b5060006001602087066020036101000a039050808251168119845116178252839450505050509392505050565b606061055c82613107565b606081612f9481601f613aef565b1015612fe25760405162461bcd60e51b815260206004820152600e60248201527f736c6963655f6f766572666c6f770000000000000000000000000000000000006044820152606401610321565b82612fed8382613aef565b101561303b5760405162461bcd60e51b815260206004820152600e60248201527f736c6963655f6f766572666c6f770000000000000000000000000000000000006044820152606401610321565b6130458284613aef565b845110156130955760405162461bcd60e51b815260206004820152601160248201527f736c6963655f6f75744f66426f756e64730000000000000000000000000000006044820152606401610321565b6060821580156130b457604051915060008252602082016040526130fe565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156130ed5780518352602092830192016130d5565b5050858452601f01601f1916604052505b50949350505050565b606061055c826020015160008460000151612e9c565b60006020828403121561312f57600080fd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff8116811461117157600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff811182821017156131aa576131aa613158565b60405290565b60405160a0810167ffffffffffffffff811182821017156131aa576131aa613158565b604051601f8201601f1916810167ffffffffffffffff811182821017156131fc576131fc613158565b604052919050565b600067ffffffffffffffff83111561321e5761321e613158565b6132316020601f19601f860116016131d3565b905082815283838301111561324557600080fd5b828260208301376000602084830101529392505050565b600082601f83011261326d57600080fd5b6118f883833560208501613204565b803563ffffffff8116811461329057600080fd5b919050565b6000806000606084860312156132aa57600080fd5b83356132b581613136565b9250602084013567ffffffffffffffff8111156132d157600080fd5b6132dd8682870161325c565b9250506132ec6040850161327c565b90509250925092565b60006020828403121561330757600080fd5b813567ffffffffffffffff81111561331e57600080fd5b8201601f8101841361332f57600080fd5b61333e84823560208401613204565b949350505050565b60008060008060008060c0878903121561335f57600080fd5b863561336a81613136565b9550602087013561337a81613136565b9450604087013567ffffffffffffffff81111561339657600080fd5b6133a289828a0161325c565b945050606087013592506133b86080880161327c565b91506133c660a0880161327c565b90509295509295509295565b6000602082840312156133e457600080fd5b81356118f881613136565b600060a0828403121561340157600080fd5b60405160a0810167ffffffffffffffff828210818311171561342557613425613158565b8160405282935084358352602085013560208401526040850135604084015260608501356060840152608085013591508082111561346257600080fd5b5061346f8582860161325c565b6080830152505092915050565b60006040828403121561348e57600080fd5b613496613187565b90508135815260208083013567ffffffffffffffff808211156134b857600080fd5b818501915085601f8301126134cc57600080fd5b8135818111156134de576134de613158565b8060051b91506134ef8483016131d3565b818152918301840191848101908884111561350957600080fd5b938501935b838510156135275784358252938501939085019061350e565b808688015250505050505092915050565b600080600080600060a0868803121561355057600080fd5b853561355b81613136565b9450602086013561356b81613136565b9350604086013567ffffffffffffffff8082111561358857600080fd5b61359489838a0161325c565b94506060880135935060808801359150808211156135b157600080fd5b9087019060a0828a0312156135c557600080fd5b6135cd6131b0565b823581526020830135828111156135e357600080fd5b6135ef8b8286016133ef565b60208301525060408301358281111561360757600080fd5b6136138b82860161347c565b60408301525060608301358281111561362b57600080fd5b6136378b82860161325c565b60608301525060808301358281111561364f57600080fd5b61365b8b82860161325c565b6080830152508093505050509295509295909350565b805164ffffffffff8116811461329057600080fd5b60006020828403121561369857600080fd5b6118f882613671565b60005b838110156136bc5781810151838201526020016136a4565b838111156136cb576000848401525b50505050565b600081518084526136e98160208601602086016136a1565b601f01601f19169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff8516815260806020820152600061372c60808301866136d1565b905064ffffffffff8416604083015263ffffffff8316606083015295945050505050565b6020815260006118f860208301846136d1565b60006020828403121561377557600080fd5b81516118f881613136565b60006060828403121561379257600080fd5b6040516060810181811067ffffffffffffffff821117156137b5576137b5613158565b604052825181526137c860208401613671565b60208201526137d960408401613671565b60408201529392505050565b600073ffffffffffffffffffffffffffffffffffffffff808716835280861660208401525063ffffffff8416604083015260806060830152611d8c60808301846136d1565b6000825161383c8184602087016136a1565b9190910192915050565b600084516138588184602089016136a1565b60609490941b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001691909301908152601481019190915260340192915050565b600073ffffffffffffffffffffffffffffffffffffffff8087168352808616602084015250608060408301526138d160808301856136d1565b905082606083015295945050505050565b73ffffffffffffffffffffffffffffffffffffffff84168152826020820152606060408201526000612bac60608301846136d1565b805182526020810151602083015260408101516040830152606081015160608301526000608082015160a0608085015261333e60a08501826136d1565b6020815260006118f86020830184613917565b60006020828403121561397957600080fd5b815180151581146118f857600080fd5b838152600060206060818401526139a36060840186613917565b83810360408501526040810185518252828601516040848401528181518084526060850191508583019450600093505b808410156139f357845182529385019360019390930192908501906139d3565b509998505050505050505050565b60008351613a138184602088016136a1565b60609390931b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000169190920190815260140192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082821015613abb57613abb613a7a565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60008219821115613b0257613b02613a7a565b500190565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415613b3957613b39613a7a565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600060ff831680613b8257613b82613b40565b8060ff84160691505092915050565b600060ff821660ff841680821015613bab57613bab613a7a565b90039392505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615613bec57613bec613a7a565b500290565b600060208284031215613c0357600080fd5b5051919050565b600082613c1957613c19613b40565b50049056fea26469706673582212209e0153d10142c4c28c6e3b5fe87c4f9f3e12f0acdc7b9f2e0b67f55f3257cfb464736f6c63430008090033
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061011b5760003560e01c8063715018a6116100b2578063b1b1b20911610081578063c6b94ab011610066578063c6b94ab014610275578063d7fd19dd14610298578063f2fde38b146102ab57600080fd5b8063b1b1b2091461023f578063c4d66de81461026257600080fd5b8063715018a6146101fe57806381ada46c146102065780638456cb59146102195780638da5cb5b1461022157600080fd5b8063461a4478116100ee578063461a4478146101c55780635c975abb146101d85780636e296e45146101e35780636f1c8d47146101eb57600080fd5b80630ecf2eea1461012057806321d800ec14610135578063299ca4781461016d5780633dbb202b146101b2575b600080fd5b61013361012e36600461311d565b6102be565b005b61015861014336600461311d565b60ca6020526000908152604090205460ff1681565b60405190151581526020015b60405180910390f35b60005461018d9073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610164565b6101336101c0366004613295565b61036d565b61018d6101d33660046132f5565b6104b5565b60655460ff16610158565b61018d610562565b6101336101f9366004613346565b6105ec565b6101336107d3565b61013361021436600461311d565b610846565b6101336108ed565b60335473ffffffffffffffffffffffffffffffffffffffff1661018d565b61015861024d36600461311d565b60cb6020526000908152604090205460ff1681565b6101336102703660046133d2565b61095c565b61015861028336600461311d565b60c96020526000908152604090205460ff1681565b6101336102a6366004613538565b610ba9565b6101336102b93660046133d2565b611078565b60335473ffffffffffffffffffffffffffffffffffffffff16331461032a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064015b60405180910390fd5b600081815260c96020526040808220805460ff191660011790555182917ff52508d5339edf0d7e5060a416df98db067af561bdc60872d29c0439eaa13a0291a250565b60006103ad6040518060400160405280601981526020017f43616e6f6e6963616c5472616e73616374696f6e436861696e000000000000008152506104b5565b905060008173ffffffffffffffffffffffffffffffffffffffff1663b8f770056040518163ffffffff1660e01b815260040160206040518083038186803b1580156103f757600080fd5b505afa15801561040b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061042f9190613686565b905060006104468633878564ffffffffff16611174565b905061045983828663ffffffff166111ef565b8573ffffffffffffffffffffffffffffffffffffffff167fcb0f7ffd78f9aee47a248fae8db181db6eee833039123e026dcbff529522e52a338785886040516104a594939291906136fd565b60405180910390a2505050505050565b600080546040517fbf40fac100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9091169063bf40fac19061050c908590600401613750565b60206040518083038186803b15801561052457600080fd5b505afa158015610538573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061055c9190613763565b92915050565b60cc5460009073ffffffffffffffffffffffffffffffffffffffff1661dead14156105cf5760405162461bcd60e51b815260206004820152601f60248201527f78446f6d61696e4d65737361676553656e646572206973206e6f7420736574006044820152606401610321565b5060cc5473ffffffffffffffffffffffffffffffffffffffff1690565b600061062c6040518060400160405280601981526020017f43616e6f6e6963616c5472616e73616374696f6e436861696e000000000000008152506104b5565b6040517f2a7f18be0000000000000000000000000000000000000000000000000000000081526004810186905290915060009073ffffffffffffffffffffffffffffffffffffffff831690632a7f18be9060240160606040518083038186803b15801561069857600080fd5b505afa1580156106ac573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106d09190613780565b905060006106e089898989611174565b905060007311110000000000000000000000000000000011113001734200000000000000000000000000000000000007878460405160200161072594939291906137e5565b604051602081830303815290604052805190602001209050826000015181146107b65760405162461bcd60e51b815260206004820152602760248201527f50726f7669646564206d65737361676520686173206e6f74206265656e20656e60448201527f7175657565642e000000000000000000000000000000000000000000000000006064820152608401610321565b6107c784838763ffffffff166111ef565b50505050505050505050565b60335473ffffffffffffffffffffffffffffffffffffffff16331461083a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610321565b6108446000611290565b565b60335473ffffffffffffffffffffffffffffffffffffffff1633146108ad5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610321565b600081815260c96020526040808220805460ff191690555182917f52c8a2680a9f4cc0ad0bf88f32096eadbebf0646ea611d93a0ce6a29a024040591a250565b60335473ffffffffffffffffffffffffffffffffffffffff1633146109545760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610321565b610844611307565b6000547501000000000000000000000000000000000000000000900460ff16806109a1575060005474010000000000000000000000000000000000000000900460ff16155b610a135760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610321565b6000547501000000000000000000000000000000000000000000900460ff16158015610a7a57600080547fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff1675010100000000000000000000000000000000000000001790555b60005473ffffffffffffffffffffffffffffffffffffffff1615610b065760405162461bcd60e51b815260206004820152602a60248201527f4c3143726f7373446f6d61696e4d657373656e67657220616c7265616479206960448201527f6e7469616c697a65642e000000000000000000000000000000000000000000006064820152608401610321565b6000805473ffffffffffffffffffffffffffffffffffffffff84167fffffffffffffffffffffffff00000000000000000000000000000000000000009182161790915560cc805490911661dead179055610b5e6113b9565b610b66611508565b610b6e61162f565b610b76611788565b8015610ba557600080547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff1690555b5050565b60026097541415610bfc5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401610321565b600260975560655460ff1615610c545760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610321565b6000610c6286868686611174565b9050610c6e81836118dc565b1515600114610ce55760405162461bcd60e51b815260206004820152602760248201527f50726f7669646564206d65737361676520636f756c64206e6f7420626520766560448201527f7269666965642e000000000000000000000000000000000000000000000000006064820152608401610321565b8051602080830191909120600081815260cb90925260409091205460ff1615610d765760405162461bcd60e51b815260206004820152602b60248201527f50726f7669646564206d6573736167652068617320616c72656164792062656560448201527f6e2072656365697665642e0000000000000000000000000000000000000000006064820152608401610321565b600081815260c9602052604090205460ff1615610dfb5760405162461bcd60e51b815260206004820152602260248201527f50726f7669646564206d65737361676520686173206265656e20626c6f636b6560448201527f642e0000000000000000000000000000000000000000000000000000000000006064820152608401610321565b610e396040518060400160405280601981526020017f43616e6f6e6963616c5472616e73616374696f6e436861696e000000000000008152506104b5565b73ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff161415610eda5760405162461bcd60e51b815260206004820152603360248201527f43616e6e6f742073656e64204c322d3e4c31206d6573736167657320746f204c60448201527f312073797374656d20636f6e7472616374732e000000000000000000000000006064820152608401610321565b60cc80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff88811691909117909155604051600091891690610f3390889061382a565b6000604051808303816000865af19150503d8060008114610f70576040519150601f19603f3d011682016040523d82523d6000602084013e610f75565b606091505b505060cc80547fffffffffffffffffffffffff00000000000000000000000000000000000000001661dead179055905080151560011415610ff557600082815260cb6020526040808220805460ff191660011790555183917f4641df4a962071e12719d8c8c8e5ac7fc4d97b927346a3d7a335b1f7517e133c91a2611021565b60405182907f99d0e048484baa1b1540b1367cb128acd7ab2946d1ed91ec10e3c85e4bf51b8f90600090a25b600083334360405160200161103893929190613846565b60408051601f198184030181529181528151602092830120600090815260ca9092529020805460ff19166001908117909155609755505050505050505050565b60335473ffffffffffffffffffffffffffffffffffffffff1633146110df5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610321565b73ffffffffffffffffffffffffffffffffffffffff81166111685760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610321565b61117181611290565b50565b60608484848460405160240161118d9493929190613898565b60408051601f198184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fcbd4ece9000000000000000000000000000000000000000000000000000000001790529050949350505050565b6040517f6fee07e000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff841690636fee07e0906112599073420000000000000000000000000000000000000790859087906004016138e2565b600060405180830381600087803b15801561127357600080fd5b505af1158015611287573d6000803e3d6000fd5b50505050505050565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60655460ff161561135a5760405162461bcd60e51b815260206004820152601060248201527f5061757361626c653a20706175736564000000000000000000000000000000006044820152606401610321565b6065805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25861138f3390565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390a1565b6000547501000000000000000000000000000000000000000000900460ff16806113fe575060005474010000000000000000000000000000000000000000900460ff16155b6114705760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610321565b6000547501000000000000000000000000000000000000000000900460ff161580156114d757600080547fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff1675010100000000000000000000000000000000000000001790555b801561117157600080547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff16905550565b6000547501000000000000000000000000000000000000000000900460ff168061154d575060005474010000000000000000000000000000000000000000900460ff16155b6115bf5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610321565b6000547501000000000000000000000000000000000000000000900460ff1615801561162657600080547fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff1675010100000000000000000000000000000000000000001790555b6114d733611290565b6000547501000000000000000000000000000000000000000000900460ff1680611674575060005474010000000000000000000000000000000000000000900460ff16155b6116e65760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610321565b6000547501000000000000000000000000000000000000000000900460ff1615801561174d57600080547fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff1675010100000000000000000000000000000000000000001790555b6065805460ff19169055801561117157600080547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff16905550565b6000547501000000000000000000000000000000000000000000900460ff16806117cd575060005474010000000000000000000000000000000000000000900460ff16155b61183f5760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610321565b6000547501000000000000000000000000000000000000000000900460ff161580156118a657600080547fffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffff1675010100000000000000000000000000000000000000001790555b6001609755801561117157600080547fffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff16905550565b60006118e7826118ff565b80156118f857506118f88383611aa1565b9392505050565b6000806119406040518060400160405280601481526020017f5374617465436f6d6d69746d656e74436861696e0000000000000000000000008152506104b5565b60208401516040517f9418bddd00000000000000000000000000000000000000000000000000000000815291925073ffffffffffffffffffffffffffffffffffffffff831691639418bddd9161199891600401613954565b60206040518083038186803b1580156119b057600080fd5b505afa1580156119c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119e89190613967565b1580156118f857508251602084015160408086015190517f4d69ee5700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff851693634d69ee5793611a51939192909190600401613989565b60206040518083038186803b158015611a6957600080fd5b505afa158015611a7d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118f89190613967565b60008083734200000000000000000000000000000000000007604051602001611acb929190613a01565b60408051601f1981840301815282825280516020918201209083015260009082015260600160408051601f198184030181529082905280516020918201207f42000000000000000000000000000000000000000000000000000000000000009183019190915291506000908190611b5b9060340160408051601f1981840301815291905260608701518751611c85565b9092509050600182151514611bfe5760405162461bcd60e51b815260206004820152604d60248201527f4d6573736167652070617373696e67207072656465706c6f7920686173206e6f60448201527f74206265656e20696e697469616c697a6564206f7220696e76616c696420707260648201527f6f6f662070726f76696465642e00000000000000000000000000000000000000608482015260a401610321565b6000611c0982611cae565b9050611c7a84604051602001611c2191815260200190565b60408051601f19818403018152908290527f010000000000000000000000000000000000000000000000000000000000000060208301529060210160405160208183030381529060405288608001518460400151611d72565b979650505050505050565b600060606000611c9486611d96565b9050611ca1818686611dc8565b9250925050935093915050565b604080516080810182526000808252602082018190529181018290526060810182905290611cdb83611ea3565b90506040518060800160405280611d0b83600081518110611cfe57611cfe613a4b565b6020026020010151611ed6565b8152602001611d2683600181518110611cfe57611cfe613a4b565b8152602001611d4e83600281518110611d4157611d41613a4b565b6020026020010151611edd565b8152602001611d6983600381518110611d4157611d41613a4b565b90529392505050565b600080611d7e86611d96565b9050611d8c81868686611fdf565b9695505050505050565b60608180519060200120604051602001611db291815260200190565b6040516020818303038152906040529050919050565b600060606000611dd785612015565b90506000806000611de9848a89612110565b81519295509093509150158080611dfd5750815b611e495760405162461bcd60e51b815260206004820152601a60248201527f50726f76696465642070726f6f6620697320696e76616c69642e0000000000006044820152606401610321565b600081611e655760405180602001604052806000815250611e91565b611e9186611e74600188613aa9565b81518110611e8457611e84613a4b565b60200260200101516125ab565b919b919a509098505050505050505050565b60408051808201825260008082526020918201528151808301909252825182528083019082015260609061055c906125d5565b600061055c825b6000602182600001511115611f345760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420524c5020627974657333322076616c75652e0000000000006044820152606401610321565b6000806000611f42856127d4565b919450925090506000816001811115611f5d57611f5d613ac0565b14611faa5760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420524c5020627974657333322076616c75652e0000000000006044820152606401610321565b6000838660200151611fbc9190613aef565b80519091506020841015611d8c5760208490036101000a90049695505050505050565b6000806000611fef878686611dc8565b91509150818015611c7a5750805160208083019190912087519188019190912014611c7a565b6060600061202283611ea3565b90506000815167ffffffffffffffff81111561204057612040613158565b60405190808252806020026020018201604052801561208557816020015b604080518082019091526060808252602082015281526020019060019003908161205e5790505b50905060005b82518110156121085760006120b88483815181106120ab576120ab613a4b565b6020026020010151612b25565b905060405180604001604052808281526020016120d483611ea3565b8152508383815181106120e9576120e9613a4b565b602002602001018190525050808061210090613b07565b91505061208b565b509392505050565b6000606081808061212087612bb5565b90506000869050600080612147604051806040016040528060608152602001606081525090565b60005b8c51811015612567578c818151811061216557612165613a4b565b60200260200101519150828461217b9190613aef565b9350612188600188613aef565b9650836121ec578151805160209091012085146121e75760405162461bcd60e51b815260206004820152601160248201527f496e76616c696420726f6f7420686173680000000000000000000000000000006044820152606401610321565b6122a9565b81515160201161224e578151805160209091012085146121e75760405162461bcd60e51b815260206004820152601b60248201527f496e76616c6964206c6172676520696e7465726e616c206861736800000000006044820152606401610321565b8461225c8360000151612d38565b146122a95760405162461bcd60e51b815260206004820152601a60248201527f496e76616c696420696e7465726e616c206e6f646520686173680000000000006044820152606401610321565b6122b560106001613aef565b826020015151141561232e5785518414156122cf57612567565b60008685815181106122e3576122e3613a4b565b602001015160f81c60f81b60f81c9050600083602001518260ff168151811061230e5761230e613a4b565b6020026020010151905061232181612d60565b9650600194505050612555565b6002826020015151141561250d57600061234783612d96565b905060008160008151811061235e5761235e613a4b565b016020015160f81c90506000612375600283613b6f565b612380906002613b91565b90506000612391848360ff16612dba565b9050600061239f8b8a612dba565b905060006123ad8383612df0565b905060ff8516600214806123c4575060ff85166003145b1561241a578083511480156123d95750808251145b156123eb576123e8818b613aef565b99505b507f80000000000000000000000000000000000000000000000000000000000000009950612567945050505050565b60ff8516158061242d575060ff85166001145b1561249f578251811461246957507f80000000000000000000000000000000000000000000000000000000000000009950612567945050505050565b612490886020015160018151811061248357612483613a4b565b6020026020010151612d60565b9a509750612555945050505050565b60405162461bcd60e51b815260206004820152602660248201527f52656365697665642061206e6f6465207769746820616e20756e6b6e6f776e2060448201527f70726566697800000000000000000000000000000000000000000000000000006064820152608401610321565b60405162461bcd60e51b815260206004820152601d60248201527f526563656976656420616e20756e706172736561626c65206e6f64652e0000006044820152606401610321565b8061255f81613b07565b91505061214a565b507f80000000000000000000000000000000000000000000000000000000000000008414866125968786612dba565b909e909d50909b509950505050505050505050565b6020810151805160609161055c916125c590600190613aa9565b815181106120ab576120ab613a4b565b60606000806125e3846127d4565b919350909150600190508160018111156125ff576125ff613ac0565b1461264c5760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420524c50206c6973742076616c75652e0000000000000000006044820152606401610321565b6040805160208082526104208201909252600091816020015b60408051808201909152600080825260208201528152602001906001900390816126655790505090506000835b86518110156127c957602082106127115760405162461bcd60e51b815260206004820152602a60248201527f50726f766964656420524c50206c6973742065786365656473206d6178206c6960448201527f7374206c656e6774682e000000000000000000000000000000000000000000006064820152608401610321565b60008061274e6040518060400160405280858c600001516127329190613aa9565b8152602001858c602001516127479190613aef565b90526127d4565b50915091506040518060400160405280838361276a9190613aef565b8152602001848b6020015161277f9190613aef565b81525085858151811061279457612794613a4b565b60209081029190910101526127aa600185613aef565b93506127b68183613aef565b6127c09084613aef565b92505050612692565b508152949350505050565b60008060008084600001511161282c5760405162461bcd60e51b815260206004820152601860248201527f524c50206974656d2063616e6e6f74206265206e756c6c2e00000000000000006044820152606401610321565b6020840151805160001a607f8111612851576000600160009450945094505050612b1e565b60b781116128cd576000612866608083613aa9565b9050808760000151116128bb5760405162461bcd60e51b815260206004820152601960248201527f496e76616c696420524c502073686f727420737472696e672e000000000000006044820152606401610321565b60019550935060009250612b1e915050565b60bf81116129bc5760006128e260b783613aa9565b9050808760000151116129375760405162461bcd60e51b815260206004820152601f60248201527f496e76616c696420524c50206c6f6e6720737472696e67206c656e6774682e006044820152606401610321565b600183015160208290036101000a90046129518183613aef565b8851116129a05760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420524c50206c6f6e6720737472696e672e00000000000000006044820152606401610321565b6129ab826001613aef565b9650945060009350612b1e92505050565b60f78111612a375760006129d160c083613aa9565b905080876000015111612a265760405162461bcd60e51b815260206004820152601760248201527f496e76616c696420524c502073686f7274206c6973742e0000000000000000006044820152606401610321565b600195509350849250612b1e915050565b6000612a4460f783613aa9565b905080876000015111612a995760405162461bcd60e51b815260206004820152601d60248201527f496e76616c696420524c50206c6f6e67206c697374206c656e6774682e0000006044820152606401610321565b600183015160208290036101000a9004612ab38183613aef565b885111612b025760405162461bcd60e51b815260206004820152601660248201527f496e76616c696420524c50206c6f6e67206c6973742e000000000000000000006044820152606401610321565b612b0d826001613aef565b9650945060019350612b1e92505050565b9193909250565b60606000806000612b35856127d4565b919450925090506000816001811115612b5057612b50613ac0565b14612b9d5760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420524c502062797465732076616c75652e00000000000000006044820152606401610321565b612bac85602001518484612e9c565b95945050505050565b6060600082516002612bc79190613bb4565b67ffffffffffffffff811115612bdf57612bdf613158565b6040519080825280601f01601f191660200182016040528015612c09576020820181803683370190505b50905060005b8351811015612d31576004848281518110612c2c57612c2c613a4b565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016901c82612c61836002613bb4565b81518110612c7157612c71613a4b565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a9053506010848281518110612cb457612cb4613a4b565b0160200151612cc6919060f81c613b6f565b60f81b82612cd5836002613bb4565b612ce0906001613aef565b81518110612cf057612cf0613a4b565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535080612d2981613b07565b915050612c0f565b5092915050565b6000602082511015612d4c57506020015190565b8180602001905181019061055c9190613bf1565b60006060602083600001511015612d8157612d7a83612f7b565b9050612d8d565b612d8a83612b25565b90505b6118f881612d38565b606061055c612db583602001516000815181106120ab576120ab613a4b565b612bb5565b606082518210612dd9575060408051602081019091526000815261055c565b6118f88383848651612deb9190613aa9565b612f86565b6000805b808451118015612e045750808351115b8015612e855750828181518110612e1d57612e1d613a4b565b602001015160f81c60f81b7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916848281518110612e5c57612e5c613a4b565b01602001517fff0000000000000000000000000000000000000000000000000000000000000016145b156118f85780612e9481613b07565b915050612df4565b606060008267ffffffffffffffff811115612eb957612eb9613158565b6040519080825280601f01601f191660200182016040528015612ee3576020820181803683370190505b509050805160001415612ef75790506118f8565b6000612f038587613aef565b90506020820160005b612f17602087613c0a565b811015612f4e5782518252612f2d602084613aef565b9250612f3a602083613aef565b915080612f4681613b07565b915050612f0c565b5060006001602087066020036101000a039050808251168119845116178252839450505050509392505050565b606061055c82613107565b606081612f9481601f613aef565b1015612fe25760405162461bcd60e51b815260206004820152600e60248201527f736c6963655f6f766572666c6f770000000000000000000000000000000000006044820152606401610321565b82612fed8382613aef565b101561303b5760405162461bcd60e51b815260206004820152600e60248201527f736c6963655f6f766572666c6f770000000000000000000000000000000000006044820152606401610321565b6130458284613aef565b845110156130955760405162461bcd60e51b815260206004820152601160248201527f736c6963655f6f75744f66426f756e64730000000000000000000000000000006044820152606401610321565b6060821580156130b457604051915060008252602082016040526130fe565b6040519150601f8416801560200281840101858101878315602002848b0101015b818310156130ed5780518352602092830192016130d5565b5050858452601f01601f1916604052505b50949350505050565b606061055c826020015160008460000151612e9c565b60006020828403121561312f57600080fd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff8116811461117157600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff811182821017156131aa576131aa613158565b60405290565b60405160a0810167ffffffffffffffff811182821017156131aa576131aa613158565b604051601f8201601f1916810167ffffffffffffffff811182821017156131fc576131fc613158565b604052919050565b600067ffffffffffffffff83111561321e5761321e613158565b6132316020601f19601f860116016131d3565b905082815283838301111561324557600080fd5b828260208301376000602084830101529392505050565b600082601f83011261326d57600080fd5b6118f883833560208501613204565b803563ffffffff8116811461329057600080fd5b919050565b6000806000606084860312156132aa57600080fd5b83356132b581613136565b9250602084013567ffffffffffffffff8111156132d157600080fd5b6132dd8682870161325c565b9250506132ec6040850161327c565b90509250925092565b60006020828403121561330757600080fd5b813567ffffffffffffffff81111561331e57600080fd5b8201601f8101841361332f57600080fd5b61333e84823560208401613204565b949350505050565b60008060008060008060c0878903121561335f57600080fd5b863561336a81613136565b9550602087013561337a81613136565b9450604087013567ffffffffffffffff81111561339657600080fd5b6133a289828a0161325c565b945050606087013592506133b86080880161327c565b91506133c660a0880161327c565b90509295509295509295565b6000602082840312156133e457600080fd5b81356118f881613136565b600060a0828403121561340157600080fd5b60405160a0810167ffffffffffffffff828210818311171561342557613425613158565b8160405282935084358352602085013560208401526040850135604084015260608501356060840152608085013591508082111561346257600080fd5b5061346f8582860161325c565b6080830152505092915050565b60006040828403121561348e57600080fd5b613496613187565b90508135815260208083013567ffffffffffffffff808211156134b857600080fd5b818501915085601f8301126134cc57600080fd5b8135818111156134de576134de613158565b8060051b91506134ef8483016131d3565b818152918301840191848101908884111561350957600080fd5b938501935b838510156135275784358252938501939085019061350e565b808688015250505050505092915050565b600080600080600060a0868803121561355057600080fd5b853561355b81613136565b9450602086013561356b81613136565b9350604086013567ffffffffffffffff8082111561358857600080fd5b61359489838a0161325c565b94506060880135935060808801359150808211156135b157600080fd5b9087019060a0828a0312156135c557600080fd5b6135cd6131b0565b823581526020830135828111156135e357600080fd5b6135ef8b8286016133ef565b60208301525060408301358281111561360757600080fd5b6136138b82860161347c565b60408301525060608301358281111561362b57600080fd5b6136378b82860161325c565b60608301525060808301358281111561364f57600080fd5b61365b8b82860161325c565b6080830152508093505050509295509295909350565b805164ffffffffff8116811461329057600080fd5b60006020828403121561369857600080fd5b6118f882613671565b60005b838110156136bc5781810151838201526020016136a4565b838111156136cb576000848401525b50505050565b600081518084526136e98160208601602086016136a1565b601f01601f19169290920160200192915050565b73ffffffffffffffffffffffffffffffffffffffff8516815260806020820152600061372c60808301866136d1565b905064ffffffffff8416604083015263ffffffff8316606083015295945050505050565b6020815260006118f860208301846136d1565b60006020828403121561377557600080fd5b81516118f881613136565b60006060828403121561379257600080fd5b6040516060810181811067ffffffffffffffff821117156137b5576137b5613158565b604052825181526137c860208401613671565b60208201526137d960408401613671565b60408201529392505050565b600073ffffffffffffffffffffffffffffffffffffffff808716835280861660208401525063ffffffff8416604083015260806060830152611d8c60808301846136d1565b6000825161383c8184602087016136a1565b9190910192915050565b600084516138588184602089016136a1565b60609490941b7fffffffffffffffffffffffffffffffffffffffff0000000000000000000000001691909301908152601481019190915260340192915050565b600073ffffffffffffffffffffffffffffffffffffffff8087168352808616602084015250608060408301526138d160808301856136d1565b905082606083015295945050505050565b73ffffffffffffffffffffffffffffffffffffffff84168152826020820152606060408201526000612bac60608301846136d1565b805182526020810151602083015260408101516040830152606081015160608301526000608082015160a0608085015261333e60a08501826136d1565b6020815260006118f86020830184613917565b60006020828403121561397957600080fd5b815180151581146118f857600080fd5b838152600060206060818401526139a36060840186613917565b83810360408501526040810185518252828601516040848401528181518084526060850191508583019450600093505b808410156139f357845182529385019360019390930192908501906139d3565b509998505050505050505050565b60008351613a138184602088016136a1565b60609390931b7fffffffffffffffffffffffffffffffffffffffff000000000000000000000000169190920190815260140192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082821015613abb57613abb613a7a565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60008219821115613b0257613b02613a7a565b500190565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415613b3957613b39613a7a565b5060010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600060ff831680613b8257613b82613b40565b8060ff84160691505092915050565b600060ff821660ff841680821015613bab57613bab613a7a565b90039392505050565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615613bec57613bec613a7a565b500290565b600060208284031215613c0357600080fd5b5051919050565b600082613c1957613c19613b40565b50049056fea26469706673582212209e0153d10142c4c28c6e3b5fe87c4f9f3e12f0acdc7b9f2e0b67f55f3257cfb464736f6c63430008090033
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
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.