ETH Price: $3,287.77 (+1.24%)
Gas: 1 Gwei

Contract

0x783f2136640c396805bF8488543ABCE4cf4Cf870
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
0x60c06040153130402022-08-10 7:27:19718 days ago1660116439IN
 Create: CRFTDStakingToken
0 ETH0.023071949.23736137

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
CRFTDStakingToken

Compiler Version
v0.8.15+commit.e14f2714

Optimization Enabled:
Yes with 100000 runs

Other Settings:
default evmVersion
File 1 of 10 : CRFTDStakingToken.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {utils} from "./utils/utils.sol";
import {ERC721} from "solmate/tokens/ERC721.sol";
import {ERC20UDS} from "UDS/tokens/ERC20UDS.sol";
import {OwnableUDS} from "UDS/auth/OwnableUDS.sol";
import {UUPSUpgrade} from "UDS/proxy/UUPSUpgrade.sol";
import {ERC20RewardUDS} from "UDS/tokens/ERC20RewardUDS.sol";

// ------------- storage

bytes32 constant DIAMOND_STORAGE_CRFTD_TOKEN = keccak256("diamond.storage.crftd.token");

function s() pure returns (CRFTDTokenDS storage diamondStorage) {
    bytes32 slot = DIAMOND_STORAGE_CRFTD_TOKEN;
    assembly { diamondStorage.slot := slot } // prettier-ignore
}

struct CRFTDTokenDS {
    uint256 rewardEndDate;
    mapping(address => uint256) rewardRate;
    mapping(address => mapping(uint256 => address)) ownerOf;
}

// ------------- errors

error ZeroReward();
error IncorrectOwner();
error CollectionNotRegistered();
error CollectionAlreadyRegistered();

//       ___           ___           ___                    _____
//      /  /\         /  /\         /  /\       ___        /  /::\
//     /  /:/        /  /::\       /  /:/_     /__/\      /  /:/\:\
//    /  /:/        /  /:/\:\     /  /:/ /\    \  \:\    /  /:/  \:\
//   /  /:/  ___   /  /::\ \:\   /  /:/ /:/     \__\:\  /__/:/ \__\:|
//  /__/:/  /  /\ /__/:/\:\_\:\ /__/:/ /:/      /  /::\ \  \:\ /  /:/
//  \  \:\ /  /:/ \__\/~|::\/:/ \  \:\/:/      /  /:/\:\ \  \:\  /:/
//   \  \:\  /:/     |  |:|::/   \  \::/      /  /:/__\/  \  \:\/:/
//    \  \:\/:/      |  |:|\/     \  \:\     /__/:/        \  \::/
//     \  \::/       |__|:|        \  \:\    \__\/          \__\/
//      \__\/         \__\|         \__\/

/// @title CRFTDStakingToken
/// @author phaze (https://github.com/0xPhaze)
/// @notice Minimal ERC721 staking contract supporting multiple collections
/// @notice Combines ERC20 Token to avoid external calls
contract CRFTDStakingToken is ERC20RewardUDS, UUPSUpgrade, OwnableUDS {
    event CollectionRegistered(address indexed collection, uint256 rewardRate);

    /* ------------- init ------------- */

    function init(string calldata name, string calldata symbol) external initializer {
        __Ownable_init();
        __ERC20_init(name, symbol, 18);
    }

    /* ------------- public ------------- */

    function rewardEndDate() public view override returns (uint256) {
        return s().rewardEndDate;
    }

    function rewardDailyRate() public pure override returns (uint256) {
        return 1e16; // 0.01
    }

    function rewardRate(address collection) public view returns (uint256) {
        return s().rewardRate[collection];
    }

    function ownerOf(address collection, uint256 id) public view returns (address) {
        return s().ownerOf[collection][id];
    }

    function getDailyReward(address user) public view returns (uint256) {
        return _getRewardMultiplier(user) * rewardDailyRate();
    }

    /* ------------- erc20 ------------- */

    function transfer(address to, uint256 amount) public virtual override returns (bool) {
        _claimReward(msg.sender);

        return ERC20UDS.transfer(to, amount);
    }

    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual override returns (bool) {
        _claimReward(from);

        return ERC20UDS.transferFrom(from, to, amount);
    }

    /* ------------- external ------------- */

    function stake(address collection, uint256[] calldata tokenIds) external {
        uint256 rate = s().rewardRate[collection];

        if (rate == 0) revert CollectionNotRegistered();

        _increaseRewardMultiplier(msg.sender, uint216(tokenIds.length * rate));

        for (uint256 i; i < tokenIds.length; ++i) {
            ERC721(collection).transferFrom(msg.sender, address(this), tokenIds[i]);

            s().ownerOf[collection][tokenIds[i]] = msg.sender;
        }
    }

    function unstake(address collection, uint256[] calldata tokenIds) external {
        uint256 rate = s().rewardRate[collection];

        if (rate == 0) revert CollectionNotRegistered();

        _decreaseRewardMultiplier(msg.sender, uint216(tokenIds.length * rate));

        for (uint256 i; i < tokenIds.length; ++i) {
            if (s().ownerOf[collection][tokenIds[i]] != msg.sender) revert IncorrectOwner();

            delete s().ownerOf[collection][tokenIds[i]];

            ERC721(collection).transferFrom(address(this), msg.sender, tokenIds[i]);
        }
    }

    function claimReward() external {
        _claimReward(msg.sender);
    }

    /* ------------- O(n) read-only ------------- */

    function stakedIdsOf(
        address collection,
        address user,
        uint256 collectionSize
    ) external view returns (uint256[] memory stakedIds) {
        return utils.getOwnedIds(s().ownerOf[collection], user, collectionSize);
    }

    /* ------------- owner ------------- */

    function registerCollection(address collection, uint200 rate) external onlyOwner {
        if (rate == 0) revert ZeroReward();
        if (s().rewardRate[collection] != 0) revert CollectionAlreadyRegistered();

        s().rewardRate[collection] = rate;

        emit CollectionRegistered(collection, rate);
    }

    function setRewardEndDate(uint256 endDate) external onlyOwner {
        s().rewardEndDate = endDate;
    }

    function airdrop(address[] calldata tos, uint256[] calldata amounts) external onlyOwner {
        for (uint256 i; i < tos.length; ++i) _mint(tos[i], amounts[i]);
    }

    /* ------------- UUPSUpgrade ------------- */

    function _authorizeUpgrade() internal override onlyOwner {}
}

File 2 of 10 : utils.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

library utils {
    function getOwnedIds(
        mapping(uint256 => address) storage ownerOf,
        address user,
        uint256 collectionSize
    ) internal view returns (uint256[] memory ids) {
        uint256 memPtr;
        uint256 idsLength;

        assembly {
            ids := mload(0x40)
            memPtr := add(ids, 32)
        }

        unchecked {
            uint256 end = collectionSize + 1;
            for (uint256 id = 0; id < end; ++id) {
                if (ownerOf[id] == user) {
                    assembly {
                        mstore(memPtr, id)
                        memPtr := add(memPtr, 32)
                        idsLength := add(idsLength, 1)
                    }
                }
            }
        }

        assembly {
            mstore(ids, idsLength)
            mstore(0x40, memPtr)
        }
    }

    function indexOf(address[] calldata arr, address addr) internal pure returns (bool found, uint256 index) {
        unchecked {
            for (uint256 i; i < arr.length; ++i) if (arr[i] == addr) return (true, i);
        }
        return (false, 0);
    }
}

File 3 of 10 : ERC721.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

/// @notice Modern, minimalist, and gas efficient ERC-721 implementation.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)
abstract contract ERC721 {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event Transfer(address indexed from, address indexed to, uint256 indexed id);

    event Approval(address indexed owner, address indexed spender, uint256 indexed id);

    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /*//////////////////////////////////////////////////////////////
                         METADATA STORAGE/LOGIC
    //////////////////////////////////////////////////////////////*/

    string public name;

    string public symbol;

    function tokenURI(uint256 id) public view virtual returns (string memory);

    /*//////////////////////////////////////////////////////////////
                      ERC721 BALANCE/OWNER STORAGE
    //////////////////////////////////////////////////////////////*/

    mapping(uint256 => address) internal _ownerOf;

    mapping(address => uint256) internal _balanceOf;

    function ownerOf(uint256 id) public view virtual returns (address owner) {
        require((owner = _ownerOf[id]) != address(0), "NOT_MINTED");
    }

    function balanceOf(address owner) public view virtual returns (uint256) {
        require(owner != address(0), "ZERO_ADDRESS");

        return _balanceOf[owner];
    }

    /*//////////////////////////////////////////////////////////////
                         ERC721 APPROVAL STORAGE
    //////////////////////////////////////////////////////////////*/

    mapping(uint256 => address) public getApproved;

    mapping(address => mapping(address => bool)) public isApprovedForAll;

    /*//////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(string memory _name, string memory _symbol) {
        name = _name;
        symbol = _symbol;
    }

    /*//////////////////////////////////////////////////////////////
                              ERC721 LOGIC
    //////////////////////////////////////////////////////////////*/

    function approve(address spender, uint256 id) public virtual {
        address owner = _ownerOf[id];

        require(msg.sender == owner || isApprovedForAll[owner][msg.sender], "NOT_AUTHORIZED");

        getApproved[id] = spender;

        emit Approval(owner, spender, id);
    }

    function setApprovalForAll(address operator, bool approved) public virtual {
        isApprovedForAll[msg.sender][operator] = approved;

        emit ApprovalForAll(msg.sender, operator, approved);
    }

    function transferFrom(
        address from,
        address to,
        uint256 id
    ) public virtual {
        require(from == _ownerOf[id], "WRONG_FROM");

        require(to != address(0), "INVALID_RECIPIENT");

        require(
            msg.sender == from || isApprovedForAll[from][msg.sender] || msg.sender == getApproved[id],
            "NOT_AUTHORIZED"
        );

        // Underflow of the sender's balance is impossible because we check for
        // ownership above and the recipient's balance can't realistically overflow.
        unchecked {
            _balanceOf[from]--;

            _balanceOf[to]++;
        }

        _ownerOf[id] = to;

        delete getApproved[id];

        emit Transfer(from, to, id);
    }

    function safeTransferFrom(
        address from,
        address to,
        uint256 id
    ) public virtual {
        transferFrom(from, to, id);

        if (to.code.length != 0)
            require(
                ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, "") ==
                    ERC721TokenReceiver.onERC721Received.selector,
                "UNSAFE_RECIPIENT"
            );
    }

    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        bytes calldata data
    ) public virtual {
        transferFrom(from, to, id);

        if (to.code.length != 0)
            require(
                ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) ==
                    ERC721TokenReceiver.onERC721Received.selector,
                "UNSAFE_RECIPIENT"
            );
    }

    /*//////////////////////////////////////////////////////////////
                              ERC165 LOGIC
    //////////////////////////////////////////////////////////////*/

    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return
            interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165
            interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721
            interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata
    }

    /*//////////////////////////////////////////////////////////////
                        INTERNAL MINT/BURN LOGIC
    //////////////////////////////////////////////////////////////*/

    function _mint(address to, uint256 id) internal virtual {
        require(to != address(0), "INVALID_RECIPIENT");

        require(_ownerOf[id] == address(0), "ALREADY_MINTED");

        // Counter overflow is incredibly unrealistic.
        unchecked {
            _balanceOf[to]++;
        }

        _ownerOf[id] = to;

        emit Transfer(address(0), to, id);
    }

    function _burn(uint256 id) internal virtual {
        address owner = _ownerOf[id];

        require(owner != address(0), "NOT_MINTED");

        // Ownership check above ensures no underflow.
        unchecked {
            _balanceOf[owner]--;
        }

        delete _ownerOf[id];

        delete getApproved[id];

        emit Transfer(owner, address(0), id);
    }

    /*//////////////////////////////////////////////////////////////
                        INTERNAL SAFE MINT LOGIC
    //////////////////////////////////////////////////////////////*/

    function _safeMint(address to, uint256 id) internal virtual {
        _mint(to, id);

        if (to.code.length != 0)
            require(
                ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, "") ==
                    ERC721TokenReceiver.onERC721Received.selector,
                "UNSAFE_RECIPIENT"
            );
    }

    function _safeMint(
        address to,
        uint256 id,
        bytes memory data
    ) internal virtual {
        _mint(to, id);

        if (to.code.length != 0)
            require(
                ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) ==
                    ERC721TokenReceiver.onERC721Received.selector,
                "UNSAFE_RECIPIENT"
            );
    }
}

/// @notice A generic interface for a contract which properly accepts ERC721 tokens.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)
abstract contract ERC721TokenReceiver {
    function onERC721Received(
        address,
        address,
        uint256,
        bytes calldata
    ) external virtual returns (bytes4) {
        return ERC721TokenReceiver.onERC721Received.selector;
    }
}

File 4 of 10 : ERC20UDS.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {Initializable} from "../auth/Initializable.sol";
import {EIP712PermitUDS} from "../auth/EIP712PermitUDS.sol";

// ------------- storage

bytes32 constant DIAMOND_STORAGE_ERC20 = keccak256("diamond.storage.erc20");

function s() pure returns (ERC20DS storage diamondStorage) {
    bytes32 slot = DIAMOND_STORAGE_ERC20;
    assembly { diamondStorage.slot := slot } // prettier-ignore
}

struct ERC20DS {
    string name;
    string symbol;
    uint8 decimals;
    uint256 totalSupply;
    mapping(address => uint256) balanceOf;
    mapping(address => mapping(address => uint256)) allowance;
}

/// @title ERC20 (Upgradeable Diamond Storage)
/// @author phaze (https://github.com/0xPhaze/UDS)
/// @author Modified from Solmate (https://github.com/Rari-Capital/solmate)
abstract contract ERC20UDS is Initializable, EIP712PermitUDS {
    event Transfer(address indexed from, address indexed to, uint256 amount);
    event Approval(address indexed owner, address indexed operator, uint256 amount);

    /* ------------- init ------------- */

    function __ERC20_init(
        string memory _name,
        string memory _symbol,
        uint8 _decimals
    ) internal initializer {
        s().name = _name;
        s().symbol = _symbol;
        s().decimals = _decimals;
    }

    /* ------------- view ------------- */

    function name() external view virtual returns (string memory) {
        return s().name;
    }

    function symbol() external view virtual returns (string memory) {
        return s().symbol;
    }

    function decimals() external view virtual returns (uint8) {
        return s().decimals;
    }

    function totalSupply() external view virtual returns (uint256) {
        return s().totalSupply;
    }

    function balanceOf(address owner) public view virtual returns (uint256) {
        return s().balanceOf[owner];
    }

    function allowance(address owner, address operator) public view virtual returns (uint256) {
        return s().allowance[owner][operator];
    }

    /* ------------- public ------------- */

    function approve(address operator, uint256 amount) public virtual returns (bool) {
        s().allowance[msg.sender][operator] = amount;

        emit Approval(msg.sender, operator, amount);

        return true;
    }

    function transfer(address to, uint256 amount) public virtual returns (bool) {
        s().balanceOf[msg.sender] -= amount;

        unchecked {
            s().balanceOf[to] += amount;
        }

        emit Transfer(msg.sender, to, amount);

        return true;
    }

    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual returns (bool) {
        uint256 allowed = s().allowance[from][msg.sender];

        if (allowed != type(uint256).max) s().allowance[from][msg.sender] = allowed - amount;

        s().balanceOf[from] -= amount;

        unchecked {
            s().balanceOf[to] += amount;
        }

        emit Transfer(from, to, amount);

        return true;
    }

    // EIP-2612 permit
    function permit(
        address owner,
        address operator,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s_
    ) public virtual {
        if (_usePermit(owner, operator, value, deadline, v, r, s_)) {
            s().allowance[owner][operator] = value;

            emit Approval(owner, operator, value);
        }
    }

    /* ------------- internal ------------- */

    function _mint(address to, uint256 amount) internal virtual {
        s().totalSupply += amount;

        unchecked {
            s().balanceOf[to] += amount;
        }

        emit Transfer(address(0), to, amount);
    }

    function _burn(address from, uint256 amount) internal virtual {
        s().balanceOf[from] -= amount;

        unchecked {
            s().totalSupply -= amount;
        }

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

File 5 of 10 : OwnableUDS.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {Initializable} from "./Initializable.sol";

// ------------- storage

bytes32 constant DIAMOND_STORAGE_OWNABLE = keccak256("diamond.storage.ownable");

function s() pure returns (OwnableDS storage diamondStorage) {
    bytes32 slot = DIAMOND_STORAGE_OWNABLE;
    assembly { diamondStorage.slot := slot } // prettier-ignore
}

struct OwnableDS {
    address owner;
}

// ------------- errors

error CallerNotOwner();

/// @title Ownable (Upgradeable Diamond Storage)
/// @author phaze (https://github.com/0xPhaze/UDS)
/// @dev Requires `__Ownable_init` to be called in proxy
abstract contract OwnableUDS is Initializable {
    event OwnerChanged(address oldOwner, address newOwner);

    function __Ownable_init() internal initializer {
        s().owner = msg.sender;
    }

    /* ------------- external ------------- */

    function owner() public view returns (address) {
        return s().owner;
    }

    function transferOwnership(address newOwner) external onlyOwner {
        s().owner = newOwner;

        emit OwnerChanged(msg.sender, newOwner);
    }

    /* ------------- modifier ------------- */

    modifier onlyOwner() {
        if (msg.sender != s().owner) revert CallerNotOwner();
        _;
    }
}

File 6 of 10 : UUPSUpgrade.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {ERC1967, ERC1967_PROXY_STORAGE_SLOT} from "./ERC1967Proxy.sol";

// ------------- errors

error OnlyProxyCallAllowed();
error DelegateCallNotAllowed();

/// @notice Minimal UUPSUpgrade
/// @author phaze (https://github.com/0xPhaze/UDS)
abstract contract UUPSUpgrade is ERC1967 {
    address private immutable __implementation = address(this);

    /* ------------- external ------------- */

    function upgradeToAndCall(address logic, bytes calldata data) external {
        _authorizeUpgrade();
        _upgradeToAndCall(logic, data);
    }

    /* ------------- view ------------- */

    function proxiableUUID() external view virtual notDelegated returns (bytes32) {
        return ERC1967_PROXY_STORAGE_SLOT;
    }

    /* ------------- virtual ------------- */

    function _authorizeUpgrade() internal virtual;

    /* ------------- modifier ------------- */

    modifier onlyProxy() {
        if (address(this) == __implementation) revert OnlyProxyCallAllowed();
        _;
    }

    modifier notDelegated() {
        if (address(this) != __implementation) revert DelegateCallNotAllowed();
        _;
    }
}

File 7 of 10 : ERC20RewardUDS.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {ERC20UDS, s as erc20ds} from "./ERC20UDS.sol";

// ------------- storage

bytes32 constant DIAMOND_STORAGE_ERC20_REWARD = keccak256("diamond.storage.erc20.reward");

function s() pure returns (ERC20RewardDS storage diamondStorage) {
    bytes32 slot = DIAMOND_STORAGE_ERC20_REWARD;
    assembly { diamondStorage.slot := slot } // prettier-ignore
}

struct UserData {
    uint216 multiplier;
    uint40 lastClaimed;
}

struct ERC20RewardDS {
    mapping(address => UserData) userData;
}

/// @title ERC20Reward (Upgradeable Diamond Storage)
/// @author phaze (https://github.com/0xPhaze/UDS)
/// @notice Allows for ERC20 reward accrual
/// @notice at a rate of rewardDailyRate() * multiplier[user] per day
/// @notice Tokens are automatically claimed before any multiplier update
abstract contract ERC20RewardUDS is ERC20UDS {
    /* ------------- virtual ------------- */

    function rewardEndDate() public view virtual returns (uint256);

    function rewardDailyRate() public view virtual returns (uint256);

    /* ------------- view ------------- */

    function totalBalanceOf(address owner) public view virtual returns (uint256) {
        return ERC20UDS.balanceOf(owner) + pendingReward(owner);
    }

    function pendingReward(address owner) public view virtual returns (uint256) {
        UserData storage userData = s().userData[owner];

        return _calculateReward(userData.multiplier, userData.lastClaimed);
    }

    /* ------------- internal ------------- */

    function _getRewardMultiplier(address owner) internal view virtual returns (uint256) {
        return s().userData[owner].multiplier;
    }

    function _calculateReward(uint256 multiplier, uint256 lastClaimed) internal view virtual returns (uint256) {
        uint256 end = rewardEndDate();

        uint256 timestamp = block.timestamp;

        if (lastClaimed > end) return 0;
        else if (timestamp > end) timestamp = end;

        // if multiplier > 0 then lastClaimed > 0
        // because _claimReward must have been called
        return ((timestamp - lastClaimed) * multiplier * rewardDailyRate()) / 1 days;
    }

    function _claimReward(address owner) internal virtual {
        UserData storage userData = s().userData[owner];

        uint256 multiplier = userData.multiplier;
        uint256 lastClaimed = userData.lastClaimed;

        if (multiplier != 0 || lastClaimed == 0) {
            // only forego minting if multiplier == 0
            // checking for amount == 0 can lead to failed transactions
            // due to too little gas being supplied through estimation
            if (multiplier != 0) {
                uint256 amount = _calculateReward(multiplier, lastClaimed);

                _mint(owner, amount);
            }

            s().userData[owner].lastClaimed = uint40(block.timestamp);
        }
    }

    function _increaseRewardMultiplier(address owner, uint216 quantity) internal virtual {
        _claimReward(owner);

        s().userData[owner].multiplier += quantity;
    }

    function _decreaseRewardMultiplier(address owner, uint216 quantity) internal virtual {
        _claimReward(owner);

        s().userData[owner].multiplier -= quantity;
    }
}

File 8 of 10 : Initializable.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {s as erc1967ds} from "../proxy/ERC1967Proxy.sol";

// ------------- errors

error ProxyCallRequired();
error AlreadyInitialized();

/// @title Initializable
/// @author phaze (https://github.com/0xPhaze/UDS)
/// @dev functions using the `initializer` modifier are only callable during proxy deployment
/// @dev functions using the `reinitializer` modifier are only callable through a proxy
/// @dev and only before a proxy upgrade migration has completed
/// @dev (only when `upgradeToAndCall`'s `initCalldata` is being executed)
/// @dev allows re-initialization during upgrades
abstract contract Initializable {
    address private immutable __implementation = address(this);

    /* ------------- modifier ------------- */

    modifier initializer() {
        if (address(this).code.length != 0) revert AlreadyInitialized();
        _;
    }

    modifier reinitializer() {
        if (address(this) == __implementation) revert ProxyCallRequired();
        if (erc1967ds().implementation == __implementation) revert AlreadyInitialized();
        _;
    }
}

File 9 of 10 : EIP712PermitUDS.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// ------------- storage

bytes32 constant DIAMOND_STORAGE_EIP_712_PERMIT = keccak256("diamond.storage.eip.712.permit");

function s() pure returns (EIP2612DS storage diamondStorage) {
    bytes32 slot = DIAMOND_STORAGE_EIP_712_PERMIT;
    assembly { diamondStorage.slot := slot } // prettier-ignore
}

struct EIP2612DS {
    mapping(address => uint256) nonces;
}

// ------------- errors

error InvalidSigner();
error DeadlineExpired();

/// @title EIP712Permit (Upgradeable Diamond Storage)
/// @author phaze (https://github.com/0xPhaze/UDS)
/// @author Modified from Solmate (https://github.com/Rari-Capital/solmate)
/// @dev `DOMAIN_SEPARATOR` needs to be re-computed every time
/// @dev for use with a proxy due to `address(this)`
abstract contract EIP712PermitUDS {
    /* ------------- public ------------- */

    function nonces(address owner) public view returns (uint256) {
        return s().nonces[owner];
    }

    function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                    keccak256("EIP712"),
                    keccak256("1"),
                    block.chainid,
                    address(this)
                )
            );
    }

    /* ------------- internal ------------- */

    function _usePermit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v_,
        bytes32 r_,
        bytes32 s_
    ) internal virtual returns (bool) {
        if (deadline < block.timestamp) revert DeadlineExpired();

        unchecked {
            uint256 nonce = s().nonces[owner]++;

            address recovered = ecrecover(
                keccak256(
                    abi.encodePacked(
                        "\x19\x01",
                        DOMAIN_SEPARATOR(),
                        keccak256(
                            abi.encode(
                                keccak256(
                                    "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
                                ),
                                owner,
                                spender,
                                value,
                                nonce,
                                deadline
                            )
                        )
                    )
                ),
                v_,
                r_,
                s_
            );

            if (recovered == address(0) || recovered != owner) revert InvalidSigner();
        }

        return true;
    }
}

File 10 of 10 : ERC1967Proxy.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// ------------- storage

// keccak256("eip1967.proxy.implementation") - 1 = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
bytes32 constant ERC1967_PROXY_STORAGE_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;

function s() pure returns (ERC1967UpgradeDS storage diamondStorage) {
    assembly { diamondStorage.slot := ERC1967_PROXY_STORAGE_SLOT } // prettier-ignore
}

struct ERC1967UpgradeDS {
    address implementation;
}

// ------------- errors

error InvalidUUID();
error NotAContract();

/// @notice ERC1967
/// @author phaze (https://github.com/0xPhaze/UDS)
abstract contract ERC1967 {
    event Upgraded(address indexed implementation);

    function _upgradeToAndCall(address logic, bytes memory data) internal {
        if (logic.code.length == 0) revert NotAContract();

        if (ERC1822(logic).proxiableUUID() != ERC1967_PROXY_STORAGE_SLOT) revert InvalidUUID();

        if (data.length != 0) {
            (bool success, ) = logic.delegatecall(data);

            if (!success) {
                assembly {
                    returndatacopy(0, 0, returndatasize())
                    revert(0, returndatasize())
                }
            }
        }

        emit Upgraded(logic);

        s().implementation = logic;
    }
}

/// @notice Minimal ERC1967Proxy
/// @author phaze (https://github.com/0xPhaze/UDS)
contract ERC1967Proxy is ERC1967 {
    constructor(address logic, bytes memory data) payable {
        _upgradeToAndCall(logic, data);
    }

    fallback() external payable {
        assembly {
            calldatacopy(0, 0, calldatasize())

            let success := delegatecall(gas(), sload(ERC1967_PROXY_STORAGE_SLOT), 0, calldatasize(), 0, 0)

            returndatacopy(0, 0, returndatasize())

            if success {
                return(0, returndatasize())
            }

            revert(0, returndatasize())
        }
    }
}

/// @notice ERC1822
/// @author phaze (https://github.com/0xPhaze/UDS)
abstract contract ERC1822 {
    function proxiableUUID() external view virtual returns (bytes32);
}

Settings
{
  "remappings": [
    "ArrayUtils/=lib/ArrayUtils/src/",
    "CRFTD/=src/",
    "UDS/=lib/UDS/src/",
    "ds-test/=lib/solmate/lib/ds-test/src/",
    "f-utils/=lib/f-utils/src/",
    "forge-std/=lib/forge-std/src/",
    "script/=script/",
    "solmate/=lib/solmate/src/",
    "src/=src/",
    "test/=test/",
    "src/=src/",
    "test/=test/",
    "script/=script/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 100000
  },
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "london",
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"CallerNotOwner","type":"error"},{"inputs":[],"name":"CollectionAlreadyRegistered","type":"error"},{"inputs":[],"name":"CollectionNotRegistered","type":"error"},{"inputs":[],"name":"DeadlineExpired","type":"error"},{"inputs":[],"name":"DelegateCallNotAllowed","type":"error"},{"inputs":[],"name":"IncorrectOwner","type":"error"},{"inputs":[],"name":"InvalidSigner","type":"error"},{"inputs":[],"name":"InvalidUUID","type":"error"},{"inputs":[],"name":"NotAContract","type":"error"},{"inputs":[],"name":"ZeroReward","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"collection","type":"address"},{"indexed":false,"internalType":"uint256","name":"rewardRate","type":"uint256"}],"name":"CollectionRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"tos","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"airdrop","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimReward","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getDailyReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"}],"name":"init","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"pendingReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s_","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint200","name":"rate","type":"uint200"}],"name":"registerCollection","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardDailyRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"rewardEndDate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"}],"name":"rewardRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"endDate","type":"uint256"}],"name":"setRewardEndDate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"collectionSize","type":"uint256"}],"name":"stakedIdsOf","outputs":[{"internalType":"uint256[]","name":"stakedIds","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"totalBalanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"unstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"logic","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60c060405230608081905260a05234801561001957600080fd5b5060805160a051612c6461003c6000396000610971015260005050612c646000f3fe608060405234801561001057600080fd5b50600436106101e55760003560e01c8063672434821161010f578063b88a802f116100a2578063dd62ed3e11610071578063dd62ed3e1461062d578063e4ab593d14610692578063f2fde38b146106b2578063f40f0f52146106c557600080fd5b8063b88a802f146105ec578063c5b41b89146105f4578063c9a3911e14610607578063d505accf1461061a57600080fd5b80637ecebe00116100de5780637ecebe001461053f5780638da5cb5b1461059457806395d89b41146105d1578063a9059cbb146105d957600080fd5b806367243482146104b15780637029144c146104c457806370a08231146104d75780637abdab561461052c57600080fd5b8063313ce567116101875780634f1ef286116101565780634f1ef2861461045a57806352d1902d1461046f5780635dbe4756146104775780635f36e2521461048a57600080fd5b8063313ce567146103585780633644e5151461038c5780633d9e7719146104345780634b0ee02a1461044757600080fd5b806318160ddd116101c357806318160ddd146102425780631f29d2dc14610269578063221ca18c146102f057806323b872dd1461034557600080fd5b806306fdde03146101ea578063095ea7b31461020857806316336c651461022b575b600080fd5b6101f26106d8565b6040516101ff9190612411565b60405180910390f35b61021b61021636600461248b565b610789565b60405190151581526020016101ff565b662386f26fc100005b6040519081526020016101ff565b7f0e539be85842d1c3b5b43263a827c1e07ab5a9c9536bf840ece723e480d80dba54610234565b6102cb61027736600461248b565b73ffffffffffffffffffffffffffffffffffffffff91821660009081527f1a092854511578a55ddb9a3e239e5eb710da1c5cb2adb4c4d5c3fe3a7e2facee6020908152604080832093835292905220541690565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101ff565b6102346102fe3660046124b5565b73ffffffffffffffffffffffffffffffffffffffff1660009081527f1a092854511578a55ddb9a3e239e5eb710da1c5cb2adb4c4d5c3fe3a7e2faced602052604090205490565b61021b6103533660046124d0565b61081e565b7f0e539be85842d1c3b5b43263a827c1e07ab5a9c9536bf840ece723e480d80db95460405160ff90911681526020016101ff565b610234604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f421979463954f2ac93264f1ce0c11a780b4a7686122abe11bac8c8244f44a3de918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b6102346104423660046124b5565b61083c565b6102346104553660046124b5565b6108b0565b61046d610468366004612555565b61090a565b005b610234610957565b61046d6104853660046125ed565b6109ed565b7f1a092854511578a55ddb9a3e239e5eb710da1c5cb2adb4c4d5c3fe3a7e2facec54610234565b61046d6104bf366004612633565b610cbb565b61046d6104d236600461269f565b610d8e565b6102346104e53660046124b5565b73ffffffffffffffffffffffffffffffffffffffff1660009081527f0e539be85842d1c3b5b43263a827c1e07ab5a9c9536bf840ece723e480d80dbb602052604090205490565b61046d61053a3660046126ff565b610e4b565b61023461054d3660046124b5565b73ffffffffffffffffffffffffffffffffffffffff1660009081527f24034dbc71162a0a127c76a8ce123f10641be888cbac564cd2e6e6f5e2c19b81602052604090205490565b7f87917b04fc43108fc3d291ac961b425fe1ddcf80087b2cb7e3c48f3e9233ea335473ffffffffffffffffffffffffffffffffffffffff166102cb565b6101f2611029565b61021b6105e736600461248b565b61105a565b61046d611076565b61046d610602366004612754565b611081565b61046d6106153660046125ed565b611115565b61046d61062836600461276d565b61133e565b61023461063b3660046127e0565b73ffffffffffffffffffffffffffffffffffffffff91821660009081527f0e539be85842d1c3b5b43263a827c1e07ab5a9c9536bf840ece723e480d80dbc6020908152604080832093909416825291909152205490565b6106a56106a03660046124d0565b6113e5565b6040516101ff9190612813565b61046d6106c03660046124b5565b611437565b6102346106d33660046124b5565b611545565b60607f0e539be85842d1c3b5b43263a827c1e07ab5a9c9536bf840ece723e480d80db7805461070690612857565b80601f016020809104026020016040519081016040528092919081815260200182805461073290612857565b801561077f5780601f106107545761010080835404028352916020019161077f565b820191906000526020600020905b81548152906001019060200180831161076257829003601f168201915b5050505050905090565b3360008181527f0e539be85842d1c3b5b43263a827c1e07ab5a9c9536bf840ece723e480d80dbc6020908152604080832073ffffffffffffffffffffffffffffffffffffffff871680855290835281842086905590518581529293909290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a35060015b92915050565b6000610829846115d9565b610834848484611725565b949350505050565b73ffffffffffffffffffffffffffffffffffffffff811660009081527f2bf76f1229f14879252da90846a528ce52c56d0ade153f3ef6c5b45141fb99c9602052604081205461081890662386f26fc10000907affffffffffffffffffffffffffffffffffffffffffffffffffffff166128d9565b60006108bb82611545565b73ffffffffffffffffffffffffffffffffffffffff831660009081527f0e539be85842d1c3b5b43263a827c1e07ab5a9c9536bf840ece723e480d80dbb60205260409020546108189190612916565b6109126118df565b6109528383838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061194f92505050565b505050565b60003073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146109c8576040517f0d89438e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90565b73ffffffffffffffffffffffffffffffffffffffff831660009081527f1a092854511578a55ddb9a3e239e5eb710da1c5cb2adb4c4d5c3fe3a7e2faced602052604081205490819003610a6c576040517fa973256400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610a7f33610a7a83856128d9565b611b95565b60005b82811015610cb45773ffffffffffffffffffffffffffffffffffffffff851660009081527f1a092854511578a55ddb9a3e239e5eb710da1c5cb2adb4c4d5c3fe3a7e2facee602052604081203391868685818110610ae257610ae261292e565b602090810292909201358352508101919091526040016000205473ffffffffffffffffffffffffffffffffffffffff1614610b49576040517f3a6bbed300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff851660009081527f1a092854511578a55ddb9a3e239e5eb710da1c5cb2adb4c4d5c3fe3a7e2facee6020526040812090858584818110610ba057610ba061292e565b6020908102929092013583525081019190915260400160002080547fffffffffffffffffffffffff000000000000000000000000000000000000000016905573ffffffffffffffffffffffffffffffffffffffff85166323b872dd3033878786818110610c0f57610c0f61292e565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e088901b16815273ffffffffffffffffffffffffffffffffffffffff958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b158015610c8b57600080fd5b505af1158015610c9f573d6000803e3d6000fd5b5050505080610cad9061295d565b9050610a82565b5050505050565b7f87917b04fc43108fc3d291ac961b425fe1ddcf80087b2cb7e3c48f3e9233ea335473ffffffffffffffffffffffffffffffffffffffff163314610d2b576040517f5cd8319200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b83811015610cb457610d7e858583818110610d4b57610d4b61292e565b9050602002016020810190610d6091906124b5565b848484818110610d7257610d7261292e565b90506020020135611c5f565b610d878161295d565b9050610d2e565b303b15610dc7576040517f0dc149f000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610dcf611d18565b610e4584848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8801819004810282018101909252868152925086915085908190840183828082843760009201919091525060129250611d9c915050565b50505050565b7f87917b04fc43108fc3d291ac961b425fe1ddcf80087b2cb7e3c48f3e9233ea335473ffffffffffffffffffffffffffffffffffffffff163314610ebb576040517f5cd8319200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8078ffffffffffffffffffffffffffffffffffffffffffffffffff16600003610f10576040517f9c1b278400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff821660009081527f1a092854511578a55ddb9a3e239e5eb710da1c5cb2adb4c4d5c3fe3a7e2faced602052604090205415610f8c576040517f41ab882d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff821660008181527f1a092854511578a55ddb9a3e239e5eb710da1c5cb2adb4c4d5c3fe3a7e2faced602090815260409182902078ffffffffffffffffffffffffffffffffffffffffffffffffff851690819055825190815291517fccfc7df822b68cdc8b0d7cd8b0255d24005c6fb4adc390a411ebdf309fa6dc099281900390910190a25050565b60607f0e539be85842d1c3b5b43263a827c1e07ab5a9c9536bf840ece723e480d80db7600101805461070690612857565b6000611065336115d9565b61106f8383611e82565b9392505050565b61107f336115d9565b565b7f87917b04fc43108fc3d291ac961b425fe1ddcf80087b2cb7e3c48f3e9233ea335473ffffffffffffffffffffffffffffffffffffffff1633146110f1576040517f5cd8319200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f1a092854511578a55ddb9a3e239e5eb710da1c5cb2adb4c4d5c3fe3a7e2facec55565b73ffffffffffffffffffffffffffffffffffffffff831660009081527f1a092854511578a55ddb9a3e239e5eb710da1c5cb2adb4c4d5c3fe3a7e2faced602052604081205490819003611194576040517fa973256400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111a7336111a283856128d9565b611f44565b60005b82811015610cb4578473ffffffffffffffffffffffffffffffffffffffff166323b872dd33308787868181106111e2576111e261292e565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e088901b16815273ffffffffffffffffffffffffffffffffffffffff958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b15801561125e57600080fd5b505af1158015611272573d6000803e3d6000fd5b505050503361129e7f1a092854511578a55ddb9a3e239e5eb710da1c5cb2adb4c4d5c3fe3a7e2facec90565b73ffffffffffffffffffffffffffffffffffffffff8716600090815260029190910160205260408120908686858181106112da576112da61292e565b90506020020135815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550806113379061295d565b90506111aa565b61134d87878787878787611fbe565b156113dc5773ffffffffffffffffffffffffffffffffffffffff87811660008181527f0e539be85842d1c3b5b43263a827c1e07ab5a9c9536bf840ece723e480d80dbc60209081526040808320948b1680845294825291829020899055815189815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a35b50505050505050565b73ffffffffffffffffffffffffffffffffffffffff831660009081527f1a092854511578a55ddb9a3e239e5eb710da1c5cb2adb4c4d5c3fe3a7e2facee602052604090206060906108349084846122f0565b7f87917b04fc43108fc3d291ac961b425fe1ddcf80087b2cb7e3c48f3e9233ea335473ffffffffffffffffffffffffffffffffffffffff1633146114a7576040517f5cd8319200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b807f87917b04fc43108fc3d291ac961b425fe1ddcf80087b2cb7e3c48f3e9233ea3380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9283161790556040805133815291831660208301527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a150565b73ffffffffffffffffffffffffffffffffffffffff811660009081527f2bf76f1229f14879252da90846a528ce52c56d0ade153f3ef6c5b45141fb99c960205260408120805461106f907affffffffffffffffffffffffffffffffffffffffffffffffffffff8116907b01000000000000000000000000000000000000000000000000000000900464ffffffffff1661235b565b73ffffffffffffffffffffffffffffffffffffffff811660009081527f2bf76f1229f14879252da90846a528ce52c56d0ade153f3ef6c5b45141fb99c96020526040902080547affffffffffffffffffffffffffffffffffffffffffffffffffffff8116907b01000000000000000000000000000000000000000000000000000000900464ffffffffff1681151580611670575080155b15610e45578115611695576000611687838361235b565b90506116938582611c5f565b505b50505073ffffffffffffffffffffffffffffffffffffffff1660009081527f2bf76f1229f14879252da90846a528ce52c56d0ade153f3ef6c5b45141fb99c96020526040902080547affffffffffffffffffffffffffffffffffffffffffffffffffffff167b0100000000000000000000000000000000000000000000000000000064ffffffffff421602179055565b73ffffffffffffffffffffffffffffffffffffffff831660009081527f0e539be85842d1c3b5b43263a827c1e07ab5a9c9536bf840ece723e480d80dbc602090815260408083203384529091528120547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146117f7576117a68382612995565b73ffffffffffffffffffffffffffffffffffffffff861660009081527f0e539be85842d1c3b5b43263a827c1e07ab5a9c9536bf840ece723e480d80dbc602090815260408083203384529091529020555b73ffffffffffffffffffffffffffffffffffffffff851660009081527f0e539be85842d1c3b5b43263a827c1e07ab5a9c9536bf840ece723e480d80dbb60205260408120805485929061184b908490612995565b909155505073ffffffffffffffffffffffffffffffffffffffff84811660008181527f0e539be85842d1c3b5b43263a827c1e07ab5a9c9536bf840ece723e480d80dbb6020908152604091829020805488019055905186815291928816917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3506001949350505050565b7f87917b04fc43108fc3d291ac961b425fe1ddcf80087b2cb7e3c48f3e9233ea335473ffffffffffffffffffffffffffffffffffffffff16331461107f576040517f5cd8319200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff163b6000036119a0576040517f09ee12d500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b8273ffffffffffffffffffffffffffffffffffffffff166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a3391906129ac565b14611a6a576040517f03ed501d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805115611aed5760008273ffffffffffffffffffffffffffffffffffffffff1682604051611a9891906129c5565b600060405180830381855af49150503d8060008114611ad3576040519150601f19603f3d011682016040523d82523d6000602084013e611ad8565b606091505b5050905080611aeb573d6000803e3d6000fd5b505b60405173ffffffffffffffffffffffffffffffffffffffff8316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a2507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b611b9e826115d9565b73ffffffffffffffffffffffffffffffffffffffff821660009081527f2bf76f1229f14879252da90846a528ce52c56d0ade153f3ef6c5b45141fb99c9602052604081208054839290611c0f9084907affffffffffffffffffffffffffffffffffffffffffffffffffffff166129e1565b92506101000a8154817affffffffffffffffffffffffffffffffffffffffffffffffffffff02191690837affffffffffffffffffffffffffffffffffffffffffffffffffffff1602179055505050565b807f0e539be85842d1c3b5b43263a827c1e07ab5a9c9536bf840ece723e480d80db76003016000828254611c939190612916565b909155505073ffffffffffffffffffffffffffffffffffffffff821660008181527f0e539be85842d1c3b5b43263a827c1e07ab5a9c9536bf840ece723e480d80dbb60209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b303b15611d51576040517f0dc149f000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f87917b04fc43108fc3d291ac961b425fe1ddcf80087b2cb7e3c48f3e9233ea3380547fffffffffffffffffffffffff00000000000000000000000000000000000000001633179055565b303b15611dd5576040517f0dc149f000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f0e539be85842d1c3b5b43263a827c1e07ab5a9c9536bf840ece723e480d80db7611e008482612a9a565b507f0e539be85842d1c3b5b43263a827c1e07ab5a9c9536bf840ece723e480d80db8611e2c8382612a9a565b507f0e539be85842d1c3b5b43263a827c1e07ab5a9c9536bf840ece723e480d80db980547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff929092169190911790555050565b3360009081527f0e539be85842d1c3b5b43263a827c1e07ab5a9c9536bf840ece723e480d80dbb6020526040812080548391908390611ec2908490612995565b909155505073ffffffffffffffffffffffffffffffffffffffff831660008181527f0e539be85842d1c3b5b43263a827c1e07ab5a9c9536bf840ece723e480d80dbb6020908152604091829020805486019055905184815233917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910161080c565b611f4d826115d9565b73ffffffffffffffffffffffffffffffffffffffff821660009081527f2bf76f1229f14879252da90846a528ce52c56d0ade153f3ef6c5b45141fb99c9602052604081208054839290611c0f9084907affffffffffffffffffffffffffffffffffffffffffffffffffffff16612bb4565b600042851015611ffa576040517f1ab7da6b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff881660009081527f24034dbc71162a0a127c76a8ce123f10641be888cbac564cd2e6e6f5e2c19b81602052604081208054600180820190925591906120f2604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f421979463954f2ac93264f1ce0c11a780b4a7686122abe11bac8c8244f44a3de918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b604080517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9602082015273ffffffffffffffffffffffffffffffffffffffff808f1692820192909252908c166060820152608081018b905260a0810185905260c081018a905260e001604051602081830303815290604052805190602001206040516020016121b39291907f190100000000000000000000000000000000000000000000000000000000000081526002810192909252602282015260420190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120600084529083018083525260ff891690820152606081018790526080810186905260a0016020604051602081039080840390855afa15801561222f573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811615806122a957508973ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b156122e0576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060019998505050505050505050565b60405160208101600060018401815b8181101561234d5760008181526020899052604090205473ffffffffffffffffffffffffffffffffffffffff808916911603612345578084526020840193506001830192505b6001016122ff565b505082526040529392505050565b6000806123867f1a092854511578a55ddb9a3e239e5eb710da1c5cb2adb4c4d5c3fe3a7e2facec5490565b9050428184111561239c57600092505050610818565b818111156123a75750805b62015180662386f26fc10000866123be8785612995565b6123c891906128d9565b6123d291906128d9565b6123dc9190612bf3565b95945050505050565b60005b838110156124005781810151838201526020016123e8565b83811115610e455750506000910152565b60208152600082518060208401526124308160408501602087016123e5565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461248657600080fd5b919050565b6000806040838503121561249e57600080fd5b6124a783612462565b946020939093013593505050565b6000602082840312156124c757600080fd5b61106f82612462565b6000806000606084860312156124e557600080fd5b6124ee84612462565b92506124fc60208501612462565b9150604084013590509250925092565b60008083601f84011261251e57600080fd5b50813567ffffffffffffffff81111561253657600080fd5b60208301915083602082850101111561254e57600080fd5b9250929050565b60008060006040848603121561256a57600080fd5b61257384612462565b9250602084013567ffffffffffffffff81111561258f57600080fd5b61259b8682870161250c565b9497909650939450505050565b60008083601f8401126125ba57600080fd5b50813567ffffffffffffffff8111156125d257600080fd5b6020830191508360208260051b850101111561254e57600080fd5b60008060006040848603121561260257600080fd5b61260b84612462565b9250602084013567ffffffffffffffff81111561262757600080fd5b61259b868287016125a8565b6000806000806040858703121561264957600080fd5b843567ffffffffffffffff8082111561266157600080fd5b61266d888389016125a8565b9096509450602087013591508082111561268657600080fd5b50612693878288016125a8565b95989497509550505050565b600080600080604085870312156126b557600080fd5b843567ffffffffffffffff808211156126cd57600080fd5b6126d98883890161250c565b909650945060208701359150808211156126f257600080fd5b506126938782880161250c565b6000806040838503121561271257600080fd5b61271b83612462565b9150602083013578ffffffffffffffffffffffffffffffffffffffffffffffffff8116811461274957600080fd5b809150509250929050565b60006020828403121561276657600080fd5b5035919050565b600080600080600080600060e0888a03121561278857600080fd5b61279188612462565b965061279f60208901612462565b95506040880135945060608801359350608088013560ff811681146127c357600080fd5b9699959850939692959460a0840135945060c09093013592915050565b600080604083850312156127f357600080fd5b6127fc83612462565b915061280a60208401612462565b90509250929050565b6020808252825182820181905260009190848201906040850190845b8181101561284b5783518352928401929184019160010161282f565b50909695505050505050565b600181811c9082168061286b57607f821691505b6020821081036128a4577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615612911576129116128aa565b500290565b60008219821115612929576129296128aa565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361298e5761298e6128aa565b5060010190565b6000828210156129a7576129a76128aa565b500390565b6000602082840312156129be57600080fd5b5051919050565b600082516129d78184602087016123e5565b9190910192915050565b60007affffffffffffffffffffffffffffffffffffffffffffffffffffff83811690831681811015612a1557612a156128aa565b039392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b601f82111561095257600081815260208120601f850160051c81016020861015612a735750805b601f850160051c820191505b81811015612a9257828155600101612a7f565b505050505050565b815167ffffffffffffffff811115612ab457612ab4612a1d565b612ac881612ac28454612857565b84612a4c565b602080601f831160018114612b1b5760008415612ae55750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555612a92565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015612b6857888601518255948401946001909101908401612b49565b5085821015612ba457878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b60007affffffffffffffffffffffffffffffffffffffffffffffffffffff808316818516808303821115612bea57612bea6128aa565b01949350505050565b600082612c29577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b50049056fea2646970667358221220e94b1470d6900843ad91113afc161e67eecd3b07d0f7d4ae6887a9501529fbb764736f6c634300080f0033

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101e55760003560e01c8063672434821161010f578063b88a802f116100a2578063dd62ed3e11610071578063dd62ed3e1461062d578063e4ab593d14610692578063f2fde38b146106b2578063f40f0f52146106c557600080fd5b8063b88a802f146105ec578063c5b41b89146105f4578063c9a3911e14610607578063d505accf1461061a57600080fd5b80637ecebe00116100de5780637ecebe001461053f5780638da5cb5b1461059457806395d89b41146105d1578063a9059cbb146105d957600080fd5b806367243482146104b15780637029144c146104c457806370a08231146104d75780637abdab561461052c57600080fd5b8063313ce567116101875780634f1ef286116101565780634f1ef2861461045a57806352d1902d1461046f5780635dbe4756146104775780635f36e2521461048a57600080fd5b8063313ce567146103585780633644e5151461038c5780633d9e7719146104345780634b0ee02a1461044757600080fd5b806318160ddd116101c357806318160ddd146102425780631f29d2dc14610269578063221ca18c146102f057806323b872dd1461034557600080fd5b806306fdde03146101ea578063095ea7b31461020857806316336c651461022b575b600080fd5b6101f26106d8565b6040516101ff9190612411565b60405180910390f35b61021b61021636600461248b565b610789565b60405190151581526020016101ff565b662386f26fc100005b6040519081526020016101ff565b7f0e539be85842d1c3b5b43263a827c1e07ab5a9c9536bf840ece723e480d80dba54610234565b6102cb61027736600461248b565b73ffffffffffffffffffffffffffffffffffffffff91821660009081527f1a092854511578a55ddb9a3e239e5eb710da1c5cb2adb4c4d5c3fe3a7e2facee6020908152604080832093835292905220541690565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101ff565b6102346102fe3660046124b5565b73ffffffffffffffffffffffffffffffffffffffff1660009081527f1a092854511578a55ddb9a3e239e5eb710da1c5cb2adb4c4d5c3fe3a7e2faced602052604090205490565b61021b6103533660046124d0565b61081e565b7f0e539be85842d1c3b5b43263a827c1e07ab5a9c9536bf840ece723e480d80db95460405160ff90911681526020016101ff565b610234604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f421979463954f2ac93264f1ce0c11a780b4a7686122abe11bac8c8244f44a3de918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b6102346104423660046124b5565b61083c565b6102346104553660046124b5565b6108b0565b61046d610468366004612555565b61090a565b005b610234610957565b61046d6104853660046125ed565b6109ed565b7f1a092854511578a55ddb9a3e239e5eb710da1c5cb2adb4c4d5c3fe3a7e2facec54610234565b61046d6104bf366004612633565b610cbb565b61046d6104d236600461269f565b610d8e565b6102346104e53660046124b5565b73ffffffffffffffffffffffffffffffffffffffff1660009081527f0e539be85842d1c3b5b43263a827c1e07ab5a9c9536bf840ece723e480d80dbb602052604090205490565b61046d61053a3660046126ff565b610e4b565b61023461054d3660046124b5565b73ffffffffffffffffffffffffffffffffffffffff1660009081527f24034dbc71162a0a127c76a8ce123f10641be888cbac564cd2e6e6f5e2c19b81602052604090205490565b7f87917b04fc43108fc3d291ac961b425fe1ddcf80087b2cb7e3c48f3e9233ea335473ffffffffffffffffffffffffffffffffffffffff166102cb565b6101f2611029565b61021b6105e736600461248b565b61105a565b61046d611076565b61046d610602366004612754565b611081565b61046d6106153660046125ed565b611115565b61046d61062836600461276d565b61133e565b61023461063b3660046127e0565b73ffffffffffffffffffffffffffffffffffffffff91821660009081527f0e539be85842d1c3b5b43263a827c1e07ab5a9c9536bf840ece723e480d80dbc6020908152604080832093909416825291909152205490565b6106a56106a03660046124d0565b6113e5565b6040516101ff9190612813565b61046d6106c03660046124b5565b611437565b6102346106d33660046124b5565b611545565b60607f0e539be85842d1c3b5b43263a827c1e07ab5a9c9536bf840ece723e480d80db7805461070690612857565b80601f016020809104026020016040519081016040528092919081815260200182805461073290612857565b801561077f5780601f106107545761010080835404028352916020019161077f565b820191906000526020600020905b81548152906001019060200180831161076257829003601f168201915b5050505050905090565b3360008181527f0e539be85842d1c3b5b43263a827c1e07ab5a9c9536bf840ece723e480d80dbc6020908152604080832073ffffffffffffffffffffffffffffffffffffffff871680855290835281842086905590518581529293909290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a35060015b92915050565b6000610829846115d9565b610834848484611725565b949350505050565b73ffffffffffffffffffffffffffffffffffffffff811660009081527f2bf76f1229f14879252da90846a528ce52c56d0ade153f3ef6c5b45141fb99c9602052604081205461081890662386f26fc10000907affffffffffffffffffffffffffffffffffffffffffffffffffffff166128d9565b60006108bb82611545565b73ffffffffffffffffffffffffffffffffffffffff831660009081527f0e539be85842d1c3b5b43263a827c1e07ab5a9c9536bf840ece723e480d80dbb60205260409020546108189190612916565b6109126118df565b6109528383838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061194f92505050565b505050565b60003073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000783f2136640c396805bf8488543abce4cf4cf87016146109c8576040517f0d89438e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90565b73ffffffffffffffffffffffffffffffffffffffff831660009081527f1a092854511578a55ddb9a3e239e5eb710da1c5cb2adb4c4d5c3fe3a7e2faced602052604081205490819003610a6c576040517fa973256400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610a7f33610a7a83856128d9565b611b95565b60005b82811015610cb45773ffffffffffffffffffffffffffffffffffffffff851660009081527f1a092854511578a55ddb9a3e239e5eb710da1c5cb2adb4c4d5c3fe3a7e2facee602052604081203391868685818110610ae257610ae261292e565b602090810292909201358352508101919091526040016000205473ffffffffffffffffffffffffffffffffffffffff1614610b49576040517f3a6bbed300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff851660009081527f1a092854511578a55ddb9a3e239e5eb710da1c5cb2adb4c4d5c3fe3a7e2facee6020526040812090858584818110610ba057610ba061292e565b6020908102929092013583525081019190915260400160002080547fffffffffffffffffffffffff000000000000000000000000000000000000000016905573ffffffffffffffffffffffffffffffffffffffff85166323b872dd3033878786818110610c0f57610c0f61292e565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e088901b16815273ffffffffffffffffffffffffffffffffffffffff958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b158015610c8b57600080fd5b505af1158015610c9f573d6000803e3d6000fd5b5050505080610cad9061295d565b9050610a82565b5050505050565b7f87917b04fc43108fc3d291ac961b425fe1ddcf80087b2cb7e3c48f3e9233ea335473ffffffffffffffffffffffffffffffffffffffff163314610d2b576040517f5cd8319200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b83811015610cb457610d7e858583818110610d4b57610d4b61292e565b9050602002016020810190610d6091906124b5565b848484818110610d7257610d7261292e565b90506020020135611c5f565b610d878161295d565b9050610d2e565b303b15610dc7576040517f0dc149f000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610dcf611d18565b610e4584848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525050604080516020601f8801819004810282018101909252868152925086915085908190840183828082843760009201919091525060129250611d9c915050565b50505050565b7f87917b04fc43108fc3d291ac961b425fe1ddcf80087b2cb7e3c48f3e9233ea335473ffffffffffffffffffffffffffffffffffffffff163314610ebb576040517f5cd8319200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8078ffffffffffffffffffffffffffffffffffffffffffffffffff16600003610f10576040517f9c1b278400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff821660009081527f1a092854511578a55ddb9a3e239e5eb710da1c5cb2adb4c4d5c3fe3a7e2faced602052604090205415610f8c576040517f41ab882d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff821660008181527f1a092854511578a55ddb9a3e239e5eb710da1c5cb2adb4c4d5c3fe3a7e2faced602090815260409182902078ffffffffffffffffffffffffffffffffffffffffffffffffff851690819055825190815291517fccfc7df822b68cdc8b0d7cd8b0255d24005c6fb4adc390a411ebdf309fa6dc099281900390910190a25050565b60607f0e539be85842d1c3b5b43263a827c1e07ab5a9c9536bf840ece723e480d80db7600101805461070690612857565b6000611065336115d9565b61106f8383611e82565b9392505050565b61107f336115d9565b565b7f87917b04fc43108fc3d291ac961b425fe1ddcf80087b2cb7e3c48f3e9233ea335473ffffffffffffffffffffffffffffffffffffffff1633146110f1576040517f5cd8319200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f1a092854511578a55ddb9a3e239e5eb710da1c5cb2adb4c4d5c3fe3a7e2facec55565b73ffffffffffffffffffffffffffffffffffffffff831660009081527f1a092854511578a55ddb9a3e239e5eb710da1c5cb2adb4c4d5c3fe3a7e2faced602052604081205490819003611194576040517fa973256400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6111a7336111a283856128d9565b611f44565b60005b82811015610cb4578473ffffffffffffffffffffffffffffffffffffffff166323b872dd33308787868181106111e2576111e261292e565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e088901b16815273ffffffffffffffffffffffffffffffffffffffff958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b15801561125e57600080fd5b505af1158015611272573d6000803e3d6000fd5b505050503361129e7f1a092854511578a55ddb9a3e239e5eb710da1c5cb2adb4c4d5c3fe3a7e2facec90565b73ffffffffffffffffffffffffffffffffffffffff8716600090815260029190910160205260408120908686858181106112da576112da61292e565b90506020020135815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550806113379061295d565b90506111aa565b61134d87878787878787611fbe565b156113dc5773ffffffffffffffffffffffffffffffffffffffff87811660008181527f0e539be85842d1c3b5b43263a827c1e07ab5a9c9536bf840ece723e480d80dbc60209081526040808320948b1680845294825291829020899055815189815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a35b50505050505050565b73ffffffffffffffffffffffffffffffffffffffff831660009081527f1a092854511578a55ddb9a3e239e5eb710da1c5cb2adb4c4d5c3fe3a7e2facee602052604090206060906108349084846122f0565b7f87917b04fc43108fc3d291ac961b425fe1ddcf80087b2cb7e3c48f3e9233ea335473ffffffffffffffffffffffffffffffffffffffff1633146114a7576040517f5cd8319200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b807f87917b04fc43108fc3d291ac961b425fe1ddcf80087b2cb7e3c48f3e9233ea3380547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff9283161790556040805133815291831660208301527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a150565b73ffffffffffffffffffffffffffffffffffffffff811660009081527f2bf76f1229f14879252da90846a528ce52c56d0ade153f3ef6c5b45141fb99c960205260408120805461106f907affffffffffffffffffffffffffffffffffffffffffffffffffffff8116907b01000000000000000000000000000000000000000000000000000000900464ffffffffff1661235b565b73ffffffffffffffffffffffffffffffffffffffff811660009081527f2bf76f1229f14879252da90846a528ce52c56d0ade153f3ef6c5b45141fb99c96020526040902080547affffffffffffffffffffffffffffffffffffffffffffffffffffff8116907b01000000000000000000000000000000000000000000000000000000900464ffffffffff1681151580611670575080155b15610e45578115611695576000611687838361235b565b90506116938582611c5f565b505b50505073ffffffffffffffffffffffffffffffffffffffff1660009081527f2bf76f1229f14879252da90846a528ce52c56d0ade153f3ef6c5b45141fb99c96020526040902080547affffffffffffffffffffffffffffffffffffffffffffffffffffff167b0100000000000000000000000000000000000000000000000000000064ffffffffff421602179055565b73ffffffffffffffffffffffffffffffffffffffff831660009081527f0e539be85842d1c3b5b43263a827c1e07ab5a9c9536bf840ece723e480d80dbc602090815260408083203384529091528120547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81146117f7576117a68382612995565b73ffffffffffffffffffffffffffffffffffffffff861660009081527f0e539be85842d1c3b5b43263a827c1e07ab5a9c9536bf840ece723e480d80dbc602090815260408083203384529091529020555b73ffffffffffffffffffffffffffffffffffffffff851660009081527f0e539be85842d1c3b5b43263a827c1e07ab5a9c9536bf840ece723e480d80dbb60205260408120805485929061184b908490612995565b909155505073ffffffffffffffffffffffffffffffffffffffff84811660008181527f0e539be85842d1c3b5b43263a827c1e07ab5a9c9536bf840ece723e480d80dbb6020908152604091829020805488019055905186815291928816917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3506001949350505050565b7f87917b04fc43108fc3d291ac961b425fe1ddcf80087b2cb7e3c48f3e9233ea335473ffffffffffffffffffffffffffffffffffffffff16331461107f576040517f5cd8319200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff163b6000036119a0576040517f09ee12d500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b8273ffffffffffffffffffffffffffffffffffffffff166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a0f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a3391906129ac565b14611a6a576040517f03ed501d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b805115611aed5760008273ffffffffffffffffffffffffffffffffffffffff1682604051611a9891906129c5565b600060405180830381855af49150503d8060008114611ad3576040519150601f19603f3d011682016040523d82523d6000602084013e611ad8565b606091505b5050905080611aeb573d6000803e3d6000fd5b505b60405173ffffffffffffffffffffffffffffffffffffffff8316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a2507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b611b9e826115d9565b73ffffffffffffffffffffffffffffffffffffffff821660009081527f2bf76f1229f14879252da90846a528ce52c56d0ade153f3ef6c5b45141fb99c9602052604081208054839290611c0f9084907affffffffffffffffffffffffffffffffffffffffffffffffffffff166129e1565b92506101000a8154817affffffffffffffffffffffffffffffffffffffffffffffffffffff02191690837affffffffffffffffffffffffffffffffffffffffffffffffffffff1602179055505050565b807f0e539be85842d1c3b5b43263a827c1e07ab5a9c9536bf840ece723e480d80db76003016000828254611c939190612916565b909155505073ffffffffffffffffffffffffffffffffffffffff821660008181527f0e539be85842d1c3b5b43263a827c1e07ab5a9c9536bf840ece723e480d80dbb60209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b303b15611d51576040517f0dc149f000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f87917b04fc43108fc3d291ac961b425fe1ddcf80087b2cb7e3c48f3e9233ea3380547fffffffffffffffffffffffff00000000000000000000000000000000000000001633179055565b303b15611dd5576040517f0dc149f000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f0e539be85842d1c3b5b43263a827c1e07ab5a9c9536bf840ece723e480d80db7611e008482612a9a565b507f0e539be85842d1c3b5b43263a827c1e07ab5a9c9536bf840ece723e480d80db8611e2c8382612a9a565b507f0e539be85842d1c3b5b43263a827c1e07ab5a9c9536bf840ece723e480d80db980547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660ff929092169190911790555050565b3360009081527f0e539be85842d1c3b5b43263a827c1e07ab5a9c9536bf840ece723e480d80dbb6020526040812080548391908390611ec2908490612995565b909155505073ffffffffffffffffffffffffffffffffffffffff831660008181527f0e539be85842d1c3b5b43263a827c1e07ab5a9c9536bf840ece723e480d80dbb6020908152604091829020805486019055905184815233917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910161080c565b611f4d826115d9565b73ffffffffffffffffffffffffffffffffffffffff821660009081527f2bf76f1229f14879252da90846a528ce52c56d0ade153f3ef6c5b45141fb99c9602052604081208054839290611c0f9084907affffffffffffffffffffffffffffffffffffffffffffffffffffff16612bb4565b600042851015611ffa576040517f1ab7da6b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff881660009081527f24034dbc71162a0a127c76a8ce123f10641be888cbac564cd2e6e6f5e2c19b81602052604081208054600180820190925591906120f2604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f421979463954f2ac93264f1ce0c11a780b4a7686122abe11bac8c8244f44a3de918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b604080517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9602082015273ffffffffffffffffffffffffffffffffffffffff808f1692820192909252908c166060820152608081018b905260a0810185905260c081018a905260e001604051602081830303815290604052805190602001206040516020016121b39291907f190100000000000000000000000000000000000000000000000000000000000081526002810192909252602282015260420190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120600084529083018083525260ff891690820152606081018790526080810186905260a0016020604051602081039080840390855afa15801561222f573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff811615806122a957508973ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614155b156122e0576040517f815e1d6400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060019998505050505050505050565b60405160208101600060018401815b8181101561234d5760008181526020899052604090205473ffffffffffffffffffffffffffffffffffffffff808916911603612345578084526020840193506001830192505b6001016122ff565b505082526040529392505050565b6000806123867f1a092854511578a55ddb9a3e239e5eb710da1c5cb2adb4c4d5c3fe3a7e2facec5490565b9050428184111561239c57600092505050610818565b818111156123a75750805b62015180662386f26fc10000866123be8785612995565b6123c891906128d9565b6123d291906128d9565b6123dc9190612bf3565b95945050505050565b60005b838110156124005781810151838201526020016123e8565b83811115610e455750506000910152565b60208152600082518060208401526124308160408501602087016123e5565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461248657600080fd5b919050565b6000806040838503121561249e57600080fd5b6124a783612462565b946020939093013593505050565b6000602082840312156124c757600080fd5b61106f82612462565b6000806000606084860312156124e557600080fd5b6124ee84612462565b92506124fc60208501612462565b9150604084013590509250925092565b60008083601f84011261251e57600080fd5b50813567ffffffffffffffff81111561253657600080fd5b60208301915083602082850101111561254e57600080fd5b9250929050565b60008060006040848603121561256a57600080fd5b61257384612462565b9250602084013567ffffffffffffffff81111561258f57600080fd5b61259b8682870161250c565b9497909650939450505050565b60008083601f8401126125ba57600080fd5b50813567ffffffffffffffff8111156125d257600080fd5b6020830191508360208260051b850101111561254e57600080fd5b60008060006040848603121561260257600080fd5b61260b84612462565b9250602084013567ffffffffffffffff81111561262757600080fd5b61259b868287016125a8565b6000806000806040858703121561264957600080fd5b843567ffffffffffffffff8082111561266157600080fd5b61266d888389016125a8565b9096509450602087013591508082111561268657600080fd5b50612693878288016125a8565b95989497509550505050565b600080600080604085870312156126b557600080fd5b843567ffffffffffffffff808211156126cd57600080fd5b6126d98883890161250c565b909650945060208701359150808211156126f257600080fd5b506126938782880161250c565b6000806040838503121561271257600080fd5b61271b83612462565b9150602083013578ffffffffffffffffffffffffffffffffffffffffffffffffff8116811461274957600080fd5b809150509250929050565b60006020828403121561276657600080fd5b5035919050565b600080600080600080600060e0888a03121561278857600080fd5b61279188612462565b965061279f60208901612462565b95506040880135945060608801359350608088013560ff811681146127c357600080fd5b9699959850939692959460a0840135945060c09093013592915050565b600080604083850312156127f357600080fd5b6127fc83612462565b915061280a60208401612462565b90509250929050565b6020808252825182820181905260009190848201906040850190845b8181101561284b5783518352928401929184019160010161282f565b50909695505050505050565b600181811c9082168061286b57607f821691505b6020821081036128a4577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615612911576129116128aa565b500290565b60008219821115612929576129296128aa565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361298e5761298e6128aa565b5060010190565b6000828210156129a7576129a76128aa565b500390565b6000602082840312156129be57600080fd5b5051919050565b600082516129d78184602087016123e5565b9190910192915050565b60007affffffffffffffffffffffffffffffffffffffffffffffffffffff83811690831681811015612a1557612a156128aa565b039392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b601f82111561095257600081815260208120601f850160051c81016020861015612a735750805b601f850160051c820191505b81811015612a9257828155600101612a7f565b505050505050565b815167ffffffffffffffff811115612ab457612ab4612a1d565b612ac881612ac28454612857565b84612a4c565b602080601f831160018114612b1b5760008415612ae55750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555612a92565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015612b6857888601518255948401946001909101908401612b49565b5085821015612ba457878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b60007affffffffffffffffffffffffffffffffffffffffffffffffffffff808316818516808303821115612bea57612bea6128aa565b01949350505050565b600082612c29577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b50049056fea2646970667358221220e94b1470d6900843ad91113afc161e67eecd3b07d0f7d4ae6887a9501529fbb764736f6c634300080f0033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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