Source Code
Latest 25 from a total of 4,057 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Pull Many | 398796628 | 1 min ago | IN | 0 ETH | 0.00000108 | ||||
| Add | 398765199 | 2 hrs ago | IN | 0 ETH | 0.00000076 | ||||
| Add | 398564357 | 16 hrs ago | IN | 0 ETH | 0.00000059 | ||||
| Add | 398328624 | 32 hrs ago | IN | 0 ETH | 0.00000049 | ||||
| Add | 398325682 | 32 hrs ago | IN | 0 ETH | 0.00000049 | ||||
| Add | 398174478 | 43 hrs ago | IN | 0 ETH | 0.00000059 | ||||
| Add | 398125308 | 46 hrs ago | IN | 0 ETH | 0.00000072 | ||||
| Add | 398097952 | 2 days ago | IN | 0 ETH | 0.00000059 | ||||
| Add | 397885561 | 2 days ago | IN | 0 ETH | 0.00000083 | ||||
| Add | 397725098 | 3 days ago | IN | 0 ETH | 0.00000098 | ||||
| Add | 397672208 | 3 days ago | IN | 0 ETH | 0.00000073 | ||||
| Add | 397340210 | 4 days ago | IN | 0 ETH | 0.00000062 | ||||
| Add | 397160836 | 4 days ago | IN | 0 ETH | 0.00000078 | ||||
| Pull Many | 397066626 | 5 days ago | IN | 0 ETH | 0.00000065 | ||||
| Add | 396742222 | 5 days ago | IN | 0 ETH | 0.00001068 | ||||
| Pull Many | 396720338 | 6 days ago | IN | 0 ETH | 0.00000132 | ||||
| Add | 396589613 | 6 days ago | IN | 0 ETH | 0.00000076 | ||||
| Add | 396571277 | 6 days ago | IN | 0 ETH | 0.00000066 | ||||
| Add | 396490371 | 6 days ago | IN | 0 ETH | 0.00000154 | ||||
| Add | 396434109 | 6 days ago | IN | 0 ETH | 0.00000116 | ||||
| Remove | 396373381 | 7 days ago | IN | 0 ETH | 0.00000076 | ||||
| Add | 396310198 | 7 days ago | IN | 0 ETH | 0.00000078 | ||||
| Pull Many | 396030518 | 7 days ago | IN | 0 ETH | 0.00000556 | ||||
| Pull Many | 396030238 | 7 days ago | IN | 0 ETH | 0.0000085 | ||||
| Pull Many | 396029946 | 7 days ago | IN | 0 ETH | 0.0000086 |
Latest 25 internal transactions (View All)
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 71965742 | 965 days ago | 0 ETH | ||||
| 71938434 | 965 days ago | 0 ETH | ||||
| 71790310 | 965 days ago | 0 ETH | ||||
| 71657726 | 966 days ago | 0 ETH | ||||
| 71657726 | 966 days ago | 0 ETH | ||||
| 71621349 | 966 days ago | 0 ETH | ||||
| 71278243 | 967 days ago | 0 ETH | ||||
| 70937211 | 968 days ago | 0 ETH | ||||
| 70814722 | 968 days ago | 0 ETH | ||||
| 70593529 | 969 days ago | 0 ETH | ||||
| 70516605 | 969 days ago | 0 ETH | ||||
| 70475454 | 969 days ago | 0 ETH | ||||
| 70474404 | 969 days ago | 0 ETH | ||||
| 70388801 | 970 days ago | 0 ETH | ||||
| 70380968 | 970 days ago | 0 ETH | ||||
| 70380968 | 970 days ago | 0 ETH | ||||
| 70315498 | 970 days ago | 0 ETH | ||||
| 70283972 | 970 days ago | 0 ETH | ||||
| 70282958 | 970 days ago | 0 ETH | ||||
| 70278483 | 970 days ago | 0 ETH | ||||
| 70254755 | 970 days ago | 0 ETH | ||||
| 70069082 | 971 days ago | 0 ETH | ||||
| 70055428 | 971 days ago | 0 ETH | ||||
| 69925387 | 971 days ago | 0 ETH | ||||
| 69917784 | 971 days ago | 0 ETH |
Latest 25 Deposits
Cross-Chain Transactions
Loading...
Loading
Contract Name:
Billing
Compiler Version
v0.8.16+commit.07a7930e
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// 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);
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
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"}]Contract Creation Code
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
Loading...
Loading
Loading...
Loading
Loading...
Loading
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.