Forkchoice Ethereum Mainnet

Address Contract Verified

Address 0xfF3Ac80c1caA08Cbd43a7e90d20c398d54C7342f
Balance 0 ETH
Nonce 1
Code Size 7054 bytes
Indexed Transactions 0 (1 on-chain, 0.9% indexed)
External Etherscan · Sourcify

Contract Bytecode

7054 bytes
0x608060405234801561001057600080fd5b506004361061011b5760003560e01c806395d89b41116100b2578063a9059cbb11610081578063dd62ed3e11610066578063dd62ed3e14610240578063ec60bcf314610253578063fc0c546a146102665761011b565b8063a9059cbb14610218578063d505accf1461022b5761011b565b806395d89b41146101c95780639dc29fac146101d1578063a0712d68146101e4578063a87430ba146101f75761011b565b8063313ce567116100ee578063313ce567146101865780633644e5151461019b57806370a08231146101a35780637ecebe00146101b65761011b565b806306fdde0314610120578063095ea7b31461013e57806318160ddd1461015e57806323b872dd14610173575b600080fd5b61012861027b565b6040516101359190611826565b60405180910390f35b61015161014c366004611652565b6102b4565b6040516101359190611787565b61016661032c565b6040516101359190611792565b61015161018136600461159f565b610332565b61018e610353565b6040516101359190611af5565b610166610358565b6101666101b1366004611549565b610367565b6101666101c4366004611549565b6103a1565b6101286103b3565b6101516101df366004611652565b6103ec565b6101516101f236600461169c565b610402565b61020a610205366004611549565b6106bd565b604051610135929190611ad2565b610151610226366004611652565b6106f9565b61023e6102393660046115df565b610706565b005b61016661024e36600461156b565b610929565b61015161026136600461159f565b610946565b61026e61095d565b604051610135919061170f565b6040518060400160405280601181526020017f5374616b65642049636520546f6b656e7300000000000000000000000000000081525081565b33600081815260026020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259061031a908690611792565b60405180910390a35060015b92915050565b60005481565b600061033e8483610981565b610349848484610a72565b5060019392505050565b601281565b6000610362610d9f565b905090565b73ffffffffffffffffffffffffffffffffffffffff166000908152600160205260409020546fffffffffffffffffffffffffffffffff1690565b60036020526000908152604090205481565b6040518060400160405280600481526020017f6e4943450000000000000000000000000000000000000000000000000000000081525081565b60006103f9338484610dff565b50600192915050565b600033610444576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161043b9061198a565b60405180910390fd5b61044c61150e565b503360009081526001602090815260408083208151808301835290546fffffffffffffffffffffffffffffffff80821683527001000000000000000000000000000000009091041692810192909252517f70a082310000000000000000000000000000000000000000000000000000000081529091907f000000000000000000000000f16e81dce15b08f326220742020379b855b87df973ffffffffffffffffffffffffffffffffffffffff16906370a082319061050e90309060040161170f565b60206040518083038186803b15801561052657600080fd5b505afa15801561053a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061055e91906116b4565b90506000805460001461057e578160005486028161057857fe5b04610580565b845b905061058b816110f2565b8351016fffffffffffffffffffffffffffffffff1683526105b06201518042016110f2565b6fffffffffffffffffffffffffffffffff90811660208086019182523360008181526001909252604082208751815494518616700100000000000000000000000000000000029086167fffffffffffffffffffffffffffffffff00000000000000000000000000000000909516949094179094169290921790925581548301909155610675907f000000000000000000000000f16e81dce15b08f326220742020379b855b87df973ffffffffffffffffffffffffffffffffffffffff16903088611142565b60405133906000907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906106aa908590611792565b60405180910390a3506001949350505050565b6001602052600090815260409020546fffffffffffffffffffffffffffffffff8082169170010000000000000000000000000000000090041682565b60006103f9338484610a72565b73ffffffffffffffffffffffffffffffffffffffff8716610753576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161043b90611a64565b83421061078c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161043b90611a9b565b73ffffffffffffffffffffffffffffffffffffffff87166000818152600360209081526040918290208054600181810190925592519092610817926107fc927f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9928e928e928e92918e910161179b565b604051602081830303815290604052805190602001206112ad565b858585604051600081526020016040526040516108379493929190611808565b6020604051602081039080840390855afa158015610859573d6000803e3d6000fd5b5050506020604051035173ffffffffffffffffffffffffffffffffffffffff16146108b0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161043b906119f8565b73ffffffffffffffffffffffffffffffffffffffff8088166000818152600260209081526040808320948b168084529490915290819020889055517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92590610918908990611792565b60405180910390a350505050505050565b600260209081526000928352604080842090915290825290205481565b60006109528483610981565b610349848484610dff565b7f000000000000000000000000f16e81dce15b08f326220742020379b855b87df981565b3373ffffffffffffffffffffffffffffffffffffffff831614156109a457610a6e565b73ffffffffffffffffffffffffffffffffffffffff821660009081526002602090815260408083203384529091529020547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114610a6c5781811015610a36576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161043b9061191c565b73ffffffffffffffffffffffffffffffffffffffff83166000908152600260209081526040808320338452909152902082820390555b505b5050565b610a7a61150e565b5073ffffffffffffffffffffffffffffffffffffffff83166000908152600160209081526040918290208251808401909352546fffffffffffffffffffffffffffffffff808216845270010000000000000000000000000000000090910416908201819052421015610b18576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161043b906118ae565b8115610d345780516fffffffffffffffffffffffffffffffff16821115610b6b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161043b90611953565b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614610d345773ffffffffffffffffffffffffffffffffffffffff8316610beb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161043b9061198a565b610bf361150e565b5073ffffffffffffffffffffffffffffffffffffffff83166000908152600160209081526040918290208251808401909352546fffffffffffffffffffffffffffffffff80821684527001000000000000000000000000000000009091041690820152610c5f836110f2565b825173ffffffffffffffffffffffffffffffffffffffff8716600090815260016020526040902080547fffffffffffffffffffffffffffffffff0000000000000000000000000000000016929091036fffffffffffffffffffffffffffffffff16919091179055610ccf836110f2565b905173ffffffffffffffffffffffffffffffffffffffff8516600090815260016020526040902080547fffffffffffffffffffffffffffffffff0000000000000000000000000000000016919092016fffffffffffffffffffffffffffffffff161790555b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef84604051610d919190611792565b60405180910390a350505050565b6000467f00000000000000000000000000000000000000000000000000000000000000018114610dd757610dd28161131d565b610df9565b7f6c9174ad4775db30f767de9ead00781064c187f06289ecee49778a8895c2b49e5b91505090565b73ffffffffffffffffffffffffffffffffffffffff8216610e4c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161043b9061198a565b610e5461150e565b5073ffffffffffffffffffffffffffffffffffffffff83166000908152600160209081526040918290208251808401909352546fffffffffffffffffffffffffffffffff808216845270010000000000000000000000000000000090910416908201819052421015610ef2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161043b906118ae565b600080546040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000f16e81dce15b08f326220742020379b855b87df916906370a0823190610f6890309060040161170f565b60206040518083038186803b158015610f8057600080fd5b505afa158015610f94573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fb891906116b4565b840281610fc157fe5b049050610fea610fd0846110f2565b83516fffffffffffffffffffffffffffffffff1690611354565b73ffffffffffffffffffffffffffffffffffffffff868116600090815260016020526040812080547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff94909416939093179092558154859003909155611085907f000000000000000000000000f16e81dce15b08f326220742020379b855b87df91685836113a6565b600073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040516110e39190611792565b60405180910390a35050505050565b60006fffffffffffffffffffffffffffffffff82111561113e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161043b906119c1565b5090565b600060608573ffffffffffffffffffffffffffffffffffffffff166323b872dd60e01b86868660405160240161117a93929190611730565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252905161120391906116cc565b6000604051808303816000865af19150503d8060008114611240576040519150601f19603f3d011682016040523d82523d6000602084013e611245565b606091505b509150915081801561126f57508051158061126f57508080602001905181019061126f919061167c565b6112a5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161043b90611a2f565b505050505050565b60006040518060400160405280600281526020017f19010000000000000000000000000000000000000000000000000000000000008152506112ed610d9f565b83604051602001611300939291906116e8565b604051602081830303815290604052805190602001209050919050565b60007f47e79534a245952e8b16893a336b85a3d9ea9fa8c573f3d803afb92a794692188230604051602001611300939291906117dc565b8082036fffffffffffffffffffffffffffffffff8084169082161115610326576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161043b90611877565b600060608473ffffffffffffffffffffffffffffffffffffffff1663a9059cbb60e01b85856040516024016113dc929190611761565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000090941693909317909252905161146591906116cc565b6000604051808303816000865af19150503d80600081146114a2576040519150601f19603f3d011682016040523d82523d6000602084013e6114a7565b606091505b50915091508180156114d15750805115806114d15750808060200190518101906114d1919061167c565b611507576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161043b906118e5565b5050505050565b604080518082019091526000808252602082015290565b803573ffffffffffffffffffffffffffffffffffffffff8116811461032657600080fd5b60006020828403121561155a578081fd5b6115648383611525565b9392505050565b6000806040838503121561157d578081fd5b6115878484611525565b91506115968460208501611525565b90509250929050565b6000806000606084860312156115b3578081fd5b83356115be81611b33565b925060208401356115ce81611b33565b929592945050506040919091013590565b600080600080600080600060e0888a0312156115f9578283fd5b6116038989611525565b96506116128960208a01611525565b95506040880135945060608801359350608088013560ff81168114611635578384fd5b9699959850939692959460a0840135945060c09093013592915050565b60008060408385031215611664578182fd5b61166e8484611525565b946020939093013593505050565b60006020828403121561168d578081fd5b81518015158114611564578182fd5b6000602082840312156116ad578081fd5b5035919050565b6000602082840312156116c5578081fd5b5051919050565b600082516116de818460208701611b03565b9190910192915050565b600084516116fa818460208901611b03565b91909101928352506020820152604001919050565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b73ffffffffffffffffffffffffffffffffffffffff9384168152919092166020820152604081019190915260600190565b73ffffffffffffffffffffffffffffffffffffffff929092168252602082015260400190565b901515815260200190565b90815260200190565b95865273ffffffffffffffffffffffffffffffffffffffff94851660208701529290931660408501526060840152608083019190915260a082015260c00190565b928352602083019190915273ffffffffffffffffffffffffffffffffffffffff16604082015260600190565b93845260ff9290921660208401526040830152606082015260800190565b6000602082528251806020840152611845816040850160208701611b03565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b60208082526015908201527f426f72696e674d6174683a20556e646572666c6f770000000000000000000000604082015260600190565b60208082526006908201527f4c6f636b65640000000000000000000000000000000000000000000000000000604082015260600190565b6020808252601c908201527f426f72696e6745524332303a205472616e73666572206661696c656400000000604082015260600190565b6020808252600d908201527f4c6f7720616c6c6f77616e636500000000000000000000000000000000000000604082015260600190565b6020808252600b908201527f4c6f772062616c616e6365000000000000000000000000000000000000000000604082015260600190565b6020808252600c908201527f5a65726f20616464726573730000000000000000000000000000000000000000604082015260600190565b6020808252601c908201527f426f72696e674d6174683a2075696e74313238204f766572666c6f7700000000604082015260600190565b6020808252600b908201527f496e76616c696420536967000000000000000000000000000000000000000000604082015260600190565b6020808252818101527f426f72696e6745524332303a205472616e7366657246726f6d206661696c6564604082015260600190565b6020808252600a908201527f5a65726f206f776e657200000000000000000000000000000000000000000000604082015260600190565b60208082526007908201527f4578706972656400000000000000000000000000000000000000000000000000604082015260600190565b6fffffffffffffffffffffffffffffffff92831681529116602082015260400190565b60ff91909116815260200190565b60005b83811015611b1e578181015183820152602001611b06565b83811115611b2d576000848401525b50505050565b73ffffffffffffffffffffffffffffffffffffffff81168114611b5557600080fd5b5056fea2646970667358221220a78789a0d025ef289ef4f73086adce9b69de5eb1dd57ccdd76fe4b2f75227e6964736f6c634300060c0033

Verified Source Code Full Match

Compiler: v0.6.12+commit.27d51765 EVM: istanbul Optimization: Yes (99999 runs)
nICE.sol 428 lines
// SPDX-License-Identifier: MIXED

// File @boringcrypto/boring-solidity/contracts/libraries/[email protected]
// License-Identifier: MIT
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;

/// @notice A library for performing overflow-/underflow-safe math,
/// updated with awesomeness from of DappHub (https://github.com/dapphub/ds-math).
library BoringMath {
    function add(uint256 a, uint256 b) internal pure returns (uint256 c) {
        require((c = a + b) >= b, "BoringMath: Add Overflow");
    }

    function sub(uint256 a, uint256 b) internal pure returns (uint256 c) {
        require((c = a - b) <= a, "BoringMath: Underflow");
    }

    function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {
        require(b == 0 || (c = a * b) / b == a, "BoringMath: Mul Overflow");
    }

    function to128(uint256 a) internal pure returns (uint128 c) {
        require(a <= uint128(-1), "BoringMath: uint128 Overflow");
        c = uint128(a);
    }

    function to64(uint256 a) internal pure returns (uint64 c) {
        require(a <= uint64(-1), "BoringMath: uint64 Overflow");
        c = uint64(a);
    }

    function to32(uint256 a) internal pure returns (uint32 c) {
        require(a <= uint32(-1), "BoringMath: uint32 Overflow");
        c = uint32(a);
    }
}

/// @notice A library for performing overflow-/underflow-safe addition and subtraction on uint128.
library BoringMath128 {
    function add(uint128 a, uint128 b) internal pure returns (uint128 c) {
        require((c = a + b) >= b, "BoringMath: Add Overflow");
    }

    function sub(uint128 a, uint128 b) internal pure returns (uint128 c) {
        require((c = a - b) <= a, "BoringMath: Underflow");
    }
}

/// @notice A library for performing overflow-/underflow-safe addition and subtraction on uint64.
library BoringMath64 {
    function add(uint64 a, uint64 b) internal pure returns (uint64 c) {
        require((c = a + b) >= b, "BoringMath: Add Overflow");
    }

    function sub(uint64 a, uint64 b) internal pure returns (uint64 c) {
        require((c = a - b) <= a, "BoringMath: Underflow");
    }
}

/// @notice A library for performing overflow-/underflow-safe addition and subtraction on uint32.
library BoringMath32 {
    function add(uint32 a, uint32 b) internal pure returns (uint32 c) {
        require((c = a + b) >= b, "BoringMath: Add Overflow");
    }

    function sub(uint32 a, uint32 b) internal pure returns (uint32 c) {
        require((c = a - b) <= a, "BoringMath: Underflow");
    }
}

// File @boringcrypto/boring-solidity/contracts/interfaces/[email protected]
// License-Identifier: MIT

interface IERC20 {
    function totalSupply() external view returns (uint256);

    function balanceOf(address account) external view returns (uint256);

    function allowance(address owner, address spender) external view returns (uint256);

    function approve(address spender, uint256 amount) external returns (bool);

    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /// @notice EIP 2612
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;
}

// File @boringcrypto/boring-solidity/contracts/libraries/[email protected]
// License-Identifier: MIT

// solhint-disable avoid-low-level-calls

library BoringERC20 {
    bytes4 private constant SIG_SYMBOL = 0x95d89b41; // symbol()
    bytes4 private constant SIG_NAME = 0x06fdde03; // name()
    bytes4 private constant SIG_DECIMALS = 0x313ce567; // decimals()
    bytes4 private constant SIG_TRANSFER = 0xa9059cbb; // transfer(address,uint256)
    bytes4 private constant SIG_TRANSFER_FROM = 0x23b872dd; // transferFrom(address,address,uint256)

    function returnDataToString(bytes memory data) internal pure returns (string memory) {
        if (data.length >= 64) {
            return abi.decode(data, (string));
        } else if (data.length == 32) {
            uint8 i = 0;
            while(i < 32 && data[i] != 0) {
                i++;
            }
            bytes memory bytesArray = new bytes(i);
            for (i = 0; i < 32 && data[i] != 0; i++) {
                bytesArray[i] = data[i];
            }
            return string(bytesArray);
        } else {
            return "???";
        }
    }

    /// @notice Provides a safe ERC20.symbol version which returns '???' as fallback string.
    /// @param token The address of the ERC-20 token contract.
    /// @return (string) Token symbol.
    function safeSymbol(IERC20 token) internal view returns (string memory) {
        (bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(SIG_SYMBOL));
        return success ? returnDataToString(data) : "???";
    }

    /// @notice Provides a safe ERC20.name version which returns '???' as fallback string.
    /// @param token The address of the ERC-20 token contract.
    /// @return (string) Token name.
    function safeName(IERC20 token) internal view returns (string memory) {
        (bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(SIG_NAME));
        return success ? returnDataToString(data) : "???";
    }

    /// @notice Provides a safe ERC20.decimals version which returns '18' as fallback value.
    /// @param token The address of the ERC-20 token contract.
    /// @return (uint8) Token decimals.
    function safeDecimals(IERC20 token) internal view returns (uint8) {
        (bool success, bytes memory data) = address(token).staticcall(abi.encodeWithSelector(SIG_DECIMALS));
        return success && data.length == 32 ? abi.decode(data, (uint8)) : 18;
    }

    /// @notice Provides a safe ERC20.transfer version for different ERC-20 implementations.
    /// Reverts on a failed transfer.
    /// @param token The address of the ERC-20 token.
    /// @param to Transfer tokens to.
    /// @param amount The token amount.
    function safeTransfer(
        IERC20 token,
        address to,
        uint256 amount
    ) internal {
        (bool success, bytes memory data) = address(token).call(abi.encodeWithSelector(SIG_TRANSFER, to, amount));
        require(success && (data.length == 0 || abi.decode(data, (bool))), "BoringERC20: Transfer failed");
    }

    /// @notice Provides a safe ERC20.transferFrom version for different ERC-20 implementations.
    /// Reverts on a failed transfer.
    /// @param token The address of the ERC-20 token.
    /// @param from Transfer tokens from.
    /// @param to Transfer tokens to.
    /// @param amount The token amount.
    function safeTransferFrom(
        IERC20 token,
        address from,
        address to,
        uint256 amount
    ) internal {
        (bool success, bytes memory data) = address(token).call(abi.encodeWithSelector(SIG_TRANSFER_FROM, from, to, amount));
        require(success && (data.length == 0 || abi.decode(data, (bool))), "BoringERC20: TransferFrom failed");
    }
}

// File @boringcrypto/boring-solidity/contracts/[email protected]
// License-Identifier: MIT
// Based on code and smartness by Ross Campbell and Keno
// Uses immutable to store the domain separator to reduce gas usage
// If the chain id changes due to a fork, the forked chain will calculate on the fly.

// solhint-disable no-inline-assembly

contract Domain {
    bytes32 private constant DOMAIN_SEPARATOR_SIGNATURE_HASH = keccak256("EIP712Domain(uint256 chainId,address verifyingContract)");
    // See https://eips.ethereum.org/EIPS/eip-191
    string private constant EIP191_PREFIX_FOR_EIP712_STRUCTURED_DATA = "\x19\x01";

    // solhint-disable var-name-mixedcase
    bytes32 private immutable _DOMAIN_SEPARATOR;
    uint256 private immutable DOMAIN_SEPARATOR_CHAIN_ID;    

    /// @dev Calculate the DOMAIN_SEPARATOR
    function _calculateDomainSeparator(uint256 chainId) private view returns (bytes32) {
        return keccak256(
            abi.encode(
                DOMAIN_SEPARATOR_SIGNATURE_HASH,
                chainId,
                address(this)
            )
        );
    }

    constructor() public {
        uint256 chainId; assembly {chainId := chainid()}
        _DOMAIN_SEPARATOR = _calculateDomainSeparator(DOMAIN_SEPARATOR_CHAIN_ID = chainId);
    }

    /// @dev Return the DOMAIN_SEPARATOR
    // It's named internal to allow making it public from the contract that uses it by creating a simple view function
    // with the desired public name, such as DOMAIN_SEPARATOR or domainSeparator.
    // solhint-disable-next-line func-name-mixedcase
    function _domainSeparator() internal view returns (bytes32) {
        uint256 chainId; assembly {chainId := chainid()}
        return chainId == DOMAIN_SEPARATOR_CHAIN_ID ? _DOMAIN_SEPARATOR : _calculateDomainSeparator(chainId);
    }

    function _getDigest(bytes32 dataHash) internal view returns (bytes32 digest) {
        digest =
            keccak256(
                abi.encodePacked(
                    EIP191_PREFIX_FOR_EIP712_STRUCTURED_DATA,
                    _domainSeparator(),
                    dataHash
                )
            );
    }
}

// File contracts/nICE.sol
//License-Identifier: MIT

// Staking in sSpell inspired by Chef Nomi's SushiBar - MIT license (originally WTFPL)
// modified by BoringCrypto for DictatorDAO

contract nICE is IERC20, Domain {
    using BoringMath for uint256;
    using BoringMath128 for uint128;
    using BoringERC20 for IERC20;

    string public constant symbol = "nICE";
    string public constant name = "Staked Ice Tokens";
    uint8 public constant decimals = 18;
    uint256 public override totalSupply;
    uint256 private constant LOCK_TIME = 24 hours;

    IERC20 public immutable token;

    constructor(IERC20 _token) public {
        token = _token;
    }

    struct User {
        uint128 balance;
        uint128 lockedUntil;
    }

    /// @notice owner > balance mapping.
    mapping(address => User) public users;
    /// @notice owner > spender > allowance mapping.
    mapping(address => mapping(address => uint256)) public override allowance;
    /// @notice owner > nonce mapping. Used in `permit`.
    mapping(address => uint256) public nonces;

    event Transfer(address indexed _from, address indexed _to, uint256 _value);
    event Approval(address indexed _owner, address indexed _spender, uint256 _value);

    function balanceOf(address user) public view override returns (uint256 balance) {
        return users[user].balance;
    }

    function _transfer(
        address from,
        address to,
        uint256 shares
    ) internal {
        User memory fromUser = users[from];
        require(block.timestamp >= fromUser.lockedUntil, "Locked");
        if (shares != 0) {
            require(fromUser.balance >= shares, "Low balance");
            if (from != to) {
                require(to != address(0), "Zero address"); // Moved down so other failed calls safe some gas
                User memory toUser = users[to];
                users[from].balance = fromUser.balance - shares.to128(); // Underflow is checked
                users[to].balance = toUser.balance + shares.to128(); // Can't overflow because totalSupply would be greater than 2^128-1;
            }
        }
        emit Transfer(from, to, shares);
    }

    function _useAllowance(address from, uint256 shares) internal {
        if (msg.sender == from) {
            return;
        }
        uint256 spenderAllowance = allowance[from][msg.sender];
        // If allowance is infinite, don't decrease it to save on gas (breaks with EIP-20).
        if (spenderAllowance != type(uint256).max) {
            require(spenderAllowance >= shares, "Low allowance");
            allowance[from][msg.sender] = spenderAllowance - shares; // Underflow is checked
        }
    }

    /// @notice Transfers `shares` tokens from `msg.sender` to `to`.
    /// @param to The address to move the tokens.
    /// @param shares of the tokens to move.
    /// @return (bool) Returns True if succeeded.
    function transfer(address to, uint256 shares) public returns (bool) {
        _transfer(msg.sender, to, shares);
        return true;
    }

    /// @notice Transfers `shares` tokens from `from` to `to`. Caller needs approval for `from`.
    /// @param from Address to draw tokens from.
    /// @param to The address to move the tokens.
    /// @param shares The token shares to move.
    /// @return (bool) Returns True if succeeded.
    function transferFrom(
        address from,
        address to,
        uint256 shares
    ) public returns (bool) {
        _useAllowance(from, shares);
        _transfer(from, to, shares);
        return true;
    }

    /// @notice Approves `amount` from sender to be spend by `spender`.
    /// @param spender Address of the party that can draw from msg.sender's account.
    /// @param amount The maximum collective amount that `spender` can draw.
    /// @return (bool) Returns True if approved.
    function approve(address spender, uint256 amount) public override returns (bool) {
        allowance[msg.sender][spender] = amount;
        emit Approval(msg.sender, spender, amount);
        return true;
    }

    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32) {
        return _domainSeparator();
    }

    // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
    bytes32 private constant PERMIT_SIGNATURE_HASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;

    /// @notice Approves `value` from `owner_` to be spend by `spender`.
    /// @param owner_ Address of the owner.
    /// @param spender The address of the spender that gets approved to draw from `owner_`.
    /// @param value The maximum collective amount that `spender` can draw.
    /// @param deadline This permit must be redeemed before this deadline (UTC timestamp in seconds).
    function permit(
        address owner_,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external override {
        require(owner_ != address(0), "Zero owner");
        require(block.timestamp < deadline, "Expired");
        require(
            ecrecover(_getDigest(keccak256(abi.encode(PERMIT_SIGNATURE_HASH, owner_, spender, value, nonces[owner_]++, deadline))), v, r, s) ==
                owner_,
            "Invalid Sig"
        );
        allowance[owner_][spender] = value;
        emit Approval(owner_, spender, value);
    }

    /// math is ok, because amount, totalSupply and shares is always 0 <= amount <= 69.000.000 * 10^18
    /// theoretically you can grow the amount/share ratio, but it's not practical and useless
    function mint(uint256 amount) public returns (bool) {
        require(msg.sender != address(0), "Zero address");
        User memory user = users[msg.sender];

        uint256 totalTokens = token.balanceOf(address(this));
        uint256 shares = totalSupply == 0 ? amount : (amount * totalSupply) / totalTokens;
        user.balance += shares.to128();
        user.lockedUntil = (block.timestamp + LOCK_TIME).to128();
        users[msg.sender] = user;
        totalSupply += shares;

        token.safeTransferFrom(msg.sender, address(this), amount);

        emit Transfer(address(0), msg.sender, shares);
        return true;
    }

    function _burn(
        address from,
        address to,
        uint256 shares
    ) internal {
        require(to != address(0), "Zero address");
        User memory user = users[from];
        require(block.timestamp >= user.lockedUntil, "Locked");
        uint256 amount = (shares * token.balanceOf(address(this))) / totalSupply;
        users[from].balance = user.balance.sub(shares.to128()); // Must check underflow
        totalSupply -= shares;

        token.safeTransfer(to, amount);

        emit Transfer(from, address(0), shares);
    }

    function burn(address to, uint256 shares) public returns (bool) {
        _burn(msg.sender, to, shares);
        return true;
    }

    function burnFrom(
        address from,
        address to,
        uint256 shares
    ) public returns (bool) {
        _useAllowance(from, shares);
        _burn(from, to, shares);
        return true;
    }
}

Read Contract

DOMAIN_SEPARATOR 0x3644e515 → bytes32
allowance 0xdd62ed3e → uint256
balanceOf 0x70a08231 → uint256
decimals 0x313ce567 → uint8
name 0x06fdde03 → string
nonces 0x7ecebe00 → uint256
symbol 0x95d89b41 → string
token 0xfc0c546a → address
totalSupply 0x18160ddd → uint256
users 0xa87430ba → uint128, uint128

Write Contract 7 functions

These functions modify contract state and require a wallet transaction to execute.

approve 0x095ea7b3
address spender
uint256 amount
returns: bool
burn 0x9dc29fac
address to
uint256 shares
returns: bool
burnFrom 0xec60bcf3
address from
address to
uint256 shares
returns: bool
mint 0xa0712d68
uint256 amount
returns: bool
permit 0xd505accf
address owner_
address spender
uint256 value
uint256 deadline
uint8 v
bytes32 r
bytes32 s
transfer 0xa9059cbb
address to
uint256 shares
returns: bool
transferFrom 0x23b872dd
address from
address to
uint256 shares
returns: bool

Recent Transactions

This address has 1 on-chain transactions, but only 0.9% of the chain is indexed. Transactions will appear as indexing progresses. View on Etherscan →