ETH Price: $3,370.12 (+2.78%)

Contract

0x2E7AfEE4d068Cdcc427Dba6AE2A7de94D15cf356
 
Transaction Hash
Method
Block
From
To
Set Approval For...210626052024-10-28 7:21:2356 days ago1730100083IN
LiquidDelegate: RIGHTS Token
0 ETH0.000342957.4535117
Burn209769772024-10-16 8:37:4768 days ago1729067867IN
LiquidDelegate: RIGHTS Token
0 ETH0.0014002710.10233287
Set Approval For...188445462023-12-22 23:06:59367 days ago1703286419IN
LiquidDelegate: RIGHTS Token
0 ETH0.0006379526.37908588
Burn187639372023-12-11 15:44:11378 days ago1702309451IN
LiquidDelegate: RIGHTS Token
0 ETH0.0079798141.96653785
Set Approval For...184875672023-11-02 23:08:35417 days ago1698966515IN
LiquidDelegate: RIGHTS Token
0 ETH0.0010677323.20567613
Burn183718872023-10-17 18:29:47433 days ago1697567387IN
LiquidDelegate: RIGHTS Token
0 ETH0.00130539.53443251
Set Approval For...183065042023-10-08 14:58:23442 days ago1696777103IN
LiquidDelegate: RIGHTS Token
0 ETH0.000210238.72338943
Set Approval For...183065032023-10-08 14:58:11442 days ago1696777091IN
LiquidDelegate: RIGHTS Token
0 ETH0.000217148.9834769
Burn181561622023-09-17 13:51:35463 days ago1694958695IN
LiquidDelegate: RIGHTS Token
0 ETH0.001447137.74600373
Burn175581052023-06-25 17:53:59547 days ago1687715639IN
LiquidDelegate: RIGHTS Token
0 ETH0.000385512.6819484
Burn175581042023-06-25 17:53:47547 days ago1687715627IN
LiquidDelegate: RIGHTS Token
0 ETH0.002035412.66413445
Set Approval For...174911922023-06-16 8:23:59556 days ago1686903839IN
LiquidDelegate: RIGHTS Token
0 ETH0.0007230115.68900225
Set Approval For...174911852023-06-16 8:22:35556 days ago1686903755IN
LiquidDelegate: RIGHTS Token
0 ETH0.0007321315.91189339
Safe Transfer Fr...173903202023-06-02 3:12:59570 days ago1685675579IN
LiquidDelegate: RIGHTS Token
0 ETH0.0076570927.71678123
Create173902982023-06-02 3:08:35570 days ago1685675315IN
LiquidDelegate: RIGHTS Token
0 ETH0.0101099725.45208203
Burn173425762023-05-26 10:06:47577 days ago1685095607IN
LiquidDelegate: RIGHTS Token
0 ETH0.0015124125.23800932
Burn173387292023-05-25 21:08:11578 days ago1685048891IN
LiquidDelegate: RIGHTS Token
0 ETH0.0028599632.31379075
Burn173387272023-05-25 21:07:47578 days ago1685048867IN
LiquidDelegate: RIGHTS Token
0 ETH0.0029420433.2434711
Burn173194062023-05-23 3:54:59580 days ago1684814099IN
LiquidDelegate: RIGHTS Token
0 ETH0.0070184937.52485493
Safe Transfer Fr...171769012023-05-03 1:20:11601 days ago1683076811IN
LiquidDelegate: RIGHTS Token
0 ETH0.0210382369.65427881
Burn171677522023-05-01 18:27:23602 days ago1682965643IN
LiquidDelegate: RIGHTS Token
0 ETH0.0139307375.91308555
Create171675512023-05-01 17:46:35602 days ago1682963195IN
LiquidDelegate: RIGHTS Token
0 ETH0.0314203672.97336374
Create171480682023-04-29 0:03:35605 days ago1682726615IN
LiquidDelegate: RIGHTS Token
0 ETH0.0129122434.08670188
Create171422162023-04-28 4:20:35605 days ago1682655635IN
LiquidDelegate: RIGHTS Token
0 ETH0.0114545531.66849579
Burn171375812023-04-27 12:42:11606 days ago1682599331IN
LiquidDelegate: RIGHTS Token
0 ETH0.0049703334.00475316
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
LiquidDelegate

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 13 : LiquidDelegate.sol
// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.17;

import {ERC721} from "solmate/tokens/ERC721.sol";
import {ERC2981} from "openzeppelin-contracts/contracts/token/common/ERC2981.sol";
import {Base64} from "openzeppelin-contracts/contracts/utils/Base64.sol";
import {Strings} from "openzeppelin-contracts/contracts/utils/Strings.sol";

import {IDelegationRegistry} from "./interfaces/IDelegationRegistry.sol";
import {INFTFlashBorrower} from "./interfaces/INFTFlashBorrower.sol";
import {INFTFlashLender} from "./interfaces/INFTFlashLender.sol";

/**
 * Built with <3 by 0xfoobar
 */

contract LiquidDelegate is ERC721, ERC2981, INFTFlashLender {
    using Strings for uint256;
    using Strings for address;

    /// @notice The expected return value from flashloan borrowers
    bytes32 public constant CALLBACK_SUCCESS = keccak256("INFTFlashBorrower.onFlashLoan");

    /// @notice The delegate.cash contract
    address public immutable DELEGATION_REGISTRY;

    struct Rights {
        address depositor;
        uint96 expiration;
        address contract_;
        uint256 tokenId;
    }

    /// @notice A mapping pointing NFT ids to Rights structs
    mapping(uint256 => Rights) public idsToRights;

    /// @notice An incrementing counter to create unique ids for each escrow deposit created
    uint256 public nextRightsId = 1;

    /// @notice The fee to create a new liquid delegation
    uint256 public creationFee = 0 ether;

    /// @notice The address which can modify royalties
    address internal royaltyOwner;

    /// @notice The address which can modify metadata images
    address internal metadataOwner;

    /// @notice The URI that serves metadata images
    string internal baseURI;

    /// @notice Emitted on each deposit creation
    event RightsCreated(uint256 indexed rightsId, address indexed depositor, address indexed contract_, uint256 tokenId, uint256 expiration);

    /// @notice Emitted on each deposit burning
    event RightsBurned(uint256 indexed rightsId, address indexed depositor, address indexed contract_, uint256 tokenId, uint256 expiration);

    constructor(address _DELEGATION_REGISTRY, address owner, string memory _baseURI) ERC721("LiquidDelegate", "RIGHTS") {
        DELEGATION_REGISTRY = _DELEGATION_REGISTRY;
        baseURI = _baseURI;
        metadataOwner = owner;
        royaltyOwner = owner;
        _setDefaultRoyalty(owner, 1000);
    }

    /// @dev See {IERC165-supportsInterface}.
    function supportsInterface(bytes4 interfaceId) public pure override(ERC721, ERC2981) returns (bool) {
        return
            interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165
            interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721
            interfaceId == 0x5b5e139f || // ERC165 Interface ID for ERC721Metadata
            interfaceId == 0x2a55205a;   // ERC165 Interface ID for ERC2981

    }

    /**
     * ----------- DEPOSIT CREATION AND BURN -----------
     */

    /// @notice Use this to deposit a timelocked escrow and create a liquid claim on its delegation rights
    /// @param contract_ The collection contract to deposit from
    /// @param tokenId The tokenId from the collection to deposit
    /// @param expiration The timestamp that the liquid delegate will expire and return the escrowed NFT
    /// @param referrer Set to the zero address by default, alternate frontends can populate this to receive half the creation fee
    function create(address contract_, uint256 tokenId, uint96 expiration, address payable referrer) external payable {
        require(msg.value == creationFee, "WRONG_FEE");
        // If referrer exists, pay half of creation fee
        if (referrer != address(0x0) && msg.value != 0) {
            // Fail silently if invalid referrer
            _pay(referrer, msg.value / 2, false);
        }
        ERC721(contract_).transferFrom(msg.sender, address(this), tokenId);
        idsToRights[nextRightsId] = Rights({
            depositor: msg.sender,
            contract_: contract_,
            tokenId: tokenId,
            expiration: expiration
        });
        _mint(msg.sender, nextRightsId);
        emit RightsCreated(nextRightsId++, msg.sender, contract_, tokenId, expiration);
    }

    /// @notice Burn delegation rights and return escrowed NFT to owner
    /// @dev Can be triggered by the owner at any time, or anyone after deposit expiry
    /// @param rightsId The id of the liquid delegate to burn
    function burn(uint256 rightsId) external {
        Rights memory rights = idsToRights[rightsId];
        require(ownerOf(rightsId) == msg.sender || block.timestamp >= rights.expiration, "INVALID_BURN");
        _burn(rightsId);
        ERC721(rights.contract_).transferFrom(address(this), rights.depositor, rights.tokenId);
        emit RightsBurned(rightsId, rights.depositor, rights.contract_, rights.tokenId, rights.expiration);
        delete idsToRights[rightsId];
    }

    /// @notice Flashloan a delegated asset to its liquid owner. 
    /// @dev Backup functionality if the underlying utility doesn't support delegate.cash yet
    /// @param rightsId The id of the liquid delegate to flashloan the escrowed NFT for
    /// @param receiver The address of the receiver implementing the INFTFlashBorrower interface
    /// @param data Unused here
    function flashLoan(
        uint256 rightsId,
        INFTFlashBorrower receiver,
        bytes calldata data
    ) external {
        Rights memory rights = idsToRights[rightsId];
        require(ownerOf(rightsId) == msg.sender, "can only flashloan your own tickets");
        ERC721(rights.contract_).transferFrom(address(this), address(receiver), rights.tokenId);
        require(
            receiver.onFlashLoan(msg.sender, rights.contract_, rights.tokenId, data) == CALLBACK_SUCCESS,
            "FlashLender: Callback failed"
        );
        ERC721(rights.contract_).transferFrom(address(receiver), address(this), rights.tokenId);
    }

    /**
     * ----------- DELEGATION -----------
     */

    /// @notice Move the airdrop claim right
    /// @dev Whenever the airdrop claim NFT transfers, update the delegation rights
    /// @param from The address to transfer from
    /// @param to The address to transfer to
    /// @param id The token id to transfer
    function transferFrom(address from, address to, uint256 id) public override {
        Rights memory rights = idsToRights[id];
        require(block.timestamp < rights.expiration, "deposit expired and cannot be transferred");
        // Reassign delegation powers
        IDelegationRegistry(DELEGATION_REGISTRY).delegateForToken(from, rights.contract_, rights.tokenId, false);
        IDelegationRegistry(DELEGATION_REGISTRY).delegateForToken(to, rights.contract_, rights.tokenId, true);
        super.transferFrom(from, to, id);
    }

    /// @dev Delegate when a liquid delegate is minted
    /// @param to The address to mint to
    /// @param id The token id to mint
    function _mint(address to, uint256 id) internal override {
        Rights memory rights = idsToRights[id];
        IDelegationRegistry(DELEGATION_REGISTRY).delegateForToken(to, rights.contract_, rights.tokenId, true);
        super._mint(to, id);
    }

    /// @dev Undelegate when a liquid delegate is burned
    function _burn(uint256 id) internal override {
        Rights memory rights = idsToRights[id];
        IDelegationRegistry(DELEGATION_REGISTRY).delegateForToken(ownerOf(id), rights.contract_, rights.tokenId, false);
        super._burn(id);
    }

    /**
     * ----------- METADATA -----------
     */

    /// @notice Set the base URI for image generation
    /// @param _baseURI The new base URI for image generation
     function setBaseURI(string memory _baseURI) external onlyMetadataOwner {
        baseURI = _baseURI;
     }

    /// @notice Return metadata for a token
    /// @dev The attributes are immutably generated onchain, the image is fetched externally
    /// @param tokenId The tokenId to fetch metadata for
    function tokenURI(uint256 tokenId) override public view returns (string memory) {
        Rights memory rights = idsToRights[tokenId];

        string memory attributes = string.concat(
            '"attributes":[',
            '{"trait_type": "Collection Address", "value": "', rights.contract_.toHexString(), '"', 
            '}, {"trait_type": "Token ID", "value": "', rights.tokenId.toString(), '"',
            '}, {"trait_type": "Expiration", "display_type": "date", "value": ', uint256(rights.expiration).toString(),
            '}, {"trait_type": "Depositor Address", "value": "', rights.depositor.toHexString(), '"'
            '}]'
        );

        string memory imageUrl = string.concat(baseURI, tokenId.toString());

        string memory metadataString = string.concat(
            '{"name": "Liquid Delegate #', tokenId.toString(), 
            '", "description": "LiquidDelegate lets you escrow your token for a chosen timeperiod and receive a liquid NFT representing the associated delegation rights.", ', 
            attributes, 
            ', "image": "', imageUrl,
            '"}'
        );
        string memory output = string.concat('data:application/json;base64,', Base64.encode(bytes(metadataString)));

        return output;
    }

    /** 
     * ----------- ROYALTIES -----------
     */

    /// @notice Set fee for creating a new liquid delegate
    /// @param _creationFee The new fee for creating a liquid delegate
    function setCreationFee(uint256 _creationFee) external {
        require(msg.sender == royaltyOwner, "ACCESS_CONTROL");
        creationFee = _creationFee;
    }

    /// @notice Claim funds
    /// @param recipient The address to send funds to
    function claimFunds(address payable recipient) external {
        require(msg.sender == royaltyOwner, "ACCESS_CONTROL");
        _pay(recipient, address(this).balance, true);
    }

    /// @dev See {ERC2981-_setDefaultRoyalty}.
    function setDefaultRoyalty(address receiver, uint96 feeNumerator) external onlyRoyaltyOwner {
        _setDefaultRoyalty(receiver, feeNumerator);
    }

    /// @dev See {ERC2981-_deleteDefaultRoyalty}.
    function deleteDefaultRoyalty() external onlyRoyaltyOwner {
        _deleteDefaultRoyalty();
    }

    /**
     * ----------- OWNERS -----------
     */

    modifier onlyRoyaltyOwner() {
        require(msg.sender == royaltyOwner, "ACCESS_CONTROL");
        _;
    }

    modifier onlyMetadataOwner() {
        require(msg.sender == metadataOwner, "ACCESS_CONTROL");
        _;
    }

    /// @notice Update the royaltyOwner
    /// @dev Can also be used to revoke this power by setting to 0x0
    /// @param _royaltyOwner The new royalty owner
    function setRoyaltyOwner(address _royaltyOwner) external onlyRoyaltyOwner {
        royaltyOwner = _royaltyOwner;
    }

    /// @notice Update the metadataOwner
    /// @dev Can also be used to revoke this power by setting to 0x0
    /// @param _metadataOwner The new metadata owner
    function setMetadataOwner(address _metadataOwner) external onlyMetadataOwner {
        metadataOwner = _metadataOwner;
    }

    /// @notice The address which can set royalties
    function owner() external view returns (address) {
        return royaltyOwner;
    }

    /// @dev Send ether
    function _pay(address payable recipient, uint256 amount, bool errorOnFail) internal {
        (bool sent,) = recipient.call{value: amount}("");
        require(sent || errorOnFail, "SEND_ETHER_FAILED");
    }
}

File 2 of 13 : IERC2981.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (interfaces/IERC2981.sol)

pragma solidity ^0.8.0;

import "../utils/introspection/IERC165.sol";

/**
 * @dev Interface for the NFT Royalty Standard.
 *
 * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal
 * support for royalty payments across all NFT marketplaces and ecosystem participants.
 *
 * _Available since v4.5._
 */
interface IERC2981 is IERC165 {
    /**
     * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of
     * exchange. The royalty amount is denominated and should be paid in that same unit of exchange.
     */
    function royaltyInfo(
        uint256 tokenId,
        uint256 salePrice
    ) external view returns (address receiver, uint256 royaltyAmount);
}

File 3 of 13 : ERC2981.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/common/ERC2981.sol)

pragma solidity ^0.8.0;

import "../../interfaces/IERC2981.sol";
import "../../utils/introspection/ERC165.sol";

/**
 * @dev Implementation of the NFT Royalty Standard, a standardized way to retrieve royalty payment information.
 *
 * Royalty information can be specified globally for all token ids via {_setDefaultRoyalty}, and/or individually for
 * specific token ids via {_setTokenRoyalty}. The latter takes precedence over the first.
 *
 * Royalty is specified as a fraction of sale price. {_feeDenominator} is overridable but defaults to 10000, meaning the
 * fee is specified in basis points by default.
 *
 * IMPORTANT: ERC-2981 only specifies a way to signal royalty information and does not enforce its payment. See
 * https://eips.ethereum.org/EIPS/eip-2981#optional-royalty-payments[Rationale] in the EIP. Marketplaces are expected to
 * voluntarily pay royalties together with sales, but note that this standard is not yet widely supported.
 *
 * _Available since v4.5._
 */
abstract contract ERC2981 is IERC2981, ERC165 {
    struct RoyaltyInfo {
        address receiver;
        uint96 royaltyFraction;
    }

    RoyaltyInfo private _defaultRoyaltyInfo;
    mapping(uint256 => RoyaltyInfo) private _tokenRoyaltyInfo;

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) {
        return interfaceId == type(IERC2981).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @inheritdoc IERC2981
     */
    function royaltyInfo(uint256 tokenId, uint256 salePrice) public view virtual override returns (address, uint256) {
        RoyaltyInfo memory royalty = _tokenRoyaltyInfo[tokenId];

        if (royalty.receiver == address(0)) {
            royalty = _defaultRoyaltyInfo;
        }

        uint256 royaltyAmount = (salePrice * royalty.royaltyFraction) / _feeDenominator();

        return (royalty.receiver, royaltyAmount);
    }

    /**
     * @dev The denominator with which to interpret the fee set in {_setTokenRoyalty} and {_setDefaultRoyalty} as a
     * fraction of the sale price. Defaults to 10000 so fees are expressed in basis points, but may be customized by an
     * override.
     */
    function _feeDenominator() internal pure virtual returns (uint96) {
        return 10000;
    }

    /**
     * @dev Sets the royalty information that all ids in this contract will default to.
     *
     * Requirements:
     *
     * - `receiver` cannot be the zero address.
     * - `feeNumerator` cannot be greater than the fee denominator.
     */
    function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual {
        require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice");
        require(receiver != address(0), "ERC2981: invalid receiver");

        _defaultRoyaltyInfo = RoyaltyInfo(receiver, feeNumerator);
    }

    /**
     * @dev Removes default royalty information.
     */
    function _deleteDefaultRoyalty() internal virtual {
        delete _defaultRoyaltyInfo;
    }

    /**
     * @dev Sets the royalty information for a specific token id, overriding the global default.
     *
     * Requirements:
     *
     * - `receiver` cannot be the zero address.
     * - `feeNumerator` cannot be greater than the fee denominator.
     */
    function _setTokenRoyalty(uint256 tokenId, address receiver, uint96 feeNumerator) internal virtual {
        require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice");
        require(receiver != address(0), "ERC2981: Invalid parameters");

        _tokenRoyaltyInfo[tokenId] = RoyaltyInfo(receiver, feeNumerator);
    }

    /**
     * @dev Resets royalty information for the token id back to the global default.
     */
    function _resetTokenRoyalty(uint256 tokenId) internal virtual {
        delete _tokenRoyaltyInfo[tokenId];
    }
}

File 4 of 13 : Base64.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Base64.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides a set of functions to operate with Base64 strings.
 *
 * _Available since v4.5._
 */
library Base64 {
    /**
     * @dev Base64 Encoding/Decoding Table
     */
    string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

    /**
     * @dev Converts a `bytes` to its Bytes64 `string` representation.
     */
    function encode(bytes memory data) internal pure returns (string memory) {
        /**
         * Inspired by Brecht Devos (Brechtpd) implementation - MIT licence
         * https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol
         */
        if (data.length == 0) return "";

        // Loads the table into memory
        string memory table = _TABLE;

        // Encoding takes 3 bytes chunks of binary data from `bytes` data parameter
        // and split into 4 numbers of 6 bits.
        // The final Base64 length should be `bytes` data length multiplied by 4/3 rounded up
        // - `data.length + 2`  -> Round up
        // - `/ 3`              -> Number of 3-bytes chunks
        // - `4 *`              -> 4 characters for each chunk
        string memory result = new string(4 * ((data.length + 2) / 3));

        /// @solidity memory-safe-assembly
        assembly {
            // Prepare the lookup table (skip the first "length" byte)
            let tablePtr := add(table, 1)

            // Prepare result pointer, jump over length
            let resultPtr := add(result, 32)

            // Run over the input, 3 bytes at a time
            for {
                let dataPtr := data
                let endPtr := add(data, mload(data))
            } lt(dataPtr, endPtr) {

            } {
                // Advance 3 bytes
                dataPtr := add(dataPtr, 3)
                let input := mload(dataPtr)

                // To write each character, shift the 3 bytes (18 bits) chunk
                // 4 times in blocks of 6 bits for each character (18, 12, 6, 0)
                // and apply logical AND with 0x3F which is the number of
                // the previous character in the ASCII table prior to the Base64 Table
                // The result is then added to the table to get the character to write,
                // and finally write it in the result pointer but with a left shift
                // of 256 (1 byte) - 8 (1 ASCII char) = 248 bits

                mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F))))
                resultPtr := add(resultPtr, 1) // Advance

                mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F))))
                resultPtr := add(resultPtr, 1) // Advance

                mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F))))
                resultPtr := add(resultPtr, 1) // Advance

                mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F))))
                resultPtr := add(resultPtr, 1) // Advance
            }

            // When data `bytes` is not exactly 3 bytes long
            // it is padded with `=` characters at the end
            switch mod(mload(data), 3)
            case 1 {
                mstore8(sub(resultPtr, 1), 0x3d)
                mstore8(sub(resultPtr, 2), 0x3d)
            }
            case 2 {
                mstore8(sub(resultPtr, 1), 0x3d)
            }
        }

        return result;
    }
}

File 5 of 13 : Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

import "./math/Math.sol";
import "./math/SignedMath.sol";

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _SYMBOLS = "0123456789abcdef";
    uint8 private constant _ADDRESS_LENGTH = 20;

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `int256` to its ASCII `string` decimal representation.
     */
    function toString(int256 value) internal pure returns (string memory) {
        return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, Math.log256(value) + 1);
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
    }

    /**
     * @dev Returns true if the two strings are equal.
     */
    function equal(string memory a, string memory b) internal pure returns (bool) {
        return keccak256(bytes(a)) == keccak256(bytes(b));
    }
}

File 6 of 13 : ERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)

pragma solidity ^0.8.0;

import "./IERC165.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

File 7 of 13 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 8 of 13 : Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    enum Rounding {
        Down, // Toward negative infinity
        Up, // Toward infinity
        Zero // Toward zero
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds up instead
     * of rounding down.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
     * with further edits by Uniswap Labs also under MIT license.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod0 := mul(x, y)
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            require(denominator > prod1, "Math: mulDiv overflow");

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
            // See https://cs.stackexchange.com/q/138556/92363.

            // Does not overflow because the denominator cannot be zero at this stage in the function.
            uint256 twos = denominator & (~denominator + 1);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
            // in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10, rounded down, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10 ** 64) {
                value /= 10 ** 64;
                result += 64;
            }
            if (value >= 10 ** 32) {
                value /= 10 ** 32;
                result += 32;
            }
            if (value >= 10 ** 16) {
                value /= 10 ** 16;
                result += 16;
            }
            if (value >= 10 ** 8) {
                value /= 10 ** 8;
                result += 8;
            }
            if (value >= 10 ** 4) {
                value /= 10 ** 4;
                result += 4;
            }
            if (value >= 10 ** 2) {
                value /= 10 ** 2;
                result += 2;
            }
            if (value >= 10 ** 1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256, rounded down, of a positive value.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
        }
    }
}

File 9 of 13 : SignedMath.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)

pragma solidity ^0.8.0;

/**
 * @dev Standard signed math utilities missing in the Solidity language.
 */
library SignedMath {
    /**
     * @dev Returns the largest of two signed numbers.
     */
    function max(int256 a, int256 b) internal pure returns (int256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two signed numbers.
     */
    function min(int256 a, int256 b) internal pure returns (int256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two signed numbers without overflow.
     * The result is rounded towards zero.
     */
    function average(int256 a, int256 b) internal pure returns (int256) {
        // Formula from the book "Hacker's Delight"
        int256 x = (a & b) + ((a ^ b) >> 1);
        return x + (int256(uint256(x) >> 255) & (a ^ b));
    }

    /**
     * @dev Returns the absolute unsigned value of a signed value.
     */
    function abs(int256 n) internal pure returns (uint256) {
        unchecked {
            // must be unchecked in order to support `n = type(int256).min`
            return uint256(n >= 0 ? n : -n);
        }
    }
}

File 10 of 13 : ERC721.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Modern, minimalist, and gas efficient ERC-721 implementation.
/// @author Solmate (https://github.com/transmissions11/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);

        require(
            to.code.length == 0 ||
                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);

        require(
            to.code.length == 0 ||
                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);

        require(
            to.code.length == 0 ||
                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);

        require(
            to.code.length == 0 ||
                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/transmissions11/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 11 of 13 : IDelegationRegistry.sol
// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.17;

/**
 * @title An immutable registry contract to be deployed as a standalone primitive
 * @dev See EIP-5639, new project launches can read previous cold wallet -> hot wallet delegations
 * from here and integrate those permissions into their flow
 */
interface IDelegationRegistry {
    /// @notice Delegation type
    enum DelegationType {
        NONE,
        ALL,
        CONTRACT,
        TOKEN
    }

    /// @notice Info about a single delegation, used for onchain enumeration
    struct DelegationInfo {
        DelegationType type_;
        address vault;
        address delegate;
        address contract_;
        uint256 tokenId;
    }

    /// @notice Info about a single contract-level delegation
    struct ContractDelegation {
        address contract_;
        address delegate;
    }

    /// @notice Info about a single token-level delegation
    struct TokenDelegation {
        address contract_;
        uint256 tokenId;
        address delegate;
    }

    /// @notice Emitted when a user delegates their entire wallet
    event DelegateForAll(address vault, address delegate, bool value);

    /// @notice Emitted when a user delegates a specific contract
    event DelegateForContract(address vault, address delegate, address contract_, bool value);

    /// @notice Emitted when a user delegates a specific token
    event DelegateForToken(address vault, address delegate, address contract_, uint256 tokenId, bool value);

    /// @notice Emitted when a user revokes all delegations
    event RevokeAllDelegates(address vault);

    /// @notice Emitted when a user revoes all delegations for a given delegate
    event RevokeDelegate(address vault, address delegate);

    /**
     * -----------  WRITE -----------
     */

    /**
     * @notice Allow the delegate to act on your behalf for all contracts
     * @param delegate The hotwallet to act on your behalf
     * @param value Whether to enable or disable delegation for this address, true for setting and false for revoking
     */
    function delegateForAll(address delegate, bool value) external;

    /**
     * @notice Allow the delegate to act on your behalf for a specific contract
     * @param delegate The hotwallet to act on your behalf
     * @param contract_ The address for the contract you're delegating
     * @param value Whether to enable or disable delegation for this address, true for setting and false for revoking
     */
    function delegateForContract(address delegate, address contract_, bool value) external;

    /**
     * @notice Allow the delegate to act on your behalf for a specific token
     * @param delegate The hotwallet to act on your behalf
     * @param contract_ The address for the contract you're delegating
     * @param tokenId The token id for the token you're delegating
     * @param value Whether to enable or disable delegation for this address, true for setting and false for revoking
     */
    function delegateForToken(address delegate, address contract_, uint256 tokenId, bool value) external;

    /**
     * @notice Revoke all delegates
     */
    function revokeAllDelegates() external;

    /**
     * @notice Revoke a specific delegate for all their permissions
     * @param delegate The hotwallet to revoke
     */
    function revokeDelegate(address delegate) external;

    /**
     * @notice Remove yourself as a delegate for a specific vault
     * @param vault The vault which delegated to the msg.sender, and should be removed
     */
    function revokeSelf(address vault) external;

    /**
     * -----------  READ -----------
     */

    /**
     * @notice Returns all active delegations a given delegate is able to claim on behalf of
     * @param delegate The delegate that you would like to retrieve delegations for
     * @return info Array of DelegationInfo structs
     */
    function getDelegationsByDelegate(address delegate) external view returns (DelegationInfo[] memory);

    /**
     * @notice Returns an array of wallet-level delegates for a given vault
     * @param vault The cold wallet who issued the delegation
     * @return addresses Array of wallet-level delegates for a given vault
     */
    function getDelegatesForAll(address vault) external view returns (address[] memory);

    /**
     * @notice Returns an array of contract-level delegates for a given vault and contract
     * @param vault The cold wallet who issued the delegation
     * @param contract_ The address for the contract you're delegating
     * @return addresses Array of contract-level delegates for a given vault and contract
     */
    function getDelegatesForContract(address vault, address contract_) external view returns (address[] memory);

    /**
     * @notice Returns an array of contract-level delegates for a given vault's token
     * @param vault The cold wallet who issued the delegation
     * @param contract_ The address for the contract holding the token
     * @param tokenId The token id for the token you're delegating
     * @return addresses Array of contract-level delegates for a given vault's token
     */
    function getDelegatesForToken(address vault, address contract_, uint256 tokenId)
        external
        view
        returns (address[] memory);

    /**
     * @notice Returns all contract-level delegations for a given vault
     * @param vault The cold wallet who issued the delegations
     * @return delegations Array of ContractDelegation structs
     */
    function getContractLevelDelegations(address vault)
        external
        view
        returns (ContractDelegation[] memory delegations);

    /**
     * @notice Returns all token-level delegations for a given vault
     * @param vault The cold wallet who issued the delegations
     * @return delegations Array of TokenDelegation structs
     */
    function getTokenLevelDelegations(address vault) external view returns (TokenDelegation[] memory delegations);

    /**
     * @notice Returns true if the address is delegated to act on the entire vault
     * @param delegate The hotwallet to act on your behalf
     * @param vault The cold wallet who issued the delegation
     */
    function checkDelegateForAll(address delegate, address vault) external view returns (bool);

    /**
     * @notice Returns true if the address is delegated to act on your behalf for a token contract or an entire vault
     * @param delegate The hotwallet to act on your behalf
     * @param contract_ The address for the contract you're delegating
     * @param vault The cold wallet who issued the delegation
     */
    function checkDelegateForContract(address delegate, address vault, address contract_)
        external
        view
        returns (bool);

    /**
     * @notice Returns true if the address is delegated to act on your behalf for a specific token, the token's contract or an entire vault
     * @param delegate The hotwallet to act on your behalf
     * @param contract_ The address for the contract you're delegating
     * @param tokenId The token id for the token you're delegating
     * @param vault The cold wallet who issued the delegation
     */
    function checkDelegateForToken(address delegate, address vault, address contract_, uint256 tokenId)
        external
        view
        returns (bool);
}

File 12 of 13 : INFTFlashBorrower.sol
pragma solidity ^0.7.0 || ^0.8.0;


interface INFTFlashBorrower {

    /**
     * @dev Receive a flash loan.
     * @param initiator The initiator of the loan.
     * @param token The loan currency.
     * @param id The tokenId lent.
     * @param data Arbitrary data structure, intended to contain user-defined parameters.
     * @return The keccak256 hash of "INFTFlashBorrower.onFlashLoan"
     */
    function onFlashLoan(
        address initiator,
        address token,
        uint256 id,
        bytes calldata data
    ) external returns (bytes32);
}

File 13 of 13 : INFTFlashLender.sol
pragma solidity ^0.7.0 || ^0.8.0;
import "./INFTFlashBorrower.sol";


interface INFTFlashLender {

    /**
     * @dev Initiate a flash loan.
     * @param rightsId The liquid delegation to flashloan the underlying escrow asset of.
     * @param receiver The receiver of the tokens in the loan, and the receiver of the callback.
     * @param data Arbitrary data structure, intended to contain user-defined parameters.
     */
    function flashLoan(
        uint256 rightsId,
        INFTFlashBorrower receiver,
        bytes calldata data
    ) external;
}

Settings
{
  "remappings": [
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "solmate/=lib/solmate/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "london",
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_DELEGATION_REGISTRY","type":"address"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"string","name":"_baseURI","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"rightsId","type":"uint256"},{"indexed":true,"internalType":"address","name":"depositor","type":"address"},{"indexed":true,"internalType":"address","name":"contract_","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"expiration","type":"uint256"}],"name":"RightsBurned","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"rightsId","type":"uint256"},{"indexed":true,"internalType":"address","name":"depositor","type":"address"},{"indexed":true,"internalType":"address","name":"contract_","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"expiration","type":"uint256"}],"name":"RightsCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"CALLBACK_SUCCESS","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DELEGATION_REGISTRY","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"rightsId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"recipient","type":"address"}],"name":"claimFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contract_","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint96","name":"expiration","type":"uint96"},{"internalType":"address payable","name":"referrer","type":"address"}],"name":"create","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"creationFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deleteDefaultRoyalty","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"rightsId","type":"uint256"},{"internalType":"contract INFTFlashBorrower","name":"receiver","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"flashLoan","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"idsToRights","outputs":[{"internalType":"address","name":"depositor","type":"address"},{"internalType":"uint96","name":"expiration","type":"uint96"},{"internalType":"address","name":"contract_","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nextRightsId","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":"uint256","name":"id","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"salePrice","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_baseURI","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_creationFee","type":"uint256"}],"name":"setCreationFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint96","name":"feeNumerator","type":"uint96"}],"name":"setDefaultRoyalty","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_metadataOwner","type":"address"}],"name":"setMetadataOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_royaltyOwner","type":"address"}],"name":"setRoyaltyOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60a060405260016009556000600a553480156200001b57600080fd5b5060405162003303380380620033038339810160408190526200003e916200023d565b6040518060400160405280600e81526020016d4c697175696444656c656761746560901b8152506040518060400160405280600681526020016552494748545360d01b8152508160009081620000959190620003c6565b506001620000a48282620003c6565b5050506001600160a01b038316608052600d620000c28282620003c6565b50600c80546001600160a01b0384166001600160a01b03199182168117909255600b80549091169091179055620000fc826103e862000105565b50505062000492565b6127106001600160601b0382161115620001795760405162461bcd60e51b815260206004820152602a60248201527f455243323938313a20726f79616c7479206665652077696c6c206578636565646044820152692073616c65507269636560b01b60648201526084015b60405180910390fd5b6001600160a01b038216620001d15760405162461bcd60e51b815260206004820152601960248201527f455243323938313a20696e76616c696420726563656976657200000000000000604482015260640162000170565b604080518082019091526001600160a01b039092168083526001600160601b039091166020909201829052600160a01b90910217600655565b80516001600160a01b03811681146200022257600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b6000806000606084860312156200025357600080fd5b6200025e846200020a565b925060206200026f8186016200020a565b60408601519093506001600160401b03808211156200028d57600080fd5b818701915087601f830112620002a257600080fd5b815181811115620002b757620002b762000227565b604051601f8201601f19908116603f01168101908382118183101715620002e257620002e262000227565b816040528281528a86848701011115620002fb57600080fd5b600093505b828410156200031f578484018601518185018701529285019262000300565b60008684830101528096505050505050509250925092565b600181811c908216806200034c57607f821691505b6020821081036200036d57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620003c157600081815260208120601f850160051c810160208610156200039c5750805b601f850160051c820191505b81811015620003bd57828155600101620003a8565b5050505b505050565b81516001600160401b03811115620003e257620003e262000227565b620003fa81620003f3845462000337565b8462000373565b602080601f831160018114620004325760008415620004195750858301515b600019600386901b1c1916600185901b178555620003bd565b600085815260208120601f198616915b82811015620004635788860151825594840194600190910190840162000442565b5085821015620004825787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b608051612e39620004ca600039600081816103e101528181610b4501528181610bb20152818161193a0152611bd20152612e396000f3fe6080604052600436106101cd5760003560e01c80635dc2d191116100f7578063a22cb46511610095578063c87b56dd11610064578063c87b56dd146105f2578063dce0b4e414610612578063e985e9c514610628578063ecde3c891461066357600080fd5b8063a22cb4651461057d578063aa1b103f1461059d578063b7d86225146105b2578063b88d4fde146105d257600080fd5b806370a08231116100d157806370a08231146104f65780638237e538146105165780638da5cb5b1461054a57806395d89b411461056857600080fd5b80635dc2d191146104235780636352211e146104b6578063693d0df2146104d657600080fd5b806323b872dd1161016f57806342842e0e1161013e57806342842e0e1461038f57806342966c68146103af5780634daadff7146103cf57806355f804b31461040357600080fd5b806323b872dd146102f05780632525b3d7146103105780632a55205a146103305780632bd94e9c1461036f57600080fd5b8063081812fc116101ab578063081812fc1461024b578063095ea7b31461029957806316531556146102b95780631c978922146102cc57600080fd5b806301ffc9a7146101d257806304634d8d1461020757806306fdde0314610229575b600080fd5b3480156101de57600080fd5b506101f26101ed3660046122cb565b610683565b60405190151581526020015b60405180910390f35b34801561021357600080fd5b50610227610222366004612314565b6106f0565b005b34801561023557600080fd5b5061023e610731565b6040516101fe919061236d565b34801561025757600080fd5b506102816102663660046123a0565b6004602052600090815260409020546001600160a01b031681565b6040516001600160a01b0390911681526020016101fe565b3480156102a557600080fd5b506102276102b43660046123b9565b6107bf565b6102276102c73660046123e5565b6108a1565b3480156102d857600080fd5b506102e260095481565b6040519081526020016101fe565b3480156102fc57600080fd5b5061022761030b366004612436565b610a6e565b34801561031c57600080fd5b5061022761032b366004612477565b610c4e565b34801561033c57600080fd5b5061035061034b366004612494565b610c9a565b604080516001600160a01b0390931683526020830191909152016101fe565b34801561037b57600080fd5b5061022761038a3660046124f8565b610d48565b34801561039b57600080fd5b506102276103aa366004612436565b610fd7565b3480156103bb57600080fd5b506102276103ca3660046123a0565b6110cf565b3480156103db57600080fd5b506102817f000000000000000000000000000000000000000000000000000000000000000081565b34801561040f57600080fd5b5061022761041e36600461256a565b6112a1565b34801561042f57600080fd5b5061047c61043e3660046123a0565b6008602052600090815260409020805460018201546002909201546001600160a01b0380831693600160a01b9093046001600160601b031692169084565b604080516001600160a01b0395861681526001600160601b03949094166020850152919093169082015260608101919091526080016101fe565b3480156104c257600080fd5b506102816104d13660046123a0565b6112d7565b3480156104e257600080fd5b506102276104f1366004612477565b61132e565b34801561050257600080fd5b506102e2610511366004612477565b611367565b34801561052257600080fd5b506102e27f15fe000ebb1eecc65da40c712f474e7b6de55062598e11a7289a519792b1e52881565b34801561055657600080fd5b50600b546001600160a01b0316610281565b34801561057457600080fd5b5061023e6113ca565b34801561058957600080fd5b5061022761059836600461261b565b6113d7565b3480156105a957600080fd5b50610227611443565b3480156105be57600080fd5b506102276105cd3660046123a0565b611479565b3480156105de57600080fd5b506102276105ed366004612659565b6114a8565b3480156105fe57600080fd5b5061023e61060d3660046123a0565b611590565b34801561061e57600080fd5b506102e2600a5481565b34801561063457600080fd5b506101f26106433660046126cc565b600560209081526000928352604080842090915290825290205460ff1681565b34801561066f57600080fd5b5061022761067e366004612477565b6116e6565b60006301ffc9a760e01b6001600160e01b0319831614806106b457506380ac58cd60e01b6001600160e01b03198316145b806106cf5750635b5e139f60e01b6001600160e01b03198316145b806106ea575063152a902d60e11b6001600160e01b03198316145b92915050565b600b546001600160a01b031633146107235760405162461bcd60e51b815260040161071a906126fa565b60405180910390fd5b61072d8282611732565b5050565b6000805461073e90612722565b80601f016020809104026020016040519081016040528092919081815260200182805461076a90612722565b80156107b75780601f1061078c576101008083540402835291602001916107b7565b820191906000526020600020905b81548152906001019060200180831161079a57829003601f168201915b505050505081565b6000818152600260205260409020546001600160a01b03163381148061080857506001600160a01b038116600090815260056020908152604080832033845290915290205460ff165b6108455760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b604482015260640161071a565b60008281526004602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b600a5434146108de5760405162461bcd60e51b815260206004820152600960248201526857524f4e475f46454560b81b604482015260640161071a565b6001600160a01b038116158015906108f557503415155b156109105761091081610909600234612772565b600061182f565b6040516323b872dd60e01b81526001600160a01b038516906323b872dd9061094090339030908890600401612794565b600060405180830381600087803b15801561095a57600080fd5b505af115801561096e573d6000803e3d6000fd5b505060408051608081018252338082526001600160601b0380881660208085019182526001600160a01b038c8116868801908152606087018d815260098054600090815260089095529890932096519351909416600160a01b029281169290921785559151600185018054919092166001600160a01b031991909116179055516002909201919091559054610a0693509091506118ce565b600980546001600160a01b038616913391906000610a23836127b8565b90915550604080518781526001600160601b03871660208201527fd54446047dcdfe0e5c18465bf25c2699a49ce7345b2fca5da0de94675c3b8d07910160405180910390a450505050565b600081815260086020908152604091829020825160808101845281546001600160a01b038082168352600160a01b9091046001600160601b0316938201849052600183015416938101939093526002015460608301524210610b245760405162461bcd60e51b815260206004820152602960248201527f6465706f736974206578706972656420616e642063616e6e6f74206265207472604482015268185b9cd9995c9c995960ba1b606482015260840161071a565b6040808201516060830151915163537a5c3d60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169263537a5c3d92610b7e928992906000906004016127d1565b600060405180830381600087803b158015610b9857600080fd5b505af1158015610bac573d6000803e3d6000fd5b505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663537a5c3d848360400151846060015160016040518563ffffffff1660e01b8152600401610c0b94939291906127d1565b600060405180830381600087803b158015610c2557600080fd5b505af1158015610c39573d6000803e3d6000fd5b50505050610c488484846119b1565b50505050565b600b546001600160a01b03163314610c785760405162461bcd60e51b815260040161071a906126fa565b600b80546001600160a01b0319166001600160a01b0392909216919091179055565b60008281526007602090815260408083208151808301909252546001600160a01b038116808352600160a01b9091046001600160601b0316928201929092528291610d0f5750604080518082019091526006546001600160a01b0381168252600160a01b90046001600160601b031660208201525b602081015160009061271090610d2e906001600160601b0316876127fa565b610d389190612772565b91519350909150505b9250929050565b600084815260086020908152604091829020825160808101845281546001600160a01b038082168352600160a01b9091046001600160601b031693820193909352600182015490921692820192909252600290910154606082015233610dad866112d7565b6001600160a01b031614610e0f5760405162461bcd60e51b815260206004820152602360248201527f63616e206f6e6c7920666c6173686c6f616e20796f7572206f776e207469636b60448201526265747360e81b606482015260840161071a565b80604001516001600160a01b03166323b872dd308684606001516040518463ffffffff1660e01b8152600401610e4793929190612794565b600060405180830381600087803b158015610e6157600080fd5b505af1158015610e75573d6000803e3d6000fd5b5050506040808301516060840151915163300322db60e21b81527f15fe000ebb1eecc65da40c712f474e7b6de55062598e11a7289a519792b1e52893506001600160a01b0388169263c00c8b6c92610ed6923392908a908a90600401612811565b6020604051808303816000875af1158015610ef5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f199190612865565b14610f665760405162461bcd60e51b815260206004820152601c60248201527f466c6173684c656e6465723a2043616c6c6261636b206661696c656400000000604482015260640161071a565b80604001516001600160a01b03166323b872dd853084606001516040518463ffffffff1660e01b8152600401610f9e93929190612794565b600060405180830381600087803b158015610fb857600080fd5b505af1158015610fcc573d6000803e3d6000fd5b505050505050505050565b610fe2838383610a6e565b6001600160a01b0382163b158061108b5750604051630a85bd0160e11b8082523360048301526001600160a01b03858116602484015260448301849052608060648401526000608484015290919084169063150b7a029060a4016020604051808303816000875af115801561105b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061107f919061287e565b6001600160e01b031916145b6110ca5760405162461bcd60e51b815260206004820152601060248201526f155394d0519157d49150d2541251539560821b604482015260640161071a565b505050565b600081815260086020908152604091829020825160808101845281546001600160a01b038082168352600160a01b9091046001600160601b031693820193909352600182015490921692820192909252600290910154606082015233611134836112d7565b6001600160a01b03161480611156575080602001516001600160601b03164210155b6111915760405162461bcd60e51b815260206004820152600c60248201526b24a72b20a624a22fa12aa92760a11b604482015260640161071a565b61119a82611b78565b6040808201518251606084015192516323b872dd60e01b81526001600160a01b03909216926323b872dd926111d59230929091600401612794565b600060405180830381600087803b1580156111ef57600080fd5b505af1158015611203573d6000803e3d6000fd5b5050505080604001516001600160a01b031681600001516001600160a01b0316837f38b768306af3c9319ae2f926fd65a8fb10e917b5544887126c57c3838d6b0ea38460600151856020015160405161126f9291909182526001600160601b0316602082015260400190565b60405180910390a45060009081526008602052604081208181556001810180546001600160a01b031916905560020155565b600c546001600160a01b031633146112cb5760405162461bcd60e51b815260040161071a906126fa565b600d61072d82826128e9565b6000818152600260205260409020546001600160a01b0316806113295760405162461bcd60e51b815260206004820152600a6024820152691393d517d3525395115160b21b604482015260640161071a565b919050565b600b546001600160a01b031633146113585760405162461bcd60e51b815260040161071a906126fa565b6113648147600161182f565b50565b60006001600160a01b0382166113ae5760405162461bcd60e51b815260206004820152600c60248201526b5a45524f5f4144445245535360a01b604482015260640161071a565b506001600160a01b031660009081526003602052604090205490565b6001805461073e90612722565b3360008181526005602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b600b546001600160a01b0316331461146d5760405162461bcd60e51b815260040161071a906126fa565b6114776000600655565b565b600b546001600160a01b031633146114a35760405162461bcd60e51b815260040161071a906126fa565b600a55565b6114b3858585610a6e565b6001600160a01b0384163b158061154a5750604051630a85bd0160e11b808252906001600160a01b0386169063150b7a02906114fb9033908a90899089908990600401612811565b6020604051808303816000875af115801561151a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061153e919061287e565b6001600160e01b031916145b6115895760405162461bcd60e51b815260206004820152601060248201526f155394d0519157d49150d2541251539560821b604482015260640161071a565b5050505050565b6000818152600860209081526040808320815160808101835281546001600160a01b038082168352600160a01b9091046001600160601b03169482019490945260018201549093169183018290526002015460608084019190915292906115f690611c66565b6116038360600151611c7c565b61161984602001516001600160601b0316611c7c565b845161162d906001600160a01b0316611c66565b60405160200161164094939291906129c5565b60405160208183030381529060405290506000600d61165e86611c7c565b60405160200161166f929190612b5f565b6040516020818303038152906040529050600061168b86611c7c565b838360405160200161169f93929190612be6565b604051602081830303815290604052905060006116bb82611d0f565b6040516020016116cb9190612d3e565b60408051601f19818403018152919052979650505050505050565b600c546001600160a01b031633146117105760405162461bcd60e51b815260040161071a906126fa565b600c80546001600160a01b0319166001600160a01b0392909216919091179055565b6127106001600160601b03821611156117a05760405162461bcd60e51b815260206004820152602a60248201527f455243323938313a20726f79616c7479206665652077696c6c206578636565646044820152692073616c65507269636560b01b606482015260840161071a565b6001600160a01b0382166117f65760405162461bcd60e51b815260206004820152601960248201527f455243323938313a20696e76616c696420726563656976657200000000000000604482015260640161071a565b604080518082019091526001600160a01b039092168083526001600160601b039091166020909201829052600160a01b90910217600655565b6000836001600160a01b03168360405160006040518083038185875af1925050503d806000811461187c576040519150601f19603f3d011682016040523d82523d6000602084013e611881565b606091505b50509050808061188e5750815b610c485760405162461bcd60e51b815260206004820152601160248201527014d1539117d15512115497d19052531151607a1b604482015260640161071a565b600081815260086020908152604091829020825160808101845281546001600160a01b038082168352600160a01b9091046001600160601b031693820193909352600180830154841682860181905260029093015460608301819052945163537a5c3d60e01b815291947f00000000000000000000000000000000000000000000000000000000000000009094169363537a5c3d93611975938993919291906004016127d1565b600060405180830381600087803b15801561198f57600080fd5b505af11580156119a3573d6000803e3d6000fd5b505050506110ca8383611e62565b6000818152600260205260409020546001600160a01b03848116911614611a075760405162461bcd60e51b815260206004820152600a60248201526957524f4e475f46524f4d60b01b604482015260640161071a565b6001600160a01b038216611a515760405162461bcd60e51b81526020600482015260116024820152701253959053125117d49150d25412515395607a1b604482015260640161071a565b336001600160a01b0384161480611a8b57506001600160a01b038316600090815260056020908152604080832033845290915290205460ff165b80611aac57506000818152600460205260409020546001600160a01b031633145b611ae95760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b604482015260640161071a565b6001600160a01b0380841660008181526003602090815260408083208054600019019055938616808352848320805460010190558583526002825284832080546001600160a01b03199081168317909155600490925284832080549092169091559251849392917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b600081815260086020908152604091829020825160808101845281546001600160a01b038082168352600160a01b9091046001600160601b03169382019390935260018201548316938101939093526002015460608301527f00000000000000000000000000000000000000000000000000000000000000001663537a5c3d611c00846112d7565b8360400151846060015160006040518563ffffffff1660e01b8152600401611c2b94939291906127d1565b600060405180830381600087803b158015611c4557600080fd5b505af1158015611c59573d6000803e3d6000fd5b5050505061072d82611f6d565b60606106ea6001600160a01b038316601461203a565b60606000611c89836121dd565b600101905060008167ffffffffffffffff811115611ca957611ca9612554565b6040519080825280601f01601f191660200182016040528015611cd3576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084611cdd57509392505050565b60608151600003611d2e57505060408051602081019091526000815290565b6000604051806060016040528060408152602001612dc46040913990506000600384516002611d5d9190612d83565b611d679190612772565b611d729060046127fa565b67ffffffffffffffff811115611d8a57611d8a612554565b6040519080825280601f01601f191660200182016040528015611db4576020820181803683370190505b509050600182016020820185865187015b80821015611e20576003820191508151603f8160121c168501518453600184019350603f81600c1c168501518453600184019350603f8160061c168501518453600184019350603f8116850151845350600183019250611dc5565b5050600386510660018114611e3c5760028114611e4f57611e57565b603d6001830353603d6002830353611e57565b603d60018303535b509195945050505050565b6001600160a01b038216611eac5760405162461bcd60e51b81526020600482015260116024820152701253959053125117d49150d25412515395607a1b604482015260640161071a565b6000818152600260205260409020546001600160a01b031615611f025760405162461bcd60e51b815260206004820152600e60248201526d1053149150511657d3525395115160921b604482015260640161071a565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6000818152600260205260409020546001600160a01b031680611fbf5760405162461bcd60e51b815260206004820152600a6024820152691393d517d3525395115160b21b604482015260640161071a565b6001600160a01b038116600081815260036020908152604080832080546000190190558583526002825280832080546001600160a01b031990811690915560049092528083208054909216909155518492907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b606060006120498360026127fa565b612054906002612d83565b67ffffffffffffffff81111561206c5761206c612554565b6040519080825280601f01601f191660200182016040528015612096576020820181803683370190505b509050600360fc1b816000815181106120b1576120b1612d96565b60200101906001600160f81b031916908160001a905350600f60fb1b816001815181106120e0576120e0612d96565b60200101906001600160f81b031916908160001a90535060006121048460026127fa565b61210f906001612d83565b90505b6001811115612187576f181899199a1a9b1b9c1cb0b131b232b360811b85600f166010811061214357612143612d96565b1a60f81b82828151811061215957612159612d96565b60200101906001600160f81b031916908160001a90535060049490941c9361218081612dac565b9050612112565b5083156121d65760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e74604482015260640161071a565b9392505050565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b831061221c5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310612248576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061226657662386f26fc10000830492506010015b6305f5e100831061227e576305f5e100830492506008015b612710831061229257612710830492506004015b606483106122a4576064830492506002015b600a83106106ea5760010192915050565b6001600160e01b03198116811461136457600080fd5b6000602082840312156122dd57600080fd5b81356121d6816122b5565b6001600160a01b038116811461136457600080fd5b80356001600160601b038116811461132957600080fd5b6000806040838503121561232757600080fd5b8235612332816122e8565b9150612340602084016122fd565b90509250929050565b60005b8381101561236457818101518382015260200161234c565b50506000910152565b602081526000825180602084015261238c816040850160208701612349565b601f01601f19169190910160400192915050565b6000602082840312156123b257600080fd5b5035919050565b600080604083850312156123cc57600080fd5b82356123d7816122e8565b946020939093013593505050565b600080600080608085870312156123fb57600080fd5b8435612406816122e8565b93506020850135925061241b604086016122fd565b9150606085013561242b816122e8565b939692955090935050565b60008060006060848603121561244b57600080fd5b8335612456816122e8565b92506020840135612466816122e8565b929592945050506040919091013590565b60006020828403121561248957600080fd5b81356121d6816122e8565b600080604083850312156124a757600080fd5b50508035926020909101359150565b60008083601f8401126124c857600080fd5b50813567ffffffffffffffff8111156124e057600080fd5b602083019150836020828501011115610d4157600080fd5b6000806000806060858703121561250e57600080fd5b843593506020850135612520816122e8565b9250604085013567ffffffffffffffff81111561253c57600080fd5b612548878288016124b6565b95989497509550505050565b634e487b7160e01b600052604160045260246000fd5b60006020828403121561257c57600080fd5b813567ffffffffffffffff8082111561259457600080fd5b818401915084601f8301126125a857600080fd5b8135818111156125ba576125ba612554565b604051601f8201601f19908116603f011681019083821181831017156125e2576125e2612554565b816040528281528760208487010111156125fb57600080fd5b826020860160208301376000928101602001929092525095945050505050565b6000806040838503121561262e57600080fd5b8235612639816122e8565b91506020830135801515811461264e57600080fd5b809150509250929050565b60008060008060006080868803121561267157600080fd5b853561267c816122e8565b9450602086013561268c816122e8565b935060408601359250606086013567ffffffffffffffff8111156126af57600080fd5b6126bb888289016124b6565b969995985093965092949392505050565b600080604083850312156126df57600080fd5b82356126ea816122e8565b9150602083013561264e816122e8565b6020808252600e908201526d1050d0d154d4d7d0d3d3951493d360921b604082015260600190565b600181811c9082168061273657607f821691505b60208210810361275657634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b60008261278f57634e487b7160e01b600052601260045260246000fd5b500490565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6000600182016127ca576127ca61275c565b5060010190565b6001600160a01b0394851681529290931660208301526040820152901515606082015260800190565b80820281158282048414176106ea576106ea61275c565b6001600160a01b038681168252851660208201526040810184905260806060820181905281018290526000828460a0840137600060a0848401015260a0601f19601f85011683010190509695505050505050565b60006020828403121561287757600080fd5b5051919050565b60006020828403121561289057600080fd5b81516121d6816122b5565b601f8211156110ca57600081815260208120601f850160051c810160208610156128c25750805b601f850160051c820191505b818110156128e1578281556001016128ce565b505050505050565b815167ffffffffffffffff81111561290357612903612554565b612917816129118454612722565b8461289b565b602080601f83116001811461294c57600084156129345750858301515b600019600386901b1c1916600185901b1785556128e1565b600085815260208120601f198616915b8281101561297b5788860151825594840194600190910190840161295c565b50858210156129995787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600081516129bb818560208601612349565b9290920192915050565b6d2261747472696275746573223a5b60901b81527f7b2274726169745f74797065223a2022436f6c6c656374696f6e204164647265600e8201526e39b9911610113b30b63ab2911d101160891b602e8201528451600090612a2d81603d850160208a01612349565b601160f91b603d918401918201527f7d2c207b2274726169745f74797065223a2022546f6b656e204944222c202276603e8201526730b63ab2911d101160c11b605e8201528551612a85816066840160208a01612349565b01612a9660668201601160f91b9052565b7f7d2c207b2274726169745f74797065223a202245787069726174696f6e222c2060678201527f22646973706c61795f74797065223a202264617465222c202276616c7565223a6087820152600160fd1b60a7820152612b48612b42612aff60a88401886129a9565b7f7d2c207b2274726169745f74797065223a20224465706f7369746f72204164648152703932b9b9911610113b30b63ab2911d101160791b602082015260310190565b856129a9565b62227d5d60e81b8152600301979650505050505050565b6000808454612b6d81612722565b60018281168015612b855760018114612b9a57612bc9565b60ff1984168752821515830287019450612bc9565b8860005260208060002060005b85811015612bc05781548a820152908401908201612ba7565b50505082870194505b505050508351612bdd818360208801612349565b01949350505050565b7f7b226e616d65223a20224c69717569642044656c656761746520230000000000815260008451612c1e81601b850160208901612349565b7f222c20226465736372697074696f6e223a20224c697175696444656c65676174601b918401918201527f65206c65747320796f7520657363726f7720796f757220746f6b656e20666f72603b8201527f20612063686f73656e2074696d65706572696f6420616e642072656365697665605b8201527f2061206c6971756964204e465420726570726573656e74696e67207468652061607b8201527f73736f6369617465642064656c65676174696f6e207269676874732e222c2000609b8201528451612cf38160ba840160208901612349565b6b16101134b6b0b3b2911d101160a11b60ba92909101918201528351612d208160c6840160208801612349565b0160c601612d328161227d60f01b9052565b60020195945050505050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000815260008251612d7681601d850160208701612349565b91909101601d0192915050565b808201808211156106ea576106ea61275c565b634e487b7160e01b600052603260045260246000fd5b600081612dbb57612dbb61275c565b50600019019056fe4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2fa264697066735822122052ce39a167f9d88126cf85a5072571fcf7179e5884acf150cf9c5324688a25ea64736f6c6343000811003300000000000000000000000000000000000076a84fef008cdabe6409d2fe638b000000000000000000000000b69319b9b3eb6cd99f5379b9b3909570f099652a00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000

Deployed Bytecode

0x6080604052600436106101cd5760003560e01c80635dc2d191116100f7578063a22cb46511610095578063c87b56dd11610064578063c87b56dd146105f2578063dce0b4e414610612578063e985e9c514610628578063ecde3c891461066357600080fd5b8063a22cb4651461057d578063aa1b103f1461059d578063b7d86225146105b2578063b88d4fde146105d257600080fd5b806370a08231116100d157806370a08231146104f65780638237e538146105165780638da5cb5b1461054a57806395d89b411461056857600080fd5b80635dc2d191146104235780636352211e146104b6578063693d0df2146104d657600080fd5b806323b872dd1161016f57806342842e0e1161013e57806342842e0e1461038f57806342966c68146103af5780634daadff7146103cf57806355f804b31461040357600080fd5b806323b872dd146102f05780632525b3d7146103105780632a55205a146103305780632bd94e9c1461036f57600080fd5b8063081812fc116101ab578063081812fc1461024b578063095ea7b31461029957806316531556146102b95780631c978922146102cc57600080fd5b806301ffc9a7146101d257806304634d8d1461020757806306fdde0314610229575b600080fd5b3480156101de57600080fd5b506101f26101ed3660046122cb565b610683565b60405190151581526020015b60405180910390f35b34801561021357600080fd5b50610227610222366004612314565b6106f0565b005b34801561023557600080fd5b5061023e610731565b6040516101fe919061236d565b34801561025757600080fd5b506102816102663660046123a0565b6004602052600090815260409020546001600160a01b031681565b6040516001600160a01b0390911681526020016101fe565b3480156102a557600080fd5b506102276102b43660046123b9565b6107bf565b6102276102c73660046123e5565b6108a1565b3480156102d857600080fd5b506102e260095481565b6040519081526020016101fe565b3480156102fc57600080fd5b5061022761030b366004612436565b610a6e565b34801561031c57600080fd5b5061022761032b366004612477565b610c4e565b34801561033c57600080fd5b5061035061034b366004612494565b610c9a565b604080516001600160a01b0390931683526020830191909152016101fe565b34801561037b57600080fd5b5061022761038a3660046124f8565b610d48565b34801561039b57600080fd5b506102276103aa366004612436565b610fd7565b3480156103bb57600080fd5b506102276103ca3660046123a0565b6110cf565b3480156103db57600080fd5b506102817f00000000000000000000000000000000000076a84fef008cdabe6409d2fe638b81565b34801561040f57600080fd5b5061022761041e36600461256a565b6112a1565b34801561042f57600080fd5b5061047c61043e3660046123a0565b6008602052600090815260409020805460018201546002909201546001600160a01b0380831693600160a01b9093046001600160601b031692169084565b604080516001600160a01b0395861681526001600160601b03949094166020850152919093169082015260608101919091526080016101fe565b3480156104c257600080fd5b506102816104d13660046123a0565b6112d7565b3480156104e257600080fd5b506102276104f1366004612477565b61132e565b34801561050257600080fd5b506102e2610511366004612477565b611367565b34801561052257600080fd5b506102e27f15fe000ebb1eecc65da40c712f474e7b6de55062598e11a7289a519792b1e52881565b34801561055657600080fd5b50600b546001600160a01b0316610281565b34801561057457600080fd5b5061023e6113ca565b34801561058957600080fd5b5061022761059836600461261b565b6113d7565b3480156105a957600080fd5b50610227611443565b3480156105be57600080fd5b506102276105cd3660046123a0565b611479565b3480156105de57600080fd5b506102276105ed366004612659565b6114a8565b3480156105fe57600080fd5b5061023e61060d3660046123a0565b611590565b34801561061e57600080fd5b506102e2600a5481565b34801561063457600080fd5b506101f26106433660046126cc565b600560209081526000928352604080842090915290825290205460ff1681565b34801561066f57600080fd5b5061022761067e366004612477565b6116e6565b60006301ffc9a760e01b6001600160e01b0319831614806106b457506380ac58cd60e01b6001600160e01b03198316145b806106cf5750635b5e139f60e01b6001600160e01b03198316145b806106ea575063152a902d60e11b6001600160e01b03198316145b92915050565b600b546001600160a01b031633146107235760405162461bcd60e51b815260040161071a906126fa565b60405180910390fd5b61072d8282611732565b5050565b6000805461073e90612722565b80601f016020809104026020016040519081016040528092919081815260200182805461076a90612722565b80156107b75780601f1061078c576101008083540402835291602001916107b7565b820191906000526020600020905b81548152906001019060200180831161079a57829003601f168201915b505050505081565b6000818152600260205260409020546001600160a01b03163381148061080857506001600160a01b038116600090815260056020908152604080832033845290915290205460ff165b6108455760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b604482015260640161071a565b60008281526004602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b600a5434146108de5760405162461bcd60e51b815260206004820152600960248201526857524f4e475f46454560b81b604482015260640161071a565b6001600160a01b038116158015906108f557503415155b156109105761091081610909600234612772565b600061182f565b6040516323b872dd60e01b81526001600160a01b038516906323b872dd9061094090339030908890600401612794565b600060405180830381600087803b15801561095a57600080fd5b505af115801561096e573d6000803e3d6000fd5b505060408051608081018252338082526001600160601b0380881660208085019182526001600160a01b038c8116868801908152606087018d815260098054600090815260089095529890932096519351909416600160a01b029281169290921785559151600185018054919092166001600160a01b031991909116179055516002909201919091559054610a0693509091506118ce565b600980546001600160a01b038616913391906000610a23836127b8565b90915550604080518781526001600160601b03871660208201527fd54446047dcdfe0e5c18465bf25c2699a49ce7345b2fca5da0de94675c3b8d07910160405180910390a450505050565b600081815260086020908152604091829020825160808101845281546001600160a01b038082168352600160a01b9091046001600160601b0316938201849052600183015416938101939093526002015460608301524210610b245760405162461bcd60e51b815260206004820152602960248201527f6465706f736974206578706972656420616e642063616e6e6f74206265207472604482015268185b9cd9995c9c995960ba1b606482015260840161071a565b6040808201516060830151915163537a5c3d60e01b81526001600160a01b037f00000000000000000000000000000000000076a84fef008cdabe6409d2fe638b169263537a5c3d92610b7e928992906000906004016127d1565b600060405180830381600087803b158015610b9857600080fd5b505af1158015610bac573d6000803e3d6000fd5b505050507f00000000000000000000000000000000000076a84fef008cdabe6409d2fe638b6001600160a01b031663537a5c3d848360400151846060015160016040518563ffffffff1660e01b8152600401610c0b94939291906127d1565b600060405180830381600087803b158015610c2557600080fd5b505af1158015610c39573d6000803e3d6000fd5b50505050610c488484846119b1565b50505050565b600b546001600160a01b03163314610c785760405162461bcd60e51b815260040161071a906126fa565b600b80546001600160a01b0319166001600160a01b0392909216919091179055565b60008281526007602090815260408083208151808301909252546001600160a01b038116808352600160a01b9091046001600160601b0316928201929092528291610d0f5750604080518082019091526006546001600160a01b0381168252600160a01b90046001600160601b031660208201525b602081015160009061271090610d2e906001600160601b0316876127fa565b610d389190612772565b91519350909150505b9250929050565b600084815260086020908152604091829020825160808101845281546001600160a01b038082168352600160a01b9091046001600160601b031693820193909352600182015490921692820192909252600290910154606082015233610dad866112d7565b6001600160a01b031614610e0f5760405162461bcd60e51b815260206004820152602360248201527f63616e206f6e6c7920666c6173686c6f616e20796f7572206f776e207469636b60448201526265747360e81b606482015260840161071a565b80604001516001600160a01b03166323b872dd308684606001516040518463ffffffff1660e01b8152600401610e4793929190612794565b600060405180830381600087803b158015610e6157600080fd5b505af1158015610e75573d6000803e3d6000fd5b5050506040808301516060840151915163300322db60e21b81527f15fe000ebb1eecc65da40c712f474e7b6de55062598e11a7289a519792b1e52893506001600160a01b0388169263c00c8b6c92610ed6923392908a908a90600401612811565b6020604051808303816000875af1158015610ef5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f199190612865565b14610f665760405162461bcd60e51b815260206004820152601c60248201527f466c6173684c656e6465723a2043616c6c6261636b206661696c656400000000604482015260640161071a565b80604001516001600160a01b03166323b872dd853084606001516040518463ffffffff1660e01b8152600401610f9e93929190612794565b600060405180830381600087803b158015610fb857600080fd5b505af1158015610fcc573d6000803e3d6000fd5b505050505050505050565b610fe2838383610a6e565b6001600160a01b0382163b158061108b5750604051630a85bd0160e11b8082523360048301526001600160a01b03858116602484015260448301849052608060648401526000608484015290919084169063150b7a029060a4016020604051808303816000875af115801561105b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061107f919061287e565b6001600160e01b031916145b6110ca5760405162461bcd60e51b815260206004820152601060248201526f155394d0519157d49150d2541251539560821b604482015260640161071a565b505050565b600081815260086020908152604091829020825160808101845281546001600160a01b038082168352600160a01b9091046001600160601b031693820193909352600182015490921692820192909252600290910154606082015233611134836112d7565b6001600160a01b03161480611156575080602001516001600160601b03164210155b6111915760405162461bcd60e51b815260206004820152600c60248201526b24a72b20a624a22fa12aa92760a11b604482015260640161071a565b61119a82611b78565b6040808201518251606084015192516323b872dd60e01b81526001600160a01b03909216926323b872dd926111d59230929091600401612794565b600060405180830381600087803b1580156111ef57600080fd5b505af1158015611203573d6000803e3d6000fd5b5050505080604001516001600160a01b031681600001516001600160a01b0316837f38b768306af3c9319ae2f926fd65a8fb10e917b5544887126c57c3838d6b0ea38460600151856020015160405161126f9291909182526001600160601b0316602082015260400190565b60405180910390a45060009081526008602052604081208181556001810180546001600160a01b031916905560020155565b600c546001600160a01b031633146112cb5760405162461bcd60e51b815260040161071a906126fa565b600d61072d82826128e9565b6000818152600260205260409020546001600160a01b0316806113295760405162461bcd60e51b815260206004820152600a6024820152691393d517d3525395115160b21b604482015260640161071a565b919050565b600b546001600160a01b031633146113585760405162461bcd60e51b815260040161071a906126fa565b6113648147600161182f565b50565b60006001600160a01b0382166113ae5760405162461bcd60e51b815260206004820152600c60248201526b5a45524f5f4144445245535360a01b604482015260640161071a565b506001600160a01b031660009081526003602052604090205490565b6001805461073e90612722565b3360008181526005602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b600b546001600160a01b0316331461146d5760405162461bcd60e51b815260040161071a906126fa565b6114776000600655565b565b600b546001600160a01b031633146114a35760405162461bcd60e51b815260040161071a906126fa565b600a55565b6114b3858585610a6e565b6001600160a01b0384163b158061154a5750604051630a85bd0160e11b808252906001600160a01b0386169063150b7a02906114fb9033908a90899089908990600401612811565b6020604051808303816000875af115801561151a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061153e919061287e565b6001600160e01b031916145b6115895760405162461bcd60e51b815260206004820152601060248201526f155394d0519157d49150d2541251539560821b604482015260640161071a565b5050505050565b6000818152600860209081526040808320815160808101835281546001600160a01b038082168352600160a01b9091046001600160601b03169482019490945260018201549093169183018290526002015460608084019190915292906115f690611c66565b6116038360600151611c7c565b61161984602001516001600160601b0316611c7c565b845161162d906001600160a01b0316611c66565b60405160200161164094939291906129c5565b60405160208183030381529060405290506000600d61165e86611c7c565b60405160200161166f929190612b5f565b6040516020818303038152906040529050600061168b86611c7c565b838360405160200161169f93929190612be6565b604051602081830303815290604052905060006116bb82611d0f565b6040516020016116cb9190612d3e565b60408051601f19818403018152919052979650505050505050565b600c546001600160a01b031633146117105760405162461bcd60e51b815260040161071a906126fa565b600c80546001600160a01b0319166001600160a01b0392909216919091179055565b6127106001600160601b03821611156117a05760405162461bcd60e51b815260206004820152602a60248201527f455243323938313a20726f79616c7479206665652077696c6c206578636565646044820152692073616c65507269636560b01b606482015260840161071a565b6001600160a01b0382166117f65760405162461bcd60e51b815260206004820152601960248201527f455243323938313a20696e76616c696420726563656976657200000000000000604482015260640161071a565b604080518082019091526001600160a01b039092168083526001600160601b039091166020909201829052600160a01b90910217600655565b6000836001600160a01b03168360405160006040518083038185875af1925050503d806000811461187c576040519150601f19603f3d011682016040523d82523d6000602084013e611881565b606091505b50509050808061188e5750815b610c485760405162461bcd60e51b815260206004820152601160248201527014d1539117d15512115497d19052531151607a1b604482015260640161071a565b600081815260086020908152604091829020825160808101845281546001600160a01b038082168352600160a01b9091046001600160601b031693820193909352600180830154841682860181905260029093015460608301819052945163537a5c3d60e01b815291947f00000000000000000000000000000000000076a84fef008cdabe6409d2fe638b9094169363537a5c3d93611975938993919291906004016127d1565b600060405180830381600087803b15801561198f57600080fd5b505af11580156119a3573d6000803e3d6000fd5b505050506110ca8383611e62565b6000818152600260205260409020546001600160a01b03848116911614611a075760405162461bcd60e51b815260206004820152600a60248201526957524f4e475f46524f4d60b01b604482015260640161071a565b6001600160a01b038216611a515760405162461bcd60e51b81526020600482015260116024820152701253959053125117d49150d25412515395607a1b604482015260640161071a565b336001600160a01b0384161480611a8b57506001600160a01b038316600090815260056020908152604080832033845290915290205460ff165b80611aac57506000818152600460205260409020546001600160a01b031633145b611ae95760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b604482015260640161071a565b6001600160a01b0380841660008181526003602090815260408083208054600019019055938616808352848320805460010190558583526002825284832080546001600160a01b03199081168317909155600490925284832080549092169091559251849392917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b600081815260086020908152604091829020825160808101845281546001600160a01b038082168352600160a01b9091046001600160601b03169382019390935260018201548316938101939093526002015460608301527f00000000000000000000000000000000000076a84fef008cdabe6409d2fe638b1663537a5c3d611c00846112d7565b8360400151846060015160006040518563ffffffff1660e01b8152600401611c2b94939291906127d1565b600060405180830381600087803b158015611c4557600080fd5b505af1158015611c59573d6000803e3d6000fd5b5050505061072d82611f6d565b60606106ea6001600160a01b038316601461203a565b60606000611c89836121dd565b600101905060008167ffffffffffffffff811115611ca957611ca9612554565b6040519080825280601f01601f191660200182016040528015611cd3576020820181803683370190505b5090508181016020015b600019016f181899199a1a9b1b9c1cb0b131b232b360811b600a86061a8153600a8504945084611cdd57509392505050565b60608151600003611d2e57505060408051602081019091526000815290565b6000604051806060016040528060408152602001612dc46040913990506000600384516002611d5d9190612d83565b611d679190612772565b611d729060046127fa565b67ffffffffffffffff811115611d8a57611d8a612554565b6040519080825280601f01601f191660200182016040528015611db4576020820181803683370190505b509050600182016020820185865187015b80821015611e20576003820191508151603f8160121c168501518453600184019350603f81600c1c168501518453600184019350603f8160061c168501518453600184019350603f8116850151845350600183019250611dc5565b5050600386510660018114611e3c5760028114611e4f57611e57565b603d6001830353603d6002830353611e57565b603d60018303535b509195945050505050565b6001600160a01b038216611eac5760405162461bcd60e51b81526020600482015260116024820152701253959053125117d49150d25412515395607a1b604482015260640161071a565b6000818152600260205260409020546001600160a01b031615611f025760405162461bcd60e51b815260206004820152600e60248201526d1053149150511657d3525395115160921b604482015260640161071a565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b6000818152600260205260409020546001600160a01b031680611fbf5760405162461bcd60e51b815260206004820152600a6024820152691393d517d3525395115160b21b604482015260640161071a565b6001600160a01b038116600081815260036020908152604080832080546000190190558583526002825280832080546001600160a01b031990811690915560049092528083208054909216909155518492907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908390a45050565b606060006120498360026127fa565b612054906002612d83565b67ffffffffffffffff81111561206c5761206c612554565b6040519080825280601f01601f191660200182016040528015612096576020820181803683370190505b509050600360fc1b816000815181106120b1576120b1612d96565b60200101906001600160f81b031916908160001a905350600f60fb1b816001815181106120e0576120e0612d96565b60200101906001600160f81b031916908160001a90535060006121048460026127fa565b61210f906001612d83565b90505b6001811115612187576f181899199a1a9b1b9c1cb0b131b232b360811b85600f166010811061214357612143612d96565b1a60f81b82828151811061215957612159612d96565b60200101906001600160f81b031916908160001a90535060049490941c9361218081612dac565b9050612112565b5083156121d65760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e74604482015260640161071a565b9392505050565b60008072184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b831061221c5772184f03e93ff9f4daa797ed6e38ed64bf6a1f0160401b830492506040015b6d04ee2d6d415b85acef81000000008310612248576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc10000831061226657662386f26fc10000830492506010015b6305f5e100831061227e576305f5e100830492506008015b612710831061229257612710830492506004015b606483106122a4576064830492506002015b600a83106106ea5760010192915050565b6001600160e01b03198116811461136457600080fd5b6000602082840312156122dd57600080fd5b81356121d6816122b5565b6001600160a01b038116811461136457600080fd5b80356001600160601b038116811461132957600080fd5b6000806040838503121561232757600080fd5b8235612332816122e8565b9150612340602084016122fd565b90509250929050565b60005b8381101561236457818101518382015260200161234c565b50506000910152565b602081526000825180602084015261238c816040850160208701612349565b601f01601f19169190910160400192915050565b6000602082840312156123b257600080fd5b5035919050565b600080604083850312156123cc57600080fd5b82356123d7816122e8565b946020939093013593505050565b600080600080608085870312156123fb57600080fd5b8435612406816122e8565b93506020850135925061241b604086016122fd565b9150606085013561242b816122e8565b939692955090935050565b60008060006060848603121561244b57600080fd5b8335612456816122e8565b92506020840135612466816122e8565b929592945050506040919091013590565b60006020828403121561248957600080fd5b81356121d6816122e8565b600080604083850312156124a757600080fd5b50508035926020909101359150565b60008083601f8401126124c857600080fd5b50813567ffffffffffffffff8111156124e057600080fd5b602083019150836020828501011115610d4157600080fd5b6000806000806060858703121561250e57600080fd5b843593506020850135612520816122e8565b9250604085013567ffffffffffffffff81111561253c57600080fd5b612548878288016124b6565b95989497509550505050565b634e487b7160e01b600052604160045260246000fd5b60006020828403121561257c57600080fd5b813567ffffffffffffffff8082111561259457600080fd5b818401915084601f8301126125a857600080fd5b8135818111156125ba576125ba612554565b604051601f8201601f19908116603f011681019083821181831017156125e2576125e2612554565b816040528281528760208487010111156125fb57600080fd5b826020860160208301376000928101602001929092525095945050505050565b6000806040838503121561262e57600080fd5b8235612639816122e8565b91506020830135801515811461264e57600080fd5b809150509250929050565b60008060008060006080868803121561267157600080fd5b853561267c816122e8565b9450602086013561268c816122e8565b935060408601359250606086013567ffffffffffffffff8111156126af57600080fd5b6126bb888289016124b6565b969995985093965092949392505050565b600080604083850312156126df57600080fd5b82356126ea816122e8565b9150602083013561264e816122e8565b6020808252600e908201526d1050d0d154d4d7d0d3d3951493d360921b604082015260600190565b600181811c9082168061273657607f821691505b60208210810361275657634e487b7160e01b600052602260045260246000fd5b50919050565b634e487b7160e01b600052601160045260246000fd5b60008261278f57634e487b7160e01b600052601260045260246000fd5b500490565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6000600182016127ca576127ca61275c565b5060010190565b6001600160a01b0394851681529290931660208301526040820152901515606082015260800190565b80820281158282048414176106ea576106ea61275c565b6001600160a01b038681168252851660208201526040810184905260806060820181905281018290526000828460a0840137600060a0848401015260a0601f19601f85011683010190509695505050505050565b60006020828403121561287757600080fd5b5051919050565b60006020828403121561289057600080fd5b81516121d6816122b5565b601f8211156110ca57600081815260208120601f850160051c810160208610156128c25750805b601f850160051c820191505b818110156128e1578281556001016128ce565b505050505050565b815167ffffffffffffffff81111561290357612903612554565b612917816129118454612722565b8461289b565b602080601f83116001811461294c57600084156129345750858301515b600019600386901b1c1916600185901b1785556128e1565b600085815260208120601f198616915b8281101561297b5788860151825594840194600190910190840161295c565b50858210156129995787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600081516129bb818560208601612349565b9290920192915050565b6d2261747472696275746573223a5b60901b81527f7b2274726169745f74797065223a2022436f6c6c656374696f6e204164647265600e8201526e39b9911610113b30b63ab2911d101160891b602e8201528451600090612a2d81603d850160208a01612349565b601160f91b603d918401918201527f7d2c207b2274726169745f74797065223a2022546f6b656e204944222c202276603e8201526730b63ab2911d101160c11b605e8201528551612a85816066840160208a01612349565b01612a9660668201601160f91b9052565b7f7d2c207b2274726169745f74797065223a202245787069726174696f6e222c2060678201527f22646973706c61795f74797065223a202264617465222c202276616c7565223a6087820152600160fd1b60a7820152612b48612b42612aff60a88401886129a9565b7f7d2c207b2274726169745f74797065223a20224465706f7369746f72204164648152703932b9b9911610113b30b63ab2911d101160791b602082015260310190565b856129a9565b62227d5d60e81b8152600301979650505050505050565b6000808454612b6d81612722565b60018281168015612b855760018114612b9a57612bc9565b60ff1984168752821515830287019450612bc9565b8860005260208060002060005b85811015612bc05781548a820152908401908201612ba7565b50505082870194505b505050508351612bdd818360208801612349565b01949350505050565b7f7b226e616d65223a20224c69717569642044656c656761746520230000000000815260008451612c1e81601b850160208901612349565b7f222c20226465736372697074696f6e223a20224c697175696444656c65676174601b918401918201527f65206c65747320796f7520657363726f7720796f757220746f6b656e20666f72603b8201527f20612063686f73656e2074696d65706572696f6420616e642072656365697665605b8201527f2061206c6971756964204e465420726570726573656e74696e67207468652061607b8201527f73736f6369617465642064656c65676174696f6e207269676874732e222c2000609b8201528451612cf38160ba840160208901612349565b6b16101134b6b0b3b2911d101160a11b60ba92909101918201528351612d208160c6840160208801612349565b0160c601612d328161227d60f01b9052565b60020195945050505050565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000815260008251612d7681601d850160208701612349565b91909101601d0192915050565b808201808211156106ea576106ea61275c565b634e487b7160e01b600052603260045260246000fd5b600081612dbb57612dbb61275c565b50600019019056fe4142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2fa264697066735822122052ce39a167f9d88126cf85a5072571fcf7179e5884acf150cf9c5324688a25ea64736f6c63430008110033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

00000000000000000000000000000000000076a84fef008cdabe6409d2fe638b000000000000000000000000b69319b9b3eb6cd99f5379b9b3909570f099652a00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : _DELEGATION_REGISTRY (address): 0x00000000000076A84feF008CDAbe6409d2FE638B
Arg [1] : owner (address): 0xB69319B9B3Eb6cD99f5379b9b3909570F099652a
Arg [2] : _baseURI (string):

-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000000076a84fef008cdabe6409d2fe638b
Arg [1] : 000000000000000000000000b69319b9b3eb6cd99f5379b9b3909570f099652a
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000060
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000000


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.