Forkchoice Ethereum Mainnet

Address Contract Verified

Address 0x3333333ACdEdBbC9Ad7bda0876e60714195681c5
Balance 1.0000 ETH ($2098.41)
Nonce 1
Code Size 3369 bytes
Indexed Transactions 0 (1 on-chain, 0.8% indexed)
External Etherscan · Sourcify

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

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 →