More Info
My Name Tag:
Not Available, login to update
[ Download CSV Export ]
View more zero value Internal Transactions in Advanced View mode
Contract Name:
FxCacheRootTunnel
Compiler Version
v0.8.11+commit.d7f03943
Optimization Enabled:
No with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.11; import {ERC20} from "../../lib/ERC20.sol"; import {FxBaseRootTunnel} from "../../tunnel/FxBaseRootTunnel.sol"; import {SafeERC20, IERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; /** * @title FxERC20RootTunnel */ contract FxCacheRootTunnel is FxBaseRootTunnel { using SafeERC20 for IERC20; // maybe DEPOSIT and MAP_TOKEN can be reduced to bytes4 bytes32 public constant DEPOSIT = keccak256("DEPOSIT"); bytes32 public constant MAP_TOKEN = keccak256("MAP_TOKEN"); mapping(address => address) public rootToChildTokens; event TokenMappedERC20(address indexed rootToken, address indexed childToken); event FxWithdrawERC20( address indexed rootToken, address indexed childToken, address indexed userAddress, uint256 amount ); event FxDepositERC20( address indexed rootToken, address indexed depositor, address indexed userAddress, uint256 amount ); constructor( address _checkpointManager, address _fxRoot ) FxBaseRootTunnel(_checkpointManager, _fxRoot) { } /** * @notice Map a token to enable its movement via the Polygon PoS network * @param rootToken address of token on root chain */ function mapToken(address rootToken, address _childToken) public { // check if token is already mapped require(rootToChildTokens[rootToken] == address(0x0), "FxERC20RootTunnel: ALREADY_MAPPED"); // MAP_TOKEN, encode(rootToken, _childToken) bytes memory message = abi.encode(MAP_TOKEN, abi.encode(rootToken, _childToken)); _sendMessageToChild(message); // add into mapped tokens rootToChildTokens[rootToken] = _childToken; emit TokenMappedERC20(rootToken, _childToken); } function deposit( address rootToken, address childToken, address user, uint256 amount, bytes memory data ) public { // map token if not mapped if (rootToChildTokens[rootToken] == address(0x0)) { mapToken(rootToken, childToken); } // transfer from depositor to this contract IERC20(rootToken).safeTransferFrom( msg.sender, // depositor address(this), // manager contract amount ); // DEPOSIT, encode(rootToken, depositor, user, amount, extra data) bytes memory message = abi.encode(DEPOSIT, abi.encode(rootToken, msg.sender, user, amount, data)); _sendMessageToChild(message); emit FxDepositERC20(rootToken, msg.sender, user, amount); } // exit processor function _processMessageFromChild(bytes memory data) internal override { (address rootToken, address childToken, address to, uint256 amount) = abi.decode( data, (address, address, address, uint256) ); // validate mapping for root to child require(rootToChildTokens[rootToken] == childToken, "FxERC20RootTunnel: INVALID_MAPPING_ON_EXIT"); // transfer from tokens to IERC20(rootToken).safeTransfer(to, amount); emit FxWithdrawERC20(rootToken, childToken, to, amount); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.11; import {IERC20} from "./IERC20.sol"; import {SafeMath} from "./SafeMath.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is IERC20 { using SafeMath for uint256; mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; uint8 private _decimals; /** * @dev Returns the name of the token. */ function name() public view returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5,05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is * called. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view returns (uint8) { return _decimals; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public virtual override returns (bool) { _transfer(msg.sender, recipient, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { _approve(msg.sender, spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * Requirements: * * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for ``sender``'s tokens of at least * `amount`. */ function transferFrom( address sender, address recipient, uint256 amount ) public virtual override returns (bool) { _transfer(sender, recipient, amount); _approve( sender, msg.sender, _allowances[sender][msg.sender].sub(amount, "ERC20: transfer amount exceeds allowance") ); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { _approve(msg.sender, spender, _allowances[msg.sender][spender].add(addedValue)); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { _approve( msg.sender, spender, _allowances[msg.sender][spender].sub(subtractedValue, "ERC20: decreased allowance below zero") ); return true; } /** * @dev Moves tokens `amount` from `sender` to `recipient`. * * This is internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer( address sender, address recipient, uint256 amount ) internal virtual { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(sender, recipient, amount); _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `to` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); emit Transfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); _totalSupply = _totalSupply.sub(amount); emit Transfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve( address owner, address spender, uint256 amount ) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } function _setupMetaData( string memory name_, string memory symbol_, uint8 decimals_ ) internal virtual { _name = name_; _symbol = symbol_; _decimals = decimals_; } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be to transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address from, address to, uint256 amount ) internal virtual {} }
// SPDX-License-Identifier: MIT pragma solidity 0.8.11; import {RLPReader} from "../lib/RLPReader.sol"; import {MerklePatriciaProof} from "../lib/MerklePatriciaProof.sol"; import {Merkle} from "../lib/Merkle.sol"; import "../lib/ExitPayloadReader.sol"; interface IFxStateSender { function sendMessageToChild(address _receiver, bytes calldata _data) external; } contract ICheckpointManager { struct HeaderBlock { bytes32 root; uint256 start; uint256 end; uint256 createdAt; address proposer; } /** * @notice mapping of checkpoint header numbers to block details * @dev These checkpoints are submited by plasma contracts */ mapping(uint256 => HeaderBlock) public headerBlocks; } abstract contract FxBaseRootTunnel { using RLPReader for RLPReader.RLPItem; using Merkle for bytes32; using ExitPayloadReader for bytes; using ExitPayloadReader for ExitPayloadReader.ExitPayload; using ExitPayloadReader for ExitPayloadReader.Log; using ExitPayloadReader for ExitPayloadReader.LogTopics; using ExitPayloadReader for ExitPayloadReader.Receipt; // keccak256(MessageSent(bytes)) bytes32 public constant SEND_MESSAGE_EVENT_SIG = 0x8c5261668696ce22758910d05bab8f186d6eb247ceac2af2e82c7dc17669b036; // state sender contract IFxStateSender public fxRoot; // root chain manager ICheckpointManager public checkpointManager; // child tunnel contract which receives and sends messages address public fxChildTunnel; // storage to avoid duplicate exits mapping(bytes32 => bool) public processedExits; constructor(address _checkpointManager, address _fxRoot) { checkpointManager = ICheckpointManager(_checkpointManager); fxRoot = IFxStateSender(_fxRoot); } // set fxChildTunnel if not set already function setFxChildTunnel(address _fxChildTunnel) public virtual { require(fxChildTunnel == address(0x0), "FxBaseRootTunnel: CHILD_TUNNEL_ALREADY_SET"); fxChildTunnel = _fxChildTunnel; } /** * @notice Send bytes message to Child Tunnel * @param message bytes message that will be sent to Child Tunnel * some message examples - * abi.encode(tokenId); * abi.encode(tokenId, tokenMetadata); * abi.encode(messageType, messageData); */ function _sendMessageToChild(bytes memory message) internal { fxRoot.sendMessageToChild(fxChildTunnel, message); } function _validateAndExtractMessage(bytes memory inputData) internal returns (bytes memory) { ExitPayloadReader.ExitPayload memory payload = inputData.toExitPayload(); bytes memory branchMaskBytes = payload.getBranchMaskAsBytes(); uint256 blockNumber = payload.getBlockNumber(); // checking if exit has already been processed // unique exit is identified using hash of (blockNumber, branchMask, receiptLogIndex) bytes32 exitHash = keccak256( abi.encodePacked( blockNumber, // first 2 nibbles are dropped while generating nibble array // this allows branch masks that are valid but bypass exitHash check (changing first 2 nibbles only) // so converting to nibble array and then hashing it MerklePatriciaProof._getNibbleArray(branchMaskBytes), payload.getReceiptLogIndex() ) ); require(processedExits[exitHash] == false, "FxRootTunnel: EXIT_ALREADY_PROCESSED"); processedExits[exitHash] = true; ExitPayloadReader.Receipt memory receipt = payload.getReceipt(); ExitPayloadReader.Log memory log = receipt.getLog(); // check child tunnel require(fxChildTunnel == log.getEmitter(), "FxRootTunnel: INVALID_FX_CHILD_TUNNEL"); bytes32 receiptRoot = payload.getReceiptRoot(); // verify receipt inclusion require( MerklePatriciaProof.verify(receipt.toBytes(), branchMaskBytes, payload.getReceiptProof(), receiptRoot), "FxRootTunnel: INVALID_RECEIPT_PROOF" ); // verify checkpoint inclusion _checkBlockMembershipInCheckpoint( blockNumber, payload.getBlockTime(), payload.getTxRoot(), receiptRoot, payload.getHeaderNumber(), payload.getBlockProof() ); ExitPayloadReader.LogTopics memory topics = log.getTopics(); require( bytes32(topics.getField(0).toUint()) == SEND_MESSAGE_EVENT_SIG, // topic0 is event sig "FxRootTunnel: INVALID_SIGNATURE" ); // received message data bytes memory message = abi.decode(log.getData(), (bytes)); // event decodes params again, so decoding bytes to get message return message; } function _checkBlockMembershipInCheckpoint( uint256 blockNumber, uint256 blockTime, bytes32 txRoot, bytes32 receiptRoot, uint256 headerNumber, bytes memory blockProof ) private view returns (uint256) { (bytes32 headerRoot, uint256 startBlock, , uint256 createdAt, ) = checkpointManager.headerBlocks(headerNumber); require( keccak256(abi.encodePacked(blockNumber, blockTime, txRoot, receiptRoot)).checkMembership( blockNumber - startBlock, headerRoot, blockProof ), "FxRootTunnel: INVALID_HEADER" ); return createdAt; } /** * @notice receive message from L2 to L1, validated by proof * @dev This function verifies if the transaction actually happened on child chain * * @param inputData RLP encoded data of the reference tx containing following list of fields * 0 - headerNumber - Checkpoint header block number containing the reference tx * 1 - blockProof - Proof that the block header (in the child chain) is a leaf in the submitted merkle root * 2 - blockNumber - Block number containing the reference tx on child chain * 3 - blockTime - Reference tx block time * 4 - txRoot - Transactions root of block * 5 - receiptRoot - Receipts root of block * 6 - receipt - Receipt of the reference transaction * 7 - receiptProof - Merkle proof of the reference receipt * 8 - branchMask - 32 bits denoting the path of receipt in merkle tree * 9 - receiptLogIndex - Log Index to read from the receipt */ function receiveMessage(bytes memory inputData) public virtual { bytes memory message = _validateAndExtractMessage(inputData); _processMessageFromChild(message); } /** * @notice Process message received from Child Tunnel * @dev function needs to be implemented to handle message as per requirement * This is called by onStateReceive function. * Since it is called via a system call, any event will not be emitted during its execution. * @param message bytes message that was sent from Child Tunnel */ function _processMessageFromChild(bytes memory message) internal virtual; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20 token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.11; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `recipient`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address recipient, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `sender` to `recipient` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address sender, address recipient, uint256 amount ) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.11; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * * - Subtraction cannot overflow. */ function sub( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { require(b <= a, errorMessage); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function div( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * * - The divisor cannot be zero. */ function mod( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } }
/* * @author Hamdi Allam [email protected] * Please reach out with any questions or concerns */ pragma solidity 0.8.11; library RLPReader { uint8 constant STRING_SHORT_START = 0x80; uint8 constant STRING_LONG_START = 0xb8; uint8 constant LIST_SHORT_START = 0xc0; uint8 constant LIST_LONG_START = 0xf8; uint8 constant WORD_SIZE = 32; struct RLPItem { uint256 len; uint256 memPtr; } struct Iterator { RLPItem item; // Item that's being iterated over. uint256 nextPtr; // Position of the next item in the list. } /* * @dev Returns the next element in the iteration. Reverts if it has not next element. * @param self The iterator. * @return The next element in the iteration. */ function next(Iterator memory self) internal pure returns (RLPItem memory) { require(hasNext(self)); uint256 ptr = self.nextPtr; uint256 itemLength = _itemLength(ptr); self.nextPtr = ptr + itemLength; return RLPItem(itemLength, ptr); } /* * @dev Returns true if the iteration has more elements. * @param self The iterator. * @return true if the iteration has more elements. */ function hasNext(Iterator memory self) internal pure returns (bool) { RLPItem memory item = self.item; return self.nextPtr < item.memPtr + item.len; } /* * @param item RLP encoded bytes */ function toRlpItem(bytes memory item) internal pure returns (RLPItem memory) { uint256 memPtr; assembly { memPtr := add(item, 0x20) } return RLPItem(item.length, memPtr); } /* * @dev Create an iterator. Reverts if item is not a list. * @param self The RLP item. * @return An 'Iterator' over the item. */ function iterator(RLPItem memory self) internal pure returns (Iterator memory) { require(isList(self)); uint256 ptr = self.memPtr + _payloadOffset(self.memPtr); return Iterator(self, ptr); } /* * @param item RLP encoded bytes */ function rlpLen(RLPItem memory item) internal pure returns (uint256) { return item.len; } /* * @param item RLP encoded bytes */ function payloadLen(RLPItem memory item) internal pure returns (uint256) { return item.len - _payloadOffset(item.memPtr); } /* * @param item RLP encoded list in bytes */ function toList(RLPItem memory item) internal pure returns (RLPItem[] memory) { require(isList(item)); uint256 items = numItems(item); RLPItem[] memory result = new RLPItem[](items); uint256 memPtr = item.memPtr + _payloadOffset(item.memPtr); uint256 dataLen; for (uint256 i = 0; i < items; i++) { dataLen = _itemLength(memPtr); result[i] = RLPItem(dataLen, memPtr); memPtr = memPtr + dataLen; } return result; } // @return indicator whether encoded payload is a list. negate this function call for isData. function isList(RLPItem memory item) internal pure returns (bool) { if (item.len == 0) return false; uint8 byte0; uint256 memPtr = item.memPtr; assembly { byte0 := byte(0, mload(memPtr)) } if (byte0 < LIST_SHORT_START) return false; return true; } /* * @dev A cheaper version of keccak256(toRlpBytes(item)) that avoids copying memory. * @return keccak256 hash of RLP encoded bytes. */ function rlpBytesKeccak256(RLPItem memory item) internal pure returns (bytes32) { uint256 ptr = item.memPtr; uint256 len = item.len; bytes32 result; assembly { result := keccak256(ptr, len) } return result; } function payloadLocation(RLPItem memory item) internal pure returns (uint256, uint256) { uint256 offset = _payloadOffset(item.memPtr); uint256 memPtr = item.memPtr + offset; uint256 len = item.len - offset; // data length return (memPtr, len); } /* * @dev A cheaper version of keccak256(toBytes(item)) that avoids copying memory. * @return keccak256 hash of the item payload. */ function payloadKeccak256(RLPItem memory item) internal pure returns (bytes32) { (uint256 memPtr, uint256 len) = payloadLocation(item); bytes32 result; assembly { result := keccak256(memPtr, len) } return result; } /** RLPItem conversions into data types **/ // @returns raw rlp encoding in bytes function toRlpBytes(RLPItem memory item) internal pure returns (bytes memory) { bytes memory result = new bytes(item.len); if (result.length == 0) return result; uint256 ptr; assembly { ptr := add(0x20, result) } copy(item.memPtr, ptr, item.len); return result; } // any non-zero byte is considered true function toBoolean(RLPItem memory item) internal pure returns (bool) { require(item.len == 1); uint256 result; uint256 memPtr = item.memPtr; assembly { result := byte(0, mload(memPtr)) } return result == 0 ? false : true; } function toAddress(RLPItem memory item) internal pure returns (address) { // 1 byte for the length prefix require(item.len == 21); return address(uint160(toUint(item))); } function toUint(RLPItem memory item) internal pure returns (uint256) { require(item.len > 0 && item.len <= 33); uint256 offset = _payloadOffset(item.memPtr); uint256 len = item.len - offset; uint256 result; uint256 memPtr = item.memPtr + offset; assembly { result := mload(memPtr) // shfit to the correct location if neccesary if lt(len, 32) { result := div(result, exp(256, sub(32, len))) } } return result; } // enforces 32 byte length function toUintStrict(RLPItem memory item) internal pure returns (uint256) { // one byte prefix require(item.len == 33); uint256 result; uint256 memPtr = item.memPtr + 1; assembly { result := mload(memPtr) } return result; } function toBytes(RLPItem memory item) internal pure returns (bytes memory) { require(item.len > 0); uint256 offset = _payloadOffset(item.memPtr); uint256 len = item.len - offset; // data length bytes memory result = new bytes(len); uint256 destPtr; assembly { destPtr := add(0x20, result) } copy(item.memPtr + offset, destPtr, len); return result; } /* * Private Helpers */ // @return number of payload items inside an encoded list. function numItems(RLPItem memory item) private pure returns (uint256) { if (item.len == 0) return 0; uint256 count = 0; uint256 currPtr = item.memPtr + _payloadOffset(item.memPtr); uint256 endPtr = item.memPtr + item.len; while (currPtr < endPtr) { currPtr = currPtr + _itemLength(currPtr); // skip over an item count++; } return count; } // @return entire rlp item byte length function _itemLength(uint256 memPtr) private pure returns (uint256) { uint256 itemLen; uint256 byte0; assembly { byte0 := byte(0, mload(memPtr)) } if (byte0 < STRING_SHORT_START) itemLen = 1; else if (byte0 < STRING_LONG_START) itemLen = byte0 - STRING_SHORT_START + 1; else if (byte0 < LIST_SHORT_START) { assembly { let byteLen := sub(byte0, 0xb7) // # of bytes the actual length is memPtr := add(memPtr, 1) // skip over the first byte /* 32 byte word size */ let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to get the len itemLen := add(dataLen, add(byteLen, 1)) } } else if (byte0 < LIST_LONG_START) { itemLen = byte0 - LIST_SHORT_START + 1; } else { assembly { let byteLen := sub(byte0, 0xf7) memPtr := add(memPtr, 1) let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to the correct length itemLen := add(dataLen, add(byteLen, 1)) } } return itemLen; } // @return number of bytes until the data function _payloadOffset(uint256 memPtr) private pure returns (uint256) { uint256 byte0; assembly { byte0 := byte(0, mload(memPtr)) } if (byte0 < STRING_SHORT_START) return 0; else if (byte0 < STRING_LONG_START || (byte0 >= LIST_SHORT_START && byte0 < LIST_LONG_START)) return 1; else if (byte0 < LIST_SHORT_START) // being explicit return byte0 - (STRING_LONG_START - 1) + 1; else return byte0 - (LIST_LONG_START - 1) + 1; } /* * @param src Pointer to source * @param dest Pointer to destination * @param len Amount of memory to copy from the source */ function copy( uint256 src, uint256 dest, uint256 len ) private pure { if (len == 0) return; // copy as many word sizes as possible for (; len >= WORD_SIZE; len -= WORD_SIZE) { assembly { mstore(dest, mload(src)) } src += WORD_SIZE; dest += WORD_SIZE; } if (len == 0) return; // left over bytes. Mask is used to remove unwanted bytes from the word uint256 mask = 256**(WORD_SIZE - len) - 1; assembly { let srcpart := and(mload(src), not(mask)) // zero out src let destpart := and(mload(dest), mask) // retrieve the bytes mstore(dest, or(destpart, srcpart)) } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.11; import {RLPReader} from "./RLPReader.sol"; library MerklePatriciaProof { /* * @dev Verifies a merkle patricia proof. * @param value The terminating value in the trie. * @param encodedPath The path in the trie leading to value. * @param rlpParentNodes The rlp encoded stack of nodes. * @param root The root hash of the trie. * @return The boolean validity of the proof. */ function verify( bytes memory value, bytes memory encodedPath, bytes memory rlpParentNodes, bytes32 root ) internal pure returns (bool) { RLPReader.RLPItem memory item = RLPReader.toRlpItem(rlpParentNodes); RLPReader.RLPItem[] memory parentNodes = RLPReader.toList(item); bytes memory currentNode; RLPReader.RLPItem[] memory currentNodeList; bytes32 nodeKey = root; uint256 pathPtr = 0; bytes memory path = _getNibbleArray(encodedPath); if (path.length == 0) { return false; } for (uint256 i = 0; i < parentNodes.length; i++) { if (pathPtr > path.length) { return false; } currentNode = RLPReader.toRlpBytes(parentNodes[i]); if (nodeKey != keccak256(currentNode)) { return false; } currentNodeList = RLPReader.toList(parentNodes[i]); if (currentNodeList.length == 17) { if (pathPtr == path.length) { if (keccak256(RLPReader.toBytes(currentNodeList[16])) == keccak256(value)) { return true; } else { return false; } } uint8 nextPathNibble = uint8(path[pathPtr]); if (nextPathNibble > 16) { return false; } nodeKey = bytes32(RLPReader.toUintStrict(currentNodeList[nextPathNibble])); pathPtr += 1; } else if (currentNodeList.length == 2) { uint256 traversed = _nibblesToTraverse(RLPReader.toBytes(currentNodeList[0]), path, pathPtr); if (pathPtr + traversed == path.length) { //leaf node if (keccak256(RLPReader.toBytes(currentNodeList[1])) == keccak256(value)) { return true; } else { return false; } } //extension node if (traversed == 0) { return false; } pathPtr += traversed; nodeKey = bytes32(RLPReader.toUintStrict(currentNodeList[1])); } else { return false; } } } function _nibblesToTraverse( bytes memory encodedPartialPath, bytes memory path, uint256 pathPtr ) private pure returns (uint256) { uint256 len = 0; // encodedPartialPath has elements that are each two hex characters (1 byte), but partialPath // and slicedPath have elements that are each one hex character (1 nibble) bytes memory partialPath = _getNibbleArray(encodedPartialPath); bytes memory slicedPath = new bytes(partialPath.length); // pathPtr counts nibbles in path // partialPath.length is a number of nibbles for (uint256 i = pathPtr; i < pathPtr + partialPath.length; i++) { bytes1 pathNibble = path[i]; slicedPath[i - pathPtr] = pathNibble; } if (keccak256(partialPath) == keccak256(slicedPath)) { len = partialPath.length; } else { len = 0; } return len; } // bytes b must be hp encoded function _getNibbleArray(bytes memory b) internal pure returns (bytes memory) { bytes memory nibbles = ""; if (b.length > 0) { uint8 offset; uint8 hpNibble = uint8(_getNthNibbleOfBytes(0, b)); if (hpNibble == 1 || hpNibble == 3) { nibbles = new bytes(b.length * 2 - 1); bytes1 oddNibble = _getNthNibbleOfBytes(1, b); nibbles[0] = oddNibble; offset = 1; } else { nibbles = new bytes(b.length * 2 - 2); offset = 0; } for (uint256 i = offset; i < nibbles.length; i++) { nibbles[i] = _getNthNibbleOfBytes(i - offset + 2, b); } } return nibbles; } function _getNthNibbleOfBytes(uint256 n, bytes memory str) private pure returns (bytes1) { return bytes1(n % 2 == 0 ? uint8(str[n / 2]) / 0x10 : uint8(str[n / 2]) % 0x10); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.11; library Merkle { function checkMembership( bytes32 leaf, uint256 index, bytes32 rootHash, bytes memory proof ) internal pure returns (bool) { require(proof.length % 32 == 0, "Invalid proof length"); uint256 proofHeight = proof.length / 32; // Proof of size n means, height of the tree is n+1. // In a tree of height n+1, max #leafs possible is 2 ^ n require(index < 2**proofHeight, "Leaf index is too big"); bytes32 proofElement; bytes32 computedHash = leaf; for (uint256 i = 32; i <= proof.length; i += 32) { assembly { proofElement := mload(add(proof, i)) } if (index % 2 == 0) { computedHash = keccak256(abi.encodePacked(computedHash, proofElement)); } else { computedHash = keccak256(abi.encodePacked(proofElement, computedHash)); } index = index / 2; } return computedHash == rootHash; } }
pragma solidity 0.8.11; import {RLPReader} from "./RLPReader.sol"; library ExitPayloadReader { using RLPReader for bytes; using RLPReader for RLPReader.RLPItem; uint8 constant WORD_SIZE = 32; struct ExitPayload { RLPReader.RLPItem[] data; } struct Receipt { RLPReader.RLPItem[] data; bytes raw; uint256 logIndex; } struct Log { RLPReader.RLPItem data; RLPReader.RLPItem[] list; } struct LogTopics { RLPReader.RLPItem[] data; } // copy paste of private copy() from RLPReader to avoid changing of existing contracts function copy( uint256 src, uint256 dest, uint256 len ) private pure { if (len == 0) return; // copy as many word sizes as possible for (; len >= WORD_SIZE; len -= WORD_SIZE) { assembly { mstore(dest, mload(src)) } src += WORD_SIZE; dest += WORD_SIZE; } // left over bytes. Mask is used to remove unwanted bytes from the word uint256 mask = 256**(WORD_SIZE - len) - 1; assembly { let srcpart := and(mload(src), not(mask)) // zero out src let destpart := and(mload(dest), mask) // retrieve the bytes mstore(dest, or(destpart, srcpart)) } } function toExitPayload(bytes memory data) internal pure returns (ExitPayload memory) { RLPReader.RLPItem[] memory payloadData = data.toRlpItem().toList(); return ExitPayload(payloadData); } function getHeaderNumber(ExitPayload memory payload) internal pure returns (uint256) { return payload.data[0].toUint(); } function getBlockProof(ExitPayload memory payload) internal pure returns (bytes memory) { return payload.data[1].toBytes(); } function getBlockNumber(ExitPayload memory payload) internal pure returns (uint256) { return payload.data[2].toUint(); } function getBlockTime(ExitPayload memory payload) internal pure returns (uint256) { return payload.data[3].toUint(); } function getTxRoot(ExitPayload memory payload) internal pure returns (bytes32) { return bytes32(payload.data[4].toUint()); } function getReceiptRoot(ExitPayload memory payload) internal pure returns (bytes32) { return bytes32(payload.data[5].toUint()); } function getReceipt(ExitPayload memory payload) internal pure returns (Receipt memory receipt) { receipt.raw = payload.data[6].toBytes(); RLPReader.RLPItem memory receiptItem = receipt.raw.toRlpItem(); if (receiptItem.isList()) { // legacy tx receipt.data = receiptItem.toList(); } else { // pop first byte before parsting receipt bytes memory typedBytes = receipt.raw; bytes memory result = new bytes(typedBytes.length - 1); uint256 srcPtr; uint256 destPtr; assembly { srcPtr := add(33, typedBytes) destPtr := add(0x20, result) } copy(srcPtr, destPtr, result.length); receipt.data = result.toRlpItem().toList(); } receipt.logIndex = getReceiptLogIndex(payload); return receipt; } function getReceiptProof(ExitPayload memory payload) internal pure returns (bytes memory) { return payload.data[7].toBytes(); } function getBranchMaskAsBytes(ExitPayload memory payload) internal pure returns (bytes memory) { return payload.data[8].toBytes(); } function getBranchMaskAsUint(ExitPayload memory payload) internal pure returns (uint256) { return payload.data[8].toUint(); } function getReceiptLogIndex(ExitPayload memory payload) internal pure returns (uint256) { return payload.data[9].toUint(); } // Receipt methods function toBytes(Receipt memory receipt) internal pure returns (bytes memory) { return receipt.raw; } function getLog(Receipt memory receipt) internal pure returns (Log memory) { RLPReader.RLPItem memory logData = receipt.data[3].toList()[receipt.logIndex]; return Log(logData, logData.toList()); } // Log methods function getEmitter(Log memory log) internal pure returns (address) { return RLPReader.toAddress(log.list[0]); } function getTopics(Log memory log) internal pure returns (LogTopics memory) { return LogTopics(log.list[1].toList()); } function getData(Log memory log) internal pure returns (bytes memory) { return log.list[2].toBytes(); } function toRlpBytes(Log memory log) internal pure returns (bytes memory) { return log.data.toRlpBytes(); } // LogTopics methods function getField(LogTopics memory topics, uint256 index) internal pure returns (RLPReader.RLPItem memory) { return topics.data[index]; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { require(isContract(target), "Address: delegate call to non-contract"); (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
{ "optimizer": { "enabled": false, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_checkpointManager","type":"address"},{"internalType":"address","name":"_fxRoot","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"rootToken","type":"address"},{"indexed":true,"internalType":"address","name":"depositor","type":"address"},{"indexed":true,"internalType":"address","name":"userAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FxDepositERC20","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"rootToken","type":"address"},{"indexed":true,"internalType":"address","name":"childToken","type":"address"},{"indexed":true,"internalType":"address","name":"userAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"FxWithdrawERC20","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"rootToken","type":"address"},{"indexed":true,"internalType":"address","name":"childToken","type":"address"}],"name":"TokenMappedERC20","type":"event"},{"inputs":[],"name":"DEPOSIT","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAP_TOKEN","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SEND_MESSAGE_EVENT_SIG","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"checkpointManager","outputs":[{"internalType":"contract ICheckpointManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"rootToken","type":"address"},{"internalType":"address","name":"childToken","type":"address"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"fxChildTunnel","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fxRoot","outputs":[{"internalType":"contract IFxStateSender","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"rootToken","type":"address"},{"internalType":"address","name":"_childToken","type":"address"}],"name":"mapToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"processedExits","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"inputData","type":"bytes"}],"name":"receiveMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rootToChildTokens","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_fxChildTunnel","type":"address"}],"name":"setFxChildTunnel","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b5060405162003e8238038062003e8283398181016040528101906200003791906200012e565b818181600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050505062000175565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000620000f682620000c9565b9050919050565b6200010881620000e9565b81146200011457600080fd5b50565b6000815190506200012881620000fd565b92915050565b60008060408385031215620001485762000147620000c4565b5b6000620001588582860162000117565b92505060206200016b8582860162000117565b9150509250929050565b613cfd80620001856000396000f3fe608060405234801561001057600080fd5b50600436106100b45760003560e01c8063972c492811610071578063972c49281461018d578063aea4e49e146101ab578063c0857ba0146101c7578063d81c8e52146101e5578063de9b771f14610203578063f953cec714610221576100b4565b80630e387de6146100b957806347400269146100d75780635af9abfd146100f3578063607f2d421461010f578063886a69ba1461013f57806388e700681461015d575b600080fd5b6100c161023d565b6040516100ce91906126f4565b60405180910390f35b6100f160048036038101906100ec9190612781565b610264565b005b61010d6004803603810190610108919061293d565b61047f565b005b61012960048036038101906101249190612a00565b610645565b6040516101369190612a48565b60405180910390f35b610147610665565b60405161015491906126f4565b60405180910390f35b61017760048036038101906101729190612a63565b610689565b6040516101849190612a9f565b60405180910390f35b6101956106bc565b6040516101a29190612a9f565b60405180910390f35b6101c560048036038101906101c09190612a63565b6106e2565b005b6101cf6107b7565b6040516101dc9190612b19565b60405180910390f35b6101ed6107dd565b6040516101fa91906126f4565b60405180910390f35b61020b610801565b6040516102189190612b55565b60405180910390f35b61023b60048036038101906102369190612b70565b610825565b005b7f8c5261668696ce22758910d05bab8f186d6eb247ceac2af2e82c7dc17669b03660001b81565b600073ffffffffffffffffffffffffffffffffffffffff16600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614610332576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161032990612c3c565b60405180910390fd5b60007f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad8383604051602001610368929190612c5c565b604051602081830303815290604052604051602001610388929190612d0d565b60405160208183030381529060405290506103a28161083f565b81600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fc21cd413746aa9146d86960ed90847c18aa555d8dfd256e0aac3954c41e3cfe260405160405180910390a3505050565b600073ffffffffffffffffffffffffffffffffffffffff16600460008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16141561051e5761051d8585610264565b5b61054b3330848873ffffffffffffffffffffffffffffffffffffffff166108f1909392919063ffffffff16565b60007f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f8218633868686604051602001610587959493929190612d4c565b6040516020818303038152906040526040516020016105a7929190612d0d565b60405160208183030381529060405290506105c18161083f565b8373ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167f8a58355ceb4626422a66b0f36743672dde8507c6be664f0e5b9de8350a132159866040516106359190612da6565b60405180910390a4505050505050565b60036020528060005260406000206000915054906101000a900460ff1681565b7f2cef46a936bdc5b7e6e8c71aa04560c41cf7d88bb26901a7e7f4936ff02accad81565b60046020528060005260406000206000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600073ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614610773576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161076a90612e33565b60405180910390fd5b80600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b7f87a7811f4bfedea3d341ad165680ae306b01aaeacc205d227629cf157dd9f82181565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60006108308261097a565b905061083b81610c7f565b5050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b4720477600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16836040518363ffffffff1660e01b81526004016108bc929190612e53565b600060405180830381600087803b1580156108d657600080fd5b505af11580156108ea573d6000803e3d6000fd5b5050505050565b610974846323b872dd60e01b85858560405160240161091293929190612e83565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050610e1c565b50505050565b6060600061098783610ee3565b9050600061099482610f17565b905060006109a183610f48565b90506000816109af84610f79565b6109b88661118f565b6040516020016109ca93929190612f17565b604051602081830303815290604052805190602001209050600015156003600083815260200190815260200160002060009054906101000a900460ff16151514610a49576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a4090612fc2565b60405180910390fd5b60016003600083815260200190815260200160002060006101000a81548160ff0219169083151502179055506000610a80856111c0565b90506000610a8d826112e5565b9050610a988161135c565b73ffffffffffffffffffffffffffffffffffffffff16600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614610b27576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b1e90613054565b60405180910390fd5b6000610b328761138d565b9050610b50610b40846113c1565b87610b4a8a6113cf565b84611400565b610b8f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b86906130e6565b60405180910390fd5b610bbd85610b9c89611706565b610ba58a611737565b84610baf8c61176b565b610bb88d61179c565b6117cd565b506000610bc983611914565b90507f8c5261668696ce22758910d05bab8f186d6eb247ceac2af2e82c7dc17669b03660001b610c0b610c0660008461195990919063ffffffff16565b611988565b60001b14610c4e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c4590613152565b60405180910390fd5b6000610c5984611a0b565b806020019051810190610c6c91906131e2565b9050809950505050505050505050919050565b60008060008084806020019051810190610c99919061327e565b93509350935093508273ffffffffffffffffffffffffffffffffffffffff16600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614610d6e576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610d6590613357565b60405180910390fd5b610d9982828673ffffffffffffffffffffffffffffffffffffffff16611a3c9092919063ffffffff16565b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167f1a77c658a097b28097b54b8acb928a569a3830a6cbed2de1f60001c0757eb0d684604051610e0d9190612da6565b60405180910390a45050505050565b6000610e7e826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16611ac29092919063ffffffff16565b9050600081511115610ede5780806020019051810190610e9e91906133a3565b610edd576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ed490613442565b60405180910390fd5b5b505050565b610eeb61265a565b6000610efe610ef984611ada565b611b08565b9050604051806020016040528082815250915050919050565b6060610f418260000151600881518110610f3457610f33613462565b5b6020026020010151611c1d565b9050919050565b6000610f728260000151600281518110610f6557610f64613462565b5b6020026020010151611988565b9050919050565b6060600060405180602001604052806000815250905060008351111561118657600080610fa7600086611cd4565b60f81c905060018160ff161480610fc1575060038160ff16145b1561108b57600160028651610fd691906134c0565b610fe0919061351a565b67ffffffffffffffff811115610ff957610ff8612812565b5b6040519080825280601f01601f19166020018201604052801561102b5781602001600182028036833780820191505090505b509250600061103b600187611cd4565b9050808460008151811061105257611051613462565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535060019250506110f7565b600280865161109a91906134c0565b6110a4919061351a565b67ffffffffffffffff8111156110bd576110bc612812565b5b6040519080825280601f01601f1916602001820160405280156110ef5781602001600182028036833780820191505090505b509250600091505b60008260ff1690505b83518110156111825761112d60028460ff168361111d919061351a565b611127919061354e565b87611cd4565b8482815181106111405761113f613462565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350808061117a906135a4565b915050611100565b5050505b80915050919050565b60006111b982600001516009815181106111ac576111ab613462565b5b6020026020010151611988565b9050919050565b6111c861266d565b6111f082600001516006815181106111e3576111e2613462565b5b6020026020010151611c1d565b816020018190525060006112078260200151611ada565b905061121281611d6c565b1561122d5761122081611b08565b82600001819052506112cd565b600082602001519050600060018251611246919061351a565b67ffffffffffffffff81111561125f5761125e612812565b5b6040519080825280601f01601f1916602001820160405280156112915781602001600182028036833780820191505090505b5090506000808360210191508260200190506112af82828551611dba565b6112c06112bb84611ada565b611b08565b8660000181905250505050505b6112d68361118f565b82604001818152505050919050565b6112ed61268e565b6000611317836000015160038151811061130a57611309613462565b5b6020026020010151611b08565b83604001518151811061132d5761132c613462565b5b60200260200101519050604051806040016040528082815260200161135183611b08565b815250915050919050565b6000611386826020015160008151811061137957611378613462565b5b6020026020010151611e57565b9050919050565b60006113b782600001516005815181106113aa576113a9613462565b5b6020026020010151611988565b60001b9050919050565b606081602001519050919050565b60606113f982600001516007815181106113ec576113eb613462565b5b6020026020010151611c1d565b9050919050565b60008061140c84611ada565b9050600061141982611b08565b9050606080600086905060008061142f8b610f79565b905060008151141561144b5760009750505050505050506116fe565b60005b86518110156116f5578151831115611471576000985050505050505050506116fe565b61149487828151811061148757611486613462565b5b6020026020010151611e7a565b9550858051906020012084146114b5576000985050505050505050506116fe565b6114d88782815181106114cb576114ca613462565b5b6020026020010151611b08565b94506011855114156115cb578151831415611548578c805190602001206115198660108151811061150c5761150b613462565b5b6020026020010151611c1d565b805190602001201415611537576001985050505050505050506116fe565b6000985050505050505050506116fe565b600082848151811061155d5761155c613462565b5b602001015160f81c60f81b60f81c905060108160ff16111561158b57600099505050505050505050506116fe565b6115b1868260ff16815181106115a4576115a3613462565b5b6020026020010151611f0a565b60001b94506001846115c3919061354e565b9350506116e2565b6002855114156116d05760006116056115fe876000815181106115f1576115f0613462565b5b6020026020010151611c1d565b8486611f41565b905082518185611615919061354e565b1415611678578d805190602001206116478760018151811061163a57611639613462565b5b6020026020010151611c1d565b80519060200120141561166657600199505050505050505050506116fe565b600099505050505050505050506116fe565b600081141561169357600099505050505050505050506116fe565b808461169f919061354e565b93506116c5866001815181106116b8576116b7613462565b5b6020026020010151611f0a565b60001b9450506116e1565b6000985050505050505050506116fe565b5b80806116ed906135a4565b91505061144e565b50505050505050505b949350505050565b6000611730826000015160038151811061172357611722613462565b5b6020026020010151611988565b9050919050565b6000611761826000015160048151811061175457611753613462565b5b6020026020010151611988565b60001b9050919050565b6000611795826000015160008151811061178857611787613462565b5b6020026020010151611988565b9050919050565b60606117c682600001516001815181106117b9576117b8613462565b5b6020026020010151611c1d565b9050919050565b600080600080600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166341539d4a876040518263ffffffff1660e01b815260040161182e9190612da6565b60a060405180830381865afa15801561184b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061186f9190613617565b50935050925092506118c5828b611886919061351a565b84878d8d8d8d60405160200161189f94939291906136b3565b60405160208183030381529060405280519060200120612077909392919063ffffffff16565b611904576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016118fb9061374d565b60405180910390fd5b8093505050509695505050505050565b61191c6126ae565b604051806020016040528061194f846020015160018151811061194257611941613462565b5b6020026020010151611b08565b8152509050919050565b6119616126c1565b8260000151828151811061197857611977613462565b5b6020026020010151905092915050565b60008082600001511180156119a257506021826000015111155b6119ab57600080fd5b60006119ba83602001516121e8565b905060008184600001516119ce919061351a565b90506000808386602001516119e3919061354e565b90508051915060208310156119ff57826020036101000a820491505b81945050505050919050565b6060611a358260200151600281518110611a2857611a27613462565b5b6020026020010151611c1d565b9050919050565b611abd8363a9059cbb60e01b8484604051602401611a5b92919061376d565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050610e1c565b505050565b6060611ad184846000856122a7565b90509392505050565b611ae26126c1565b600060208301905060405180604001604052808451815260200182815250915050919050565b6060611b1382611d6c565b611b1c57600080fd5b6000611b27836123bb565b905060008167ffffffffffffffff811115611b4557611b44612812565b5b604051908082528060200260200182016040528015611b7e57816020015b611b6b6126c1565b815260200190600190039081611b635790505b5090506000611b9085602001516121e8565b8560200151611b9f919061354e565b9050600080600090505b84811015611c1057611bba83612449565b9150604051806040016040528083815260200184815250848281518110611be457611be3613462565b5b60200260200101819052508183611bfb919061354e565b92508080611c08906135a4565b915050611ba9565b5082945050505050919050565b60606000826000015111611c3057600080fd5b6000611c3f83602001516121e8565b90506000818460000151611c53919061351a565b905060008167ffffffffffffffff811115611c7157611c70612812565b5b6040519080825280601f01601f191660200182016040528015611ca35781602001600182028036833780820191505090505b5090506000816020019050611cc8848760200151611cc1919061354e565b8285612525565b81945050505050919050565b600080600284611ce491906137c5565b14611d2757601082600285611cf991906137f6565b81518110611d0a57611d09613462565b5b602001015160f81c60f81b60f81c611d229190613834565b611d61565b601082600285611d3791906137f6565b81518110611d4857611d47613462565b5b602001015160f81c60f81b60f81c611d609190613865565b5b60f81b905092915050565b60008082600001511415611d835760009050611db5565b60008083602001519050805160001a915060c060ff168260ff161015611dae57600092505050611db5565b6001925050505b919050565b6000811415611dc857611e52565b5b602060ff168110611e135782518252602060ff1683611de8919061354e565b9250602060ff1682611dfa919061354e565b9150602060ff1681611e0c919061351a565b9050611dc9565b6000600182602060ff16611e27919061351a565b610100611e3491906139c9565b611e3e919061351a565b905080198451168184511681811785525050505b505050565b60006015826000015114611e6a57600080fd5b611e7382611988565b9050919050565b60606000826000015167ffffffffffffffff811115611e9c57611e9b612812565b5b6040519080825280601f01601f191660200182016040528015611ece5781602001600182028036833780820191505090505b509050600081511415611ee45780915050611f05565b6000816020019050611eff8460200151828660000151612525565b81925050505b919050565b60006021826000015114611f1d57600080fd5b60008060018460200151611f31919061354e565b9050805191508192505050919050565b600080600090506000611f5386610f79565b90506000815167ffffffffffffffff811115611f7257611f71612812565b5b6040519080825280601f01601f191660200182016040528015611fa45781602001600182028036833780820191505090505b50905060008590505b825186611fba919061354e565b811015612045576000878281518110611fd657611fd5613462565b5b602001015160f81c60f81b905080838884611ff1919061351a565b8151811061200257612001613462565b5b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535050808061203d906135a4565b915050611fad565b50808051906020012082805190602001201415612065578151925061206a565b600092505b8293505050509392505050565b6000806020835161208891906137c5565b146120c8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120bf90613a60565b60405180910390fd5b6000602083516120d891906137f6565b90508060026120e791906139c9565b8510612128576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161211f90613acc565b60405180910390fd5b6000808790506000602090505b855181116121d757808601519250600060028961215291906137c5565b141561218857818360405160200161216b929190613aec565b6040516020818303038152906040528051906020012091506121b4565b828260405160200161219b929190613aec565b6040516020818303038152906040528051906020012091505b6002886121c191906137f6565b97506020816121d0919061354e565b9050612135565b508581149350505050949350505050565b600080825160001a9050608060ff168110156122085760009150506122a2565b60b860ff1681108061222d575060c060ff16811015801561222c575060f860ff1681105b5b1561223c5760019150506122a2565b60c060ff168110156122775760018060b86122579190613b18565b60ff1682612265919061351a565b61226f919061354e565b9150506122a2565b60018060f86122869190613b18565b60ff1682612294919061351a565b61229e919061354e565b9150505b919050565b6060824710156122ec576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016122e390613bbe565b60405180910390fd5b6122f5856125d0565b612334576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161232b90613c2a565b60405180910390fd5b6000808673ffffffffffffffffffffffffffffffffffffffff16858760405161235d9190613c4a565b60006040518083038185875af1925050503d806000811461239a576040519150601f19603f3d011682016040523d82523d6000602084013e61239f565b606091505b50915091506123af8282866125f3565b92505050949350505050565b600080826000015114156123d25760009050612444565b6000806123e284602001516121e8565b84602001516123f1919061354e565b9050600084600001518560200151612409919061354e565b90505b8082101561243d5761241d82612449565b82612428919061354e565b91508280612435906135a4565b93505061240c565b8293505050505b919050565b6000806000835160001a9050608060ff1681101561246a576001915061251b565b60b860ff16811015612499576001608060ff1682612488919061351a565b612492919061354e565b915061251a565b60c060ff168110156124c95760b78103600185019450806020036101000a85510460018201810193505050612519565b60f860ff168110156124f857600160c060ff16826124e7919061351a565b6124f1919061354e565b9150612518565b60f78103600185019450806020036101000a855104600182018101935050505b5b5b5b8192505050919050565b6000811415612533576125cb565b5b602060ff16811061257e5782518252602060ff1683612553919061354e565b9250602060ff1682612565919061354e565b9150602060ff1681612577919061351a565b9050612534565b600081141561258c576125cb565b6000600182602060ff166125a0919061351a565b6101006125ad91906139c9565b6125b7919061351a565b905080198451168184511681811785525050505b505050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b6060831561260357829050612653565b6000835111156126165782518084602001fd5b816040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161264a9190613ca5565b60405180910390fd5b9392505050565b6040518060200160405280606081525090565b60405180606001604052806060815260200160608152602001600081525090565b60405180604001604052806126a16126c1565b8152602001606081525090565b6040518060200160405280606081525090565b604051806040016040528060008152602001600081525090565b6000819050919050565b6126ee816126db565b82525050565b600060208201905061270960008301846126e5565b92915050565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061274e82612723565b9050919050565b61275e81612743565b811461276957600080fd5b50565b60008135905061277b81612755565b92915050565b6000806040838503121561279857612797612719565b5b60006127a68582860161276c565b92505060206127b78582860161276c565b9150509250929050565b6000819050919050565b6127d4816127c1565b81146127df57600080fd5b50565b6000813590506127f1816127cb565b92915050565b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61284a82612801565b810181811067ffffffffffffffff8211171561286957612868612812565b5b80604052505050565b600061287c61270f565b90506128888282612841565b919050565b600067ffffffffffffffff8211156128a8576128a7612812565b5b6128b182612801565b9050602081019050919050565b82818337600083830152505050565b60006128e06128db8461288d565b612872565b9050828152602081018484840111156128fc576128fb6127fc565b5b6129078482856128be565b509392505050565b600082601f830112612924576129236127f7565b5b81356129348482602086016128cd565b91505092915050565b600080600080600060a0868803121561295957612958612719565b5b60006129678882890161276c565b95505060206129788882890161276c565b94505060406129898882890161276c565b935050606061299a888289016127e2565b925050608086013567ffffffffffffffff8111156129bb576129ba61271e565b5b6129c78882890161290f565b9150509295509295909350565b6129dd816126db565b81146129e857600080fd5b50565b6000813590506129fa816129d4565b92915050565b600060208284031215612a1657612a15612719565b5b6000612a24848285016129eb565b91505092915050565b60008115159050919050565b612a4281612a2d565b82525050565b6000602082019050612a5d6000830184612a39565b92915050565b600060208284031215612a7957612a78612719565b5b6000612a878482850161276c565b91505092915050565b612a9981612743565b82525050565b6000602082019050612ab46000830184612a90565b92915050565b6000819050919050565b6000612adf612ada612ad584612723565b612aba565b612723565b9050919050565b6000612af182612ac4565b9050919050565b6000612b0382612ae6565b9050919050565b612b1381612af8565b82525050565b6000602082019050612b2e6000830184612b0a565b92915050565b6000612b3f82612ae6565b9050919050565b612b4f81612b34565b82525050565b6000602082019050612b6a6000830184612b46565b92915050565b600060208284031215612b8657612b85612719565b5b600082013567ffffffffffffffff811115612ba457612ba361271e565b5b612bb08482850161290f565b91505092915050565b600082825260208201905092915050565b7f46784552433230526f6f7454756e6e656c3a20414c52454144595f4d4150504560008201527f4400000000000000000000000000000000000000000000000000000000000000602082015250565b6000612c26602183612bb9565b9150612c3182612bca565b604082019050919050565b60006020820190508181036000830152612c5581612c19565b9050919050565b6000604082019050612c716000830185612a90565b612c7e6020830184612a90565b9392505050565b600081519050919050565b600082825260208201905092915050565b60005b83811015612cbf578082015181840152602081019050612ca4565b83811115612cce576000848401525b50505050565b6000612cdf82612c85565b612ce98185612c90565b9350612cf9818560208601612ca1565b612d0281612801565b840191505092915050565b6000604082019050612d2260008301856126e5565b8181036020830152612d348184612cd4565b90509392505050565b612d46816127c1565b82525050565b600060a082019050612d616000830188612a90565b612d6e6020830187612a90565b612d7b6040830186612a90565b612d886060830185612d3d565b8181036080830152612d9a8184612cd4565b90509695505050505050565b6000602082019050612dbb6000830184612d3d565b92915050565b7f467842617365526f6f7454756e6e656c3a204348494c445f54554e4e454c5f4160008201527f4c52454144595f53455400000000000000000000000000000000000000000000602082015250565b6000612e1d602a83612bb9565b9150612e2882612dc1565b604082019050919050565b60006020820190508181036000830152612e4c81612e10565b9050919050565b6000604082019050612e686000830185612a90565b8181036020830152612e7a8184612cd4565b90509392505050565b6000606082019050612e986000830186612a90565b612ea56020830185612a90565b612eb26040830184612d3d565b949350505050565b6000819050919050565b612ed5612ed0826127c1565b612eba565b82525050565b600081905092915050565b6000612ef182612c85565b612efb8185612edb565b9350612f0b818560208601612ca1565b80840191505092915050565b6000612f238286612ec4565b602082019150612f338285612ee6565b9150612f3f8284612ec4565b602082019150819050949350505050565b7f4678526f6f7454756e6e656c3a20455849545f414c52454144595f50524f434560008201527f5353454400000000000000000000000000000000000000000000000000000000602082015250565b6000612fac602483612bb9565b9150612fb782612f50565b604082019050919050565b60006020820190508181036000830152612fdb81612f9f565b9050919050565b7f4678526f6f7454756e6e656c3a20494e56414c49445f46585f4348494c445f5460008201527f554e4e454c000000000000000000000000000000000000000000000000000000602082015250565b600061303e602583612bb9565b915061304982612fe2565b604082019050919050565b6000602082019050818103600083015261306d81613031565b9050919050565b7f4678526f6f7454756e6e656c3a20494e56414c49445f524543454950545f505260008201527f4f4f460000000000000000000000000000000000000000000000000000000000602082015250565b60006130d0602383612bb9565b91506130db82613074565b604082019050919050565b600060208201905081810360008301526130ff816130c3565b9050919050565b7f4678526f6f7454756e6e656c3a20494e56414c49445f5349474e415455524500600082015250565b600061313c601f83612bb9565b915061314782613106565b602082019050919050565b6000602082019050818103600083015261316b8161312f565b9050919050565b60006131856131808461288d565b612872565b9050828152602081018484840111156131a1576131a06127fc565b5b6131ac848285612ca1565b509392505050565b600082601f8301126131c9576131c86127f7565b5b81516131d9848260208601613172565b91505092915050565b6000602082840312156131f8576131f7612719565b5b600082015167ffffffffffffffff8111156132165761321561271e565b5b613222848285016131b4565b91505092915050565b600061323682612723565b9050919050565b6132468161322b565b811461325157600080fd5b50565b6000815190506132638161323d565b92915050565b600081519050613278816127cb565b92915050565b6000806000806080858703121561329857613297612719565b5b60006132a687828801613254565b94505060206132b787828801613254565b93505060406132c887828801613254565b92505060606132d987828801613269565b91505092959194509250565b7f46784552433230526f6f7454756e6e656c3a20494e56414c49445f4d4150504960008201527f4e475f4f4e5f4558495400000000000000000000000000000000000000000000602082015250565b6000613341602a83612bb9565b915061334c826132e5565b604082019050919050565b6000602082019050818103600083015261337081613334565b9050919050565b61338081612a2d565b811461338b57600080fd5b50565b60008151905061339d81613377565b92915050565b6000602082840312156133b9576133b8612719565b5b60006133c78482850161338e565b91505092915050565b7f5361666545524332303a204552433230206f7065726174696f6e20646964206e60008201527f6f74207375636365656400000000000000000000000000000000000000000000602082015250565b600061342c602a83612bb9565b9150613437826133d0565b604082019050919050565b6000602082019050818103600083015261345b8161341f565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006134cb826127c1565b91506134d6836127c1565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561350f5761350e613491565b5b828202905092915050565b6000613525826127c1565b9150613530836127c1565b92508282101561354357613542613491565b5b828203905092915050565b6000613559826127c1565b9150613564836127c1565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0382111561359957613598613491565b5b828201905092915050565b60006135af826127c1565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8214156135e2576135e1613491565b5b600182019050919050565b6000815190506135fc816129d4565b92915050565b60008151905061361181612755565b92915050565b600080600080600060a0868803121561363357613632612719565b5b6000613641888289016135ed565b955050602061365288828901613269565b945050604061366388828901613269565b935050606061367488828901613269565b925050608061368588828901613602565b9150509295509295909350565b6000819050919050565b6136ad6136a8826126db565b613692565b82525050565b60006136bf8287612ec4565b6020820191506136cf8286612ec4565b6020820191506136df828561369c565b6020820191506136ef828461369c565b60208201915081905095945050505050565b7f4678526f6f7454756e6e656c3a20494e56414c49445f48454144455200000000600082015250565b6000613737601c83612bb9565b915061374282613701565b602082019050919050565b600060208201905081810360008301526137668161372a565b9050919050565b60006040820190506137826000830185612a90565b61378f6020830184612d3d565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b60006137d0826127c1565b91506137db836127c1565b9250826137eb576137ea613796565b5b828206905092915050565b6000613801826127c1565b915061380c836127c1565b92508261381c5761381b613796565b5b828204905092915050565b600060ff82169050919050565b600061383f82613827565b915061384a83613827565b92508261385a57613859613796565b5b828206905092915050565b600061387082613827565b915061387b83613827565b92508261388b5761388a613796565b5b828204905092915050565b60008160011c9050919050565b6000808291508390505b60018511156138ed578086048111156138c9576138c8613491565b5b60018516156138d85780820291505b80810290506138e685613896565b94506138ad565b94509492505050565b60008261390657600190506139c2565b8161391457600090506139c2565b816001811461392a576002811461393457613963565b60019150506139c2565b60ff84111561394657613945613491565b5b8360020a91508482111561395d5761395c613491565b5b506139c2565b5060208310610133831016604e8410600b84101617156139985782820a90508381111561399357613992613491565b5b6139c2565b6139a584848460016138a3565b925090508184048111156139bc576139bb613491565b5b81810290505b9392505050565b60006139d4826127c1565b91506139df836127c1565b9250613a0c7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff84846138f6565b905092915050565b7f496e76616c69642070726f6f66206c656e677468000000000000000000000000600082015250565b6000613a4a601483612bb9565b9150613a5582613a14565b602082019050919050565b60006020820190508181036000830152613a7981613a3d565b9050919050565b7f4c65616620696e64657820697320746f6f206269670000000000000000000000600082015250565b6000613ab6601583612bb9565b9150613ac182613a80565b602082019050919050565b60006020820190508181036000830152613ae581613aa9565b9050919050565b6000613af8828561369c565b602082019150613b08828461369c565b6020820191508190509392505050565b6000613b2382613827565b9150613b2e83613827565b925082821015613b4157613b40613491565b5b828203905092915050565b7f416464726573733a20696e73756666696369656e742062616c616e636520666f60008201527f722063616c6c0000000000000000000000000000000000000000000000000000602082015250565b6000613ba8602683612bb9565b9150613bb382613b4c565b604082019050919050565b60006020820190508181036000830152613bd781613b9b565b9050919050565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000600082015250565b6000613c14601d83612bb9565b9150613c1f82613bde565b602082019050919050565b60006020820190508181036000830152613c4381613c07565b9050919050565b6000613c568284612ee6565b915081905092915050565b600081519050919050565b6000613c7782613c61565b613c818185612bb9565b9350613c91818560208601612ca1565b613c9a81612801565b840191505092915050565b60006020820190508181036000830152613cbf8184613c6c565b90509291505056fea26469706673582212208d729417840e1581a6125ae3ba50dafe86f0c2d26d6d67675d9fc2cbb4fa854164736f6c634300080b003300000000000000000000000086e4dc95c7fbdbf52e33d563bbdb00823894c287000000000000000000000000fe5e5d361b2ad62c541bab87c45a0b9b018389a2
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000086e4dc95c7fbdbf52e33d563bbdb00823894c287000000000000000000000000fe5e5d361b2ad62c541bab87c45a0b9b018389a2
-----Decoded View---------------
Arg [0] : _checkpointManager (address): 0x86E4Dc95c7FBdBf52e33D563BbDB00823894C287
Arg [1] : _fxRoot (address): 0xfe5e5D361b2ad62c541bAb87C45a0B9B018389a2
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 00000000000000000000000086e4dc95c7fbdbf52e33d563bbdb00823894c287
Arg [1] : 000000000000000000000000fe5e5d361b2ad62c541bab87c45a0b9b018389a2
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.
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.