Address Contract Verified
Address
0x3333333ACdEdBbC9Ad7bda0876e60714195681c5
Balance
1.0000 ETH ($2098.41)
Nonce
1
Code Size
3369 bytes
Creator
0x02280165...429f at tx 0x34597a56...4294c0
Indexed Transactions
0 (1 on-chain, 0.8% indexed)
Contract Bytecode
3369 bytes
0x6080604052600436106101445760003560e01c80636a9efeab116100b6578063b4b577ad1161006f578063b4b577ad14610351578063c661065714610366578063ddca3f4314610386578063e0a0b5861461039b578063e3824462146103b0578063fee3f7f9146103c55761014b565b80636a9efeab146102a55780637d008a40146102c75780638da5cb5b146102da57806390a7e05b146102ef57806392773c551461030f578063a250e1921461032f5761014b565b8063405e28f811610108578063405e28f8146102065780634903b0d11461021b5780635383db201461023b5780635409491a1461025b57806358680d0b146102705780635d552b68146102855761014b565b8063140522881461016f57806318299fc21461019a5780631ec0cdc1146101ba5780632081066c146101dc57806330c54085146101f15761014b565b3661014b57005b34801561015757600080fd5b5060115461016d906001600160a01b03166103da565b005b34801561017b57600080fd5b506101846103fe565b6040516101919190610c94565b60405180910390f35b3480156101a657600080fd5b5061016d6101b5366004610aba565b610404565b3480156101c657600080fd5b506101cf6104f0565b6040516101919190610bad565b3480156101e857600080fd5b506101846104ff565b3480156101fd57600080fd5b5061016d610505565b34801561021257600080fd5b5061018461066b565b34801561022757600080fd5b50610184610236366004610b30565b610671565b34801561024757600080fd5b5061016d610256366004610a73565b61068f565b34801561026757600080fd5b506101846106c8565b34801561027c57600080fd5b506101846106ce565b34801561029157600080fd5b506101846102a0366004610b30565b6106d4565b3480156102b157600080fd5b506102ba61084c565b6040516101919190610c9d565b61016d6102d5366004610b60565b61085f565b3480156102e657600080fd5b506101cf6108cf565b3480156102fb57600080fd5b5061018461030a366004610b30565b6108de565b34801561031b57600080fd5b5061018461032a366004610afd565b610914565b34801561033b57600080fd5b50610344610975565b6040516101919190610cae565b34801561035d57600080fd5b5061018461098c565b34801561037257600080fd5b506101cf610381366004610b30565b610992565b34801561039257600080fd5b506101846109b9565b3480156103a757600080fd5b506101846109bf565b3480156103bc57600080fd5b506101846109c5565b3480156103d157600080fd5b506101846109cb565b3660008037600080366000845af43d6000803e8080156103f9573d6000f35b3d6000fd5b60095481565b6011546040516000916060916001600160a01b0390911690610430908890889088908890602401610bda565b60408051601f198184030181529181526020820180516001600160e01b0316630f7c084960e21b179052516104659190610b91565b600060405180830381855af49150503d80600081146104a0576040519150601f19603f3d011682016040523d82523d6000602084013e6104a5565b606091505b5091509150816104de578051156104d9578060405162461bcd60e51b81526004016104d09190610bfd565b60405180910390fd5b600080fd5b6104e886856109d1565b505050505050565b600e546001600160a01b031681565b60085481565b60005b600381101561066857600080828154811061051f57fe5b6000918252602082200154600180546001600160a01b039092169350908490811061054657fe5b9060005260206000200154826001600160a01b03166370a08231306040518263ffffffff1660e01b815260040161057d9190610bad565b60206040518083038186803b15801561059557600080fd5b505afa1580156105a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105cd9190610b48565b039050801561065e5760125460405163a9059cbb60e01b81526001600160a01b038481169263a9059cbb9261060a92909116908590600401610bc1565b602060405180830381600087803b15801561062457600080fd5b505af1158015610638573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061065c9190610a9a565b505b5050600101610508565b50565b600a5481565b6001818154811061067e57fe5b600091825260209091200154905081565b6004546001600160a01b031633146106a657600080fd5b601280546001600160a01b0319166001600160a01b0392909216919091179055565b60065481565b600c5481565b6013546040516370a0823160e01b815260009182916002916001600160a01b0316906370a082319061070a903390600401610bad565b60206040518083038186803b15801561072257600080fd5b505afa158015610736573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061075a9190610b48565b6013546040516370a0823160e01b81526001600160a01b03909116906370a082319061078a903290600401610bad565b60206040518083038186803b1580156107a257600080fd5b505afa1580156107b6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107da9190610b48565b01816107e257fe5b0490506801a055690d9db80000811015610800576000915050610847565b60006108158268056bc75e2d63100000610a47565b905060006108288564174876e800610a47565b9050600068056bc75e2d63100000620186a08402049190910293505050505b919050565b600e54600160e01b900463ffffffff1681565b6004546001600160a01b031633146108895760405162461bcd60e51b81526004016104d090610c67565b804710156108a95760405162461bcd60e51b81526004016104d090610c30565b60148490556015839055838303828203816108c057fe5b05601655504790036017555050565b6004546001600160a01b031681565b60006014548210806108f1575081601554105b156108fe57506000610847565b6017546014548303601654024701019050919050565b600083600f0b60001461092c5764e8d4a51000830292505b683635c9adc5dea00000831061096a576000610947436108de565b90506000610960610957856106d4565b600a8404610a47565b925061096e915050565b5060005b9392505050565b600e54600160a01b900467ffffffffffffffff1681565b60075481565b6000818154811061099f57fe5b6000918252602090912001546001600160a01b0316905081565b60025481565b600b5481565b600d5481565b60035481565b81600f0b6000146109e45764e8d4a51000025b683635c9adc5dea000008110610a435760006109ff436108de565b90506000610a0f6109573a6106d4565b604051909150329082156108fc029083906000818181858888f19350505050158015610a3f573d6000803e3d6000fd5b5050505b5050565b6000818310610a565781610a58565b825b90505b92915050565b8035600f81900b8114610a5b57600080fd5b600060208284031215610a84578081fd5b81356001600160a01b038116811461096e578182fd5b600060208284031215610aab578081fd5b8151801515811461096e578182fd5b60008060008060808587031215610acf578283fd5b610ad98686610a61565b9350610ae88660208701610a61565b93969395505050506040820135916060013590565b600080600060608486031215610b11578283fd5b610b1b8585610a61565b95602085013595506040909401359392505050565b600060208284031215610b41578081fd5b5035919050565b600060208284031215610b59578081fd5b5051919050565b60008060008060808587031215610b75578384fd5b5050823594602084013594506040840135936060013592509050565b60008251610ba3818460208701610cc3565b9190910192915050565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b600f94850b81529290930b60208301526040820152606081019190915260800190565b6000602082528251806020840152610c1c816040850160208701610cc3565b601f01601f19169190910160400192915050565b60208082526017908201527f62616c616e6365203c20746f74616c436173686261636b000000000000000000604082015260600190565b60208082526013908201527236b9b39739b2b73232b9101e9e9037bbb732b960691b604082015260600190565b90815260200190565b63ffffffff91909116815260200190565b67ffffffffffffffff91909116815260200190565b60005b83811015610cde578181015183820152602001610cc6565b83811115610ced576000848401525b5050505056fea264697066735822122098f50b03b9ab98babc375a6542b3d8c23f6fe968082d38523b1d3665aabea1d564736f6c634300060c0033
Verified Source Code Full Match
Compiler: v0.6.12+commit.27d51765
EVM: istanbul
Optimization: Yes (200 runs)
Math.sol 31 lines
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
/**
* @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, so we distribute
return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
}
}
Context.sol 24 lines
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
/*
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with GSN meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address payable) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
return msg.data;
}
}
SafeMath.sol 159 lines
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero");
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts with custom message when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}
Ownable.sol 68 lines
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
import "../GSN/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor () internal {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(_owner == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
ERC20.sol 306 lines
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
import "../../GSN/Context.sol";
import "./IERC20.sol";
import "../../math/SafeMath.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
* For a generic mechanism see {ERC20PresetMinterPauser}.
*
* TIP: For a detailed writeup see our guide
* https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* We have followed general OpenZeppelin guidelines: functions revert instead
* of returning `false` on failure. This behavior is nonetheless conventional
* and does not conflict with the expectations of ERC20 applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*
* Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
* functions have been added to mitigate the well-known issues around setting
* allowances. See {IERC20-approve}.
*/
contract ERC20 is Context, IERC20 {
using SafeMath for uint256;
mapping (address => uint256) private _balances;
mapping (address => mapping (address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
uint8 private _decimals;
/**
* @dev Sets the values for {name} and {symbol}, initializes {decimals} with
* a default value of 18.
*
* To select a different value for {decimals}, use {_setupDecimals}.
*
* All three of these values are immutable: they can only be set once during
* construction.
*/
constructor (string memory name_, string memory symbol_) public {
_name = name_;
_symbol = symbol_;
_decimals = 18;
}
/**
* @dev Returns the name of the token.
*/
function name() public view returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5,05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is
* called.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view returns (uint8) {
return _decimals;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view override returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view override returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `recipient` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(_msgSender(), recipient, amount);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 amount) public virtual override returns (bool) {
_approve(_msgSender(), spender, amount);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* Requirements:
*
* - `sender` and `recipient` cannot be the zero address.
* - `sender` must have a balance of at least `amount`.
* - the caller must have allowance for ``sender``'s tokens of at least
* `amount`.
*/
function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(sender, recipient, amount);
_approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
return true;
}
/**
* @dev Moves tokens `amount` from `sender` to `recipient`.
*
* This is internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* Requirements:
*
* - `sender` cannot be the zero address.
* - `recipient` cannot be the zero address.
* - `sender` must have a balance of at least `amount`.
*/
function _transfer(address sender, address recipient, uint256 amount) internal virtual {
require(sender != address(0), "ERC20: transfer from the zero address");
require(recipient != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(sender, recipient, amount);
_balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
_balances[recipient] = _balances[recipient].add(amount);
emit Transfer(sender, recipient, amount);
}
/** @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* Requirements:
*
* - `to` cannot be the zero address.
*/
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply = _totalSupply.add(amount);
_balances[account] = _balances[account].add(amount);
emit Transfer(address(0), account, amount);
}
/**
* @dev Destroys `amount` tokens from `account`, reducing the
* total supply.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
*/
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
_balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
_totalSupply = _totalSupply.sub(amount);
emit Transfer(account, address(0), amount);
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*/
function _approve(address owner, address spender, uint256 amount) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/**
* @dev Sets {decimals} to a value other than the default one of 18.
*
* WARNING: This function should only be called from the constructor. Most
* applications that interact with token contracts will not expect
* {decimals} to ever change, and may work incorrectly if it does.
*/
function _setupDecimals(uint8 decimals_) internal {
_decimals = decimals_;
}
/**
* @dev Hook that is called before any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* will be to transferred to `to`.
* - when `from` is zero, `amount` tokens will be minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens will be burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
}
IERC20.sol 77 lines
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}
ERC20Burnable.sol 42 lines
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
import "../../GSN/Context.sol";
import "./ERC20.sol";
/**
* @dev Extension of {ERC20} that allows token holders to destroy both their own
* tokens and those that they have an allowance for, in a way that can be
* recognized off-chain (via event analysis).
*/
abstract contract ERC20Burnable is Context, ERC20 {
using SafeMath for uint256;
/**
* @dev Destroys `amount` tokens from the caller.
*
* See {ERC20-_burn}.
*/
function burn(uint256 amount) public virtual {
_burn(_msgSender(), amount);
}
/**
* @dev Destroys `amount` tokens from `account`, deducting from the caller's
* allowance.
*
* See {ERC20-_burn} and {ERC20-allowance}.
*
* Requirements:
*
* - the caller must have allowance for ``accounts``'s tokens of at least
* `amount`.
*/
function burnFrom(address account, uint256 amount) public virtual {
uint256 decreasedAllowance = allowance(account, _msgSender()).sub(amount, "ERC20: burn amount exceeds allowance");
_approve(account, _msgSender(), decreasedAllowance);
_burn(account, amount);
}
}
SigToken.sol 266 lines
// SPDX-License-Identifier: MIT
pragma solidity 0.6.12;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20Burnable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
// SushiToken with Governance.
contract SigToken is ERC20, Ownable, ERC20Burnable {
using SafeMath for uint256;
// Bitcoin-like supply system:
// 50 tokens per block (however it's Ethereum ~15 seconds block vs Bitcoin 10 minutes)
// every 210,000 blocks is halving ~ 36 days 11 hours
// 32 eras ~ 3 years 71 days 16 hours until complete mint
// 21,000,000 is total supply
//
// i,e. if each block is about 15 seconds on average:
// 40,320 blocks/week
// 2,016,000 tokens/week before first halving
// 10,500,000 total before first halving
//
uint256 constant MAX_MAIN_SUPPLY = 21_000_000 * 1e18;
// the first week mint has x2 bonus = +2,016,000
// the second week mint has x1.5 bonus = +1,008,000
//
uint256 constant BONUS_SUPPLY = 3_024_000 * 1e18;
// so total max supply is 24,024,000 + 24 to init the uniswap pool
uint256 constant MAX_TOTAL_SUPPLY = MAX_MAIN_SUPPLY + BONUS_SUPPLY;
// The block number when SIG mining starts.
uint256 public startBlock;
uint256 constant DECIMALS_MUL = 1e18;
uint256 constant BLOCKS_PER_WEEK = 40_320;
uint256 constant HALVING_BLOCKS = 210_000;
// uint265 constant INITIAL_BLOCK_REWARD = 50;
function maxRewardMintAfterBlocks(uint256 t) public pure returns (uint256) {
// the first week x2 mint
if (t < BLOCKS_PER_WEEK) {
return DECIMALS_MUL * 100 * t;
}
// second week x1.5 mint
if (t < BLOCKS_PER_WEEK * 2) {
return DECIMALS_MUL * (100 * BLOCKS_PER_WEEK + 75 * (t - BLOCKS_PER_WEEK));
}
// after two weeks standard bitcoin issuance model https://en.bitcoin.it/wiki/Controlled_supply
uint256 totalBonus = DECIMALS_MUL * (BLOCKS_PER_WEEK * 50 + BLOCKS_PER_WEEK * 25);
assert(totalBonus >= 0);
// how many halvings so far?
uint256 era = t / HALVING_BLOCKS;
assert(0 <= era);
if (32 <= era) return MAX_TOTAL_SUPPLY;
// total reward before current era (mul base reward 50)
// sum : 1 + 1/2 + 1/4 … 1/2^n == 2 - 1/2^n == 1 - 1/1<<n == 1 - 1>>n
// era reward per block (*1e18 *50)
if (era == 0) {
return totalBonus + DECIMALS_MUL* 50 * (t % HALVING_BLOCKS);
}
uint256 eraRewardPerBlock = (DECIMALS_MUL >> era);
// assert(0 <= eraRewardPerBlock);
uint256 bcReward = (DECIMALS_MUL + DECIMALS_MUL - (eraRewardPerBlock<<1) ) * 50 * HALVING_BLOCKS;
// assert(0 <= bcReward);
// reward in the last era which isn't over
uint256 eraReward = eraRewardPerBlock * 50 * (t % HALVING_BLOCKS);
// assert(0 <= eraReward);
uint256 result = totalBonus + bcReward + eraReward;
assert(0 <= result);
return result;
}
constructor(
uint256 _tinyMint
) public ERC20("xSigma", "SIG") {
// dev needs a little of SIG tokens for uniswap SIG/ETH initialization
_mint(msg.sender, _tinyMint);
}
/// @notice Creates `_amount` token to `_to`. Must only be called by the owner (MasterChef).
function mint(address _to, uint256 _amount) public onlyOwner {
_mint(_to, _amount);
_moveDelegates(address(0), _delegates[_to], _amount);
}
// Copied and modified from YAM code:
// https://github.com/yam-finance/yam-protocol/blob/master/contracts/token/YAMGovernanceStorage.sol
// https://github.com/yam-finance/yam-protocol/blob/master/contracts/token/YAMGovernance.sol
// Which is copied and modified from COMPOUND:
// https://github.com/compound-finance/compound-protocol/blob/master/contracts/Governance/Comp.sol
/// @dev A record of each accounts delegate
mapping (address => address) internal _delegates;
/// @notice A checkpoint for marking number of votes from a given block
struct Checkpoint {
uint32 fromBlock;
uint256 votes;
}
/// @notice A record of votes checkpoints for each account, by index
mapping (address => mapping (uint32 => Checkpoint)) public checkpoints;
/// @notice The number of checkpoints for each account
mapping (address => uint32) public numCheckpoints;
/// @notice The EIP-712 typehash for the contract's domain
bytes32 public constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)");
/// @notice The EIP-712 typehash for the delegation struct used by the contract
bytes32 public constant DELEGATION_TYPEHASH = keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");
/// @notice A record of states for signing / validating signatures
mapping (address => uint) public nonces;
/// @notice An event thats emitted when an account changes its delegate
event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);
/// @notice An event thats emitted when a delegate account's vote balance changes
event DelegateVotesChanged(address indexed delegate, uint previousBalance, uint newBalance);
/**
* @notice Delegate votes from `msg.sender` to `delegatee`
* @param delegator The address to get delegatee for
*/
function delegates(address delegator) external view returns (address) {
return _delegates[delegator];
}
/**
* @notice Delegate votes from `msg.sender` to `delegatee`
* @param delegatee The address to delegate votes to
*/
function delegate(address delegatee) external {
return _delegate(msg.sender, delegatee);
}
/**
* @notice Delegates votes from signatory to `delegatee`
* @param delegatee The address to delegate votes to
* @param nonce The contract state required to match the signature
* @param expiry The time at which to expire the signature
* @param v The recovery byte of the signature
* @param r Half of the ECDSA signature pair
* @param s Half of the ECDSA signature pair
*/
function delegateBySig(address delegatee, uint nonce, uint expiry, uint8 v, bytes32 r, bytes32 s) external {
bytes32 domainSeparator = keccak256(abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name())), getChainId(), address(this)));
bytes32 structHash = keccak256(abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry));
bytes32 digest = keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
address signatory = ecrecover(digest, v, r, s);
require(signatory != address(0), "SIG::delegateBySig: invalid signature");
require(nonce == nonces[signatory]++, "SIG::delegateBySig: invalid nonce");
require(now <= expiry, "SIG::delegateBySig: signature expired");
return _delegate(signatory, delegatee);
}
/**
* @notice Gets the current votes balance for `account`
* @param account The address to get votes balance
* @return The number of current votes for `account`
*/
function getCurrentVotes(address account) external view returns (uint256) {
uint32 nCheckpoints = numCheckpoints[account];
return nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : 0;
}
/**
* @notice Determine the prior number of votes for an account as of a block number
* @dev Block number must be a finalized block or else this function will revert to prevent misinformation.
* @param account The address of the account to check
* @param blockNumber The block number to get the vote balance at
* @return The number of votes the account had as of the given block
*/
function getPriorVotes(address account, uint blockNumber) external view returns (uint256) {
require(blockNumber < block.number, "SIG::getPriorVotes: not yet determined");
uint32 nCheckpoints = numCheckpoints[account];
if (nCheckpoints == 0) {
return 0;
}
// First check most recent balance
if (checkpoints[account][nCheckpoints - 1].fromBlock <= blockNumber) {
return checkpoints[account][nCheckpoints - 1].votes;
}
// Next check implicit zero balance
if (checkpoints[account][0].fromBlock > blockNumber) {
return 0;
}
uint32 lower = 0;
uint32 upper = nCheckpoints - 1;
while (upper > lower) {
uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow
Checkpoint memory cp = checkpoints[account][center];
if (cp.fromBlock == blockNumber) {
return cp.votes;
} else if (cp.fromBlock < blockNumber) {
lower = center;
} else {
upper = center - 1;
}
}
return checkpoints[account][lower].votes;
}
function _delegate(address delegator, address delegatee) internal {
address currentDelegate = _delegates[delegator];
uint256 delegatorBalance = balanceOf(delegator); // balance of underlying SIGs (not scaled);
_delegates[delegator] = delegatee;
emit DelegateChanged(delegator, currentDelegate, delegatee);
_moveDelegates(currentDelegate, delegatee, delegatorBalance);
}
function _moveDelegates(address srcRep, address dstRep, uint256 amount) internal {
if (srcRep != dstRep && amount > 0) {
if (srcRep != address(0)) {
// decrease old representative
uint32 srcRepNum = numCheckpoints[srcRep];
uint256 srcRepOld = srcRepNum > 0 ? checkpoints[srcRep][srcRepNum - 1].votes : 0;
uint256 srcRepNew = srcRepOld.sub(amount);
_writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew);
}
if (dstRep != address(0)) {
// increase new representative
uint32 dstRepNum = numCheckpoints[dstRep];
uint256 dstRepOld = dstRepNum > 0 ? checkpoints[dstRep][dstRepNum - 1].votes : 0;
uint256 dstRepNew = dstRepOld.add(amount);
_writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew);
}
}
}
function _writeCheckpoint(address delegatee, uint32 nCheckpoints, uint256 oldVotes, uint256 newVotes) internal {
uint32 blockNumber = safe32(block.number, "SIG::_writeCheckpoint: block number exceeds 32 bits");
if (nCheckpoints > 0 && checkpoints[delegatee][nCheckpoints - 1].fromBlock == blockNumber) {
checkpoints[delegatee][nCheckpoints - 1].votes = newVotes;
} else {
checkpoints[delegatee][nCheckpoints] = Checkpoint(blockNumber, newVotes);
numCheckpoints[delegatee] = nCheckpoints + 1;
}
emit DelegateVotesChanged(delegatee, oldVotes, newVotes);
}
function safe32(uint n, string memory errorMessage) internal pure returns (uint32) {
require(n < 2**32, errorMessage);
return uint32(n);
}
function getChainId() internal pure returns (uint) {
uint256 chainId;
assembly { chainId := chainid() }
return chainId;
}
}
SigThreePoolProxy.sol 256 lines
// SPDX-License-Identifier: MIT
// Fork of Swerve's YPoolDelegator https://etherscan.io/address/0x329239599afB305DA0A2eC69c58F8a6697F9F88d#code
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/math/Math.sol";
import "./SigToken.sol";
contract SigThreePoolProxy {
uint256 constant N_COINS = 3;
address[] public coins;
uint256[] public balances;
uint256 constant FEE_DENOMINATOR = 10* 10 ** 9;
uint256 constant MAX_ADMIN_FEE = 10 * 10 ** 9; // 1%
uint256 constant MAX_FEE = 5 * 10 ** 9; // 0.5%
uint256 public fee;
uint256 public admin_fee;
address public owner;
address token;
uint256 public initial_A;
uint256 public future_A;
uint256 public initial_A_time;
uint256 public future_A_time;
uint256 public admin_actions_deadline;
uint256 public transfer_ownership_deadline;
uint256 public future_fee;
uint256 public future_admin_fee;
address public future_owner;
// fill the rest of current slot to fix https://github.com/vyperlang/vyper/issues/2270
uint64 public slot_fill_0;
uint32 public slot_fill_1;
bool is_killed;
uint256 kill_deadline;
uint256 constant KILL_DEADLINE_DT = 2 * 30 * 86400;
// following 3 variables aren't part of proxy implementation and go after all 3pool's variables
address delegationTarget;
address dutchAuction;
SigToken sigToken;
constructor(
address _owner,
address[N_COINS] memory _coinsIn,
address _pool_token,
uint256 _A,
uint256 _fee,
uint256 _admin_fee,
// additional variables
address _delegationTarget,
address _dutchAuction,
SigToken _sigToken
) public {
for (uint256 i = 0; i < N_COINS; i++) {
require(_coinsIn[i] != address(0));
balances.push(0);
coins.push(_coinsIn[i]);
}
initial_A = _A;
future_A = _A;
fee = _fee;
admin_fee = _admin_fee;
owner = _owner;
is_killed = false;
kill_deadline = block.timestamp + KILL_DEADLINE_DT;
token = _pool_token;
// gas can be optimized if used constant instead of variables
delegationTarget = _delegationTarget;
dutchAuction = _dutchAuction;
sigToken = _sigToken;
}
// template from https://github.com/OpenZeppelin/openzeppelin-sdk/blob/master/packages/lib/contracts/upgradeability/Proxy.sol
/**
* @dev Delegates the current call to `implementation`.
*
* This function does not return to its internal call site, it will return directly to the external caller.
*/
function _delegate(address implementation) internal {
// // solhint-disable-next-line no-inline-assembly
assembly {
// Copy msg.data. We take full control of memory in this inline assembly
// block because it will not return to Solidity code. We overwrite the
// Solidity scratch pad at memory position 0.
calldatacopy(0, 0, calldatasize())
// Call the implementation.
// out and outsize are 0 because we don't know the size yet.
let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
// Copy the returned data.
returndatacopy(0, 0, returndatasize())
switch result
// delegatecall returns 0 on error.
case 0 { revert(0, returndatasize()) }
default { return(0, returndatasize()) }
}
}
fallback () external {
_delegate(delegationTarget);
}
receive () external payable {}
// this function can be called by anyone, but fees go directly to the auction
function withdraw_admin_fees() public {
for (uint256 i = 0; i < N_COINS; i++) {
IERC20 coin = IERC20(coins[i]);
uint256 value = IERC20(coin).balanceOf(address(this)) - balances[i];
if (value > 0) {
coin.transfer(dutchAuction, value);
}
}
}
function changeAuction(address newAuction) public {
require(msg.sender == owner);
dutchAuction = newAuction;
}
/**
* @dev
* The code below implements an additional exchange2 function, which does normal exchange delegate call
* plus gives users some cashback, if possible
*/
uint256 constant CASHBACK_EXCHANGE_THRESHOLD_0 = 1000e18; // at least 1000 stablecoins to get reward
uint256 constant CASHBACK_SIG_LOW_AMOUNT = 30e18;
uint256 constant CASHBACK_SIG_HIGH_AMOUNT = 100e18;
uint256 constant CASHBACK_MAX_GAS_PRICE = 100e9; // 100 gwei
uint256 startBlock;
uint256 endBlock;
int256 a;
int256 c;
/**
* @notice Set parameters for cashback, such that
* availableCashbackEther(startBlock) = initCashback
* availableCashbackEther(endBlock) = totalCashback >= initCashback
* @param _startBlock - first block of the cashback
* @param _endBlock - last block of the cashback
* @param initCashback - about of ETH cashback available at _startBlock
* @param totalCashback - total amount of ETH available at _endBlock
*
*/
function setCashbackEther(
uint256 _startBlock,
uint256 _endBlock,
int256 initCashback,
int256 totalCashback
) public payable {
require(msg.sender == owner, "msg.sender == owner");
require(address(this).balance >= uint256(totalCashback), "balance < totalCashback");
startBlock = _startBlock;
endBlock = _endBlock;
// t := (block.number - _startBlock) <=> t from 0 .. E
// l(t) := a*t + b is a line, such
// l(0) = a*0 + b = init
// l(E) = a*E + b = total
//
// ethPerBlock*(block.number - _startBlock) + initCashback = totalCashback unlocked so far until block.number]
//
// B := contract balance(t = 0)
// safe(t) - how much of balance is untouchable
// safe(0) = B - init
// safe(E) = B - total
// safe(t) = B - l(t) = B - (a*t + b) = B-b - a*t;
// allow to spend (t) = balance(t) - safe(t) = balance(t) - (B-b - a*t) = balance(t) - B+b + a*t =
// = balance(t) + a*t + c, where c = b-B;
// <=> c = init - balance(_startBlock);
a = (totalCashback - initCashback) / int256(_endBlock - _startBlock);
c = initCashback - int256(address(this).balance);
// allow to spend (t) = balance(t) + a*t + c
}
/**
* @notice how mush ETH is available for the cashback at the currBlock
* invariant: availableCashbackEther(t) <= address(this).balance
* to keep invariant: we **MUST** use address(this).balance in calc
*/
function availableCashbackEther(uint256 currBlock) view public returns(uint256) {
if (currBlock < startBlock || endBlock < currBlock) return 0;
return uint256(int256(address(this).balance) + a * int256(currBlock - startBlock) + c);
}
/**
* @notice how much cashback tx.origin would get if there's full funding
*/
function entitledCashbackEther(uint256 txGasPrice) public view returns (uint256) {
// people who trade via contract calc with 50% penalty
uint256 sigBalance = (sigToken.balanceOf(tx.origin) + sigToken.balanceOf(msg.sender)) / 2;
if (sigBalance < CASHBACK_SIG_LOW_AMOUNT) return 0;
// level from 0 ... CASHBACK_SIG_HIGH_AMOUNT linear
uint256 cashBackLevel = Math.min(sigBalance, CASHBACK_SIG_HIGH_AMOUNT);
// does user use reasonable gasprice?
uint256 gasPrice = Math.min(txGasPrice, CASHBACK_MAX_GAS_PRICE);
// 100_000 gas units - maximum cashback
uint256 gasUnitsCashback = (100_000 * cashBackLevel / CASHBACK_SIG_HIGH_AMOUNT);
return gasUnitsCashback * gasPrice;
}
function payCashbackEther(int128 coinId, uint256 amount) private {
// coinId = 0 => DAI(1e18), 1||2 => USDC||USDT(1e6), so make them all 1e18
if (coinId != 0) amount *= 1e12;
// to whom should we give cashback?
if (amount >= CASHBACK_EXCHANGE_THRESHOLD_0) {
// how much ETH are we ready to spend?
uint256 availableEth = availableCashbackEther(block.number);
// how much cashback to give?
// use not all availableEth but some part that it depleted gradually rather than completely after certain payback
uint256 cashback = Math.min(entitledCashbackEther(tx.gasprice), availableEth * 1/10);
tx.origin.transfer(cashback);
}
}
// the same code as of above function, but for view only
function calcCashbackEther(int128 coinId, uint256 amount, uint256 txGasPrice) public view returns (uint256) {
// coinId = 0 => DAI(1e18), 1||2 => USDC||USDT(1e6), so make them all 1e18
if (coinId != 0) amount *= 1e12;
// to whom should we give cashback?
if (amount >= CASHBACK_EXCHANGE_THRESHOLD_0) {
// how much ETH are we ready to spend?
uint256 availableEth = availableCashbackEther(block.number);
// how much cashback to give?
// use not all availableEth but some part that it depleted gradually rather than completely after certain payback
uint256 cashback = Math.min(entitledCashbackEther(txGasPrice), availableEth * 1/10);
return cashback;
}
return 0;
}
function exchange2(int128 i, int128 j, uint256 dx, uint256 min_dy) public {
(bool success, bytes memory result) = delegationTarget.delegatecall(
abi.encodeWithSignature("exchange(int128,int128,uint256,uint256)", i, j, dx, min_dy)
// signature of exchange(int128,int128,uint256,uint256) - 0x3df02124
);
if (!success) {
if (result.length > 0) {
revert(string(result));
} else {
revert();
}
}
// give cashback
payCashbackEther(i, dx);
}
}
Read Contract
admin_actions_deadline 0x405e28f8 → uint256
admin_fee 0xfee3f7f9 → uint256
availableCashbackEther 0x90a7e05b → uint256
balances 0x4903b0d1 → uint256
calcCashbackEther 0x92773c55 → uint256
coins 0xc6610657 → address
entitledCashbackEther 0x5d552b68 → uint256
fee 0xddca3f43 → uint256
future_A 0xb4b577ad → uint256
future_A_time 0x14052288 → uint256
future_admin_fee 0xe3824462 → uint256
future_fee 0x58680d0b → uint256
future_owner 0x1ec0cdc1 → address
initial_A 0x5409491a → uint256
initial_A_time 0x2081066c → uint256
owner 0x8da5cb5b → address
slot_fill_0 0xa250e192 → uint64
slot_fill_1 0x6a9efeab → uint32
transfer_ownership_deadline 0xe0a0b586 → uint256
Write Contract 4 functions
These functions modify contract state and require a wallet transaction to execute.
changeAuction 0x5383db20
address newAuction
exchange2 0x18299fc2
int128 i
int128 j
uint256 dx
uint256 min_dy
setCashbackEther 0x7d008a40
uint256 _startBlock
uint256 _endBlock
int256 initCashback
int256 totalCashback
withdraw_admin_fees 0x30c54085
No parameters
Token Balances (3)
View Transfers →Recent Transactions
This address has 1 on-chain transactions, but only 0.8% of the chain is indexed. Transactions will appear as indexing progresses. View on Etherscan →