ETH Price: $3,602.22 (+4.16%)

Contract

0x1B07D3344188908Fb6DEcEac381f3eE63C48477a
Transaction Hash
Method
Block
From
To
Pull Many3987966282025-11-10 13:26:071 min ago1762781167IN
0x1B07D334...63C48477a
0 ETH0.000001080.018286
Add3987651992025-11-10 11:15:262 hrs ago1762773326IN
0x1B07D334...63C48477a
0 ETH0.000000760.01
Add3985643572025-11-09 21:19:4116 hrs ago1762723181IN
0x1B07D334...63C48477a
0 ETH0.000000590.01
Add3983286242025-11-09 4:58:1032 hrs ago1762664290IN
0x1B07D334...63C48477a
0 ETH0.000000490.01
Add3983256822025-11-09 4:45:5432 hrs ago1762663554IN
0x1B07D334...63C48477a
0 ETH0.000000490.01
Add3981744782025-11-08 18:15:5643 hrs ago1762625756IN
0x1B07D334...63C48477a
0 ETH0.000000590.01
Add3981253082025-11-08 14:51:2546 hrs ago1762613485IN
0x1B07D334...63C48477a
0 ETH0.000000720.013257
Add3980979522025-11-08 12:57:392 days ago1762606659IN
0x1B07D334...63C48477a
0 ETH0.000000590.01
Add3978855612025-11-07 22:13:572 days ago1762553637IN
0x1B07D334...63C48477a
0 ETH0.000000830.01136
Add3977250982025-11-07 11:06:433 days ago1762513603IN
0x1B07D334...63C48477a
0 ETH0.000000980.012224
Add3976722082025-11-07 7:26:383 days ago1762500398IN
0x1B07D334...63C48477a
0 ETH0.000000730.012199
Add3973402102025-11-06 8:25:064 days ago1762417506IN
0x1B07D334...63C48477a
0 ETH0.000000620.01
Add3971608362025-11-05 19:58:224 days ago1762372702IN
0x1B07D334...63C48477a
0 ETH0.000000780.01
Pull Many3970666262025-11-05 13:26:245 days ago1762349184IN
0x1B07D334...63C48477a
0 ETH0.000000650.010596
Add3967422222025-11-04 14:57:155 days ago1762268235IN
0x1B07D334...63C48477a
0 ETH0.000010680.135377
Pull Many3967203382025-11-04 13:26:166 days ago1762262776IN
0x1B07D334...63C48477a
0 ETH0.000001320.014858
Add3965896132025-11-04 4:22:406 days ago1762230160IN
0x1B07D334...63C48477a
0 ETH0.000000760.01
Add3965712772025-11-04 3:06:216 days ago1762225581IN
0x1B07D334...63C48477a
0 ETH0.000000660.01117
Add3964903712025-11-03 21:29:286 days ago1762205368IN
0x1B07D334...63C48477a
0 ETH0.000001540.020057
Add3964341092025-11-03 17:35:186 days ago1762191318IN
0x1B07D334...63C48477a
0 ETH0.000001160.01467
Remove3963733812025-11-03 13:22:437 days ago1762176163IN
0x1B07D334...63C48477a
0 ETH0.000000760.010614
Add3963101982025-11-03 9:00:007 days ago1762160400IN
0x1B07D334...63C48477a
0 ETH0.000000780.01
Pull Many3960305182025-11-02 13:36:197 days ago1762090579IN
0x1B07D334...63C48477a
0 ETH0.000005560.01
Pull Many3960302382025-11-02 13:35:087 days ago1762090508IN
0x1B07D334...63C48477a
0 ETH0.00000850.01
Pull Many3960299462025-11-02 13:33:557 days ago1762090435IN
0x1B07D334...63C48477a
0 ETH0.00000860.01
View all transactions

Latest 25 internal transactions (View All)

Parent Transaction Hash Block From To
719657422023-03-21 2:00:04965 days ago1679364004
0x1B07D334...63C48477a
0 ETH
719384342023-03-21 0:03:40965 days ago1679357020
0x1B07D334...63C48477a
0 ETH
717903102023-03-20 13:43:00965 days ago1679319780
0x1B07D334...63C48477a
0 ETH
716577262023-03-20 4:33:17966 days ago1679286797
0x1B07D334...63C48477a
0 ETH
716577262023-03-20 4:33:17966 days ago1679286797
0x1B07D334...63C48477a
0 ETH
716213492023-03-20 2:00:04966 days ago1679277604
0x1B07D334...63C48477a
0 ETH
712782432023-03-19 2:00:03967 days ago1679191203
0x1B07D334...63C48477a
0 ETH
709372112023-03-18 2:00:05968 days ago1679104805
0x1B07D334...63C48477a
0 ETH
708147222023-03-17 17:20:29968 days ago1679073629
0x1B07D334...63C48477a
0 ETH
705935292023-03-17 2:00:04969 days ago1679018404
0x1B07D334...63C48477a
0 ETH
705166052023-03-16 20:19:39969 days ago1678997979
0x1B07D334...63C48477a
0 ETH
704754542023-03-16 17:25:01969 days ago1678987501
0x1B07D334...63C48477a
0 ETH
704744042023-03-16 17:20:37969 days ago1678987237
0x1B07D334...63C48477a
0 ETH
703888012023-03-16 11:28:31970 days ago1678966111
0x1B07D334...63C48477a
0 ETH
703809682023-03-16 10:55:17970 days ago1678964117
0x1B07D334...63C48477a
0 ETH
703809682023-03-16 10:55:17970 days ago1678964117
0x1B07D334...63C48477a
0 ETH
703154982023-03-16 6:21:26970 days ago1678947686
0x1B07D334...63C48477a
0 ETH
702839722023-03-16 4:05:01970 days ago1678939501
0x1B07D334...63C48477a
0 ETH
702829582023-03-16 4:00:39970 days ago1678939239
0x1B07D334...63C48477a
0 ETH
702784832023-03-16 3:41:24970 days ago1678938084
0x1B07D334...63C48477a
0 ETH
702547552023-03-16 2:00:04970 days ago1678932004
0x1B07D334...63C48477a
0 ETH
700690822023-03-15 12:19:40971 days ago1678882780
0x1B07D334...63C48477a
0 ETH
700554282023-03-15 11:22:09971 days ago1678879329
0x1B07D334...63C48477a
0 ETH
699253872023-03-15 2:00:04971 days ago1678845604
0x1B07D334...63C48477a
0 ETH
699177842023-03-15 1:27:00971 days ago1678843620
0x1B07D334...63C48477a
0 ETH
View All Internal Transactions

Latest 25 Deposits

L2 Txn Hash L1 Deposit Txn Value Token
0x134428b25d1dbbeacfeda1d68aaef554c68795e297e7ff43dbe2e51e9edf0e752025-11-10 4:32:478 hrs ago1762749167687 Graph Token (GRT)
0x755bfc70ab75583e20341ef10b10b4aa497fa84801d177a5ddd0fe3877dd28cd2025-11-07 13:06:353 days ago17625207951,003 Graph Token (GRT)
0x83d43d17d3775690d31942359d4437c5a7345af291eddb74a62d74061e6619ee2025-11-06 20:20:353 days ago17624604356,338 Graph Token (GRT)
0x28df13223a4b2e9f8470da8436ea7fe78751391a1edc0f02f41423aef9e2ed392025-11-04 1:31:476 days ago1762219907849.39403189 Graph Token (GRT)
0xda2025d01fb71aa5c6d6ca671353abbd95a3121d5ed68956323e0a61650e22522025-10-31 20:06:359 days ago1761941195492 Graph Token (GRT)
0xacbe3a4e08beb4ee30e2d7622a9e38e12b2a9092ce219ca9ea25531946d9bbf32025-10-31 12:43:3510 days ago17619146151,235 Graph Token (GRT)
0xc4784f38b3905b58af0ec7ae9d2ac3daadb213674bb9c230729eea9f0de579222025-10-29 20:56:4711 days ago1761771407238 Graph Token (GRT)
0xed66419c0ef67d850a159f978728ff331ab97f9b1c3768423be6071f17871cbe2025-10-28 14:55:1112 days ago1761663311125 Graph Token (GRT)
0xb376bb258134ac406ed9794b63119b0792ef55797fee025d81c4f656f82b14f62025-10-27 17:19:2313 days ago1761585563778 Graph Token (GRT)
0xae260dab5ce4691d17422d6d28d51d62eaafc289bdf21c22c2fa693cfa3538962025-10-27 3:26:2314 days ago17615355835,292.01700426856 Graph Token (GRT)
0xfd1c540268726517dcdb9aab6a8f820fdd0577bdf9f8bdc1b9e8030c1163ddfd2025-10-24 2:14:4717 days ago1761272087324 Graph Token (GRT)
0xeaddf0319282b2dfab6f3d1e01e97c3dd6465a86418c97cad012bb48e4ba3ec02025-10-17 4:42:5924 days ago17606761791,468.1999676 Graph Token (GRT)
0x0c0eaf6198a82ee260854e1d0a69f53f407601262548dbbedc08c6b4db0018dd2025-10-17 1:03:5924 days ago1760663039375 Graph Token (GRT)
0xed33c514703bfaef9994f703cf7f7dda8a1f7efad221e2d0eb20f096760ec0af2025-10-16 7:54:1125 days ago1760601251302 Graph Token (GRT)
0x0c12fde26ce36a9eb94149a056b0abfdec4993de8937610ceae355607843c4352025-10-16 7:36:1125 days ago1760600171124 Graph Token (GRT)
0x6c989bb96a1bf3ed0404a3e4fa81313e90ac18163a87839050759ba63cf63b572025-10-15 5:36:4726 days ago1760506607698 Graph Token (GRT)
0x09b9048e2381f98c20887e1c3ae811ac8a20107b139f50e0432328a1b7bd213e2025-10-15 3:49:5926 days ago17605001995,790 Graph Token (GRT)
0x6d8bc6257175abe661970c84f1e5a48a033da221241c299074e66783546ce73b2025-10-14 15:53:5926 days ago17604572397,197.48326091653 Graph Token (GRT)
0x5967ba2be71644e1d428c03ff2d1d8a9133e65c0a4626cccc925a79b10f139fe2025-10-12 18:51:2328 days ago1760295083593 Graph Token (GRT)
0x74f2659d45a63e6fdbf106b9eed98697c49ff2d8a6f8fda4f2322cefe1fa1ed92025-10-11 15:59:2329 days ago1760198363400 Graph Token (GRT)
0x6c599549222758b6eb5fb0d31d91ae593ced84db8d3b9f7b5e70d7cbc6b3df512025-10-11 15:57:2329 days ago1760198243100 Graph Token (GRT)
0x32dc24cc30e6942e19eb206fb1cd3a179d32c12c90f65d5bafba300594dbe2562025-10-09 12:12:3532 days ago1760011955239 Graph Token (GRT)
0x930a6fe5b56d12e66454d92a2acde4a64dec6eedbbe48a31ae5281b12fabe11e2025-10-08 9:37:2333 days ago175991624397 Graph Token (GRT)
0x0e1d774feda5ec316be32c0778f63aed73ace1b5464ecc1c8208045c601eef2d2025-10-04 7:52:2337 days ago175956434314 Graph Token (GRT)
0x6c139ce47a1e0b0bb86b0ac7dc04b2e75eb3cbae522753b80dab759d0b8aadee2025-10-01 19:44:5939 days ago175934789914.35196832 Graph Token (GRT)
View All Deposits

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Billing

Compiler Version
v0.8.16+commit.07a7930e

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.16;

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { Math } from "@openzeppelin/contracts/utils/math/Math.sol";
import { IBilling } from "./IBilling.sol";
import { Governed } from "./Governed.sol";
import { Rescuable } from "./Rescuable.sol";
import { AddressAliasHelper } from "./arbitrum/AddressAliasHelper.sol";

/**
 * @title Billing Contract
 * @dev The billing contract allows for Graph Tokens to be added by a user. The token can then
 * be pulled by a permissioned set of users named 'collectors'. It is owned and controlled by the 'governor'.
 */
contract Billing is IBilling, Governed, Rescuable {
    // -- State --

    // The contract for interacting with The Graph Token
    IERC20 private immutable graphToken;
    // True for addresses that are Collectors
    mapping(address => bool) public isCollector;

    // maps user address --> user billing balance
    mapping(address => uint256) public userBalances;

    // The L2 token gateway address
    address public l2TokenGateway;

    // The L1 BillingConnector address
    address public l1BillingConnector;

    // -- Events --

    /**
     * @dev User adds tokens
     */
    event TokensAdded(address indexed user, uint256 amount);

    /**
     * @dev User removes tokens
     */
    event TokensRemoved(address indexed from, address indexed to, uint256 amount);

    /**
     * @dev User tried to remove tokens from L1,
     * but they did not have enough balance
     */
    event InsufficientBalanceForRemoval(address indexed from, address indexed to, uint256 amount);

    /**
     * @dev Gateway pulled tokens from a user
     */
    event TokensPulled(address indexed user, uint256 amount);

    /**
     * @dev Collector added or removed
     */
    event CollectorUpdated(address indexed collector, bool enabled);

    /**
     * @dev L2 Token Gateway address updated
     */
    event L2TokenGatewayUpdated(address l2TokenGateway);

    /**
     * @dev L1 BillingConnector address updated
     */
    event L1BillingConnectorUpdated(address l1BillingConnector);

    /**
     * @notice Constructor function for the Billing contract
     * @dev Note that the l1BillingConnector address must be provided
     * afterwards through setL1BillingConnector, since it's expected
     * to be deployed after this one.
     * @param _collector   Initial collector address
     * @param _token     Graph Token address
     * @param _governor  Governor address
     */
    constructor(
        address _collector,
        IERC20 _token,
        address _governor,
        address _l2TokenGateway
    ) Governed(_governor) {
        _setCollector(_collector, true);
        _setL2TokenGateway(_l2TokenGateway);
        graphToken = _token;
    }

    /**
     * @dev Check if the caller is a Collector.
     */
    modifier onlyCollector() {
        require(isCollector[msg.sender], "Caller must be Collector");
        _;
    }

    /**
     * @dev Check if the caller is the L2 token gateway.
     */
    modifier onlyL2TokenGateway() {
        require(msg.sender == l2TokenGateway, "Caller must be L2 token gateway");
        _;
    }

    /**
     * @dev Check if the caller is the L2 alias of the L1 BillingConnector
     */
    modifier onlyL1BillingConnector() {
        require(l1BillingConnector != address(0), "BillingConnector not set");
        require(
            msg.sender == AddressAliasHelper.applyL1ToL2Alias(l1BillingConnector),
            "Caller must be L1 BillingConnector"
        );
        _;
    }

    /**
     * @notice Set or unset an address as an allowed Collector
     * @param _collector  Collector address
     * @param _enabled True to set the _collector address as a Collector, false to remove it
     */
    function setCollector(address _collector, bool _enabled) external override onlyGovernor {
        _setCollector(_collector, _enabled);
    }

    /**
     * @notice Sets the L2 token gateway address
     * @param _l2TokenGateway New address for the L2 token gateway
     */
    function setL2TokenGateway(address _l2TokenGateway) external override onlyGovernor {
        _setL2TokenGateway(_l2TokenGateway);
    }

    /**
     * @notice Sets the L1 Billing Connector address
     * @param _l1BillingConnector New address for the L1 BillingConnector (without any aliasing!)
     */
    function setL1BillingConnector(address _l1BillingConnector) external override onlyGovernor {
        require(_l1BillingConnector != address(0), "L1 Billing Connector cannot be 0");
        l1BillingConnector = _l1BillingConnector;
        emit L1BillingConnectorUpdated(_l1BillingConnector);
    }

    /**
     * @notice Add tokens into the billing contract
     * @dev Ensure graphToken.approve() is called on the billing contract first
     * @param _amount  Amount of tokens to add
     */
    function add(uint256 _amount) external override {
        _pullAndAdd(msg.sender, msg.sender, _amount);
    }

    /**
     * @notice Add tokens into the billing contract for any user
     * @dev Ensure graphToken.approve() is called on the billing contract first
     * @param _to  Address that tokens are being added to
     * @param _amount  Amount of tokens to add
     */
    function addTo(address _to, uint256 _amount) external override {
        _pullAndAdd(msg.sender, _to, _amount);
    }

    /**
     * @notice Receive tokens with a callhook from the Arbitrum GRT bridge
     * @dev Expects an `address user` in the encoded _data.
     * @param _from Token sender in L1
     * @param _amount Amount of tokens that were transferred
     * @param _data ABI-encoded callhook data: contains address that tokens are being added to
     */
    function onTokenTransfer(
        address _from,
        uint256 _amount,
        bytes calldata _data
    ) external override onlyL2TokenGateway {
        require(l1BillingConnector != address(0), "BillingConnector not set");
        require(_from == l1BillingConnector, "Invalid L1 sender!");
        address user = abi.decode(_data, (address));
        _add(user, _amount);
    }

    /**
     * @notice Remove tokens from the billing contract, from L1
     * @dev This can only be called from the BillingConnector on L1.
     * If the user does not have enough balance, rather than reverting,
     * this function will succeed and emit InsufficientBalanceForRemoval.
     * @param _from  Address from which the tokens are removed
     * @param _to Address to send the tokens
     * @param _amount  Amount of tokens to remove
     */
    function removeFromL1(
        address _from,
        address _to,
        uint256 _amount
    ) external override onlyL1BillingConnector {
        require(_to != address(0), "destination != 0");
        require(_amount != 0, "Must remove more than 0");
        if (userBalances[_from] >= _amount) {
            userBalances[_from] = userBalances[_from] - _amount;
            graphToken.transfer(_to, _amount);
            emit TokensRemoved(_from, _to, _amount);
        } else {
            emit InsufficientBalanceForRemoval(_from, _to, _amount);
        }
    }

    /**
     * @notice Add tokens into the billing contract in bulk
     * @dev Ensure graphToken.approve() is called on the billing contract first
     * @param _to  Array of addresses where to add tokens
     * @param _amount  Array of amount of tokens to add to each account
     */
    function addToMany(address[] calldata _to, uint256[] calldata _amount) external override {
        require(_to.length == _amount.length, "Lengths not equal");

        // Get total amount to add
        uint256 totalAmount = 0;
        for (uint256 i = 0; i < _amount.length; i++) {
            require(_amount[i] > 0, "Must add more than 0");
            totalAmount += _amount[i];
        }
        graphToken.transferFrom(msg.sender, address(this), totalAmount);

        // Add each amount
        for (uint256 i = 0; i < _to.length; i++) {
            address user = _to[i];
            require(user != address(0), "user != 0");
            userBalances[user] += _amount[i];
            emit TokensAdded(user, _amount[i]);
        }
    }

    /**
     * @notice Remove tokens from the billing contract
     * @dev Tokens will be removed from the sender's balance
     * @param _to  Address that tokens will be sent to
     * @param _amount  Amount of tokens to remove
     */
    function remove(address _to, uint256 _amount) external override {
        require(_to != address(0), "destination != 0");
        require(_amount != 0, "Must remove more than 0");
        require(userBalances[msg.sender] >= _amount, "Too much removed");
        userBalances[msg.sender] = userBalances[msg.sender] - _amount;
        graphToken.transfer(_to, _amount);
        emit TokensRemoved(msg.sender, _to, _amount);
    }

    /**
     * @notice Collector pulls tokens from the billing contract
     * @param _user  Address that tokens are being pulled from
     * @param _amount  Amount of tokens to pull
     * @param _to Destination to send pulled tokens
     */
    function pull(
        address _user,
        uint256 _amount,
        address _to
    ) external override onlyCollector {
        uint256 maxAmount = _pull(_user, _amount);
        _sendTokens(_to, maxAmount);
    }

    /**
     * @notice Collector pulls tokens from many users in the billing contract
     * @param _users  Addresses that tokens are being pulled from
     * @param _amounts  Amounts of tokens to pull from each user
     * @param _to Destination to send pulled tokens
     */
    function pullMany(
        address[] calldata _users,
        uint256[] calldata _amounts,
        address _to
    ) external override onlyCollector {
        require(_users.length == _amounts.length, "Lengths not equal");
        uint256 totalPulled;
        for (uint256 i = 0; i < _users.length; i++) {
            uint256 userMax = _pull(_users[i], _amounts[i]);
            totalPulled = totalPulled + userMax;
        }
        _sendTokens(_to, totalPulled);
    }

    /**
     * @notice Allows the Governor to rescue any ERC20 tokens sent to this contract by accident
     * @param _to  Destination address to send the tokens
     * @param _token  Token address of the token that was accidentally sent to the contract
     * @param _amount  Amount of tokens to pull
     */
    function rescueTokens(
        address _to,
        address _token,
        uint256 _amount
    ) external onlyGovernor {
        _rescueTokens(_to, _token, _amount);
    }

    /**
     * @dev Collector pulls tokens from the billing contract. Uses Math.min() so that it won't fail
     * in the event that a user removes in front of the Collector pulling
     * @param _user  Address that tokens are being pulled from
     * @param _amount  Amount of tokens to pull
     */
    function _pull(address _user, uint256 _amount) internal returns (uint256) {
        uint256 maxAmount = Math.min(_amount, userBalances[_user]);
        if (maxAmount > 0) {
            userBalances[_user] = userBalances[_user] - maxAmount;
            emit TokensPulled(_user, maxAmount);
        }
        return maxAmount;
    }

    /**
     * @dev Send tokens to a destination account
     * @param _to Address where to send tokens
     * @param _amount Amount of tokens to send
     */
    function _sendTokens(address _to, uint256 _amount) internal {
        if (_amount > 0) {
            require(_to != address(0), "Cannot transfer to empty address");
            graphToken.transfer(_to, _amount);
        }
    }

    /**
     * @dev Set or unset an address as an allowed Collector
     * @param _collector  Collector address
     * @param _enabled True to set the _collector address as a Collector, false to remove it
     */
    function _setCollector(address _collector, bool _enabled) internal {
        require(_collector != address(0), "Collector cannot be 0");
        isCollector[_collector] = _enabled;
        emit CollectorUpdated(_collector, _enabled);
    }

    /**
     * @dev Set the new L2 token gateway address
     * @param _l2TokenGateway  New L2 token gateway address
     */
    function _setL2TokenGateway(address _l2TokenGateway) internal {
        require(_l2TokenGateway != address(0), "L2 Token Gateway cannot be 0");
        l2TokenGateway = _l2TokenGateway;
        emit L2TokenGatewayUpdated(_l2TokenGateway);
    }

    /**
     * @dev Pull, then add tokens into the billing contract
     * Ensure graphToken.approve() is called on the billing contract first
     * @param _from  Address that is sending tokens
     * @param _user  User that is adding tokens
     * @param _amount  Amount of tokens to add
     */
    function _pullAndAdd(
        address _from,
        address _user,
        uint256 _amount
    ) private {
        require(_amount != 0, "Must add more than 0");
        require(_user != address(0), "user != 0");
        graphToken.transferFrom(_from, address(this), _amount);
        _add(_user, _amount);
    }

    /**
     * @dev Add tokens into the billing account balance for a user
     * Tokens must already be in this contract's balance
     * @param _user  User that is adding tokens
     * @param _amount  Amount of tokens to add
     */
    function _add(address _user, uint256 _amount) private {
        userBalances[_user] = userBalances[_user] + _amount;
        emit TokensAdded(_user, _amount);
    }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.16;

/**
 * @title Graph Governance contract
 * @dev Allows a contract to be owned and controlled by the 'governor'
 */
contract Governed {
    // -- State --

    // The address of the governor
    address public governor;
    // The address of the pending governor
    address public pendingGovernor;

    // -- Events --

    // Emit when the pendingGovernor state variable is updated
    event NewPendingOwnership(address indexed from, address indexed to);
    // Emit when the governor state variable is updated
    event NewOwnership(address indexed from, address indexed to);

    /**
     * @dev Check if the caller is the governor.
     */
    modifier onlyGovernor() {
        require(msg.sender == governor, "Only Governor can call");
        _;
    }

    /**
     * @dev Initialize the governor with the _initGovernor param.
     * @param _initGovernor Governor address
     */
    constructor(address _initGovernor) {
        require(_initGovernor != address(0), "Governor must not be 0");
        governor = _initGovernor;
    }

    /**
     * @dev Admin function to begin change of governor. The `_newGovernor` must call
     * `acceptOwnership` to finalize the transfer.
     * @param _newGovernor Address of new `governor`
     */
    function transferOwnership(address _newGovernor) external onlyGovernor {
        require(_newGovernor != address(0), "Governor must be set");

        address oldPendingGovernor = pendingGovernor;
        pendingGovernor = _newGovernor;

        emit NewPendingOwnership(oldPendingGovernor, pendingGovernor);
    }

    /**
     * @dev Admin function for pending governor to accept role and update governor.
     * This function must called by the pending governor.
     */
    function acceptOwnership() external {
        require(pendingGovernor != address(0) && msg.sender == pendingGovernor, "Caller must be pending governor");

        address oldGovernor = governor;
        address oldPendingGovernor = pendingGovernor;

        governor = pendingGovernor;
        pendingGovernor = address(0);

        emit NewOwnership(oldGovernor, governor);
        emit NewPendingOwnership(oldPendingGovernor, pendingGovernor);
    }
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.16;

interface IBilling {
    /**
     * @dev Set or unset an address as an allowed Collector
     * @param _collector  Collector address
     * @param _enabled True to set the _collector address as a Collector, false to remove it
     */
    function setCollector(address _collector, bool _enabled) external; // onlyGovernor

    /**
     * @dev Sets the L2 token gateway address
     * @param _l2TokenGateway New address for the L2 token gateway
     */
    function setL2TokenGateway(address _l2TokenGateway) external;

    /**
     * @dev Sets the L1 Billing Connector address
     * @param _l1BillingConnector New address for the L1 BillingConnector (without any aliasing!)
     */
    function setL1BillingConnector(address _l1BillingConnector) external;

    /**
     * @dev Add tokens into the billing contract
     * @param _amount  Amount of tokens to add
     */
    function add(uint256 _amount) external;

    /**
     * @dev Add tokens into the billing contract for any user
     * @param _to  Address that tokens are being added to
     * @param _amount  Amount of tokens to add
     */
    function addTo(address _to, uint256 _amount) external;

    /**
     * @dev Receive tokens with a callhook from the Arbitrum GRT bridge
     * Expects an `address user` in the encoded _data.
     * @param _from Token sender in L1
     * @param _amount Amount of tokens that were transferred
     * @param _data ABI-encoded callhook data: contains address that tokens are being added to
     */
    function onTokenTransfer(
        address _from,
        uint256 _amount,
        bytes calldata _data
    ) external;

    /**
     * @dev Remove tokens from the billing contract, from L1
     * This can only be called from the BillingConnector on L1.
     * @param _from  Address from which the tokens are removed
     * @param _to Address to send the tokens
     * @param _amount  Amount of tokens to remove
     */
    function removeFromL1(
        address _from,
        address _to,
        uint256 _amount
    ) external;

    /**
     * @dev Add tokens into the billing contract in bulk
     * Ensure graphToken.approve() is called on the billing contract first
     * @param _to  Array of addresses where to add tokens
     * @param _amount  Array of amount of tokens to add to each account
     */
    function addToMany(address[] calldata _to, uint256[] calldata _amount) external;

    /**
     * @dev Remove tokens from the billing contract
     * Tokens will be removed from the sender's balance
     * @param _to  Address that tokens are being moved to
     * @param _amount  Amount of tokens to remove
     */
    function remove(address _to, uint256 _amount) external;

    /**
     * @dev Collector pulls tokens from the billing contract
     * @param _user  Address that tokens are being pulled from
     * @param _amount  Amount of tokens to pull
     * @param _to Destination to send pulled tokens
     */
    function pull(
        address _user,
        uint256 _amount,
        address _to
    ) external;

    /**
     * @dev Collector pulls tokens from many users in the billing contract
     * @param _users  Addresses that tokens are being pulled from
     * @param _amounts  Amounts of tokens to pull from each user
     * @param _to Destination to send pulled tokens
     */
    function pullMany(
        address[] calldata _users,
        uint256[] calldata _amounts,
        address _to
    ) external;
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.16;

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

/**
 * @title Rescuable contract
 * @dev Allows a contract to have a function to rescue tokens sent by mistake.
 * The contract must implement the external rescueTokens function or similar,
 * that calls this contract's _rescueTokens.
 */
contract Rescuable {
    /**
     * @dev Tokens rescued by the permissioned user
     */
    event TokensRescued(address indexed to, address indexed token, uint256 amount);

    /**
     * @dev Allows a permissioned user to rescue any ERC20 tokens sent to this contract by accident
     * @param _to  Destination address to send the tokens
     * @param _token  Token address of the token that was accidentally sent to the contract
     * @param _amount  Amount of tokens to pull
     */
    function _rescueTokens(
        address _to,
        address _token,
        uint256 _amount
    ) internal {
        require(_to != address(0), "Cannot send to address(0)");
        require(_amount != 0, "Cannot rescue 0 tokens");
        IERC20 token = IERC20(_token);
        require(token.transfer(_to, _amount), "Rescue tokens failed");
        emit TokensRescued(_to, _token, _amount);
    }
}

// SPDX-License-Identifier: Apache-2.0

/*
 * Copyright 2019-2021, Offchain Labs, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Originally copied from:
 * https://github.com/OffchainLabs/arbitrum/tree/84e64dee6ee82adbf8ec34fd4b86c207a61d9007/packages/arb-bridge-eth
 *
 * MODIFIED from Offchain Labs' implementation:
 * - Changed solidity version to 0.8.16 ([email protected])
 *
 */

pragma solidity ^0.8.16;

library AddressAliasHelper {
    uint160 constant offset = uint160(0x1111000000000000000000000000000000001111);

    /// @notice Utility function that converts the address in the L1 that submitted a tx to
    /// the inbox to the msg.sender viewed in the L2
    /// @param l1Address the address in the L1 that triggered the tx to L2
    /// @return l2Address L2 address as viewed in msg.sender
    function applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {
        l2Address = address(uint160(l1Address) + offset);
    }

    /// @notice Utility function that converts the msg.sender viewed in the L2 to the
    /// address in the L1 that submitted a tx to the inbox
    /// @param l2Address L2 address as viewed in msg.sender
    /// @return l1Address the address in the L1 that triggered the tx to L2
    function undoL1ToL2Alias(address l2Address) internal pure returns (address l1Address) {
        l1Address = address(uint160(l2Address) - offset);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/math/Math.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    enum Rounding {
        Down, // Toward negative infinity
        Up, // Toward infinity
        Zero // Toward zero
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a >= b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
     * with further edits by Uniswap Labs also under MIT license.
     */
    function mulDiv(
        uint256 x,
        uint256 y,
        uint256 denominator
    ) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod0 := mul(x, y)
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1);

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
            // See https://cs.stackexchange.com/q/138556/92363.

            // Does not overflow because the denominator cannot be zero at this stage in the function.
            uint256 twos = denominator & (~denominator + 1);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
            // in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(
        uint256 x,
        uint256 y,
        uint256 denominator,
        Rounding rounding
    ) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. It the number is not a perfect square, the value is rounded down.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`.
        // We also know that `k`, the position of the most significant bit, is such that `msb(a) = 2**k`.
        // This gives `2**k < a <= 2**(k+1)` → `2**(k/2) <= sqrt(a) < 2 ** (k/2+1)`.
        // Using an algorithm similar to the msb conmputation, we are able to compute `result = 2**(k/2)` which is a
        // good first aproximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1;
        uint256 x = a;
        if (x >> 128 > 0) {
            x >>= 128;
            result <<= 64;
        }
        if (x >> 64 > 0) {
            x >>= 64;
            result <<= 32;
        }
        if (x >> 32 > 0) {
            x >>= 32;
            result <<= 16;
        }
        if (x >> 16 > 0) {
            x >>= 16;
            result <<= 8;
        }
        if (x >> 8 > 0) {
            x >>= 8;
            result <<= 4;
        }
        if (x >> 4 > 0) {
            x >>= 4;
            result <<= 2;
        }
        if (x >> 2 > 0) {
            result <<= 1;
        }

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        uint256 result = sqrt(a);
        if (rounding == Rounding.Up && result * result < a) {
            result += 1;
        }
        return result;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

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

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);
}

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

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"_collector","type":"address"},{"internalType":"contract IERC20","name":"_token","type":"address"},{"internalType":"address","name":"_governor","type":"address"},{"internalType":"address","name":"_l2TokenGateway","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"collector","type":"address"},{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"}],"name":"CollectorUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"InsufficientBalanceForRemoval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"l1BillingConnector","type":"address"}],"name":"L1BillingConnectorUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"l2TokenGateway","type":"address"}],"name":"L2TokenGatewayUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"NewOwnership","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"NewPendingOwnership","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokensAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokensPulled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokensRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokensRescued","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"add","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"addTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_to","type":"address[]"},{"internalType":"uint256[]","name":"_amount","type":"uint256[]"}],"name":"addToMany","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"governor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isCollector","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"l1BillingConnector","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"l2TokenGateway","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"onTokenTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pendingGovernor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_to","type":"address"}],"name":"pull","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_users","type":"address[]"},{"internalType":"uint256[]","name":"_amounts","type":"uint256[]"},{"internalType":"address","name":"_to","type":"address"}],"name":"pullMany","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"remove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"removeFromL1","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"rescueTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_collector","type":"address"},{"internalType":"bool","name":"_enabled","type":"bool"}],"name":"setCollector","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_l1BillingConnector","type":"address"}],"name":"setL1BillingConnector","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_l2TokenGateway","type":"address"}],"name":"setL2TokenGateway","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newGovernor","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userBalances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]

60a06040523480156200001157600080fd5b5060405162001e4038038062001e4083398101604081905262000034916200025a565b816001600160a01b038116620000915760405162461bcd60e51b815260206004820152601660248201527f476f7665726e6f72206d757374206e6f7420626520300000000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0392909216919091179055620000be846001620000de565b620000c98162000195565b50506001600160a01b031660805250620002c2565b6001600160a01b038216620001365760405162461bcd60e51b815260206004820152601560248201527f436f6c6c6563746f722063616e6e6f7420626520300000000000000000000000604482015260640162000088565b6001600160a01b038216600081815260026020908152604091829020805460ff191685151590811790915591519182527f949457f2c83e79cb62d2f4f8a997d128579a78f100b40b1832fc0981b22c113f910160405180910390a25050565b6001600160a01b038116620001ed5760405162461bcd60e51b815260206004820152601c60248201527f4c3220546f6b656e20476174657761792063616e6e6f74206265203000000000604482015260640162000088565b600480546001600160a01b0319166001600160a01b0383169081179091556040519081527f1f759e8cff804228c1e67fdffab0a7799ef3e9a7c29e6daf3306718037c57cd59060200160405180910390a150565b6001600160a01b03811681146200025757600080fd5b50565b600080600080608085870312156200027157600080fd5b84516200027e8162000241565b6020860151909450620002918162000241565b6040860151909350620002a48162000241565b6060860151909250620002b78162000241565b939692955090935050565b608051611b46620002fa6000396000818161056c01528181610ae001528181610f04015281816111e701526113090152611b466000f3fe608060405234801561001057600080fd5b506004361061012c5760003560e01c8063a4c0ed36116100ad578063e7fa527211610071578063e7fa52721461029d578063ef9aab68146102b0578063f29573ff146102c3578063f2fde38b146102d6578063f67a1389146102e957600080fd5b8063a4c0ed361461023e578063abe7f1ab14610251578063cea9d26f14610264578063df2cc13f14610277578063e3056a341461028a57600080fd5b806362129804116100f457806362129804146101ca57806373429da1146101fd57806379ba509714610210578063904e85a7146102185780639d4d15c51461022b57600080fd5b806307251d88146101315780630c340a24146101465780631003e2d21461017657806323d7fab91461018957806326224c641461019c575b600080fd5b61014461013f366004611740565b6102fc565b005b600054610159906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b610144610184366004611782565b610379565b61014461019736600461179b565b610387565b6101bc6101aa3660046117dc565b60036020526000908152604090205481565b60405190815260200161016d565b6101ed6101d83660046117dc565b60026020526000908152604090205460ff1681565b604051901515815260200161016d565b61014461020b3660046117dc565b610678565b61014461074d565b6101446102263660046117dc565b610854565b600554610159906001600160a01b031681565b61014461024c3660046117f9565b610887565b61014461025f366004611882565b6109a7565b61014461027236600461179b565b610b92565b6101446102853660046118bc565b610bc7565b600154610159906001600160a01b031681565b600454610159906001600160a01b031681565b6101446102be366004611941565b610bff565b6101446102d1366004611882565b610d27565b6101446102e43660046117dc565b610d32565b6101446102f73660046119c5565b610dfb565b3360009081526002602052604090205460ff1661035b5760405162461bcd60e51b815260206004820152601860248201527721b0b63632b91036bab9ba1031329021b7b63632b1ba37b960411b60448201526064015b60405180910390fd5b600061036784846110b2565b90506103738282611165565b50505050565b610384333383611254565b50565b6005546001600160a01b03166103da5760405162461bcd60e51b8152602060048201526018602482015277109a5b1b1a5b99d0dbdb9b9958dd1bdc881b9bdd081cd95d60421b6044820152606401610352565b6005546103ef906001600160a01b0316611381565b6001600160a01b0316336001600160a01b03161461045a5760405162461bcd60e51b815260206004820152602260248201527f43616c6c6572206d757374206265204c312042696c6c696e67436f6e6e65637460448201526137b960f11b6064820152608401610352565b6001600160a01b0382166104a35760405162461bcd60e51b815260206004820152601060248201526f064657374696e6174696f6e20213d20360841b6044820152606401610352565b806000036104ed5760405162461bcd60e51b815260206004820152601760248201527604d7573742072656d6f7665206d6f7265207468616e203604c1b6044820152606401610352565b6001600160a01b038316600090815260036020526040902054811161062e576001600160a01b038316600090815260036020526040902054610530908290611a47565b6001600160a01b038481166000908152600360205260409081902092909255905163a9059cbb60e01b81528382166004820152602481018390527f00000000000000000000000000000000000000000000000000000000000000009091169063a9059cbb906044016020604051808303816000875af11580156105b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105db9190611a5a565b50816001600160a01b0316836001600160a01b03167fcb0d9492300e48f4eaf3458b81c403bc7526f77735669f42e2378e5813d838578360405161062191815260200190565b60405180910390a3505050565b816001600160a01b0316836001600160a01b03167ff86e16a86e860585f2e9d57b1515a2283367ba44092e7a7e86139aac5b2e63898360405161062191815260200190565b505050565b6000546001600160a01b031633146106a25760405162461bcd60e51b815260040161035290611a77565b6001600160a01b0381166106f85760405162461bcd60e51b815260206004820181905260248201527f4c312042696c6c696e6720436f6e6e6563746f722063616e6e6f7420626520306044820152606401610352565b600580546001600160a01b0319166001600160a01b0383169081179091556040519081527f222eb2fdc329e9bd45f2e3a7204bfdd26a07aa95512ed8d6f9e0d6d9a7f21974906020015b60405180910390a150565b6001546001600160a01b03161580159061077157506001546001600160a01b031633145b6107bd5760405162461bcd60e51b815260206004820152601f60248201527f43616c6c6572206d7573742062652070656e64696e6720676f7665726e6f72006044820152606401610352565b60008054600180546001600160a01b038082166001600160a01b0319808616821787559092169092556040519190921692829184917f0ac6deed30eef60090c749850e10f2fa469e3e25fec1d1bef2853003f6e6f18f91a36001546040516001600160a01b03918216918316907f76563ad561b7036ae716b9b25cb521b21463240f104c97e12f25877f2235f33d90600090a35050565b6000546001600160a01b0316331461087e5760405162461bcd60e51b815260040161035290611a77565b610384816113a1565b6004546001600160a01b031633146108e15760405162461bcd60e51b815260206004820152601f60248201527f43616c6c6572206d757374206265204c3220746f6b656e2067617465776179006044820152606401610352565b6005546001600160a01b03166109345760405162461bcd60e51b8152602060048201526018602482015277109a5b1b1a5b99d0dbdb9b9958dd1bdc881b9bdd081cd95d60421b6044820152606401610352565b6005546001600160a01b038581169116146109865760405162461bcd60e51b8152602060048201526012602482015271496e76616c6964204c312073656e6465722160701b6044820152606401610352565b6000610994828401846117dc565b90506109a08185611445565b5050505050565b6001600160a01b0382166109f05760405162461bcd60e51b815260206004820152601060248201526f064657374696e6174696f6e20213d20360841b6044820152606401610352565b80600003610a3a5760405162461bcd60e51b815260206004820152601760248201527604d7573742072656d6f7665206d6f7265207468616e203604c1b6044820152606401610352565b33600090815260036020526040902054811115610a8c5760405162461bcd60e51b815260206004820152601060248201526f151bdbc81b5d58da081c995b5bdd995960821b6044820152606401610352565b33600090815260036020526040902054610aa7908290611a47565b3360009081526003602052604090819020919091555163a9059cbb60e01b81526001600160a01b038381166004830152602482018390527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303816000875af1158015610b29573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b4d9190611a5a565b506040518181526001600160a01b0383169033907fcb0d9492300e48f4eaf3458b81c403bc7526f77735669f42e2378e5813d838579060200160405180910390a35050565b6000546001600160a01b03163314610bbc5760405162461bcd60e51b815260040161035290611a77565b6106738383836114c4565b6000546001600160a01b03163314610bf15760405162461bcd60e51b815260040161035290611a77565b610bfb828261166f565b5050565b3360009081526002602052604090205460ff16610c595760405162461bcd60e51b815260206004820152601860248201527721b0b63632b91036bab9ba1031329021b7b63632b1ba37b960411b6044820152606401610352565b838214610c9c5760405162461bcd60e51b815260206004820152601160248201527013195b99dd1a1cc81b9bdd08195c5d585b607a1b6044820152606401610352565b6000805b85811015610d14576000610cf2888884818110610cbf57610cbf611aa7565b9050602002016020810190610cd491906117dc565b878785818110610ce657610ce6611aa7565b905060200201356110b2565b9050610cfe8184611abd565b9250508080610d0c90611ad0565b915050610ca0565b50610d1f8282611165565b505050505050565b610bfb338383611254565b6000546001600160a01b03163314610d5c5760405162461bcd60e51b815260040161035290611a77565b6001600160a01b038116610da95760405162461bcd60e51b815260206004820152601460248201527311dbdd995c9b9bdc881b5d5cdd081899481cd95d60621b6044820152606401610352565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f76563ad561b7036ae716b9b25cb521b21463240f104c97e12f25877f2235f33d90600090a35050565b828114610e3e5760405162461bcd60e51b815260206004820152601160248201527013195b99dd1a1cc81b9bdd08195c5d585b607a1b6044820152606401610352565b6000805b82811015610ee1576000848483818110610e5e57610e5e611aa7565b9050602002013511610ea95760405162461bcd60e51b815260206004820152601460248201527304d75737420616464206d6f7265207468616e20360641b6044820152606401610352565b838382818110610ebb57610ebb611aa7565b9050602002013582610ecd9190611abd565b915080610ed981611ad0565b915050610e42565b506040516323b872dd60e01b8152336004820152306024820152604481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906323b872dd906064016020604051808303816000875af1158015610f55573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f799190611a5a565b5060005b84811015610d1f576000868683818110610f9957610f99611aa7565b9050602002016020810190610fae91906117dc565b90506001600160a01b038116610ff25760405162461bcd60e51b815260206004820152600960248201526807573657220213d20360bc1b6044820152606401610352565b84848381811061100457611004611aa7565b9050602002013560036000836001600160a01b03166001600160a01b03168152602001908152602001600020600082825461103f9190611abd565b90915550506001600160a01b0381167f0eaac1064ee8d13f83091f388597ffb5ff2d2e59f6a16aae2a74ba7f2d13c8d986868581811061108157611081611aa7565b9050602002013560405161109791815260200190565b60405180910390a250806110aa81611ad0565b915050610f7d565b6001600160a01b03821660009081526003602052604081205481906110d8908490611715565b9050801561115c576001600160a01b038416600090815260036020526040902054611104908290611a47565b6001600160a01b038516600081815260036020526040908190209290925590517f3c3f210f5fb914ad3522d4b423e3db16130d0409700cb7b1827ccc90f341ac2f906111539084815260200190565b60405180910390a25b90505b92915050565b8015610bfb576001600160a01b0382166111c15760405162461bcd60e51b815260206004820181905260248201527f43616e6e6f74207472616e7366657220746f20656d70747920616464726573736044820152606401610352565b60405163a9059cbb60e01b81526001600160a01b038381166004830152602482018390527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303816000875af1158015611230573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106739190611a5a565b8060000361129b5760405162461bcd60e51b815260206004820152601460248201527304d75737420616464206d6f7265207468616e20360641b6044820152606401610352565b6001600160a01b0382166112dd5760405162461bcd60e51b815260206004820152600960248201526807573657220213d20360bc1b6044820152606401610352565b6040516323b872dd60e01b81526001600160a01b038481166004830152306024830152604482018390527f000000000000000000000000000000000000000000000000000000000000000016906323b872dd906064016020604051808303816000875af1158015611352573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113769190611a5a565b506106738282611445565b600061115f73111100000000000000000000000000000000111183611ae9565b6001600160a01b0381166113f75760405162461bcd60e51b815260206004820152601c60248201527f4c3220546f6b656e20476174657761792063616e6e6f742062652030000000006044820152606401610352565b600480546001600160a01b0319166001600160a01b0383169081179091556040519081527f1f759e8cff804228c1e67fdffab0a7799ef3e9a7c29e6daf3306718037c57cd590602001610742565b6001600160a01b038216600090815260036020526040902054611469908290611abd565b6001600160a01b038316600081815260036020526040908190209290925590517f0eaac1064ee8d13f83091f388597ffb5ff2d2e59f6a16aae2a74ba7f2d13c8d9906114b89084815260200190565b60405180910390a25050565b6001600160a01b03831661151a5760405162461bcd60e51b815260206004820152601960248201527f43616e6e6f742073656e6420746f2061646472657373283029000000000000006044820152606401610352565b806000036115635760405162461bcd60e51b815260206004820152601660248201527543616e6e6f7420726573637565203020746f6b656e7360501b6044820152606401610352565b60405163a9059cbb60e01b81526001600160a01b0384811660048301526024820183905283919082169063a9059cbb906044016020604051808303816000875af11580156115b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115d99190611a5a565b61161c5760405162461bcd60e51b815260206004820152601460248201527314995cd8dd59481d1bdad95b9cc819985a5b195960621b6044820152606401610352565b826001600160a01b0316846001600160a01b03167f77023e19c7343ad491fd706c36335ca0e738340a91f29b1fd81e2673d44896c48460405161166191815260200190565b60405180910390a350505050565b6001600160a01b0382166116bd5760405162461bcd60e51b81526020600482015260156024820152740436f6c6c6563746f722063616e6e6f74206265203605c1b6044820152606401610352565b6001600160a01b038216600081815260026020908152604091829020805460ff191685151590811790915591519182527f949457f2c83e79cb62d2f4f8a997d128579a78f100b40b1832fc0981b22c113f91016114b8565b6000818310611724578161115c565b5090919050565b6001600160a01b038116811461038457600080fd5b60008060006060848603121561175557600080fd5b83356117608161172b565b92506020840135915060408401356117778161172b565b809150509250925092565b60006020828403121561179457600080fd5b5035919050565b6000806000606084860312156117b057600080fd5b83356117bb8161172b565b925060208401356117cb8161172b565b929592945050506040919091013590565b6000602082840312156117ee57600080fd5b813561115c8161172b565b6000806000806060858703121561180f57600080fd5b843561181a8161172b565b935060208501359250604085013567ffffffffffffffff8082111561183e57600080fd5b818701915087601f83011261185257600080fd5b81358181111561186157600080fd5b88602082850101111561187357600080fd5b95989497505060200194505050565b6000806040838503121561189557600080fd5b82356118a08161172b565b946020939093013593505050565b801515811461038457600080fd5b600080604083850312156118cf57600080fd5b82356118da8161172b565b915060208301356118ea816118ae565b809150509250929050565b60008083601f84011261190757600080fd5b50813567ffffffffffffffff81111561191f57600080fd5b6020830191508360208260051b850101111561193a57600080fd5b9250929050565b60008060008060006060868803121561195957600080fd5b853567ffffffffffffffff8082111561197157600080fd5b61197d89838a016118f5565b9097509550602088013591508082111561199657600080fd5b506119a3888289016118f5565b90945092505060408601356119b78161172b565b809150509295509295909350565b600080600080604085870312156119db57600080fd5b843567ffffffffffffffff808211156119f357600080fd5b6119ff888389016118f5565b90965094506020870135915080821115611a1857600080fd5b50611a25878288016118f5565b95989497509550505050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561115f5761115f611a31565b600060208284031215611a6c57600080fd5b815161115c816118ae565b60208082526016908201527513db9b1e4811dbdd995c9b9bdc8818d85b8818d85b1b60521b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b8082018082111561115f5761115f611a31565b600060018201611ae257611ae2611a31565b5060010190565b6001600160a01b03818116838216019080821115611b0957611b09611a31565b509291505056fea264697066735822122029f7b5582a59a4be03a2fb6d1521bb11128ec9e11ea58e8f41bfcc4c6959763764736f6c6343000810003300000000000000000000000076c00f71f4dace63fd83ec80dbc8c30a88b2891c0000000000000000000000009623063377ad1b27544c965ccd7342f7ea7e88c70000000000000000000000004528fd7868c91ef64b9907450ee8d82dc639612c00000000000000000000000065e1a5e8946e7e87d9774f5288f41c30a99fd302

Deployed Bytecode

0x608060405234801561001057600080fd5b506004361061012c5760003560e01c8063a4c0ed36116100ad578063e7fa527211610071578063e7fa52721461029d578063ef9aab68146102b0578063f29573ff146102c3578063f2fde38b146102d6578063f67a1389146102e957600080fd5b8063a4c0ed361461023e578063abe7f1ab14610251578063cea9d26f14610264578063df2cc13f14610277578063e3056a341461028a57600080fd5b806362129804116100f457806362129804146101ca57806373429da1146101fd57806379ba509714610210578063904e85a7146102185780639d4d15c51461022b57600080fd5b806307251d88146101315780630c340a24146101465780631003e2d21461017657806323d7fab91461018957806326224c641461019c575b600080fd5b61014461013f366004611740565b6102fc565b005b600054610159906001600160a01b031681565b6040516001600160a01b0390911681526020015b60405180910390f35b610144610184366004611782565b610379565b61014461019736600461179b565b610387565b6101bc6101aa3660046117dc565b60036020526000908152604090205481565b60405190815260200161016d565b6101ed6101d83660046117dc565b60026020526000908152604090205460ff1681565b604051901515815260200161016d565b61014461020b3660046117dc565b610678565b61014461074d565b6101446102263660046117dc565b610854565b600554610159906001600160a01b031681565b61014461024c3660046117f9565b610887565b61014461025f366004611882565b6109a7565b61014461027236600461179b565b610b92565b6101446102853660046118bc565b610bc7565b600154610159906001600160a01b031681565b600454610159906001600160a01b031681565b6101446102be366004611941565b610bff565b6101446102d1366004611882565b610d27565b6101446102e43660046117dc565b610d32565b6101446102f73660046119c5565b610dfb565b3360009081526002602052604090205460ff1661035b5760405162461bcd60e51b815260206004820152601860248201527721b0b63632b91036bab9ba1031329021b7b63632b1ba37b960411b60448201526064015b60405180910390fd5b600061036784846110b2565b90506103738282611165565b50505050565b610384333383611254565b50565b6005546001600160a01b03166103da5760405162461bcd60e51b8152602060048201526018602482015277109a5b1b1a5b99d0dbdb9b9958dd1bdc881b9bdd081cd95d60421b6044820152606401610352565b6005546103ef906001600160a01b0316611381565b6001600160a01b0316336001600160a01b03161461045a5760405162461bcd60e51b815260206004820152602260248201527f43616c6c6572206d757374206265204c312042696c6c696e67436f6e6e65637460448201526137b960f11b6064820152608401610352565b6001600160a01b0382166104a35760405162461bcd60e51b815260206004820152601060248201526f064657374696e6174696f6e20213d20360841b6044820152606401610352565b806000036104ed5760405162461bcd60e51b815260206004820152601760248201527604d7573742072656d6f7665206d6f7265207468616e203604c1b6044820152606401610352565b6001600160a01b038316600090815260036020526040902054811161062e576001600160a01b038316600090815260036020526040902054610530908290611a47565b6001600160a01b038481166000908152600360205260409081902092909255905163a9059cbb60e01b81528382166004820152602481018390527f0000000000000000000000009623063377ad1b27544c965ccd7342f7ea7e88c79091169063a9059cbb906044016020604051808303816000875af11580156105b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105db9190611a5a565b50816001600160a01b0316836001600160a01b03167fcb0d9492300e48f4eaf3458b81c403bc7526f77735669f42e2378e5813d838578360405161062191815260200190565b60405180910390a3505050565b816001600160a01b0316836001600160a01b03167ff86e16a86e860585f2e9d57b1515a2283367ba44092e7a7e86139aac5b2e63898360405161062191815260200190565b505050565b6000546001600160a01b031633146106a25760405162461bcd60e51b815260040161035290611a77565b6001600160a01b0381166106f85760405162461bcd60e51b815260206004820181905260248201527f4c312042696c6c696e6720436f6e6e6563746f722063616e6e6f7420626520306044820152606401610352565b600580546001600160a01b0319166001600160a01b0383169081179091556040519081527f222eb2fdc329e9bd45f2e3a7204bfdd26a07aa95512ed8d6f9e0d6d9a7f21974906020015b60405180910390a150565b6001546001600160a01b03161580159061077157506001546001600160a01b031633145b6107bd5760405162461bcd60e51b815260206004820152601f60248201527f43616c6c6572206d7573742062652070656e64696e6720676f7665726e6f72006044820152606401610352565b60008054600180546001600160a01b038082166001600160a01b0319808616821787559092169092556040519190921692829184917f0ac6deed30eef60090c749850e10f2fa469e3e25fec1d1bef2853003f6e6f18f91a36001546040516001600160a01b03918216918316907f76563ad561b7036ae716b9b25cb521b21463240f104c97e12f25877f2235f33d90600090a35050565b6000546001600160a01b0316331461087e5760405162461bcd60e51b815260040161035290611a77565b610384816113a1565b6004546001600160a01b031633146108e15760405162461bcd60e51b815260206004820152601f60248201527f43616c6c6572206d757374206265204c3220746f6b656e2067617465776179006044820152606401610352565b6005546001600160a01b03166109345760405162461bcd60e51b8152602060048201526018602482015277109a5b1b1a5b99d0dbdb9b9958dd1bdc881b9bdd081cd95d60421b6044820152606401610352565b6005546001600160a01b038581169116146109865760405162461bcd60e51b8152602060048201526012602482015271496e76616c6964204c312073656e6465722160701b6044820152606401610352565b6000610994828401846117dc565b90506109a08185611445565b5050505050565b6001600160a01b0382166109f05760405162461bcd60e51b815260206004820152601060248201526f064657374696e6174696f6e20213d20360841b6044820152606401610352565b80600003610a3a5760405162461bcd60e51b815260206004820152601760248201527604d7573742072656d6f7665206d6f7265207468616e203604c1b6044820152606401610352565b33600090815260036020526040902054811115610a8c5760405162461bcd60e51b815260206004820152601060248201526f151bdbc81b5d58da081c995b5bdd995960821b6044820152606401610352565b33600090815260036020526040902054610aa7908290611a47565b3360009081526003602052604090819020919091555163a9059cbb60e01b81526001600160a01b038381166004830152602482018390527f0000000000000000000000009623063377ad1b27544c965ccd7342f7ea7e88c7169063a9059cbb906044016020604051808303816000875af1158015610b29573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b4d9190611a5a565b506040518181526001600160a01b0383169033907fcb0d9492300e48f4eaf3458b81c403bc7526f77735669f42e2378e5813d838579060200160405180910390a35050565b6000546001600160a01b03163314610bbc5760405162461bcd60e51b815260040161035290611a77565b6106738383836114c4565b6000546001600160a01b03163314610bf15760405162461bcd60e51b815260040161035290611a77565b610bfb828261166f565b5050565b3360009081526002602052604090205460ff16610c595760405162461bcd60e51b815260206004820152601860248201527721b0b63632b91036bab9ba1031329021b7b63632b1ba37b960411b6044820152606401610352565b838214610c9c5760405162461bcd60e51b815260206004820152601160248201527013195b99dd1a1cc81b9bdd08195c5d585b607a1b6044820152606401610352565b6000805b85811015610d14576000610cf2888884818110610cbf57610cbf611aa7565b9050602002016020810190610cd491906117dc565b878785818110610ce657610ce6611aa7565b905060200201356110b2565b9050610cfe8184611abd565b9250508080610d0c90611ad0565b915050610ca0565b50610d1f8282611165565b505050505050565b610bfb338383611254565b6000546001600160a01b03163314610d5c5760405162461bcd60e51b815260040161035290611a77565b6001600160a01b038116610da95760405162461bcd60e51b815260206004820152601460248201527311dbdd995c9b9bdc881b5d5cdd081899481cd95d60621b6044820152606401610352565b600180546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f76563ad561b7036ae716b9b25cb521b21463240f104c97e12f25877f2235f33d90600090a35050565b828114610e3e5760405162461bcd60e51b815260206004820152601160248201527013195b99dd1a1cc81b9bdd08195c5d585b607a1b6044820152606401610352565b6000805b82811015610ee1576000848483818110610e5e57610e5e611aa7565b9050602002013511610ea95760405162461bcd60e51b815260206004820152601460248201527304d75737420616464206d6f7265207468616e20360641b6044820152606401610352565b838382818110610ebb57610ebb611aa7565b9050602002013582610ecd9190611abd565b915080610ed981611ad0565b915050610e42565b506040516323b872dd60e01b8152336004820152306024820152604481018290527f0000000000000000000000009623063377ad1b27544c965ccd7342f7ea7e88c76001600160a01b0316906323b872dd906064016020604051808303816000875af1158015610f55573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f799190611a5a565b5060005b84811015610d1f576000868683818110610f9957610f99611aa7565b9050602002016020810190610fae91906117dc565b90506001600160a01b038116610ff25760405162461bcd60e51b815260206004820152600960248201526807573657220213d20360bc1b6044820152606401610352565b84848381811061100457611004611aa7565b9050602002013560036000836001600160a01b03166001600160a01b03168152602001908152602001600020600082825461103f9190611abd565b90915550506001600160a01b0381167f0eaac1064ee8d13f83091f388597ffb5ff2d2e59f6a16aae2a74ba7f2d13c8d986868581811061108157611081611aa7565b9050602002013560405161109791815260200190565b60405180910390a250806110aa81611ad0565b915050610f7d565b6001600160a01b03821660009081526003602052604081205481906110d8908490611715565b9050801561115c576001600160a01b038416600090815260036020526040902054611104908290611a47565b6001600160a01b038516600081815260036020526040908190209290925590517f3c3f210f5fb914ad3522d4b423e3db16130d0409700cb7b1827ccc90f341ac2f906111539084815260200190565b60405180910390a25b90505b92915050565b8015610bfb576001600160a01b0382166111c15760405162461bcd60e51b815260206004820181905260248201527f43616e6e6f74207472616e7366657220746f20656d70747920616464726573736044820152606401610352565b60405163a9059cbb60e01b81526001600160a01b038381166004830152602482018390527f0000000000000000000000009623063377ad1b27544c965ccd7342f7ea7e88c7169063a9059cbb906044016020604051808303816000875af1158015611230573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106739190611a5a565b8060000361129b5760405162461bcd60e51b815260206004820152601460248201527304d75737420616464206d6f7265207468616e20360641b6044820152606401610352565b6001600160a01b0382166112dd5760405162461bcd60e51b815260206004820152600960248201526807573657220213d20360bc1b6044820152606401610352565b6040516323b872dd60e01b81526001600160a01b038481166004830152306024830152604482018390527f0000000000000000000000009623063377ad1b27544c965ccd7342f7ea7e88c716906323b872dd906064016020604051808303816000875af1158015611352573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113769190611a5a565b506106738282611445565b600061115f73111100000000000000000000000000000000111183611ae9565b6001600160a01b0381166113f75760405162461bcd60e51b815260206004820152601c60248201527f4c3220546f6b656e20476174657761792063616e6e6f742062652030000000006044820152606401610352565b600480546001600160a01b0319166001600160a01b0383169081179091556040519081527f1f759e8cff804228c1e67fdffab0a7799ef3e9a7c29e6daf3306718037c57cd590602001610742565b6001600160a01b038216600090815260036020526040902054611469908290611abd565b6001600160a01b038316600081815260036020526040908190209290925590517f0eaac1064ee8d13f83091f388597ffb5ff2d2e59f6a16aae2a74ba7f2d13c8d9906114b89084815260200190565b60405180910390a25050565b6001600160a01b03831661151a5760405162461bcd60e51b815260206004820152601960248201527f43616e6e6f742073656e6420746f2061646472657373283029000000000000006044820152606401610352565b806000036115635760405162461bcd60e51b815260206004820152601660248201527543616e6e6f7420726573637565203020746f6b656e7360501b6044820152606401610352565b60405163a9059cbb60e01b81526001600160a01b0384811660048301526024820183905283919082169063a9059cbb906044016020604051808303816000875af11580156115b5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115d99190611a5a565b61161c5760405162461bcd60e51b815260206004820152601460248201527314995cd8dd59481d1bdad95b9cc819985a5b195960621b6044820152606401610352565b826001600160a01b0316846001600160a01b03167f77023e19c7343ad491fd706c36335ca0e738340a91f29b1fd81e2673d44896c48460405161166191815260200190565b60405180910390a350505050565b6001600160a01b0382166116bd5760405162461bcd60e51b81526020600482015260156024820152740436f6c6c6563746f722063616e6e6f74206265203605c1b6044820152606401610352565b6001600160a01b038216600081815260026020908152604091829020805460ff191685151590811790915591519182527f949457f2c83e79cb62d2f4f8a997d128579a78f100b40b1832fc0981b22c113f91016114b8565b6000818310611724578161115c565b5090919050565b6001600160a01b038116811461038457600080fd5b60008060006060848603121561175557600080fd5b83356117608161172b565b92506020840135915060408401356117778161172b565b809150509250925092565b60006020828403121561179457600080fd5b5035919050565b6000806000606084860312156117b057600080fd5b83356117bb8161172b565b925060208401356117cb8161172b565b929592945050506040919091013590565b6000602082840312156117ee57600080fd5b813561115c8161172b565b6000806000806060858703121561180f57600080fd5b843561181a8161172b565b935060208501359250604085013567ffffffffffffffff8082111561183e57600080fd5b818701915087601f83011261185257600080fd5b81358181111561186157600080fd5b88602082850101111561187357600080fd5b95989497505060200194505050565b6000806040838503121561189557600080fd5b82356118a08161172b565b946020939093013593505050565b801515811461038457600080fd5b600080604083850312156118cf57600080fd5b82356118da8161172b565b915060208301356118ea816118ae565b809150509250929050565b60008083601f84011261190757600080fd5b50813567ffffffffffffffff81111561191f57600080fd5b6020830191508360208260051b850101111561193a57600080fd5b9250929050565b60008060008060006060868803121561195957600080fd5b853567ffffffffffffffff8082111561197157600080fd5b61197d89838a016118f5565b9097509550602088013591508082111561199657600080fd5b506119a3888289016118f5565b90945092505060408601356119b78161172b565b809150509295509295909350565b600080600080604085870312156119db57600080fd5b843567ffffffffffffffff808211156119f357600080fd5b6119ff888389016118f5565b90965094506020870135915080821115611a1857600080fd5b50611a25878288016118f5565b95989497509550505050565b634e487b7160e01b600052601160045260246000fd5b8181038181111561115f5761115f611a31565b600060208284031215611a6c57600080fd5b815161115c816118ae565b60208082526016908201527513db9b1e4811dbdd995c9b9bdc8818d85b8818d85b1b60521b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b8082018082111561115f5761115f611a31565b600060018201611ae257611ae2611a31565b5060010190565b6001600160a01b03818116838216019080821115611b0957611b09611a31565b509291505056fea264697066735822122029f7b5582a59a4be03a2fb6d1521bb11128ec9e11ea58e8f41bfcc4c6959763764736f6c63430008100033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

00000000000000000000000076c00f71f4dace63fd83ec80dbc8c30a88b2891c0000000000000000000000009623063377ad1b27544c965ccd7342f7ea7e88c70000000000000000000000004528fd7868c91ef64b9907450ee8d82dc639612c00000000000000000000000065e1a5e8946e7e87d9774f5288f41c30a99fd302

-----Decoded View---------------
Arg [0] : _collector (address): 0x76C00F71F4dACE63fd83eC80dBc8c30a88B2891c
Arg [1] : _token (address): 0x9623063377AD1B27544C965cCd7342f7EA7e88C7
Arg [2] : _governor (address): 0x4528FD7868c91Ef64B9907450Ee8d82dC639612c
Arg [3] : _l2TokenGateway (address): 0x65E1a5e8946e7E87d9774f5288f41c30a99fD302

-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 00000000000000000000000076c00f71f4dace63fd83ec80dbc8c30a88b2891c
Arg [1] : 0000000000000000000000009623063377ad1b27544c965ccd7342f7ea7e88c7
Arg [2] : 0000000000000000000000004528fd7868c91ef64b9907450ee8d82dc639612c
Arg [3] : 00000000000000000000000065e1a5e8946e7e87d9774f5288f41c30a99fd302


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.