ETH Price: $1,618.90 (-1.02%)
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
L1GraphTokenGateway

Compiler Version
v0.7.6+commit.7338295f

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 26 : L1GraphTokenGateway.sol
// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.7.6;
pragma abicoder v2;

import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/Initializable.sol";
import { AddressUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
import { SafeMathUpgradeable } from "@openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol";

import { L1ArbitrumMessenger } from "../arbitrum/L1ArbitrumMessenger.sol";
import { IBridge } from "../arbitrum/IBridge.sol";
import { IInbox } from "../arbitrum/IInbox.sol";
import { IOutbox } from "../arbitrum/IOutbox.sol";
import { ITokenGateway } from "../arbitrum/ITokenGateway.sol";
import { Managed } from "../governance/Managed.sol";
import { GraphTokenGateway } from "./GraphTokenGateway.sol";
import { IGraphToken } from "../token/IGraphToken.sol";

/**
 * @title L1 Graph Token Gateway Contract
 * @dev Provides the L1 side of the Ethereum-Arbitrum GRT bridge. Sends GRT to the L2 chain
 * by escrowing them and sending a message to the L2 gateway, and receives tokens from L2 by
 * releasing them from escrow.
 * Based on Offchain Labs' reference implementation and Livepeer's arbitrum-lpt-bridge
 * (See: https://github.com/OffchainLabs/arbitrum/tree/master/packages/arb-bridge-peripherals/contracts/tokenbridge
 * and https://github.com/livepeer/arbitrum-lpt-bridge)
 */
contract L1GraphTokenGateway is Initializable, GraphTokenGateway, L1ArbitrumMessenger {
    using SafeMathUpgradeable for uint256;

    /// Address of the Graph Token contract on L2
    address public l2GRT;
    /// Address of the Arbitrum Inbox
    address public inbox;
    /// Address of the Arbitrum Gateway Router on L1
    address public l1Router;
    /// Address of the L2GraphTokenGateway on L2 that is the counterpart of this gateway
    address public l2Counterpart;
    /// Address of the BridgeEscrow contract that holds the GRT in the bridge
    address public escrow;
    /// Addresses for which this mapping is true are allowed to send callhooks in outbound transfers
    mapping(address => bool) public callhookAllowlist;
    /// Total amount minted from L2
    uint256 public totalMintedFromL2;
    /// Accumulated allowance for tokens minted from L2 at lastL2MintAllowanceUpdateBlock
    uint256 public accumulatedL2MintAllowanceSnapshot;
    /// Block at which new L2 allowance starts accumulating
    uint256 public lastL2MintAllowanceUpdateBlock;
    /// New L2 mint allowance per block
    uint256 public l2MintAllowancePerBlock;

    /// Emitted when an outbound transfer is initiated, i.e. tokens are deposited from L1 to L2
    event DepositInitiated(
        address l1Token,
        address indexed from,
        address indexed to,
        uint256 indexed sequenceNumber,
        uint256 amount
    );

    /// Emitted when an incoming transfer is finalized, i.e tokens are withdrawn from L2 to L1
    event WithdrawalFinalized(
        address l1Token,
        address indexed from,
        address indexed to,
        uint256 indexed exitNum,
        uint256 amount
    );

    /// Emitted when the Arbitrum Inbox and Gateway Router addresses have been updated
    event ArbitrumAddressesSet(address inbox, address l1Router);
    /// Emitted when the L2 GRT address has been updated
    event L2TokenAddressSet(address l2GRT);
    /// Emitted when the counterpart L2GraphTokenGateway address has been updated
    event L2CounterpartAddressSet(address l2Counterpart);
    /// Emitted when the escrow address has been updated
    event EscrowAddressSet(address escrow);
    /// Emitted when an address is added to the callhook allowlist
    event AddedToCallhookAllowlist(address newAllowlisted);
    /// Emitted when an address is removed from the callhook allowlist
    event RemovedFromCallhookAllowlist(address notAllowlisted);
    /// Emitted when the L2 mint allowance per block is updated
    event L2MintAllowanceUpdated(
        uint256 accumulatedL2MintAllowanceSnapshot,
        uint256 l2MintAllowancePerBlock,
        uint256 lastL2MintAllowanceUpdateBlock
    );
    /// Emitted when tokens are minted due to an incoming transfer from L2
    event TokensMintedFromL2(uint256 amount);

    /**
     * @dev Allows a function to be called only by the gateway's L2 counterpart.
     * The message will actually come from the Arbitrum Bridge, but the Outbox
     * can tell us who the sender from L2 is.
     */
    modifier onlyL2Counterpart() {
        require(inbox != address(0), "INBOX_NOT_SET");
        require(l2Counterpart != address(0), "L2_COUNTERPART_NOT_SET");

        // a message coming from the counterpart gateway was executed by the bridge
        IBridge bridge = IInbox(inbox).bridge();
        require(msg.sender == address(bridge), "NOT_FROM_BRIDGE");

        // and the outbox reports that the L2 address of the sender is the counterpart gateway
        address l2ToL1Sender = IOutbox(bridge.activeOutbox()).l2ToL1Sender();
        require(l2ToL1Sender == l2Counterpart, "ONLY_COUNTERPART_GATEWAY");
        _;
    }

    /**
     * @notice Initialize the L1GraphTokenGateway contract.
     * @dev The contract will be paused.
     * Note some parameters have to be set separately as they are generally
     * not expected to be available at initialization time:
     * - inbox  and l1Router using setArbitrumAddresses
     * - l2GRT using setL2TokenAddress
     * - l2Counterpart using setL2CounterpartAddress
     * - escrow using setEscrowAddress
     * - allowlisted callhook callers using addToCallhookAllowlist
     * - pauseGuardian using setPauseGuardian
     * @param _controller Address of the Controller that manages this contract
     */
    function initialize(address _controller) external onlyImpl initializer {
        Managed._initialize(_controller);
        _paused = true;
    }

    /**
     * @notice Sets the addresses for L1 contracts provided by Arbitrum
     * @param _inbox Address of the Inbox that is part of the Arbitrum Bridge
     * @param _l1Router Address of the Gateway Router
     */
    function setArbitrumAddresses(address _inbox, address _l1Router) external onlyGovernor {
        require(_inbox != address(0), "INVALID_INBOX");
        require(_l1Router != address(0), "INVALID_L1_ROUTER");
        require(!callhookAllowlist[_l1Router], "ROUTER_CANT_BE_ALLOWLISTED");
        require(AddressUpgradeable.isContract(_inbox), "INBOX_MUST_BE_CONTRACT");
        require(AddressUpgradeable.isContract(_l1Router), "ROUTER_MUST_BE_CONTRACT");
        inbox = _inbox;
        l1Router = _l1Router;
        emit ArbitrumAddressesSet(_inbox, _l1Router);
    }

    /**
     * @notice Sets the address of the L2 Graph Token
     * @param _l2GRT Address of the GRT contract on L2
     */
    function setL2TokenAddress(address _l2GRT) external onlyGovernor {
        require(_l2GRT != address(0), "INVALID_L2_GRT");
        l2GRT = _l2GRT;
        emit L2TokenAddressSet(_l2GRT);
    }

    /**
     * @notice Sets the address of the counterpart gateway on L2
     * @param _l2Counterpart Address of the corresponding L2GraphTokenGateway on Arbitrum
     */
    function setL2CounterpartAddress(address _l2Counterpart) external onlyGovernor {
        require(_l2Counterpart != address(0), "INVALID_L2_COUNTERPART");
        l2Counterpart = _l2Counterpart;
        emit L2CounterpartAddressSet(_l2Counterpart);
    }

    /**
     * @notice Sets the address of the escrow contract on L1
     * @param _escrow Address of the BridgeEscrow
     */
    function setEscrowAddress(address _escrow) external onlyGovernor {
        require(_escrow != address(0), "INVALID_ESCROW");
        require(AddressUpgradeable.isContract(_escrow), "MUST_BE_CONTRACT");
        escrow = _escrow;
        emit EscrowAddressSet(_escrow);
    }

    /**
     * @notice Adds an address to the callhook allowlist.
     * This address will be allowed to include callhooks when transferring tokens.
     * @param _newAllowlisted Address to add to the allowlist
     */
    function addToCallhookAllowlist(address _newAllowlisted) external onlyGovernor {
        require(_newAllowlisted != address(0), "INVALID_ADDRESS");
        require(_newAllowlisted != l1Router, "CANT_ALLOW_ROUTER");
        require(AddressUpgradeable.isContract(_newAllowlisted), "MUST_BE_CONTRACT");
        require(!callhookAllowlist[_newAllowlisted], "ALREADY_ALLOWLISTED");
        callhookAllowlist[_newAllowlisted] = true;
        emit AddedToCallhookAllowlist(_newAllowlisted);
    }

    /**
     * @notice Removes an address from the callhook allowlist.
     * This address will no longer be allowed to include callhooks when transferring tokens.
     * @param _notAllowlisted Address to remove from the allowlist
     */
    function removeFromCallhookAllowlist(address _notAllowlisted) external onlyGovernor {
        require(_notAllowlisted != address(0), "INVALID_ADDRESS");
        require(callhookAllowlist[_notAllowlisted], "NOT_ALLOWLISTED");
        callhookAllowlist[_notAllowlisted] = false;
        emit RemovedFromCallhookAllowlist(_notAllowlisted);
    }

    /**
     * @dev Updates the L2 mint allowance per block
     * It is meant to be called _after_ the issuancePerBlock is updated in L2.
     * The caller should provide the new issuance per block and the block at which it was updated,
     * the function will automatically compute the values so that the bridge's mint allowance
     * correctly tracks the maximum rewards minted in L2.
     * @param _l2IssuancePerBlock New issuancePerBlock that has been set in L2
     * @param _updateBlockNum L1 Block number at which issuancePerBlock was updated in L2
     */
    function updateL2MintAllowance(uint256 _l2IssuancePerBlock, uint256 _updateBlockNum)
        external
        onlyGovernor
    {
        require(_updateBlockNum < block.number, "BLOCK_MUST_BE_PAST");
        require(_updateBlockNum > lastL2MintAllowanceUpdateBlock, "BLOCK_MUST_BE_INCREMENTING");
        accumulatedL2MintAllowanceSnapshot = accumulatedL2MintAllowanceAtBlock(_updateBlockNum);
        lastL2MintAllowanceUpdateBlock = _updateBlockNum;
        l2MintAllowancePerBlock = _l2IssuancePerBlock;
        emit L2MintAllowanceUpdated(
            accumulatedL2MintAllowanceSnapshot,
            l2MintAllowancePerBlock,
            lastL2MintAllowanceUpdateBlock
        );
    }

    /**
     * @dev Manually sets the parameters used to compute the L2 mint allowance
     * The use of this function is not recommended, use updateL2MintAllowance instead;
     * this one is only meant to be used as a backup recovery if a previous call to
     * updateL2MintAllowance was done with incorrect values.
     * @param _accumulatedL2MintAllowanceSnapshot Accumulated L2 mint allowance at L1 block _lastL2MintAllowanceUpdateBlock
     * @param _l2MintAllowancePerBlock L2 issuance per block since block number _lastL2MintAllowanceUpdateBlock
     * @param _lastL2MintAllowanceUpdateBlock L1 Block number at which issuancePerBlock was last updated in L2
     */
    function setL2MintAllowanceParametersManual(
        uint256 _accumulatedL2MintAllowanceSnapshot,
        uint256 _l2MintAllowancePerBlock,
        uint256 _lastL2MintAllowanceUpdateBlock
    ) external onlyGovernor {
        require(_lastL2MintAllowanceUpdateBlock < block.number, "BLOCK_MUST_BE_PAST");
        accumulatedL2MintAllowanceSnapshot = _accumulatedL2MintAllowanceSnapshot;
        l2MintAllowancePerBlock = _l2MintAllowancePerBlock;
        lastL2MintAllowanceUpdateBlock = _lastL2MintAllowanceUpdateBlock;
        emit L2MintAllowanceUpdated(
            accumulatedL2MintAllowanceSnapshot,
            l2MintAllowancePerBlock,
            lastL2MintAllowanceUpdateBlock
        );
    }

    /**
     * @notice Creates and sends a retryable ticket to transfer GRT to L2 using the Arbitrum Inbox.
     * The tokens are escrowed by the gateway until they are withdrawn back to L1.
     * The ticket must be redeemed on L2 to receive tokens at the specified address.
     * Note that the caller must previously allow the gateway to spend the specified amount of GRT.
     * @dev maxGas and gasPriceBid must be set using Arbitrum's NodeInterface.estimateRetryableTicket method.
     * Also note that allowlisted senders (some protocol contracts) can include additional calldata
     * for a callhook to be executed on the L2 side when the tokens are received. In this case, the L2 transaction
     * can revert if the callhook reverts, potentially locking the tokens on the bridge if the callhook
     * never succeeds. This requires extra care when adding contracts to the allowlist, but is necessary to ensure that
     * the tickets can be retried in the case of a temporary failure, and to ensure the atomicity of callhooks
     * with token transfers.
     * @param _l1Token L1 Address of the GRT contract (needed for compatibility with Arbitrum Gateway Router)
     * @param _to Recipient address on L2
     * @param _amount Amount of tokens to transfer
     * @param _maxGas Gas limit for L2 execution of the ticket
     * @param _gasPriceBid Price per gas on L2
     * @param _data Encoded maxSubmissionCost and sender address along with additional calldata
     * @return Sequence number of the retryable ticket created by Inbox
     */
    function outboundTransfer(
        address _l1Token,
        address _to,
        uint256 _amount,
        uint256 _maxGas,
        uint256 _gasPriceBid,
        bytes calldata _data
    ) external payable override notPaused returns (bytes memory) {
        IGraphToken token = graphToken();
        require(_amount != 0, "INVALID_ZERO_AMOUNT");
        require(_l1Token == address(token), "TOKEN_NOT_GRT");
        require(_to != address(0), "INVALID_DESTINATION");

        // nested scopes to avoid stack too deep errors
        address from;
        uint256 seqNum;
        {
            uint256 maxSubmissionCost;
            bytes memory outboundCalldata;
            {
                bytes memory extraData;
                (from, maxSubmissionCost, extraData) = _parseOutboundData(_data);
                require(
                    extraData.length == 0 || callhookAllowlist[msg.sender] == true,
                    "CALL_HOOK_DATA_NOT_ALLOWED"
                );
                require(maxSubmissionCost != 0, "NO_SUBMISSION_COST");
                outboundCalldata = getOutboundCalldata(_l1Token, from, _to, _amount, extraData);
            }
            {
                L2GasParams memory gasParams = L2GasParams(
                    maxSubmissionCost,
                    _maxGas,
                    _gasPriceBid
                );
                // transfer tokens to escrow
                token.transferFrom(from, escrow, _amount);
                seqNum = sendTxToL2(
                    inbox,
                    l2Counterpart,
                    from,
                    msg.value,
                    0,
                    gasParams,
                    outboundCalldata
                );
            }
        }
        emit DepositInitiated(_l1Token, from, _to, seqNum, _amount);

        return abi.encode(seqNum);
    }

    /**
     * @notice Receives withdrawn tokens from L2
     * The equivalent tokens are released from escrow and sent to the destination.
     * @dev can only accept transactions coming from the L2 GRT Gateway.
     * The last parameter is unused but kept for compatibility with Arbitrum gateways,
     * and the encoded exitNum is assumed to be 0.
     * @param _l1Token L1 Address of the GRT contract (needed for compatibility with Arbitrum Gateway Router)
     * @param _from Address of the sender
     * @param _to Recipient address on L1
     * @param _amount Amount of tokens transferred
     */
    function finalizeInboundTransfer(
        address _l1Token,
        address _from,
        address _to,
        uint256 _amount,
        bytes calldata // _data, contains exitNum, unused by this contract
    ) external payable override notPaused onlyL2Counterpart {
        IGraphToken token = graphToken();
        require(_l1Token == address(token), "TOKEN_NOT_GRT");

        uint256 escrowBalance = token.balanceOf(escrow);
        if (_amount > escrowBalance) {
            // This will revert if trying to mint more than allowed
            _mintFromL2(_amount.sub(escrowBalance));
        }
        token.transferFrom(escrow, _to, _amount);

        emit WithdrawalFinalized(_l1Token, _from, _to, 0, _amount);
    }

    /**
     * @notice Calculate the L2 address of a bridged token
     * @dev In our case, this would only work for GRT.
     * @param _l1ERC20 address of L1 GRT contract
     * @return L2 address of the bridged GRT token
     */
    function calculateL2TokenAddress(address _l1ERC20) external view override returns (address) {
        IGraphToken token = graphToken();
        if (_l1ERC20 != address(token)) {
            return address(0);
        }
        return l2GRT;
    }

    /**
     * @notice Get the address of the L2GraphTokenGateway
     * @dev This is added for compatibility with the Arbitrum Router's
     * gateway registration process.
     * @return Address of the L2 gateway connected to this gateway
     */
    function counterpartGateway() external view returns (address) {
        return l2Counterpart;
    }

    /**
     * @notice Creates calldata required to create a retryable ticket
     * @dev encodes the target function with its params which
     * will be called on L2 when the retryable ticket is redeemed
     * @param _l1Token Address of the Graph token contract on L1
     * @param _from Address on L1 from which we're transferring tokens
     * @param _to Address on L2 to which we're transferring tokens
     * @param _amount Amount of GRT to transfer
     * @param _data Additional call data for the L2 transaction, which must be empty unless the caller is allowlisted
     * @return Encoded calldata (including function selector) for the L2 transaction
     */
    function getOutboundCalldata(
        address _l1Token,
        address _from,
        address _to,
        uint256 _amount,
        bytes memory _data
    ) public pure returns (bytes memory) {
        return
            abi.encodeWithSelector(
                ITokenGateway.finalizeInboundTransfer.selector,
                _l1Token,
                _from,
                _to,
                _amount,
                _data
            );
    }

    /**
     * @dev Runs state validation before unpausing, reverts if
     * something is not set properly
     */
    function _checksBeforeUnpause() internal view override {
        require(inbox != address(0), "INBOX_NOT_SET");
        require(l1Router != address(0), "ROUTER_NOT_SET");
        require(l2Counterpart != address(0), "L2_COUNTERPART_NOT_SET");
        require(escrow != address(0), "ESCROW_NOT_SET");
    }

    /**
     * @notice Decodes calldata required for migration of tokens
     * @dev Data must include maxSubmissionCost, extraData can be left empty. When the router
     * sends an outbound message, data also contains the from address.
     * @param _data encoded callhook data
     * @return Sender of the tx
     * @return Base ether value required to keep retryable ticket alive
     * @return Additional data sent to L2
     */
    function _parseOutboundData(bytes calldata _data)
        private
        view
        returns (
            address,
            uint256,
            bytes memory
        )
    {
        address from;
        uint256 maxSubmissionCost;
        bytes memory extraData;
        if (msg.sender == l1Router) {
            // Data encoded by the Gateway Router includes the sender address
            (from, extraData) = abi.decode(_data, (address, bytes));
        } else {
            from = msg.sender;
            extraData = _data;
        }
        // User-encoded data contains the max retryable ticket submission cost
        // and additional L2 calldata
        (maxSubmissionCost, extraData) = abi.decode(extraData, (uint256, bytes));
        return (from, maxSubmissionCost, extraData);
    }

    /**
     * @dev Get the accumulated L2 mint allowance at a particular block number
     * @param _blockNum Block at which allowance will be computed
     * @return The accumulated GRT amount that can be minted from L2 at the specified block
     */
    function accumulatedL2MintAllowanceAtBlock(uint256 _blockNum) public view returns (uint256) {
        require(_blockNum >= lastL2MintAllowanceUpdateBlock, "INVALID_BLOCK_FOR_MINT_ALLOWANCE");
        return
            accumulatedL2MintAllowanceSnapshot.add(
                l2MintAllowancePerBlock.mul(_blockNum.sub(lastL2MintAllowanceUpdateBlock))
            );
    }

    /**
     * @dev Mint new L1 tokens coming  from L2
     * This will check if the amount to mint is within the L2's mint allowance, and revert otherwise.
     * The tokens will be sent to the bridge escrow (from where they will then be sent to the destinatary
     * of the current inbound transfer).
     * @param _amount Number of tokens to mint
     */
    function _mintFromL2(uint256 _amount) internal {
        // If we're trying to mint more than allowed, something's gone terribly wrong
        // (either the L2 issuance is wrong, or the Arbitrum bridge has been compromised)
        require(_l2MintAmountAllowed(_amount), "INVALID_L2_MINT_AMOUNT");
        totalMintedFromL2 = totalMintedFromL2.add(_amount);
        graphToken().mint(escrow, _amount);
        emit TokensMintedFromL2(_amount);
    }

    /**
     * @dev Check if minting a certain amount of tokens from L2 is within allowance
     * @param _amount Number of tokens that would be minted
     * @return true if minting those tokens is allowed, or false if it would be over allowance
     */
    function _l2MintAmountAllowed(uint256 _amount) internal view returns (bool) {
        return (totalMintedFromL2.add(_amount) <= accumulatedL2MintAllowanceAtBlock(block.number));
    }
}

File 2 of 26 : Initializable.sol
// SPDX-License-Identifier: MIT

// solhint-disable-next-line compiler-version
pragma solidity >=0.4.24 <0.8.0;

import "../utils/AddressUpgradeable.sol";

/**
 * @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 {UpgradeableProxy-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 || _isConstructor() || !_initialized, "Initializable: contract is already initialized");

        bool isTopLevelCall = !_initializing;
        if (isTopLevelCall) {
            _initializing = true;
            _initialized = true;
        }

        _;

        if (isTopLevelCall) {
            _initializing = false;
        }
    }

    /// @dev Returns true if and only if the function is running in the constructor
    function _isConstructor() private view returns (bool) {
        return !AddressUpgradeable.isContract(address(this));
    }
}

File 3 of 26 : AddressUpgradeable.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.2 <0.8.0;

/**
 * @dev Collection of functions related to the address type
 */
library AddressUpgradeable {
    /**
     * @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
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        // solhint-disable-next-line no-inline-assembly
        assembly { size := extcodesize(account) }
        return size > 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");

        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
        (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");

        // solhint-disable-next-line avoid-low-level-calls
        (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");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.staticcall(data);
        return _verifyCallResult(success, returndata, errorMessage);
    }

    function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private 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

                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 4 of 26 : SafeMathUpgradeable.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @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 SafeMathUpgradeable {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        uint256 c = a + b;
        if (c < a) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the substraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b > a) return (false, 0);
        return (true, a - b);
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, 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 (true, 0);
        uint256 c = a * b;
        if (c / a != b) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b == 0) return (false, 0);
        return (true, a / b);
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b == 0) return (false, 0);
        return (true, a % b);
    }

    /**
     * @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) {
        require(b <= a, "SafeMath: subtraction overflow");
        return a - b;
    }

    /**
     * @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) {
        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, reverting 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) {
        require(b > 0, "SafeMath: division by zero");
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting 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) {
        require(b > 0, "SafeMath: modulo by zero");
        return a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * 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);
        return a - b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryDiv}.
     *
     * 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);
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * 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;
    }
}

File 5 of 26 : L1ArbitrumMessenger.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2020, 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.
 *
 * Originally copied from:
 * https://github.com/OffchainLabs/arbitrum/tree/e3a6307ad8a2dc2cad35728a2a9908cfd8dd8ef9/packages/arb-bridge-peripherals
 *
 * MODIFIED from Offchain Labs' implementation:
 * - Changed solidity version to 0.7.6 ([email protected])
 *
 */

pragma solidity ^0.7.6;

import "./IInbox.sol";
import "./IOutbox.sol";

/// @notice L1 utility contract to assist with L1 <=> L2 interactions
/// @dev this is an abstract contract instead of library so the functions can be easily overriden when testing
abstract contract L1ArbitrumMessenger {
    event TxToL2(address indexed _from, address indexed _to, uint256 indexed _seqNum, bytes _data);

    struct L2GasParams {
        uint256 _maxSubmissionCost;
        uint256 _maxGas;
        uint256 _gasPriceBid;
    }

    function sendTxToL2(
        address _inbox,
        address _to,
        address _user,
        uint256 _l1CallValue,
        uint256 _l2CallValue,
        L2GasParams memory _l2GasParams,
        bytes memory _data
    ) internal virtual returns (uint256) {
        // alternative function entry point when struggling with the stack size
        return
            sendTxToL2(
                _inbox,
                _to,
                _user,
                _l1CallValue,
                _l2CallValue,
                _l2GasParams._maxSubmissionCost,
                _l2GasParams._maxGas,
                _l2GasParams._gasPriceBid,
                _data
            );
    }

    function sendTxToL2(
        address _inbox,
        address _to,
        address _user,
        uint256 _l1CallValue,
        uint256 _l2CallValue,
        uint256 _maxSubmissionCost,
        uint256 _maxGas,
        uint256 _gasPriceBid,
        bytes memory _data
    ) internal virtual returns (uint256) {
        uint256 seqNum = IInbox(_inbox).createRetryableTicket{ value: _l1CallValue }(
            _to,
            _l2CallValue,
            _maxSubmissionCost,
            _user,
            _user,
            _maxGas,
            _gasPriceBid,
            _data
        );
        emit TxToL2(_user, _to, seqNum, _data);
        return seqNum;
    }

    function getBridge(address _inbox) internal view virtual returns (IBridge) {
        return IInbox(_inbox).bridge();
    }

    /// @dev the l2ToL1Sender behaves as the tx.origin, the msg.sender should be validated to protect against reentrancies
    function getL2ToL1Sender(address _inbox) internal view virtual returns (address) {
        IOutbox outbox = IOutbox(getBridge(_inbox).activeOutbox());
        address l2ToL1Sender = outbox.l2ToL1Sender();

        require(l2ToL1Sender != address(0), "NO_SENDER");
        return l2ToL1Sender;
    }
}

File 6 of 26 : IBridge.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 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.
 *
 * Originally copied from:
 * https://github.com/OffchainLabs/arbitrum/tree/e3a6307ad8a2dc2cad35728a2a9908cfd8dd8ef9/packages/arb-bridge-eth
 *
 * MODIFIED from Offchain Labs' implementation:
 * - Changed solidity version to 0.7.6 ([email protected])
 *
 */

pragma solidity ^0.7.6;

interface IBridge {
    event MessageDelivered(
        uint256 indexed messageIndex,
        bytes32 indexed beforeInboxAcc,
        address inbox,
        uint8 kind,
        address sender,
        bytes32 messageDataHash
    );

    event BridgeCallTriggered(
        address indexed outbox,
        address indexed destAddr,
        uint256 amount,
        bytes data
    );

    event InboxToggle(address indexed inbox, bool enabled);

    event OutboxToggle(address indexed outbox, bool enabled);

    function deliverMessageToInbox(
        uint8 kind,
        address sender,
        bytes32 messageDataHash
    ) external payable returns (uint256);

    function executeCall(
        address destAddr,
        uint256 amount,
        bytes calldata data
    ) external returns (bool success, bytes memory returnData);

    // These are only callable by the admin
    function setInbox(address inbox, bool enabled) external;

    function setOutbox(address inbox, bool enabled) external;

    // View functions

    function activeOutbox() external view returns (address);

    function allowedInboxes(address inbox) external view returns (bool);

    function allowedOutboxes(address outbox) external view returns (bool);

    function inboxAccs(uint256 index) external view returns (bytes32);

    function messageCount() external view returns (uint256);
}

File 7 of 26 : IInbox.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 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.
 *
 * Originally copied from:
 * https://github.com/OffchainLabs/arbitrum/tree/e3a6307ad8a2dc2cad35728a2a9908cfd8dd8ef9/packages/arb-bridge-eth
 *
 * MODIFIED from Offchain Labs' implementation:
 * - Changed solidity version to 0.7.6 ([email protected])
 *
 */

pragma solidity ^0.7.6;

import "./IBridge.sol";
import "./IMessageProvider.sol";

interface IInbox is IMessageProvider {
    function sendL2Message(bytes calldata messageData) external returns (uint256);

    function sendUnsignedTransaction(
        uint256 maxGas,
        uint256 gasPriceBid,
        uint256 nonce,
        address destAddr,
        uint256 amount,
        bytes calldata data
    ) external returns (uint256);

    function sendContractTransaction(
        uint256 maxGas,
        uint256 gasPriceBid,
        address destAddr,
        uint256 amount,
        bytes calldata data
    ) external returns (uint256);

    function sendL1FundedUnsignedTransaction(
        uint256 maxGas,
        uint256 gasPriceBid,
        uint256 nonce,
        address destAddr,
        bytes calldata data
    ) external payable returns (uint256);

    function sendL1FundedContractTransaction(
        uint256 maxGas,
        uint256 gasPriceBid,
        address destAddr,
        bytes calldata data
    ) external payable returns (uint256);

    function createRetryableTicket(
        address destAddr,
        uint256 arbTxCallValue,
        uint256 maxSubmissionCost,
        address submissionRefundAddress,
        address valueRefundAddress,
        uint256 maxGas,
        uint256 gasPriceBid,
        bytes calldata data
    ) external payable returns (uint256);

    function depositEth(uint256 maxSubmissionCost) external payable returns (uint256);

    function bridge() external view returns (IBridge);

    function pauseCreateRetryables() external;

    function unpauseCreateRetryables() external;

    function startRewriteAddress() external;

    function stopRewriteAddress() external;
}

File 8 of 26 : IOutbox.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 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.
 *
 * Originally copied from:
 * https://github.com/OffchainLabs/arbitrum/tree/e3a6307ad8a2dc2cad35728a2a9908cfd8dd8ef9/packages/arb-bridge-eth
 *
 * MODIFIED from Offchain Labs' implementation:
 * - Changed solidity version to 0.7.6 ([email protected])
 *
 */

pragma solidity ^0.7.6;

interface IOutbox {
    event OutboxEntryCreated(
        uint256 indexed batchNum,
        uint256 outboxEntryIndex,
        bytes32 outputRoot,
        uint256 numInBatch
    );
    event OutBoxTransactionExecuted(
        address indexed destAddr,
        address indexed l2Sender,
        uint256 indexed outboxEntryIndex,
        uint256 transactionIndex
    );

    function l2ToL1Sender() external view returns (address);

    function l2ToL1Block() external view returns (uint256);

    function l2ToL1EthBlock() external view returns (uint256);

    function l2ToL1Timestamp() external view returns (uint256);

    function l2ToL1BatchNum() external view returns (uint256);

    function l2ToL1OutputId() external view returns (bytes32);

    function processOutgoingMessages(bytes calldata sendsData, uint256[] calldata sendLengths)
        external;

    function outboxEntryExists(uint256 batchNum) external view returns (bool);
}

File 9 of 26 : ITokenGateway.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2020, 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.
 *
 * Originally copied from:
 * https://github.com/OffchainLabs/arbitrum/tree/e3a6307ad8a2dc2cad35728a2a9908cfd8dd8ef9/packages/arb-bridge-peripherals
 *
 * MODIFIED from Offchain Labs' implementation:
 * - Changed solidity version to 0.7.6 ([email protected])
 *
 */

pragma solidity ^0.7.6;

interface ITokenGateway {
    /// @notice event deprecated in favor of DepositInitiated and WithdrawalInitiated
    // event OutboundTransferInitiated(
    //     address token,
    //     address indexed _from,
    //     address indexed _to,
    //     uint256 indexed _transferId,
    //     uint256 _amount,
    //     bytes _data
    // );

    /// @notice event deprecated in favor of DepositFinalized and WithdrawalFinalized
    // event InboundTransferFinalized(
    //     address token,
    //     address indexed _from,
    //     address indexed _to,
    //     uint256 indexed _transferId,
    //     uint256 _amount,
    //     bytes _data
    // );

    function outboundTransfer(
        address _token,
        address _to,
        uint256 _amount,
        uint256 _maxGas,
        uint256 _gasPriceBid,
        bytes calldata _data
    ) external payable returns (bytes memory);

    function finalizeInboundTransfer(
        address _token,
        address _from,
        address _to,
        uint256 _amount,
        bytes calldata _data
    ) external payable;

    /**
     * @notice Calculate the address used when bridging an ERC20 token
     * @dev the L1 and L2 address oracles may not always be in sync.
     * For example, a custom token may have been registered but not deployed or the contract self destructed.
     * @param l1ERC20 address of L1 token
     * @return L2 address of a bridged ERC20 token
     */
    function calculateL2TokenAddress(address l1ERC20) external view returns (address);
}

File 10 of 26 : Managed.sol
// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.7.6;

import { IController } from "./IController.sol";

import { ICuration } from "../curation/ICuration.sol";
import { IEpochManager } from "../epochs/IEpochManager.sol";
import { IRewardsManager } from "../rewards/IRewardsManager.sol";
import { IStaking } from "../staking/IStaking.sol";
import { IGraphToken } from "../token/IGraphToken.sol";
import { ITokenGateway } from "../arbitrum/ITokenGateway.sol";

import { IManaged } from "./IManaged.sol";

/**
 * @title Graph Managed contract
 * @dev The Managed contract provides an interface to interact with the Controller.
 * It also provides local caching for contract addresses. This mechanism relies on calling the
 * public `syncAllContracts()` function whenever a contract changes in the controller.
 *
 * Inspired by Livepeer:
 * https://github.com/livepeer/protocol/blob/streamflow/contracts/Controller.sol
 */
abstract contract Managed is IManaged {
    // -- State --

    /// Controller that contract is registered with
    IController public controller;
    /// @dev Cache for the addresses of the contracts retrieved from the controller
    mapping(bytes32 => address) private _addressCache;
    /// @dev Gap for future storage variables
    uint256[10] private __gap;

    // Immutables
    bytes32 private immutable CURATION = keccak256("Curation");
    bytes32 private immutable EPOCH_MANAGER = keccak256("EpochManager");
    bytes32 private immutable REWARDS_MANAGER = keccak256("RewardsManager");
    bytes32 private immutable STAKING = keccak256("Staking");
    bytes32 private immutable GRAPH_TOKEN = keccak256("GraphToken");
    bytes32 private immutable GRAPH_TOKEN_GATEWAY = keccak256("GraphTokenGateway");

    // -- Events --

    /// Emitted when a contract parameter has been updated
    event ParameterUpdated(string param);
    /// Emitted when the controller address has been set
    event SetController(address controller);

    /// Emitted when contract with `nameHash` is synced to `contractAddress`.
    event ContractSynced(bytes32 indexed nameHash, address contractAddress);

    // -- Modifiers --

    /**
     * @dev Revert if the controller is paused or partially paused
     */
    function _notPartialPaused() internal view {
        require(!controller.paused(), "Paused");
        require(!controller.partialPaused(), "Partial-paused");
    }

    /**
     * @dev Revert if the controller is paused
     */
    function _notPaused() internal view virtual {
        require(!controller.paused(), "Paused");
    }

    /**
     * @dev Revert if the caller is not the governor
     */
    function _onlyGovernor() internal view {
        require(msg.sender == controller.getGovernor(), "Only Controller governor");
    }

    /**
     * @dev Revert if the caller is not the Controller
     */
    function _onlyController() internal view {
        require(msg.sender == address(controller), "Caller must be Controller");
    }

    /**
     * @dev Revert if the controller is paused or partially paused
     */
    modifier notPartialPaused() {
        _notPartialPaused();
        _;
    }

    /**
     * @dev Revert if the controller is paused
     */
    modifier notPaused() {
        _notPaused();
        _;
    }

    /**
     * @dev Revert if the caller is not the Controller
     */
    modifier onlyController() {
        _onlyController();
        _;
    }

    /**
     * @dev Revert if the caller is not the governor
     */
    modifier onlyGovernor() {
        _onlyGovernor();
        _;
    }

    // -- Functions --

    /**
     * @dev Initialize a Managed contract
     * @param _controller Address for the Controller that manages this contract
     */
    function _initialize(address _controller) internal {
        _setController(_controller);
    }

    /**
     * @notice Set Controller. Only callable by current controller.
     * @param _controller Controller contract address
     */
    function setController(address _controller) external override onlyController {
        _setController(_controller);
    }

    /**
     * @dev Set controller.
     * @param _controller Controller contract address
     */
    function _setController(address _controller) internal {
        require(_controller != address(0), "Controller must be set");
        controller = IController(_controller);
        emit SetController(_controller);
    }

    /**
     * @dev Return Curation interface
     * @return Curation contract registered with Controller
     */
    function curation() internal view returns (ICuration) {
        return ICuration(_resolveContract(CURATION));
    }

    /**
     * @dev Return EpochManager interface
     * @return Epoch manager contract registered with Controller
     */
    function epochManager() internal view returns (IEpochManager) {
        return IEpochManager(_resolveContract(EPOCH_MANAGER));
    }

    /**
     * @dev Return RewardsManager interface
     * @return Rewards manager contract registered with Controller
     */
    function rewardsManager() internal view returns (IRewardsManager) {
        return IRewardsManager(_resolveContract(REWARDS_MANAGER));
    }

    /**
     * @dev Return Staking interface
     * @return Staking contract registered with Controller
     */
    function staking() internal view returns (IStaking) {
        return IStaking(_resolveContract(STAKING));
    }

    /**
     * @dev Return GraphToken interface
     * @return Graph token contract registered with Controller
     */
    function graphToken() internal view returns (IGraphToken) {
        return IGraphToken(_resolveContract(GRAPH_TOKEN));
    }

    /**
     * @dev Return GraphTokenGateway (L1 or L2) interface
     * @return Graph token gateway contract registered with Controller
     */
    function graphTokenGateway() internal view returns (ITokenGateway) {
        return ITokenGateway(_resolveContract(GRAPH_TOKEN_GATEWAY));
    }

    /**
     * @dev Resolve a contract address from the cache or the Controller if not found
     * @param _nameHash keccak256 hash of the contract name
     * @return Address of the contract
     */
    function _resolveContract(bytes32 _nameHash) internal view returns (address) {
        address contractAddress = _addressCache[_nameHash];
        if (contractAddress == address(0)) {
            contractAddress = controller.getContractProxy(_nameHash);
        }
        return contractAddress;
    }

    /**
     * @dev Cache a contract address from the Controller registry.
     * @param _name Name of the contract to sync into the cache
     */
    function _syncContract(string memory _name) internal {
        bytes32 nameHash = keccak256(abi.encodePacked(_name));
        address contractAddress = controller.getContractProxy(nameHash);
        if (_addressCache[nameHash] != contractAddress) {
            _addressCache[nameHash] = contractAddress;
            emit ContractSynced(nameHash, contractAddress);
        }
    }

    /**
     * @notice Sync protocol contract addresses from the Controller registry
     * @dev This function will cache all the contracts using the latest addresses
     * Anyone can call the function whenever a Proxy contract change in the
     * controller to ensure the protocol is using the latest version
     */
    function syncAllContracts() external {
        _syncContract("Curation");
        _syncContract("EpochManager");
        _syncContract("RewardsManager");
        _syncContract("Staking");
        _syncContract("GraphToken");
        _syncContract("GraphTokenGateway");
    }
}

File 11 of 26 : GraphTokenGateway.sol
// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.7.6;

import { GraphUpgradeable } from "../upgrades/GraphUpgradeable.sol";
import { ITokenGateway } from "../arbitrum/ITokenGateway.sol";
import { Pausable } from "../governance/Pausable.sol";
import { Managed } from "../governance/Managed.sol";

/**
 * @title L1/L2 Graph Token Gateway
 * @dev This includes everything that's shared between the L1 and L2 sides of the bridge.
 */
abstract contract GraphTokenGateway is GraphUpgradeable, Pausable, Managed, ITokenGateway {
    /// @dev Storage gap added in case we need to add state variables to this contract
    uint256[50] private __gap;

    /**
     * @dev Check if the caller is the Controller's governor or this contract's pause guardian.
     */
    modifier onlyGovernorOrGuardian() {
        require(
            msg.sender == controller.getGovernor() || msg.sender == pauseGuardian,
            "Only Governor or Guardian"
        );
        _;
    }

    /**
     * @notice Change the Pause Guardian for this contract
     * @param _newPauseGuardian The address of the new Pause Guardian
     */
    function setPauseGuardian(address _newPauseGuardian) external onlyGovernor {
        require(_newPauseGuardian != address(0), "PauseGuardian must be set");
        _setPauseGuardian(_newPauseGuardian);
    }

    /**
     * @notice Change the paused state of the contract
     * @param _newPaused New value for the pause state (true means the transfers will be paused)
     */
    function setPaused(bool _newPaused) external onlyGovernorOrGuardian {
        if (!_newPaused) {
            _checksBeforeUnpause();
        }
        _setPaused(_newPaused);
    }

    /**
     * @notice Getter to access paused state of this contract
     * @return True if the contract is paused, false otherwise
     */
    function paused() external view returns (bool) {
        return _paused;
    }

    /**
     * @dev Override the default pausing from Managed to allow pausing this
     * particular contract instead of pausing from the Controller.
     */
    function _notPaused() internal view override {
        require(!_paused, "Paused (contract)");
    }

    /**
     * @dev Runs state validation before unpausing, reverts if
     * something is not set properly
     */
    function _checksBeforeUnpause() internal view virtual;
}

File 12 of 26 : IGraphToken.sol
// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.7.6;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

interface IGraphToken is IERC20 {
    // -- Mint and Burn --

    function burn(uint256 amount) external;

    function burnFrom(address _from, uint256 amount) external;

    function mint(address _to, uint256 _amount) external;

    // -- Mint Admin --

    function addMinter(address _account) external;

    function removeMinter(address _account) external;

    function renounceMinter() external;

    function isMinter(address _account) external view returns (bool);

    // -- Permit --

    function permit(
        address _owner,
        address _spender,
        uint256 _value,
        uint256 _deadline,
        uint8 _v,
        bytes32 _r,
        bytes32 _s
    ) external;

    // -- Allowance --

    function increaseAllowance(address spender, uint256 addedValue) external returns (bool);

    function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);
}

File 13 of 26 : IMessageProvider.sol
// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 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.
 *
 * Originally copied from:
 * https://github.com/OffchainLabs/arbitrum/tree/e3a6307ad8a2dc2cad35728a2a9908cfd8dd8ef9/packages/arb-bridge-eth
 *
 * MODIFIED from Offchain Labs' implementation:
 * - Changed solidity version to 0.7.6 ([email protected])
 *
 */

pragma solidity ^0.7.6;

interface IMessageProvider {
    event InboxMessageDelivered(uint256 indexed messageNum, bytes data);

    event InboxMessageDeliveredFromOrigin(uint256 indexed messageNum);
}

File 14 of 26 : IController.sol
// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity >=0.6.12 <0.8.0;

interface IController {
    function getGovernor() external view returns (address);

    // -- Registry --

    function setContractProxy(bytes32 _id, address _contractAddress) external;

    function unsetContractProxy(bytes32 _id) external;

    function updateController(bytes32 _id, address _controller) external;

    function getContractProxy(bytes32 _id) external view returns (address);

    // -- Pausing --

    function setPartialPaused(bool _partialPaused) external;

    function setPaused(bool _paused) external;

    function setPauseGuardian(address _newPauseGuardian) external;

    function paused() external view returns (bool);

    function partialPaused() external view returns (bool);
}

File 15 of 26 : ICuration.sol
// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.7.6;

import "./IGraphCurationToken.sol";

interface ICuration {
    // -- Configuration --

    function setDefaultReserveRatio(uint32 _defaultReserveRatio) external;

    function setMinimumCurationDeposit(uint256 _minimumCurationDeposit) external;

    function setCurationTaxPercentage(uint32 _percentage) external;

    function setCurationTokenMaster(address _curationTokenMaster) external;

    // -- Curation --

    function mint(
        bytes32 _subgraphDeploymentID,
        uint256 _tokensIn,
        uint256 _signalOutMin
    ) external returns (uint256, uint256);

    function burn(
        bytes32 _subgraphDeploymentID,
        uint256 _signalIn,
        uint256 _tokensOutMin
    ) external returns (uint256);

    function collect(bytes32 _subgraphDeploymentID, uint256 _tokens) external;

    // -- Getters --

    function isCurated(bytes32 _subgraphDeploymentID) external view returns (bool);

    function getCuratorSignal(address _curator, bytes32 _subgraphDeploymentID)
        external
        view
        returns (uint256);

    function getCurationPoolSignal(bytes32 _subgraphDeploymentID) external view returns (uint256);

    function getCurationPoolTokens(bytes32 _subgraphDeploymentID) external view returns (uint256);

    function tokensToSignal(bytes32 _subgraphDeploymentID, uint256 _tokensIn)
        external
        view
        returns (uint256, uint256);

    function signalToTokens(bytes32 _subgraphDeploymentID, uint256 _signalIn)
        external
        view
        returns (uint256);

    function curationTaxPercentage() external view returns (uint32);
}

File 16 of 26 : IEpochManager.sol
// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.7.6;

interface IEpochManager {
    // -- Configuration --

    function setEpochLength(uint256 _epochLength) external;

    // -- Epochs

    function runEpoch() external;

    // -- Getters --

    function isCurrentEpochRun() external view returns (bool);

    function blockNum() external view returns (uint256);

    function blockHash(uint256 _block) external view returns (bytes32);

    function currentEpoch() external view returns (uint256);

    function currentEpochBlock() external view returns (uint256);

    function currentEpochBlockSinceStart() external view returns (uint256);

    function epochsSince(uint256 _epoch) external view returns (uint256);

    function epochsSinceUpdate() external view returns (uint256);
}

File 17 of 26 : IRewardsManager.sol
// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.7.6;

interface IRewardsManager {
    /**
     * @dev Stores accumulated rewards and snapshots related to a particular SubgraphDeployment.
     */
    struct Subgraph {
        uint256 accRewardsForSubgraph;
        uint256 accRewardsForSubgraphSnapshot;
        uint256 accRewardsPerSignalSnapshot;
        uint256 accRewardsPerAllocatedToken;
    }

    // -- Config --

    function setIssuancePerBlock(uint256 _issuancePerBlock) external;

    function setMinimumSubgraphSignal(uint256 _minimumSubgraphSignal) external;

    // -- Denylist --

    function setSubgraphAvailabilityOracle(address _subgraphAvailabilityOracle) external;

    function setDenied(bytes32 _subgraphDeploymentID, bool _deny) external;

    function setDeniedMany(bytes32[] calldata _subgraphDeploymentID, bool[] calldata _deny)
        external;

    function isDenied(bytes32 _subgraphDeploymentID) external view returns (bool);

    // -- Getters --

    function getNewRewardsPerSignal() external view returns (uint256);

    function getAccRewardsPerSignal() external view returns (uint256);

    function getAccRewardsForSubgraph(bytes32 _subgraphDeploymentID)
        external
        view
        returns (uint256);

    function getAccRewardsPerAllocatedToken(bytes32 _subgraphDeploymentID)
        external
        view
        returns (uint256, uint256);

    function getRewards(address _allocationID) external view returns (uint256);

    // -- Updates --

    function updateAccRewardsPerSignal() external returns (uint256);

    function takeRewards(address _allocationID) external returns (uint256);

    // -- Hooks --

    function onSubgraphSignalUpdate(bytes32 _subgraphDeploymentID) external returns (uint256);

    function onSubgraphAllocationUpdate(bytes32 _subgraphDeploymentID) external returns (uint256);
}

File 18 of 26 : IStaking.sol
// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity >=0.6.12 <0.8.0;
pragma abicoder v2;

import "./IStakingData.sol";

interface IStaking is IStakingData {
    // -- Allocation Data --

    /**
     * @dev Possible states an allocation can be
     * States:
     * - Null = indexer == address(0)
     * - Active = not Null && tokens > 0
     * - Closed = Active && closedAtEpoch != 0
     * - Finalized = Closed && closedAtEpoch + channelDisputeEpochs > now()
     * - Claimed = not Null && tokens == 0
     */
    enum AllocationState {
        Null,
        Active,
        Closed,
        Finalized,
        Claimed
    }

    // -- Configuration --

    function setMinimumIndexerStake(uint256 _minimumIndexerStake) external;

    function setThawingPeriod(uint32 _thawingPeriod) external;

    function setCurationPercentage(uint32 _percentage) external;

    function setProtocolPercentage(uint32 _percentage) external;

    function setChannelDisputeEpochs(uint32 _channelDisputeEpochs) external;

    function setMaxAllocationEpochs(uint32 _maxAllocationEpochs) external;

    function setRebateRatio(uint32 _alphaNumerator, uint32 _alphaDenominator) external;

    function setDelegationRatio(uint32 _delegationRatio) external;

    function setDelegationParameters(
        uint32 _indexingRewardCut,
        uint32 _queryFeeCut,
        uint32 _cooldownBlocks
    ) external;

    function setDelegationParametersCooldown(uint32 _blocks) external;

    function setDelegationUnbondingPeriod(uint32 _delegationUnbondingPeriod) external;

    function setDelegationTaxPercentage(uint32 _percentage) external;

    function setSlasher(address _slasher, bool _allowed) external;

    function setAssetHolder(address _assetHolder, bool _allowed) external;

    // -- Operation --

    function setOperator(address _operator, bool _allowed) external;

    function isOperator(address _operator, address _indexer) external view returns (bool);

    // -- Staking --

    function stake(uint256 _tokens) external;

    function stakeTo(address _indexer, uint256 _tokens) external;

    function unstake(uint256 _tokens) external;

    function slash(
        address _indexer,
        uint256 _tokens,
        uint256 _reward,
        address _beneficiary
    ) external;

    function withdraw() external;

    function setRewardsDestination(address _destination) external;

    // -- Delegation --

    function delegate(address _indexer, uint256 _tokens) external returns (uint256);

    function undelegate(address _indexer, uint256 _shares) external returns (uint256);

    function withdrawDelegated(address _indexer, address _newIndexer) external returns (uint256);

    // -- Channel management and allocations --

    function allocate(
        bytes32 _subgraphDeploymentID,
        uint256 _tokens,
        address _allocationID,
        bytes32 _metadata,
        bytes calldata _proof
    ) external;

    function allocateFrom(
        address _indexer,
        bytes32 _subgraphDeploymentID,
        uint256 _tokens,
        address _allocationID,
        bytes32 _metadata,
        bytes calldata _proof
    ) external;

    function closeAllocation(address _allocationID, bytes32 _poi) external;

    function closeAllocationMany(CloseAllocationRequest[] calldata _requests) external;

    function closeAndAllocate(
        address _oldAllocationID,
        bytes32 _poi,
        address _indexer,
        bytes32 _subgraphDeploymentID,
        uint256 _tokens,
        address _allocationID,
        bytes32 _metadata,
        bytes calldata _proof
    ) external;

    function collect(uint256 _tokens, address _allocationID) external;

    function claim(address _allocationID, bool _restake) external;

    function claimMany(address[] calldata _allocationID, bool _restake) external;

    // -- Getters and calculations --

    function hasStake(address _indexer) external view returns (bool);

    function getIndexerStakedTokens(address _indexer) external view returns (uint256);

    function getIndexerCapacity(address _indexer) external view returns (uint256);

    function getAllocation(address _allocationID) external view returns (Allocation memory);

    function getAllocationState(address _allocationID) external view returns (AllocationState);

    function isAllocation(address _allocationID) external view returns (bool);

    function getSubgraphAllocatedTokens(bytes32 _subgraphDeploymentID)
        external
        view
        returns (uint256);

    function getDelegation(address _indexer, address _delegator)
        external
        view
        returns (Delegation memory);

    function isDelegator(address _indexer, address _delegator) external view returns (bool);
}

File 19 of 26 : IManaged.sol
// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.7.6;

interface IManaged {
    function setController(address _controller) external;
}

File 20 of 26 : IGraphCurationToken.sol
// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.7.6;

import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";

interface IGraphCurationToken is IERC20Upgradeable {
    function initialize(address _owner) external;

    function burnFrom(address _account, uint256 _amount) external;

    function mint(address _to, uint256 _amount) external;
}

File 21 of 26 : IERC20Upgradeable.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20Upgradeable {
    /**
     * @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);
}

File 22 of 26 : IStakingData.sol
// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity >=0.6.12 <0.8.0;

interface IStakingData {
    /**
     * @dev Allocate GRT tokens for the purpose of serving queries of a subgraph deployment
     * An allocation is created in the allocate() function and consumed in claim()
     */
    struct Allocation {
        address indexer;
        bytes32 subgraphDeploymentID;
        uint256 tokens; // Tokens allocated to a SubgraphDeployment
        uint256 createdAtEpoch; // Epoch when it was created
        uint256 closedAtEpoch; // Epoch when it was closed
        uint256 collectedFees; // Collected fees for the allocation
        uint256 effectiveAllocation; // Effective allocation when closed
        uint256 accRewardsPerAllocatedToken; // Snapshot used for reward calc
    }

    /**
     * @dev Represents a request to close an allocation with a specific proof of indexing.
     * This is passed when calling closeAllocationMany to define the closing parameters for
     * each allocation.
     */
    struct CloseAllocationRequest {
        address allocationID;
        bytes32 poi;
    }

    // -- Delegation Data --

    /**
     * @dev Delegation pool information. One per indexer.
     */
    struct DelegationPool {
        uint32 cooldownBlocks; // Blocks to wait before updating parameters
        uint32 indexingRewardCut; // in PPM
        uint32 queryFeeCut; // in PPM
        uint256 updatedAtBlock; // Block when the pool was last updated
        uint256 tokens; // Total tokens as pool reserves
        uint256 shares; // Total shares minted in the pool
        mapping(address => Delegation) delegators; // Mapping of delegator => Delegation
    }

    /**
     * @dev Individual delegation data of a delegator in a pool.
     */
    struct Delegation {
        uint256 shares; // Shares owned by a delegator in the pool
        uint256 tokensLocked; // Tokens locked for undelegation
        uint256 tokensLockedUntil; // Block when locked tokens can be withdrawn
    }
}

File 23 of 26 : IERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <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 `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);
}

File 24 of 26 : GraphUpgradeable.sol
// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.7.6;

import { IGraphProxy } from "./IGraphProxy.sol";

/**
 * @title Graph Upgradeable
 * @dev This contract is intended to be inherited from upgradeable contracts.
 */
abstract contract GraphUpgradeable {
    /**
     * @dev Storage slot with the address of the current implementation.
     * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
     * validated in the constructor.
     */
    bytes32 internal constant IMPLEMENTATION_SLOT =
        0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;

    /**
     * @dev Check if the caller is the proxy admin.
     */
    modifier onlyProxyAdmin(IGraphProxy _proxy) {
        require(msg.sender == _proxy.admin(), "Caller must be the proxy admin");
        _;
    }

    /**
     * @dev Check if the caller is the implementation.
     */
    modifier onlyImpl() {
        require(msg.sender == _implementation(), "Only implementation");
        _;
    }

    /**
     * @dev Returns the current implementation.
     * @return impl Address of the current implementation
     */
    function _implementation() internal view returns (address impl) {
        bytes32 slot = IMPLEMENTATION_SLOT;
        // solhint-disable-next-line no-inline-assembly
        assembly {
            impl := sload(slot)
        }
    }

    /**
     * @notice Accept to be an implementation of proxy.
     * @param _proxy Proxy to accept
     */
    function acceptProxy(IGraphProxy _proxy) external onlyProxyAdmin(_proxy) {
        _proxy.acceptUpgrade();
    }

    /**
     * @notice Accept to be an implementation of proxy and then call a function from the new
     * implementation as specified by `_data`, which should be an encoded function call. This is
     * useful to initialize new storage variables in the proxied contract.
     * @param _proxy Proxy to accept
     * @param _data Calldata for the initialization function call (including selector)
     */
    function acceptProxyAndCall(IGraphProxy _proxy, bytes calldata _data)
        external
        onlyProxyAdmin(_proxy)
    {
        _proxy.acceptUpgradeAndCall(_data);
    }
}

File 25 of 26 : Pausable.sol
// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.7.6;

abstract contract Pausable {
    /**
     * @dev "Partial paused" pauses exit and enter functions for GRT, but not internal
     * functions, such as allocating
     */
    bool internal _partialPaused;
    /**
     * @dev Paused will pause all major protocol functions
     */
    bool internal _paused;

    /// Timestamp for the last time the partial pause was set
    uint256 public lastPausePartialTime;
    /// Timestamp for the last time the full pause was set
    uint256 public lastPauseTime;

    /// Pause guardian is a separate entity from the governor that can
    /// pause and unpause the protocol, fully or partially
    address public pauseGuardian;

    /// Emitted when the partial pause state changed
    event PartialPauseChanged(bool isPaused);
    /// Emitted when the full pause state changed
    event PauseChanged(bool isPaused);
    /// Emitted when the pause guardian is changed
    event NewPauseGuardian(address indexed oldPauseGuardian, address indexed pauseGuardian);

    /**
     * @dev Change the partial paused state of the contract
     * @param _toPause New value for the partial pause state (true means the contracts will be partially paused)
     */
    function _setPartialPaused(bool _toPause) internal {
        if (_toPause == _partialPaused) {
            return;
        }
        _partialPaused = _toPause;
        if (_partialPaused) {
            lastPausePartialTime = block.timestamp;
        }
        emit PartialPauseChanged(_partialPaused);
    }

    /**
     * @dev Change the paused state of the contract
     * @param _toPause New value for the pause state (true means the contracts will be paused)
     */
    function _setPaused(bool _toPause) internal {
        if (_toPause == _paused) {
            return;
        }
        _paused = _toPause;
        if (_paused) {
            lastPauseTime = block.timestamp;
        }
        emit PauseChanged(_paused);
    }

    /**
     * @dev Change the Pause Guardian
     * @param newPauseGuardian The address of the new Pause Guardian
     */
    function _setPauseGuardian(address newPauseGuardian) internal {
        address oldPauseGuardian = pauseGuardian;
        pauseGuardian = newPauseGuardian;
        emit NewPauseGuardian(oldPauseGuardian, pauseGuardian);
    }
}

File 26 of 26 : IGraphProxy.sol
// SPDX-License-Identifier: GPL-2.0-or-later

pragma solidity ^0.7.6;

interface IGraphProxy {
    function admin() external returns (address);

    function setAdmin(address _newAdmin) external;

    function implementation() external returns (address);

    function pendingImplementation() external returns (address);

    function upgradeTo(address _newImplementation) external;

    function acceptUpgrade() external;

    function acceptUpgradeAndCall(bytes calldata data) external;
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newAllowlisted","type":"address"}],"name":"AddedToCallhookAllowlist","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"inbox","type":"address"},{"indexed":false,"internalType":"address","name":"l1Router","type":"address"}],"name":"ArbitrumAddressesSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"nameHash","type":"bytes32"},{"indexed":false,"internalType":"address","name":"contractAddress","type":"address"}],"name":"ContractSynced","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"l1Token","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"sequenceNumber","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"DepositInitiated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"escrow","type":"address"}],"name":"EscrowAddressSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"l2Counterpart","type":"address"}],"name":"L2CounterpartAddressSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"accumulatedL2MintAllowanceSnapshot","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"l2MintAllowancePerBlock","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lastL2MintAllowanceUpdateBlock","type":"uint256"}],"name":"L2MintAllowanceUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"l2GRT","type":"address"}],"name":"L2TokenAddressSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldPauseGuardian","type":"address"},{"indexed":true,"internalType":"address","name":"pauseGuardian","type":"address"}],"name":"NewPauseGuardian","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"param","type":"string"}],"name":"ParameterUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isPaused","type":"bool"}],"name":"PartialPauseChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"isPaused","type":"bool"}],"name":"PauseChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"notAllowlisted","type":"address"}],"name":"RemovedFromCallhookAllowlist","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"controller","type":"address"}],"name":"SetController","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokensMintedFromL2","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_from","type":"address"},{"indexed":true,"internalType":"address","name":"_to","type":"address"},{"indexed":true,"internalType":"uint256","name":"_seqNum","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"_data","type":"bytes"}],"name":"TxToL2","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"l1Token","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"exitNum","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"WithdrawalFinalized","type":"event"},{"inputs":[{"internalType":"contract IGraphProxy","name":"_proxy","type":"address"}],"name":"acceptProxy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IGraphProxy","name":"_proxy","type":"address"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"acceptProxyAndCall","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_blockNum","type":"uint256"}],"name":"accumulatedL2MintAllowanceAtBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"accumulatedL2MintAllowanceSnapshot","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newAllowlisted","type":"address"}],"name":"addToCallhookAllowlist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_l1ERC20","type":"address"}],"name":"calculateL2TokenAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"callhookAllowlist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"controller","outputs":[{"internalType":"contract IController","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"counterpartGateway","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"escrow","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_l1Token","type":"address"},{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"finalizeInboundTransfer","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_l1Token","type":"address"},{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"getOutboundCalldata","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"inbox","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_controller","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"l1Router","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"l2Counterpart","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"l2GRT","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"l2MintAllowancePerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastL2MintAllowanceUpdateBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastPausePartialTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastPauseTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_l1Token","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_maxGas","type":"uint256"},{"internalType":"uint256","name":"_gasPriceBid","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"outboundTransfer","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"pauseGuardian","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_notAllowlisted","type":"address"}],"name":"removeFromCallhookAllowlist","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_inbox","type":"address"},{"internalType":"address","name":"_l1Router","type":"address"}],"name":"setArbitrumAddresses","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_controller","type":"address"}],"name":"setController","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_escrow","type":"address"}],"name":"setEscrowAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_l2Counterpart","type":"address"}],"name":"setL2CounterpartAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_accumulatedL2MintAllowanceSnapshot","type":"uint256"},{"internalType":"uint256","name":"_l2MintAllowancePerBlock","type":"uint256"},{"internalType":"uint256","name":"_lastL2MintAllowanceUpdateBlock","type":"uint256"}],"name":"setL2MintAllowanceParametersManual","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_l2GRT","type":"address"}],"name":"setL2TokenAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newPauseGuardian","type":"address"}],"name":"setPauseGuardian","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_newPaused","type":"bool"}],"name":"setPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"syncAllContracts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalMintedFromL2","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_l2IssuancePerBlock","type":"uint256"},{"internalType":"uint256","name":"_updateBlockNum","type":"uint256"}],"name":"updateL2MintAllowance","outputs":[],"stateMutability":"nonpayable","type":"function"}]

6101406040527fe6876326c1291dfcbbd3864a6816d698cd591defc7aa2153d7f9c4c04016c89f6080527fc713c3df6d14cdf946460395d09af88993ee2b948b1a808161494e32c5f6706360a0527f966f1e8d8d8014e05f6ec4a57138da9be1f7c5a7f802928a18072f7c5318076160c0527f1df41cd916959d1163dc8f0671a666ea8a3e434c13e40faef527133b5d16703460e0527f45fc200c7e4544e457d3c5709bfe0d520442c30bbcbdaede89e8d4a4bbc19247610100527fd362cac9cb75c10d67bcc0b7eeb0b1ef48bb5420b556c092d4fd7f758816fcf0610120523480156100eb57600080fd5b5060805160a05160c05160e051610100516101205161304561011c6000395080611d3d5250505050506130456000f3fe60806040526004361061020f5760003560e01c80638f438f1711610118578063cac60872116100a0578063d6866ea51161006f578063d6866ea514610595578063ddeb63b5146105aa578063e2fdcc17146105ca578063f77c4791146105df578063fb0e722b146105f45761020f565b8063cac608721461052d578063d2ce7d6514610542578063d426f70014610555578063d653b022146105755761020f565b8063a0c76a96116100e7578063a0c76a9614610480578063a2594d82146104ad578063a7e28d48146104cd578063b83d696e146104ed578063c4d66de81461050d5761020f565b80638f438f171461040b57806391b4ded91461042b57806392eefe9b146104405780639ce7abe5146104605761020f565b806348bde20c1161019b578063721302631161016a578063721302631461038c57806373aea0ae146103ac5780637fee3d43146103c15780638e7c8efe146103e15780638f3112c5146103f65761020f565b806348bde20c146103205780634c381870146103405780635c975abb146103555780636cda3798146103775761020f565b806322ca40a8116101e257806322ca40a8146102a157806324a3d622146102c15780632db09c1c146102e35780632e567b36146102f8578063407395e01461030b5761020f565b8063011e68e31461021457806311dd71291461023657806316c38b3c146102615780631c5b777614610281575b600080fd5b34801561022057600080fd5b5061023461022f36600461254e565b610609565b005b34801561024257600080fd5b5061024b610696565b6040516102589190612f08565b60405180910390f35b34801561026d57600080fd5b5061023461027c366004612790565b61069c565b34801561028d57600080fd5b5061024b61029c36600461281b565b610794565b3480156102ad57600080fd5b506102346102bc36600461254e565b6107ed565b3480156102cd57600080fd5b506102d6610866565b6040516102589190612942565b3480156102ef57600080fd5b506102d6610875565b61023461030636600461260c565b610884565b34801561031757600080fd5b506102d6610c56565b34801561032c57600080fd5b5061023461033b36600461254e565b610c65565b34801561034c57600080fd5b506102d6610cd1565b34801561036157600080fd5b5061036a610ce0565b60405161025891906129f3565b34801561038357600080fd5b5061024b610cf0565b34801561039857600080fd5b506102346103a73660046128eb565b610cf6565b3480156103b857600080fd5b5061024b610d6d565b3480156103cd57600080fd5b506102346103dc3660046128ca565b610d73565b3480156103ed57600080fd5b506102d6610e11565b34801561040257600080fd5b5061024b610e20565b34801561041757600080fd5b5061023461042636600461254e565b610e26565b34801561043757600080fd5b5061024b610f33565b34801561044c57600080fd5b5061023461045b36600461254e565b610f39565b34801561046c57600080fd5b5061023461047b3660046127c8565b610f4a565b34801561048c57600080fd5b506104a061049b36600461268f565b6110a0565b60405161025891906129fe565b3480156104b957600080fd5b506102346104c836600461254e565b611100565b3480156104d957600080fd5b506102d66104e836600461254e565b61121b565b3480156104f957600080fd5b5061036a61050836600461254e565b61125e565b34801561051957600080fd5b5061023461052836600461254e565b611273565b34801561053957600080fd5b5061024b611395565b6104a061055036600461270c565b61139b565b34801561056157600080fd5b5061023461057036600461254e565b611606565b34801561058157600080fd5b506102346105903660046125d4565b6116bc565b3480156105a157600080fd5b506102346117f5565b3480156105b657600080fd5b506102346105c536600461254e565b611901565b3480156105d657600080fd5b506102d661199f565b3480156105eb57600080fd5b506102d66119ae565b34801561060057600080fd5b506102d66119bd565b6106116119cc565b6001600160a01b0381166106405760405162461bcd60e51b815260040161063790612eb0565b60405180910390fd5b604280546001600160a01b0319166001600160a01b0383161790556040517f9a6e2b45041fa2939015ac2bd7e80b890de28d7154ef04b0f52a94fa4e88091d9061068b908390612942565b60405180910390a150565b604b5481565b6004805460408051634fc07d7560e01b815290516001600160a01b0390921692634fc07d75928282019260209290829003018186803b1580156106de57600080fd5b505afa1580156106f2573d6000803e3d6000fd5b505050506040513d602081101561070857600080fd5b50516001600160a01b031633148061072a57506003546001600160a01b031633145b61077b576040805162461bcd60e51b815260206004820152601960248201527f4f6e6c7920476f7665726e6f72206f7220477561726469616e00000000000000604482015290519081900360640190fd5b8061078857610788611a96565b61079181611b36565b50565b6000604a548210156107b85760405162461bcd60e51b815260040161063790612b7e565b6107e56107dc6107d3604a5485611bc790919063ffffffff16565b604b5490611c29565b60495490611c89565b90505b919050565b6107f56119cc565b6001600160a01b03811661081b5760405162461bcd60e51b815260040161063790612cca565b604580546001600160a01b0319166001600160a01b0383161790556040517f75d3e58d9088e31d57a8da4c52196f9d30e8f6fd45543bbe506679e2bef8eaa79061068b908390612942565b6003546001600160a01b031681565b6045546001600160a01b031690565b61088c611ce3565b6043546001600160a01b03166108b45760405162461bcd60e51b815260040161063790612b57565b6045546001600160a01b03166108dc5760405162461bcd60e51b815260040161063790612ed8565b604354604080516373c6754960e11b815290516000926001600160a01b03169163e78cea92916004808301926020929190829003018186803b15801561092157600080fd5b505afa158015610935573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610959919061256a565b9050336001600160a01b038216146109835760405162461bcd60e51b815260040161063790612a6a565b6000816001600160a01b031663ab5d89436040518163ffffffff1660e01b815260040160206040518083038186803b1580156109be57600080fd5b505afa1580156109d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109f6919061256a565b6001600160a01b03166380648b026040518163ffffffff1660e01b815260040160206040518083038186803b158015610a2e57600080fd5b505afa158015610a42573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a66919061256a565b6045549091506001600160a01b03808316911614610a965760405162461bcd60e51b815260040161063790612e79565b6000610aa0611d36565b9050806001600160a01b0316896001600160a01b031614610ad35760405162461bcd60e51b815260040161063790612e2b565b6046546040516370a0823160e01b81526000916001600160a01b03808516926370a0823192610b06921690600401612942565b60206040518083038186803b158015610b1e57600080fd5b505afa158015610b32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b569190612833565b905080871115610b7257610b72610b6d8883611bc7565b611d66565b6046546040516323b872dd60e01b81526001600160a01b03848116926323b872dd92610ba892909116908c908c906004016129b6565b602060405180830381600087803b158015610bc257600080fd5b505af1158015610bd6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bfa91906127ac565b506000886001600160a01b03168a6001600160a01b03167f891afe029c75c4f8c5855fc3480598bc5a53739344f6ae575bdb7ea2a79f56b38d8b604051610c429291906129da565b60405180910390a450505050505050505050565b6044546001600160a01b031681565b610c6d6119cc565b6001600160a01b038116610cc8576040805162461bcd60e51b815260206004820152601960248201527f5061757365477561726469616e206d7573742062652073657400000000000000604482015290519081900360640190fd5b61079181611e37565b6042546001600160a01b031681565b6000546301000000900460ff1690565b60015481565b610cfe6119cc565b438110610d1d5760405162461bcd60e51b815260040161063790612c67565b6049839055604b829055604a8190556040517fbfdf0135edba030abcdb9dfcdd3856c401a97acac62e96ba34714ae9cff0ebe690610d6090859085908590612f11565b60405180910390a1505050565b604a5481565b610d7b6119cc565b438110610d9a5760405162461bcd60e51b815260040161063790612c67565b604a548111610dbb5760405162461bcd60e51b815260040161063790612abc565b610dc481610794565b6049819055604a829055604b8390556040517fbfdf0135edba030abcdb9dfcdd3856c401a97acac62e96ba34714ae9cff0ebe691610e059185908590612f11565b60405180910390a15050565b6045546001600160a01b031681565b60485481565b610e2e6119cc565b6001600160a01b038116610e545760405162461bcd60e51b815260040161063790612a11565b6044546001600160a01b0382811691161415610e825760405162461bcd60e51b815260040161063790612e00565b610e8b81611e8b565b610ea75760405162461bcd60e51b815260040161063790612d77565b6001600160a01b03811660009081526047602052604090205460ff1615610ee05760405162461bcd60e51b815260040161063790612c3a565b6001600160a01b03811660009081526047602052604090819020805460ff19166001179055517ff3b329c349ad69ad25f0137ff68c2eaf5ad22fc53cd7a1cfe40a52b19499c1d29061068b908390612942565b60025481565b610f41611e91565b61079181611ef0565b82806001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381600087803b158015610f8657600080fd5b505af1158015610f9a573d6000803e3d6000fd5b505050506040513d6020811015610fb057600080fd5b50516001600160a01b0316331461100e576040805162461bcd60e51b815260206004820152601e60248201527f43616c6c6572206d757374206265207468652070726f78792061646d696e0000604482015290519081900360640190fd5b60405163623faf6160e01b8152602060048201908152602482018490526001600160a01b0386169163623faf619186918691908190604401848480828437600081840152601f19601f8201169050808301925050509350505050600060405180830381600087803b15801561108257600080fd5b505af1158015611096573d6000803e3d6000fd5b5050505050505050565b6060632e567b3660e01b86868686866040516024016110c3959493929190612970565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152905095945050505050565b80806001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561113c57600080fd5b505af1158015611150573d6000803e3d6000fd5b505050506040513d602081101561116657600080fd5b50516001600160a01b031633146111c4576040805162461bcd60e51b815260206004820152601e60248201527f43616c6c6572206d757374206265207468652070726f78792061646d696e0000604482015290519081900360640190fd5b816001600160a01b03166359fc20bb6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156111ff57600080fd5b505af1158015611213573d6000803e3d6000fd5b505050505050565b600080611226611d36565b9050806001600160a01b0316836001600160a01b03161461124b5760009150506107e8565b50506042546001600160a01b0316919050565b60476020526000908152604090205460ff1681565b61127b611f98565b6001600160a01b0316336001600160a01b0316146112d6576040805162461bcd60e51b815260206004820152601360248201527227b7363c9034b6b83632b6b2b73a30ba34b7b760691b604482015290519081900360640190fd5b600054610100900460ff16806112ef57506112ef611fbd565b806112fd575060005460ff16155b6113385760405162461bcd60e51b815260040180806020018281038252602e815260200180612fc1602e913960400191505060405180910390fd5b600054610100900460ff16158015611363576000805460ff1961ff0019909116610100171660011790555b61136c82610f41565b6000805463ff000000191663010000001790558015611391576000805461ff00191690555b5050565b60495481565b60606113a5611ce3565b60006113af611d36565b9050866113ce5760405162461bcd60e51b815260040161063790612b2a565b806001600160a01b0316896001600160a01b0316146113ff5760405162461bcd60e51b815260040161063790612e2b565b6001600160a01b0388166114255760405162461bcd60e51b815260040161063790612cfa565b60008060006060806114378989611fce565b80519297509094509150158061146157503360009081526047602052604090205460ff1615156001145b61147d5760405162461bcd60e51b815260040161063790612dc9565b8261149a5760405162461bcd60e51b815260040161063790612c0e565b6114a78e868f8f856110a0565b915050600060405180606001604052808481526020018c81526020018b8152509050856001600160a01b03166323b872dd86604660009054906101000a90046001600160a01b03168f6040518463ffffffff1660e01b815260040161150e939291906129b6565b602060405180830381600087803b15801561152857600080fd5b505af115801561153c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061156091906127ac565b50604354604554611583916001600160a01b039081169116873460008688612067565b9350505050808a6001600160a01b0316836001600160a01b03167fb8910b9960c443aac3240b98585384e3a6f109fbf6969e264c3f183d69aba7e18e8d6040516115ce9291906129da565b60405180910390a4806040516020016115e79190612f08565b6040516020818303038152906040529350505050979650505050505050565b61160e6119cc565b6001600160a01b0381166116345760405162461bcd60e51b815260040161063790612a11565b6001600160a01b03811660009081526047602052604090205460ff1661166c5760405162461bcd60e51b815260040161063790612a93565b6001600160a01b03811660009081526047602052604090819020805460ff19169055517f418f3ae472ec14bb195924385de80a9e9303050c823552568af2adb8388d9d099061068b908390612942565b6116c46119cc565b6001600160a01b0382166116ea5760405162461bcd60e51b815260040161063790612e52565b6001600160a01b0381166117105760405162461bcd60e51b815260040161063790612be3565b6001600160a01b03811660009081526047602052604090205460ff16156117495760405162461bcd60e51b815260040161063790612c93565b61175282611e8b565b61176e5760405162461bcd60e51b815260040161063790612bb3565b61177781611e8b565b6117935760405162461bcd60e51b815260040161063790612af3565b604380546001600160a01b038085166001600160a01b03199283161790925560448054928416929091169190911790556040517fc5f09bf22bb39edf3e4c5f4fd5c4809125836ddc8a0937099d04f53f31eda23d90610e059084908490612956565b61181e6040518060400160405280600881526020016721bab930ba34b7b760c11b815250612092565b61184b6040518060400160405280600c81526020016b22b837b1b426b0b730b3b2b960a11b815250612092565b61187a6040518060400160405280600e81526020016d2932bbb0b93239a6b0b730b3b2b960911b815250612092565b6118a2604051806040016040528060078152602001665374616b696e6760c81b815250612092565b6118cd6040518060400160405280600a81526020016923b930b8342a37b5b2b760b11b815250612092565b6118ff604051806040016040528060118152602001704772617068546f6b656e4761746577617960781b815250612092565b565b6119096119cc565b6001600160a01b03811661192f5760405162461bcd60e51b815260040161063790612d4f565b61193881611e8b565b6119545760405162461bcd60e51b815260040161063790612d77565b604680546001600160a01b0319166001600160a01b0383161790556040517f14229a64f0a7328601813f0f794bb1dbc59363f1ed61c2f957d00517e6140e189061068b908390612942565b6046546001600160a01b031681565b6004546001600160a01b031681565b6043546001600160a01b031681565b6004805460408051634fc07d7560e01b815290516001600160a01b0390921692634fc07d75928282019260209290829003018186803b158015611a0e57600080fd5b505afa158015611a22573d6000803e3d6000fd5b505050506040513d6020811015611a3857600080fd5b50516001600160a01b031633146118ff576040805162461bcd60e51b815260206004820152601860248201527f4f6e6c7920436f6e74726f6c6c657220676f7665726e6f720000000000000000604482015290519081900360640190fd5b6043546001600160a01b0316611abe5760405162461bcd60e51b815260040161063790612b57565b6044546001600160a01b0316611ae65760405162461bcd60e51b815260040161063790612d27565b6045546001600160a01b0316611b0e5760405162461bcd60e51b815260040161063790612ed8565b6046546001600160a01b03166118ff5760405162461bcd60e51b815260040161063790612da1565b600060039054906101000a900460ff1615158115151415611b5657610791565b6000805463ff000000191663010000008315158102919091179182905560ff91041615611b8257426002555b60005460408051630100000090920460ff1615158252517f8fb6c181ee25a520cf3dd6565006ef91229fcfe5a989566c2a3b8c115570cec5916020908290030190a150565b600082821115611c1e576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b508082035b92915050565b600082611c3857506000611c23565b82820282848281611c4557fe5b0414611c825760405162461bcd60e51b8152600401808060200182810382526021815260200180612fef6021913960400191505060405180910390fd5b9392505050565b600082820183811015611c82576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6000546301000000900460ff16156118ff576040805162461bcd60e51b81526020600482015260116024820152705061757365642028636f6e74726163742960781b604482015290519081900360640190fd5b6000611d617f0000000000000000000000000000000000000000000000000000000000000000612204565b905090565b611d6f8161229e565b611d8b5760405162461bcd60e51b815260040161063790612a3a565b604854611d989082611c89565b604855611da3611d36565b6046546040516340c10f1960e01b81526001600160a01b03928316926340c10f1992611dd69291169085906004016129da565b600060405180830381600087803b158015611df057600080fd5b505af1158015611e04573d6000803e3d6000fd5b505050507f4f8ca17191c10265804777143e4643b72f8a4c63ad6a973e2ed85532194abf828160405161068b9190612f08565b600380546001600160a01b038381166001600160a01b03198316179283905560405191811692169082907f0613b6ee6a04f0d09f390e4d9318894b9f6ac7fd83897cd8d18896ba579c401e90600090a35050565b3b151590565b6004546001600160a01b031633146118ff576040805162461bcd60e51b815260206004820152601960248201527f43616c6c6572206d75737420626520436f6e74726f6c6c657200000000000000604482015290519081900360640190fd5b6001600160a01b038116611f44576040805162461bcd60e51b815260206004820152601660248201527510dbdb9d1c9bdb1b195c881b5d5cdd081899481cd95d60521b604482015290519081900360640190fd5b600480546001600160a01b0383166001600160a01b0319909116811790915560408051918252517f4ff638452bbf33c012645d18ae6f05515ff5f2d1dfb0cece8cbf018c60903f709181900360200190a150565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b6000611fc830611e8b565b15905090565b60445460009081906060908290819083906001600160a01b031633141561200557611ffb87890189612586565b9093509050612042565b33925087878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293505050505b80806020019051810190612056919061284b565b939650945091925050509250925092565b60006120868888888888886000015189602001518a604001518a6122be565b98975050505050505050565b6000816040516020018082805190602001908083835b602083106120c75780518252601f1990920191602091820191016120a8565b51815160209384036101000a60001901801990921691161790526040805192909401828103601f1901835280855282519282019290922060048054637bb20d2f60e11b85529084018290529451909750600096506001600160a01b03909416945063f7641a5e93602480840194509192909190829003018186803b15801561214e57600080fd5b505afa158015612162573d6000803e3d6000fd5b505050506040513d602081101561217857600080fd5b50516000838152600560205260409020549091506001600160a01b038083169116146121ff5760008281526005602090815260409182902080546001600160a01b0319166001600160a01b0385169081179091558251908152915184927fd0e7a942b1fc38c411c4f53d153ba14fd24542a6a35ebacd9b6afca1a154e20692908290030190a25b505050565b6000818152600560205260408120546001600160a01b0316806107e5576004805460408051637bb20d2f60e11b8152928301869052516001600160a01b039091169163f7641a5e916024808301926020929190829003018186803b15801561226b57600080fd5b505afa15801561227f573d6000803e3d6000fd5b505050506040513d602081101561229557600080fd5b50519392505050565b60006122a943610794565b6048546122b69084611c89565b111592915050565b6000808a6001600160a01b031663679b6ded898c8a8a8e8f8c8c8c6040518a63ffffffff1660e01b815260040180896001600160a01b03168152602001888152602001878152602001866001600160a01b03168152602001856001600160a01b0316815260200184815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b8381101561236a578181015183820152602001612352565b50505050905090810190601f1680156123975780820380516001836020036101000a031916815260200191505b5099505050505050505050506020604051808303818588803b1580156123bc57600080fd5b505af11580156123d0573d6000803e3d6000fd5b50505050506040513d60208110156123e757600080fd5b81019080805190602001909291905050509050808a6001600160a01b03168a6001600160a01b03167fc1d1490cf25c3b40d600dfb27c7680340ed1ab901b7e8f3551280968a3b372b0866040518080602001828103825283818151815260200191508051906020019080838360005b8381101561246e578181015183820152602001612456565b50505050905090810190601f16801561249b5780820380516001836020036101000a031916815260200191505b509250505060405180910390a49a9950505050505050505050565b60008083601f8401126124c7578182fd5b50813567ffffffffffffffff8111156124de578182fd5b6020830191508360208285010111156124f657600080fd5b9250929050565b600082601f83011261250d578081fd5b813561252061251b82612f4b565b612f27565b818152846020838601011115612534578283fd5b816020850160208301379081016020019190915292915050565b60006020828403121561255f578081fd5b8135611c8281612f9d565b60006020828403121561257b578081fd5b8151611c8281612f9d565b60008060408385031215612598578081fd5b82356125a381612f9d565b9150602083013567ffffffffffffffff8111156125be578182fd5b6125ca858286016124fd565b9150509250929050565b600080604083850312156125e6578182fd5b82356125f181612f9d565b9150602083013561260181612f9d565b809150509250929050565b60008060008060008060a08789031215612624578182fd5b863561262f81612f9d565b9550602087013561263f81612f9d565b9450604087013561264f81612f9d565b935060608701359250608087013567ffffffffffffffff811115612671578283fd5b61267d89828a016124b6565b979a9699509497509295939492505050565b600080600080600060a086880312156126a6578081fd5b85356126b181612f9d565b945060208601356126c181612f9d565b935060408601356126d181612f9d565b925060608601359150608086013567ffffffffffffffff8111156126f3578182fd5b6126ff888289016124fd565b9150509295509295909350565b600080600080600080600060c0888a031215612726578081fd5b873561273181612f9d565b9650602088013561274181612f9d565b955060408801359450606088013593506080880135925060a088013567ffffffffffffffff811115612771578182fd5b61277d8a828b016124b6565b989b979a50959850939692959293505050565b6000602082840312156127a1578081fd5b8135611c8281612fb2565b6000602082840312156127bd578081fd5b8151611c8281612fb2565b6000806000604084860312156127dc578081fd5b83356127e781612f9d565b9250602084013567ffffffffffffffff811115612802578182fd5b61280e868287016124b6565b9497909650939450505050565b60006020828403121561282c578081fd5b5035919050565b600060208284031215612844578081fd5b5051919050565b6000806040838503121561285d578182fd5b82519150602083015167ffffffffffffffff81111561287a578182fd5b8301601f8101851361288a578182fd5b805161289861251b82612f4b565b8181528660208385010111156128ac578384fd5b6128bd826020830160208601612f6d565b8093505050509250929050565b600080604083850312156128dc578182fd5b50508035926020909101359150565b6000806000606084860312156128ff578081fd5b505081359360208301359350604090920135919050565b6000815180845261292e816020860160208601612f6d565b601f01601f19169290920160200192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b0386811682528581166020830152841660408201526060810183905260a0608082018190526000906129ab90830184612916565b979650505050505050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b03929092168252602082015260400190565b901515815260200190565b600060208252611c826020830184612916565b6020808252600f908201526e494e56414c49445f4144445245535360881b604082015260600190565b6020808252601690820152751253959053125117d30c97d352539517d05353d5539560521b604082015260600190565b6020808252600f908201526e4e4f545f46524f4d5f42524944474560881b604082015260600190565b6020808252600f908201526e1393d517d0531313d5d31254d51151608a1b604082015260600190565b6020808252601a908201527f424c4f434b5f4d5553545f42455f494e4352454d454e54494e47000000000000604082015260600190565b60208082526017908201527f524f555445525f4d5553545f42455f434f4e5452414354000000000000000000604082015260600190565b6020808252601390820152721253959053125117d6915493d7d05353d55395606a1b604082015260600190565b6020808252600d908201526c12539093d617d393d517d4d155609a1b604082015260600190565b6020808252818101527f494e56414c49445f424c4f434b5f464f525f4d494e545f414c4c4f57414e4345604082015260600190565b60208082526016908201527512539093d617d35554d517d09157d0d3d395149050d560521b604082015260600190565b60208082526011908201527024a72b20a624a22fa618afa927aaaa22a960791b604082015260600190565b6020808252601290820152711393d7d4d550935254d4d253d397d0d3d4d560721b604082015260600190565b6020808252601390820152721053149150511657d0531313d5d31254d51151606a1b604082015260600190565b602080825260129082015271109313d0d2d7d35554d517d09157d41054d560721b604082015260600190565b6020808252601a908201527f524f555445525f43414e545f42455f414c4c4f574c4953544544000000000000604082015260600190565b6020808252601690820152751253959053125117d30c97d0d3d5539511549410549560521b604082015260600190565b60208082526013908201527224a72b20a624a22fa222a9aa24a720aa24a7a760691b604082015260600190565b6020808252600e908201526d1493d555115497d393d517d4d15560921b604082015260600190565b6020808252600e908201526d494e56414c49445f455343524f5760901b604082015260600190565b60208082526010908201526f135554d517d09157d0d3d395149050d560821b604082015260600190565b6020808252600e908201526d1154d0d493d5d7d393d517d4d15560921b604082015260600190565b6020808252601a908201527f43414c4c5f484f4f4b5f444154415f4e4f545f414c4c4f574544000000000000604082015260600190565b60208082526011908201527021a0a72a2fa0a62627abafa927aaaa22a960791b604082015260600190565b6020808252600d908201526c1513d2d15397d393d517d1d495609a1b604082015260600190565b6020808252600d908201526c0929cac82989288be929c849eb609b1b604082015260600190565b60208082526018908201527f4f4e4c595f434f554e544552504152545f474154455741590000000000000000604082015260600190565b6020808252600e908201526d1253959053125117d30c97d1d49560921b604082015260600190565b602080825260169082015275130c97d0d3d5539511549410549517d393d517d4d15560521b604082015260600190565b90815260200190565b9283526020830191909152604082015260600190565b60405181810167ffffffffffffffff81118282101715612f4357fe5b604052919050565b600067ffffffffffffffff821115612f5f57fe5b50601f01601f191660200190565b60005b83811015612f88578181015183820152602001612f70565b83811115612f97576000848401525b50505050565b6001600160a01b038116811461079157600080fd5b801515811461079157600080fdfe496e697469616c697a61626c653a20636f6e747261637420697320616c726561647920696e697469616c697a6564536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a26469706673582212208b012a7dfd44a2bbe8bdcbd17c47507a3fad55d26a64977beb2e9a702ac7ad9864736f6c63430007060033

Deployed Bytecode

0x60806040526004361061020f5760003560e01c80638f438f1711610118578063cac60872116100a0578063d6866ea51161006f578063d6866ea514610595578063ddeb63b5146105aa578063e2fdcc17146105ca578063f77c4791146105df578063fb0e722b146105f45761020f565b8063cac608721461052d578063d2ce7d6514610542578063d426f70014610555578063d653b022146105755761020f565b8063a0c76a96116100e7578063a0c76a9614610480578063a2594d82146104ad578063a7e28d48146104cd578063b83d696e146104ed578063c4d66de81461050d5761020f565b80638f438f171461040b57806391b4ded91461042b57806392eefe9b146104405780639ce7abe5146104605761020f565b806348bde20c1161019b578063721302631161016a578063721302631461038c57806373aea0ae146103ac5780637fee3d43146103c15780638e7c8efe146103e15780638f3112c5146103f65761020f565b806348bde20c146103205780634c381870146103405780635c975abb146103555780636cda3798146103775761020f565b806322ca40a8116101e257806322ca40a8146102a157806324a3d622146102c15780632db09c1c146102e35780632e567b36146102f8578063407395e01461030b5761020f565b8063011e68e31461021457806311dd71291461023657806316c38b3c146102615780631c5b777614610281575b600080fd5b34801561022057600080fd5b5061023461022f36600461254e565b610609565b005b34801561024257600080fd5b5061024b610696565b6040516102589190612f08565b60405180910390f35b34801561026d57600080fd5b5061023461027c366004612790565b61069c565b34801561028d57600080fd5b5061024b61029c36600461281b565b610794565b3480156102ad57600080fd5b506102346102bc36600461254e565b6107ed565b3480156102cd57600080fd5b506102d6610866565b6040516102589190612942565b3480156102ef57600080fd5b506102d6610875565b61023461030636600461260c565b610884565b34801561031757600080fd5b506102d6610c56565b34801561032c57600080fd5b5061023461033b36600461254e565b610c65565b34801561034c57600080fd5b506102d6610cd1565b34801561036157600080fd5b5061036a610ce0565b60405161025891906129f3565b34801561038357600080fd5b5061024b610cf0565b34801561039857600080fd5b506102346103a73660046128eb565b610cf6565b3480156103b857600080fd5b5061024b610d6d565b3480156103cd57600080fd5b506102346103dc3660046128ca565b610d73565b3480156103ed57600080fd5b506102d6610e11565b34801561040257600080fd5b5061024b610e20565b34801561041757600080fd5b5061023461042636600461254e565b610e26565b34801561043757600080fd5b5061024b610f33565b34801561044c57600080fd5b5061023461045b36600461254e565b610f39565b34801561046c57600080fd5b5061023461047b3660046127c8565b610f4a565b34801561048c57600080fd5b506104a061049b36600461268f565b6110a0565b60405161025891906129fe565b3480156104b957600080fd5b506102346104c836600461254e565b611100565b3480156104d957600080fd5b506102d66104e836600461254e565b61121b565b3480156104f957600080fd5b5061036a61050836600461254e565b61125e565b34801561051957600080fd5b5061023461052836600461254e565b611273565b34801561053957600080fd5b5061024b611395565b6104a061055036600461270c565b61139b565b34801561056157600080fd5b5061023461057036600461254e565b611606565b34801561058157600080fd5b506102346105903660046125d4565b6116bc565b3480156105a157600080fd5b506102346117f5565b3480156105b657600080fd5b506102346105c536600461254e565b611901565b3480156105d657600080fd5b506102d661199f565b3480156105eb57600080fd5b506102d66119ae565b34801561060057600080fd5b506102d66119bd565b6106116119cc565b6001600160a01b0381166106405760405162461bcd60e51b815260040161063790612eb0565b60405180910390fd5b604280546001600160a01b0319166001600160a01b0383161790556040517f9a6e2b45041fa2939015ac2bd7e80b890de28d7154ef04b0f52a94fa4e88091d9061068b908390612942565b60405180910390a150565b604b5481565b6004805460408051634fc07d7560e01b815290516001600160a01b0390921692634fc07d75928282019260209290829003018186803b1580156106de57600080fd5b505afa1580156106f2573d6000803e3d6000fd5b505050506040513d602081101561070857600080fd5b50516001600160a01b031633148061072a57506003546001600160a01b031633145b61077b576040805162461bcd60e51b815260206004820152601960248201527f4f6e6c7920476f7665726e6f72206f7220477561726469616e00000000000000604482015290519081900360640190fd5b8061078857610788611a96565b61079181611b36565b50565b6000604a548210156107b85760405162461bcd60e51b815260040161063790612b7e565b6107e56107dc6107d3604a5485611bc790919063ffffffff16565b604b5490611c29565b60495490611c89565b90505b919050565b6107f56119cc565b6001600160a01b03811661081b5760405162461bcd60e51b815260040161063790612cca565b604580546001600160a01b0319166001600160a01b0383161790556040517f75d3e58d9088e31d57a8da4c52196f9d30e8f6fd45543bbe506679e2bef8eaa79061068b908390612942565b6003546001600160a01b031681565b6045546001600160a01b031690565b61088c611ce3565b6043546001600160a01b03166108b45760405162461bcd60e51b815260040161063790612b57565b6045546001600160a01b03166108dc5760405162461bcd60e51b815260040161063790612ed8565b604354604080516373c6754960e11b815290516000926001600160a01b03169163e78cea92916004808301926020929190829003018186803b15801561092157600080fd5b505afa158015610935573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610959919061256a565b9050336001600160a01b038216146109835760405162461bcd60e51b815260040161063790612a6a565b6000816001600160a01b031663ab5d89436040518163ffffffff1660e01b815260040160206040518083038186803b1580156109be57600080fd5b505afa1580156109d2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109f6919061256a565b6001600160a01b03166380648b026040518163ffffffff1660e01b815260040160206040518083038186803b158015610a2e57600080fd5b505afa158015610a42573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a66919061256a565b6045549091506001600160a01b03808316911614610a965760405162461bcd60e51b815260040161063790612e79565b6000610aa0611d36565b9050806001600160a01b0316896001600160a01b031614610ad35760405162461bcd60e51b815260040161063790612e2b565b6046546040516370a0823160e01b81526000916001600160a01b03808516926370a0823192610b06921690600401612942565b60206040518083038186803b158015610b1e57600080fd5b505afa158015610b32573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b569190612833565b905080871115610b7257610b72610b6d8883611bc7565b611d66565b6046546040516323b872dd60e01b81526001600160a01b03848116926323b872dd92610ba892909116908c908c906004016129b6565b602060405180830381600087803b158015610bc257600080fd5b505af1158015610bd6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bfa91906127ac565b506000886001600160a01b03168a6001600160a01b03167f891afe029c75c4f8c5855fc3480598bc5a53739344f6ae575bdb7ea2a79f56b38d8b604051610c429291906129da565b60405180910390a450505050505050505050565b6044546001600160a01b031681565b610c6d6119cc565b6001600160a01b038116610cc8576040805162461bcd60e51b815260206004820152601960248201527f5061757365477561726469616e206d7573742062652073657400000000000000604482015290519081900360640190fd5b61079181611e37565b6042546001600160a01b031681565b6000546301000000900460ff1690565b60015481565b610cfe6119cc565b438110610d1d5760405162461bcd60e51b815260040161063790612c67565b6049839055604b829055604a8190556040517fbfdf0135edba030abcdb9dfcdd3856c401a97acac62e96ba34714ae9cff0ebe690610d6090859085908590612f11565b60405180910390a1505050565b604a5481565b610d7b6119cc565b438110610d9a5760405162461bcd60e51b815260040161063790612c67565b604a548111610dbb5760405162461bcd60e51b815260040161063790612abc565b610dc481610794565b6049819055604a829055604b8390556040517fbfdf0135edba030abcdb9dfcdd3856c401a97acac62e96ba34714ae9cff0ebe691610e059185908590612f11565b60405180910390a15050565b6045546001600160a01b031681565b60485481565b610e2e6119cc565b6001600160a01b038116610e545760405162461bcd60e51b815260040161063790612a11565b6044546001600160a01b0382811691161415610e825760405162461bcd60e51b815260040161063790612e00565b610e8b81611e8b565b610ea75760405162461bcd60e51b815260040161063790612d77565b6001600160a01b03811660009081526047602052604090205460ff1615610ee05760405162461bcd60e51b815260040161063790612c3a565b6001600160a01b03811660009081526047602052604090819020805460ff19166001179055517ff3b329c349ad69ad25f0137ff68c2eaf5ad22fc53cd7a1cfe40a52b19499c1d29061068b908390612942565b60025481565b610f41611e91565b61079181611ef0565b82806001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381600087803b158015610f8657600080fd5b505af1158015610f9a573d6000803e3d6000fd5b505050506040513d6020811015610fb057600080fd5b50516001600160a01b0316331461100e576040805162461bcd60e51b815260206004820152601e60248201527f43616c6c6572206d757374206265207468652070726f78792061646d696e0000604482015290519081900360640190fd5b60405163623faf6160e01b8152602060048201908152602482018490526001600160a01b0386169163623faf619186918691908190604401848480828437600081840152601f19601f8201169050808301925050509350505050600060405180830381600087803b15801561108257600080fd5b505af1158015611096573d6000803e3d6000fd5b5050505050505050565b6060632e567b3660e01b86868686866040516024016110c3959493929190612970565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152905095945050505050565b80806001600160a01b031663f851a4406040518163ffffffff1660e01b8152600401602060405180830381600087803b15801561113c57600080fd5b505af1158015611150573d6000803e3d6000fd5b505050506040513d602081101561116657600080fd5b50516001600160a01b031633146111c4576040805162461bcd60e51b815260206004820152601e60248201527f43616c6c6572206d757374206265207468652070726f78792061646d696e0000604482015290519081900360640190fd5b816001600160a01b03166359fc20bb6040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156111ff57600080fd5b505af1158015611213573d6000803e3d6000fd5b505050505050565b600080611226611d36565b9050806001600160a01b0316836001600160a01b03161461124b5760009150506107e8565b50506042546001600160a01b0316919050565b60476020526000908152604090205460ff1681565b61127b611f98565b6001600160a01b0316336001600160a01b0316146112d6576040805162461bcd60e51b815260206004820152601360248201527227b7363c9034b6b83632b6b2b73a30ba34b7b760691b604482015290519081900360640190fd5b600054610100900460ff16806112ef57506112ef611fbd565b806112fd575060005460ff16155b6113385760405162461bcd60e51b815260040180806020018281038252602e815260200180612fc1602e913960400191505060405180910390fd5b600054610100900460ff16158015611363576000805460ff1961ff0019909116610100171660011790555b61136c82610f41565b6000805463ff000000191663010000001790558015611391576000805461ff00191690555b5050565b60495481565b60606113a5611ce3565b60006113af611d36565b9050866113ce5760405162461bcd60e51b815260040161063790612b2a565b806001600160a01b0316896001600160a01b0316146113ff5760405162461bcd60e51b815260040161063790612e2b565b6001600160a01b0388166114255760405162461bcd60e51b815260040161063790612cfa565b60008060006060806114378989611fce565b80519297509094509150158061146157503360009081526047602052604090205460ff1615156001145b61147d5760405162461bcd60e51b815260040161063790612dc9565b8261149a5760405162461bcd60e51b815260040161063790612c0e565b6114a78e868f8f856110a0565b915050600060405180606001604052808481526020018c81526020018b8152509050856001600160a01b03166323b872dd86604660009054906101000a90046001600160a01b03168f6040518463ffffffff1660e01b815260040161150e939291906129b6565b602060405180830381600087803b15801561152857600080fd5b505af115801561153c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061156091906127ac565b50604354604554611583916001600160a01b039081169116873460008688612067565b9350505050808a6001600160a01b0316836001600160a01b03167fb8910b9960c443aac3240b98585384e3a6f109fbf6969e264c3f183d69aba7e18e8d6040516115ce9291906129da565b60405180910390a4806040516020016115e79190612f08565b6040516020818303038152906040529350505050979650505050505050565b61160e6119cc565b6001600160a01b0381166116345760405162461bcd60e51b815260040161063790612a11565b6001600160a01b03811660009081526047602052604090205460ff1661166c5760405162461bcd60e51b815260040161063790612a93565b6001600160a01b03811660009081526047602052604090819020805460ff19169055517f418f3ae472ec14bb195924385de80a9e9303050c823552568af2adb8388d9d099061068b908390612942565b6116c46119cc565b6001600160a01b0382166116ea5760405162461bcd60e51b815260040161063790612e52565b6001600160a01b0381166117105760405162461bcd60e51b815260040161063790612be3565b6001600160a01b03811660009081526047602052604090205460ff16156117495760405162461bcd60e51b815260040161063790612c93565b61175282611e8b565b61176e5760405162461bcd60e51b815260040161063790612bb3565b61177781611e8b565b6117935760405162461bcd60e51b815260040161063790612af3565b604380546001600160a01b038085166001600160a01b03199283161790925560448054928416929091169190911790556040517fc5f09bf22bb39edf3e4c5f4fd5c4809125836ddc8a0937099d04f53f31eda23d90610e059084908490612956565b61181e6040518060400160405280600881526020016721bab930ba34b7b760c11b815250612092565b61184b6040518060400160405280600c81526020016b22b837b1b426b0b730b3b2b960a11b815250612092565b61187a6040518060400160405280600e81526020016d2932bbb0b93239a6b0b730b3b2b960911b815250612092565b6118a2604051806040016040528060078152602001665374616b696e6760c81b815250612092565b6118cd6040518060400160405280600a81526020016923b930b8342a37b5b2b760b11b815250612092565b6118ff604051806040016040528060118152602001704772617068546f6b656e4761746577617960781b815250612092565b565b6119096119cc565b6001600160a01b03811661192f5760405162461bcd60e51b815260040161063790612d4f565b61193881611e8b565b6119545760405162461bcd60e51b815260040161063790612d77565b604680546001600160a01b0319166001600160a01b0383161790556040517f14229a64f0a7328601813f0f794bb1dbc59363f1ed61c2f957d00517e6140e189061068b908390612942565b6046546001600160a01b031681565b6004546001600160a01b031681565b6043546001600160a01b031681565b6004805460408051634fc07d7560e01b815290516001600160a01b0390921692634fc07d75928282019260209290829003018186803b158015611a0e57600080fd5b505afa158015611a22573d6000803e3d6000fd5b505050506040513d6020811015611a3857600080fd5b50516001600160a01b031633146118ff576040805162461bcd60e51b815260206004820152601860248201527f4f6e6c7920436f6e74726f6c6c657220676f7665726e6f720000000000000000604482015290519081900360640190fd5b6043546001600160a01b0316611abe5760405162461bcd60e51b815260040161063790612b57565b6044546001600160a01b0316611ae65760405162461bcd60e51b815260040161063790612d27565b6045546001600160a01b0316611b0e5760405162461bcd60e51b815260040161063790612ed8565b6046546001600160a01b03166118ff5760405162461bcd60e51b815260040161063790612da1565b600060039054906101000a900460ff1615158115151415611b5657610791565b6000805463ff000000191663010000008315158102919091179182905560ff91041615611b8257426002555b60005460408051630100000090920460ff1615158252517f8fb6c181ee25a520cf3dd6565006ef91229fcfe5a989566c2a3b8c115570cec5916020908290030190a150565b600082821115611c1e576040805162461bcd60e51b815260206004820152601e60248201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604482015290519081900360640190fd5b508082035b92915050565b600082611c3857506000611c23565b82820282848281611c4557fe5b0414611c825760405162461bcd60e51b8152600401808060200182810382526021815260200180612fef6021913960400191505060405180910390fd5b9392505050565b600082820183811015611c82576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6000546301000000900460ff16156118ff576040805162461bcd60e51b81526020600482015260116024820152705061757365642028636f6e74726163742960781b604482015290519081900360640190fd5b6000611d617f45fc200c7e4544e457d3c5709bfe0d520442c30bbcbdaede89e8d4a4bbc19247612204565b905090565b611d6f8161229e565b611d8b5760405162461bcd60e51b815260040161063790612a3a565b604854611d989082611c89565b604855611da3611d36565b6046546040516340c10f1960e01b81526001600160a01b03928316926340c10f1992611dd69291169085906004016129da565b600060405180830381600087803b158015611df057600080fd5b505af1158015611e04573d6000803e3d6000fd5b505050507f4f8ca17191c10265804777143e4643b72f8a4c63ad6a973e2ed85532194abf828160405161068b9190612f08565b600380546001600160a01b038381166001600160a01b03198316179283905560405191811692169082907f0613b6ee6a04f0d09f390e4d9318894b9f6ac7fd83897cd8d18896ba579c401e90600090a35050565b3b151590565b6004546001600160a01b031633146118ff576040805162461bcd60e51b815260206004820152601960248201527f43616c6c6572206d75737420626520436f6e74726f6c6c657200000000000000604482015290519081900360640190fd5b6001600160a01b038116611f44576040805162461bcd60e51b815260206004820152601660248201527510dbdb9d1c9bdb1b195c881b5d5cdd081899481cd95d60521b604482015290519081900360640190fd5b600480546001600160a01b0383166001600160a01b0319909116811790915560408051918252517f4ff638452bbf33c012645d18ae6f05515ff5f2d1dfb0cece8cbf018c60903f709181900360200190a150565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b6000611fc830611e8b565b15905090565b60445460009081906060908290819083906001600160a01b031633141561200557611ffb87890189612586565b9093509050612042565b33925087878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152509293505050505b80806020019051810190612056919061284b565b939650945091925050509250925092565b60006120868888888888886000015189602001518a604001518a6122be565b98975050505050505050565b6000816040516020018082805190602001908083835b602083106120c75780518252601f1990920191602091820191016120a8565b51815160209384036101000a60001901801990921691161790526040805192909401828103601f1901835280855282519282019290922060048054637bb20d2f60e11b85529084018290529451909750600096506001600160a01b03909416945063f7641a5e93602480840194509192909190829003018186803b15801561214e57600080fd5b505afa158015612162573d6000803e3d6000fd5b505050506040513d602081101561217857600080fd5b50516000838152600560205260409020549091506001600160a01b038083169116146121ff5760008281526005602090815260409182902080546001600160a01b0319166001600160a01b0385169081179091558251908152915184927fd0e7a942b1fc38c411c4f53d153ba14fd24542a6a35ebacd9b6afca1a154e20692908290030190a25b505050565b6000818152600560205260408120546001600160a01b0316806107e5576004805460408051637bb20d2f60e11b8152928301869052516001600160a01b039091169163f7641a5e916024808301926020929190829003018186803b15801561226b57600080fd5b505afa15801561227f573d6000803e3d6000fd5b505050506040513d602081101561229557600080fd5b50519392505050565b60006122a943610794565b6048546122b69084611c89565b111592915050565b6000808a6001600160a01b031663679b6ded898c8a8a8e8f8c8c8c6040518a63ffffffff1660e01b815260040180896001600160a01b03168152602001888152602001878152602001866001600160a01b03168152602001856001600160a01b0316815260200184815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b8381101561236a578181015183820152602001612352565b50505050905090810190601f1680156123975780820380516001836020036101000a031916815260200191505b5099505050505050505050506020604051808303818588803b1580156123bc57600080fd5b505af11580156123d0573d6000803e3d6000fd5b50505050506040513d60208110156123e757600080fd5b81019080805190602001909291905050509050808a6001600160a01b03168a6001600160a01b03167fc1d1490cf25c3b40d600dfb27c7680340ed1ab901b7e8f3551280968a3b372b0866040518080602001828103825283818151815260200191508051906020019080838360005b8381101561246e578181015183820152602001612456565b50505050905090810190601f16801561249b5780820380516001836020036101000a031916815260200191505b509250505060405180910390a49a9950505050505050505050565b60008083601f8401126124c7578182fd5b50813567ffffffffffffffff8111156124de578182fd5b6020830191508360208285010111156124f657600080fd5b9250929050565b600082601f83011261250d578081fd5b813561252061251b82612f4b565b612f27565b818152846020838601011115612534578283fd5b816020850160208301379081016020019190915292915050565b60006020828403121561255f578081fd5b8135611c8281612f9d565b60006020828403121561257b578081fd5b8151611c8281612f9d565b60008060408385031215612598578081fd5b82356125a381612f9d565b9150602083013567ffffffffffffffff8111156125be578182fd5b6125ca858286016124fd565b9150509250929050565b600080604083850312156125e6578182fd5b82356125f181612f9d565b9150602083013561260181612f9d565b809150509250929050565b60008060008060008060a08789031215612624578182fd5b863561262f81612f9d565b9550602087013561263f81612f9d565b9450604087013561264f81612f9d565b935060608701359250608087013567ffffffffffffffff811115612671578283fd5b61267d89828a016124b6565b979a9699509497509295939492505050565b600080600080600060a086880312156126a6578081fd5b85356126b181612f9d565b945060208601356126c181612f9d565b935060408601356126d181612f9d565b925060608601359150608086013567ffffffffffffffff8111156126f3578182fd5b6126ff888289016124fd565b9150509295509295909350565b600080600080600080600060c0888a031215612726578081fd5b873561273181612f9d565b9650602088013561274181612f9d565b955060408801359450606088013593506080880135925060a088013567ffffffffffffffff811115612771578182fd5b61277d8a828b016124b6565b989b979a50959850939692959293505050565b6000602082840312156127a1578081fd5b8135611c8281612fb2565b6000602082840312156127bd578081fd5b8151611c8281612fb2565b6000806000604084860312156127dc578081fd5b83356127e781612f9d565b9250602084013567ffffffffffffffff811115612802578182fd5b61280e868287016124b6565b9497909650939450505050565b60006020828403121561282c578081fd5b5035919050565b600060208284031215612844578081fd5b5051919050565b6000806040838503121561285d578182fd5b82519150602083015167ffffffffffffffff81111561287a578182fd5b8301601f8101851361288a578182fd5b805161289861251b82612f4b565b8181528660208385010111156128ac578384fd5b6128bd826020830160208601612f6d565b8093505050509250929050565b600080604083850312156128dc578182fd5b50508035926020909101359150565b6000806000606084860312156128ff578081fd5b505081359360208301359350604090920135919050565b6000815180845261292e816020860160208601612f6d565b601f01601f19169290920160200192915050565b6001600160a01b0391909116815260200190565b6001600160a01b0392831681529116602082015260400190565b6001600160a01b0386811682528581166020830152841660408201526060810183905260a0608082018190526000906129ab90830184612916565b979650505050505050565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b03929092168252602082015260400190565b901515815260200190565b600060208252611c826020830184612916565b6020808252600f908201526e494e56414c49445f4144445245535360881b604082015260600190565b6020808252601690820152751253959053125117d30c97d352539517d05353d5539560521b604082015260600190565b6020808252600f908201526e4e4f545f46524f4d5f42524944474560881b604082015260600190565b6020808252600f908201526e1393d517d0531313d5d31254d51151608a1b604082015260600190565b6020808252601a908201527f424c4f434b5f4d5553545f42455f494e4352454d454e54494e47000000000000604082015260600190565b60208082526017908201527f524f555445525f4d5553545f42455f434f4e5452414354000000000000000000604082015260600190565b6020808252601390820152721253959053125117d6915493d7d05353d55395606a1b604082015260600190565b6020808252600d908201526c12539093d617d393d517d4d155609a1b604082015260600190565b6020808252818101527f494e56414c49445f424c4f434b5f464f525f4d494e545f414c4c4f57414e4345604082015260600190565b60208082526016908201527512539093d617d35554d517d09157d0d3d395149050d560521b604082015260600190565b60208082526011908201527024a72b20a624a22fa618afa927aaaa22a960791b604082015260600190565b6020808252601290820152711393d7d4d550935254d4d253d397d0d3d4d560721b604082015260600190565b6020808252601390820152721053149150511657d0531313d5d31254d51151606a1b604082015260600190565b602080825260129082015271109313d0d2d7d35554d517d09157d41054d560721b604082015260600190565b6020808252601a908201527f524f555445525f43414e545f42455f414c4c4f574c4953544544000000000000604082015260600190565b6020808252601690820152751253959053125117d30c97d0d3d5539511549410549560521b604082015260600190565b60208082526013908201527224a72b20a624a22fa222a9aa24a720aa24a7a760691b604082015260600190565b6020808252600e908201526d1493d555115497d393d517d4d15560921b604082015260600190565b6020808252600e908201526d494e56414c49445f455343524f5760901b604082015260600190565b60208082526010908201526f135554d517d09157d0d3d395149050d560821b604082015260600190565b6020808252600e908201526d1154d0d493d5d7d393d517d4d15560921b604082015260600190565b6020808252601a908201527f43414c4c5f484f4f4b5f444154415f4e4f545f414c4c4f574544000000000000604082015260600190565b60208082526011908201527021a0a72a2fa0a62627abafa927aaaa22a960791b604082015260600190565b6020808252600d908201526c1513d2d15397d393d517d1d495609a1b604082015260600190565b6020808252600d908201526c0929cac82989288be929c849eb609b1b604082015260600190565b60208082526018908201527f4f4e4c595f434f554e544552504152545f474154455741590000000000000000604082015260600190565b6020808252600e908201526d1253959053125117d30c97d1d49560921b604082015260600190565b602080825260169082015275130c97d0d3d5539511549410549517d393d517d4d15560521b604082015260600190565b90815260200190565b9283526020830191909152604082015260600190565b60405181810167ffffffffffffffff81118282101715612f4357fe5b604052919050565b600067ffffffffffffffff821115612f5f57fe5b50601f01601f191660200190565b60005b83811015612f88578181015183820152602001612f70565b83811115612f97576000848401525b50505050565b6001600160a01b038116811461079157600080fd5b801515811461079157600080fdfe496e697469616c697a61626c653a20636f6e747261637420697320616c726561647920696e697469616c697a6564536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f77a26469706673582212208b012a7dfd44a2bbe8bdcbd17c47507a3fad55d26a64977beb2e9a702ac7ad9864736f6c63430007060033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

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.