ETH Price: $3,435.58 (-1.46%)

Contract

0xA65178961D63964F2AC2515Ca243175Ad440F927
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Redeem Elemental...214582412024-12-22 13:09:473 days ago1734872987IN
0xA6517896...Ad440F927
0 ETH0.000900517.07925192
Redeem Elemental...214324622024-12-18 22:41:237 days ago1734561683IN
0xA6517896...Ad440F927
0 ETH0.007894316.29926054
Redeem Elemental...213930902024-12-13 10:48:1112 days ago1734086891IN
0xA6517896...Ad440F927
0 ETH0.0057381317.71298368
Redeem Elemental...213930772024-12-13 10:45:1112 days ago1734086711IN
0xA6517896...Ad440F927
0 ETH0.0078781513.32440086
Redeem Derivativ...209521962024-10-12 21:26:4774 days ago1728768407IN
0xA6517896...Ad440F927
0 ETH0.0014808711.64144004
Redeem Derivativ...206224162024-08-27 20:49:11120 days ago1724791751IN
0xA6517896...Ad440F927
0 ETH0.000197531.55259418
Redeem Derivativ...206013712024-08-24 22:14:35123 days ago1724537675IN
0xA6517896...Ad440F927
0 ETH0.000636391.31389476
Redeem Derivativ...204517462024-08-04 0:57:23144 days ago1722733043IN
0xA6517896...Ad440F927
0 ETH0.000142111.11702703
Redeem Derivativ...203033002024-07-14 7:38:35164 days ago1720942715IN
0xA6517896...Ad440F927
0 ETH0.000339662.67003312
Redeem Derivativ...202898892024-07-12 10:41:23166 days ago1720780883IN
0xA6517896...Ad440F927
0 ETH0.000381583
Redeem Derivativ...202478922024-07-06 13:53:59172 days ago1720274039IN
0xA6517896...Ad440F927
0 ETH0.000377992.97178047
Redeem Elemental...200926952024-06-14 21:20:35194 days ago1718400035IN
0xA6517896...Ad440F927
0 ETH0.001043638.20513973
Redeem Derivativ...200503052024-06-08 23:10:23200 days ago1717888223IN
0xA6517896...Ad440F927
0 ETH0.001685984.94317963
Redeem Elemental...200360422024-06-06 23:22:59202 days ago1717716179IN
0xA6517896...Ad440F927
0 ETH0.0051777818.00611287
Redeem Derivativ...198531952024-05-12 9:58:23227 days ago1715507903IN
0xA6517896...Ad440F927
0 ETH0.00038933.53571821
Redeem Derivativ...196647262024-04-16 1:18:47254 days ago1713230327IN
0xA6517896...Ad440F927
0 ETH0.000840657.6348649
Redeem Derivativ...196449342024-04-13 6:41:35256 days ago1712990495IN
0xA6517896...Ad440F927
0 ETH0.001374110.80045452
Redeem Derivativ...195984202024-04-06 18:17:35263 days ago1712427455IN
0xA6517896...Ad440F927
0 ETH0.001646112.94039615
Redeem Elemental...195087792024-03-25 3:16:35276 days ago1711336595IN
0xA6517896...Ad440F927
0 ETH0.0027551315.25248495
Redeem Derivativ...195087662024-03-25 3:13:59276 days ago1711336439IN
0xA6517896...Ad440F927
0 ETH0.0082331514.83667184
Redeem Derivativ...194498712024-03-16 20:37:59284 days ago1710621479IN
0xA6517896...Ad440F927
0 ETH0.0044604235.06433025
Redeem Derivativ...193123172024-02-26 14:24:47303 days ago1708957487IN
0xA6517896...Ad440F927
0 ETH0.0096736976.04688692
Redeem Elemental...190656572024-01-22 23:57:23338 days ago1705967843IN
0xA6517896...Ad440F927
0 ETH0.0043656410.13235008
Redeem Elemental...190656522024-01-22 23:56:23338 days ago1705967783IN
0xA6517896...Ad440F927
0 ETH0.0065018510.99664965
Redeem Elemental...190656442024-01-22 23:54:47338 days ago1705967687IN
0xA6517896...Ad440F927
0 ETH0.0070867611.64900706
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block
From
To
214582412024-12-22 13:09:473 days ago1734872987
0xA6517896...Ad440F927
0 ETH
214582412024-12-22 13:09:473 days ago1734872987
0xA6517896...Ad440F927
0 ETH
214582412024-12-22 13:09:473 days ago1734872987
0xA6517896...Ad440F927
0 ETH
214324622024-12-18 22:41:237 days ago1734561683
0xA6517896...Ad440F927
0 ETH
214324622024-12-18 22:41:237 days ago1734561683
0xA6517896...Ad440F927
0 ETH
214324622024-12-18 22:41:237 days ago1734561683
0xA6517896...Ad440F927
0 ETH
214324622024-12-18 22:41:237 days ago1734561683
0xA6517896...Ad440F927
0 ETH
214324622024-12-18 22:41:237 days ago1734561683
0xA6517896...Ad440F927
0 ETH
214324622024-12-18 22:41:237 days ago1734561683
0xA6517896...Ad440F927
0 ETH
214324622024-12-18 22:41:237 days ago1734561683
0xA6517896...Ad440F927
0 ETH
214324622024-12-18 22:41:237 days ago1734561683
0xA6517896...Ad440F927
0 ETH
214324622024-12-18 22:41:237 days ago1734561683
0xA6517896...Ad440F927
0 ETH
214324622024-12-18 22:41:237 days ago1734561683
0xA6517896...Ad440F927
0 ETH
213930902024-12-13 10:48:1112 days ago1734086891
0xA6517896...Ad440F927
0 ETH
213930902024-12-13 10:48:1112 days ago1734086891
0xA6517896...Ad440F927
0 ETH
213930902024-12-13 10:48:1112 days ago1734086891
0xA6517896...Ad440F927
0 ETH
213930902024-12-13 10:48:1112 days ago1734086891
0xA6517896...Ad440F927
0 ETH
213930902024-12-13 10:48:1112 days ago1734086891
0xA6517896...Ad440F927
0 ETH
213930902024-12-13 10:48:1112 days ago1734086891
0xA6517896...Ad440F927
0 ETH
213930902024-12-13 10:48:1112 days ago1734086891
0xA6517896...Ad440F927
0 ETH
213930772024-12-13 10:45:1112 days ago1734086711
0xA6517896...Ad440F927
0 ETH
213930772024-12-13 10:45:1112 days ago1734086711
0xA6517896...Ad440F927
0 ETH
213930772024-12-13 10:45:1112 days ago1734086711
0xA6517896...Ad440F927
0 ETH
213930772024-12-13 10:45:1112 days ago1734086711
0xA6517896...Ad440F927
0 ETH
213930772024-12-13 10:45:1112 days ago1734086711
0xA6517896...Ad440F927
0 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
DoubleDrop

Compiler Version
v0.8.16+commit.07a7930e

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 11 : DoubleDrop.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;

import "openzeppelin-contracts/contracts/token/ERC721/IERC721.sol";
import "openzeppelin-contracts/contracts/access/Ownable.sol";

import "./IDoubleDropNFT.sol";
import "./IDoubleDrop.sol";
import "./IProvenance.sol";
import "./SignedRedeemer.sol";

/// @title The Hashmasks Double Drop
/// @author fancyrats.io
/**
 * @notice Holders of Hashmasks NFTs can redeem Hashmasks Elementals, Derivatives, or burn their masks to get both!
 * Holders can only choose one redemption option per Hashmask NFT.
 * Once a selection is made, that NFT cannot be used to redeem again! Choose wisely!
 */
/**
 * @dev Hashmasks holders must set approval for this contract in order to "burn".
 * The original Hashmasks contract does not have burn functionality, so we move masks into the 0xdEaD wallet.
 * Elementals and Derivatives contracts must be deployed and addresses set prior to activating redemption.
 */
contract DoubleDrop is IDoubleDrop, Ownable, SignedRedeemer {
    event ElementalsRedeemed(uint256[] indexed tokenIds, address indexed redeemer);
    event DerivativesRedeemed(uint256[] indexed tokenIds, address indexed redeemer);
    event HashmasksBurned(uint256[] indexed tokenIds, address indexed redeemer);

    address private constant BURN_ADDRESS = 0x000000000000000000000000000000000000dEaD;

    bool public isActive;
    bool public contractsInitialized;

    uint256 public elementalsProvenance;

    mapping(uint256 => bool) public redeemedHashmasks;

    IERC721 public hashmasks;
    IDoubleDropNFT public derivatives;
    IDoubleDropNFT public elementals;

    constructor(address signer_) Ownable() SignedRedeemer(signer_) {}

    /// @notice Redeem Hashmasks Elementals NFTs
    /// @dev Resulting Elementals will have matching token IDs.
    /// @param signature Signed message from our website that validates token ownership
    /// @param tokenIds Ordered array of Hashmasks NFT ids used to claim the Elementals.
    function redeemElementals(bytes calldata signature, uint256[] calldata tokenIds)
        public
        isValidRedemption(signature, tokenIds)
    {
        emit ElementalsRedeemed(tokenIds, msg.sender);
        elementals.redeem(tokenIds, msg.sender);
    }

    /// @notice Redeem Hashmasks Derivatives NFTs
    /// @dev Resulting Derivatives will have matching token IDs.
    /// @param signature Signed message from our website that validates token ownership
    /// @param tokenIds Ordered array of Hashmasks NFT ids used to claim the Derivatives.
    function redeemDerivatives(bytes calldata signature, uint256[] calldata tokenIds)
        public
        isValidRedemption(signature, tokenIds)
    {
        emit DerivativesRedeemed(tokenIds, msg.sender);
        derivatives.redeem(tokenIds, msg.sender);
    }

    /**
     * @notice Burns Hashmasks and redeems one elemental and one derivative per Hashmask burned.
     * Requires this contract to be approved as an operator for the Hashmasks tokens provided.
     * CAUTION: ONLY APPROVE OR SETAPPROVALFORALL FROM THEHASHMASKS.COM
     * CAUTION: THIS ACTION IS PERMANENT. Holders will not be able to retrieve their burned Hashmask NFTs.
     */
    /**
     * @dev Resulting Derivatives and Elementals will have matching token IDs.
     *  Approval must be managed on the frontend.
     */
    /// @param signature Signed message from our website that validates token ownership
    /// @param tokenIds Ordered array of Hashmasks NFT ids to burn and use for double redemption
    function burnMasksForDoubleRedemption(bytes calldata signature, uint256[] calldata tokenIds)
        public
        isValidRedemption(signature, tokenIds)
    {
        emit HashmasksBurned(tokenIds, msg.sender);
        emit ElementalsRedeemed(tokenIds, msg.sender);
        emit DerivativesRedeemed(tokenIds, msg.sender);

        _burnMasks(tokenIds);
        elementals.redeem(tokenIds, msg.sender);
        derivatives.redeem(tokenIds, msg.sender);
    }

    /**
     * @notice Sets the Derivatives and Elementals contract addresses for redemption.
     * Caller must be contract owner.
     * CAUTION: ADDRESSES CAN ONLY BE SET ONCE.
     */
    /// @dev derivativesAddress and elementalsAddress must conform to IDoubleDropNFT
    /// @param hashmasksAddress The Hashmasks NFT contract address
    /// @param derivativesAddress The Hashmasks Derivatives NFT contract address
    /// @param elementalsAddress The Hashmasks Elementals NFT contract address
    function setTokenContracts(address hashmasksAddress, address derivativesAddress, address elementalsAddress)
        public
        onlyOwner
    {
        if (contractsInitialized) revert ContractsAlreadyInitialized();
        if (hashmasksAddress == address(0) || derivativesAddress == address(0) || elementalsAddress == address(0)) {
            revert ContractsCannotBeNull();
        }

        contractsInitialized = true;
        hashmasks = IERC721(hashmasksAddress);
        derivatives = IDoubleDropNFT(derivativesAddress);
        elementals = IDoubleDropNFT(elementalsAddress);
    }

    /**
     * @notice Asks the ProvenanceGenerator for a random number
     * Caller must be contract owner
     * Can only be set once
     */
    /// @dev Provenance implementation uses chainlink, so that will need setup first
    /// @param generatorAddress Contract conforming to IProvenance
    function setRandomProvenance(address generatorAddress) public onlyOwner {
        if (elementalsProvenance != 0) revert ElementalsProvenanceAlreadySet();
        if (generatorAddress == address(0)) revert ProvenanceContractCannotBeNull();

        IProvenance provenanceGenerator = IProvenance(generatorAddress);
        elementalsProvenance = provenanceGenerator.getRandomProvenance();

        if (elementalsProvenance == 0) revert ElementalsProvenanceNotSet();
    }

    /**
     * @notice Sets the known signer address used by the redemption backend to validate ownership
     * Caller must be contract owner.
     */
    /// @dev signer is responsible for signing redemption messages on the backend
    /// @param signer_ public address to expected to sign redemption signatures
    function setSigner(address signer_) public onlyOwner {
        _setSigner(signer_);
    }

    /**
     * @notice Turn on/off Double Drop redemption.
     * Starts out paused.
     * Caller must be contract owner.
     */
    /// @dev setTokenContracts must be called prior to activating.
    /// @param isActive_ updated redemption active status. false to pause. true to resume.
    function setIsActive(bool isActive_) public onlyOwner {
        if (address(hashmasks) == address(0) || address(derivatives) == address(0) || address(elementals) == address(0))
        {
            revert ContractsNotInitialized();
        }
        if (elementalsProvenance == 0) revert ElementalsProvenanceNotSet();
        isActive = isActive_;
    }

    function _burnMasks(uint256[] calldata tokenIds) private {
        for (uint256 i = 0; i < tokenIds.length; i++) {
            hashmasks.safeTransferFrom(msg.sender, BURN_ADDRESS, tokenIds[i]);
        }
    }

    modifier isValidRedemption(bytes calldata signature, uint256[] calldata tokenIds) {
        if (!isActive) revert RedemptionNotActive();
        if (!validateSignature(signature, tokenIds, msg.sender)) revert InvalidSignature();
        for (uint256 i = 0; i < tokenIds.length; i++) {
            if (hashmasks.ownerOf(tokenIds[i]) != msg.sender) revert NotTokenOwner();
            if (redeemedHashmasks[tokenIds[i]]) revert TokenAlreadyRedeemed();
            redeemedHashmasks[tokenIds[i]] = true;
        }
        _;
    }
}

File 2 of 11 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

File 3 of 11 : IERC721.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.0;

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

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes calldata data
    ) external;

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the caller.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool _approved) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);
}

File 4 of 11 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

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

pragma solidity ^0.8.0;

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _HEX_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) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

        if (value == 0) {
            return "0";
        }
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return "0x00";
        }
        uint256 temp = value;
        uint256 length = 0;
        while (temp != 0) {
            length++;
            temp >>= 8;
        }
        return toHexString(value, length);
    }

    /**
     * @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] = _HEX_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);
    }
}

File 6 of 11 : ECDSA.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/ECDSA.sol)

pragma solidity ^0.8.0;

import "../Strings.sol";

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    enum RecoverError {
        NoError,
        InvalidSignature,
        InvalidSignatureLength,
        InvalidSignatureS,
        InvalidSignatureV
    }

    function _throwError(RecoverError error) private pure {
        if (error == RecoverError.NoError) {
            return; // no error: do nothing
        } else if (error == RecoverError.InvalidSignature) {
            revert("ECDSA: invalid signature");
        } else if (error == RecoverError.InvalidSignatureLength) {
            revert("ECDSA: invalid signature length");
        } else if (error == RecoverError.InvalidSignatureS) {
            revert("ECDSA: invalid signature 's' value");
        } else if (error == RecoverError.InvalidSignatureV) {
            revert("ECDSA: invalid signature 'v' value");
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature` or error string. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     *
     * _Available since v4.3._
     */
    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
        // Check the signature length
        // - case 65: r,s,v signature (standard)
        // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            /// @solidity memory-safe-assembly
            assembly {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            return tryRecover(hash, v, r, s);
        } else if (signature.length == 64) {
            bytes32 r;
            bytes32 vs;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            /// @solidity memory-safe-assembly
            assembly {
                r := mload(add(signature, 0x20))
                vs := mload(add(signature, 0x40))
            }
            return tryRecover(hash, r, vs);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength);
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, signature);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
     *
     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
     *
     * _Available since v4.3._
     */
    function tryRecover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal pure returns (address, RecoverError) {
        bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
        uint8 v = uint8((uint256(vs) >> 255) + 27);
        return tryRecover(hash, v, r, s);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
     *
     * _Available since v4.2._
     */
    function recover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, r, vs);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
     * `r` and `s` signature fields separately.
     *
     * _Available since v4.3._
     */
    function tryRecover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address, RecoverError) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return (address(0), RecoverError.InvalidSignatureS);
        }
        if (v != 27 && v != 28) {
            return (address(0), RecoverError.InvalidSignatureV);
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        if (signer == address(0)) {
            return (address(0), RecoverError.InvalidSignature);
        }

        return (signer, RecoverError.NoError);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from a `hash`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
        // 32 is the length in bytes of hash,
        // enforced by the type signature above
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from `s`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
    }

    /**
     * @dev Returns an Ethereum Signed Typed Data, created from a
     * `domainSeparator` and a `structHash`. This produces hash corresponding
     * to the one signed with the
     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
     * JSON-RPC method as part of EIP-712.
     *
     * See {recover}.
     */
    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
    }
}

File 7 of 11 : 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 11 : IDoubleDrop.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;

interface IDoubleDrop {
    /**
      * Elementals provenance contract cannot be null
      */
    error ProvenanceContractCannotBeNull();

    /**
      * Elementals provenance not set
      */
    error ElementalsProvenanceNotSet();

    /**
      * Elementals provenance already set
      */
    error ElementalsProvenanceAlreadySet();

    /**
     * Redemption contracts already set
     */
    error ContractsAlreadyInitialized();

    /**
     * Redemption contracts cannot be NULL
     */
    error ContractsCannotBeNull();

    /**
     * Redemption contracts are not yet set
     */
    error ContractsNotInitialized();

    /**
     * Redemption is not active
     */
    error RedemptionNotActive();

    /**
     * Invalid signature provided
     */
    error InvalidSignature();

    /**
     * Hashmask token already used for redemption
     */
    error TokenAlreadyRedeemed();

    /**
     * Address is not the token owner
     */
    error NotTokenOwner();
}

File 9 of 11 : IDoubleDropNFT.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;

interface IDoubleDropNFT {
    /**
     * The token does not exist.
     */
    error URIQueryForNonexistentToken();

    /**
     * Metadata frozen. Cannot set new base URI.
     */
    error MetadataFrozen();

    /**
     * Cannot set redeemer contract multiple times
     */
    error RedeemerAlreadySet();

    /**
     * Redeemer contract not set
     */
    error RedeemerNotSet();

    /**
     * Only the redeemer contract can mint
     */
    error OnlyRedeemerCanMint();

    function redeem(uint256[] calldata _tokenIds, address _to) external;
}

File 10 of 11 : IProvenance.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;

interface IProvenance {
    function getRandomProvenance() external returns (uint256);

    error ProvenanceAlreadyRequested();
    error ProvenanceAlreadyGenerated();
    error ProvenanceNotGenerated();
}

File 11 of 11 : SignedRedeemer.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;

import "openzeppelin-contracts/contracts/utils/cryptography/ECDSA.sol";

contract SignedRedeemer {
    using ECDSA for bytes32;

    address public signer;

    constructor(address signer_) {
        signer = signer_;
    }

    /**
     * @notice Uses ECDSA to validate the provided signature was signed by the known address.
     */
    /**
     * @dev For a given unique ordered array of tokenIds,
     * a valid signature is a message keccack256(abi.encode(owner, tokenIds)) signed by the known address.
     */
    /// @param signature Signed message
    /// @param tokenIds ordered unique array of tokenIds encoded in the signed message
    /// @param to token owner encoded in the signed message
    function validateSignature(
        bytes memory signature,
        uint256[] calldata tokenIds, // must be in numeric order
        address to
    ) public view returns (bool) {
        bytes memory message = abi.encode(to, tokenIds);
        bytes32 messageHash = ECDSA.toEthSignedMessageHash(keccak256(message));
        address recovered = messageHash.recover(signature);
        return signer == recovered;
    }

    function _setSigner(address signer_) internal {
        signer = signer_;
    }
}

Settings
{
  "remappings": [
    "ERC721A/=lib/ERC721A/contracts/",
    "chainlink/=lib/chainlink/",
    "ds-test/=lib/solmate/lib/ds-test/src/",
    "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":"signer_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ContractsAlreadyInitialized","type":"error"},{"inputs":[],"name":"ContractsCannotBeNull","type":"error"},{"inputs":[],"name":"ContractsNotInitialized","type":"error"},{"inputs":[],"name":"ElementalsProvenanceAlreadySet","type":"error"},{"inputs":[],"name":"ElementalsProvenanceNotSet","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"NotTokenOwner","type":"error"},{"inputs":[],"name":"ProvenanceContractCannotBeNull","type":"error"},{"inputs":[],"name":"RedemptionNotActive","type":"error"},{"inputs":[],"name":"TokenAlreadyRedeemed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"indexed":true,"internalType":"address","name":"redeemer","type":"address"}],"name":"DerivativesRedeemed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"indexed":true,"internalType":"address","name":"redeemer","type":"address"}],"name":"ElementalsRedeemed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"indexed":true,"internalType":"address","name":"redeemer","type":"address"}],"name":"HashmasksBurned","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"burnMasksForDoubleRedemption","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"contractsInitialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"derivatives","outputs":[{"internalType":"contract IDoubleDropNFT","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"elementals","outputs":[{"internalType":"contract IDoubleDropNFT","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"elementalsProvenance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"hashmasks","outputs":[{"internalType":"contract IERC721","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"redeemDerivatives","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"redeemElementals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"redeemedHashmasks","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"isActive_","type":"bool"}],"name":"setIsActive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"generatorAddress","type":"address"}],"name":"setRandomProvenance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"signer_","type":"address"}],"name":"setSigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"hashmasksAddress","type":"address"},{"internalType":"address","name":"derivativesAddress","type":"address"},{"internalType":"address","name":"elementalsAddress","type":"address"}],"name":"setTokenContracts","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"signer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"address","name":"to","type":"address"}],"name":"validateSignature","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]

608060405234801561001057600080fd5b506040516118fe3803806118fe83398101604081905261002f916100af565b806100393361005f565b600180546001600160a01b0319166001600160a01b0392909216919091179055506100df565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000602082840312156100c157600080fd5b81516001600160a01b03811681146100d857600080fd5b9392505050565b611810806100ee6000396000f3fe608060405234801561001057600080fd5b50600436106101215760003560e01c80637ab4757d116100ad578063a8a5cad311610071578063a8a5cad314610267578063c7c3f2a21461027a578063c8daa2511461028d578063d4f986d7146102a0578063f2fde38b146102b457600080fd5b80637ab4757d1461020a57806384e7e3db1461021d5780638da5cb5b1461023057806391b7c74014610241578063a04d4e361461025457600080fd5b80632908afc9116100f45780632908afc9146101b25780632e146249146101c9578063693d33fe146101dc5780636c19e783146101ef578063715018a61461020257600080fd5b8063156cfedb1461012657806322f3e2d41461015e578063238ac933146101725780632750fc781461019d575b600080fd5b6101496101343660046113d3565b60036020526000908152604090205460ff1681565b60405190151581526020015b60405180910390f35b60015461014990600160a01b900460ff1681565b600154610185906001600160a01b031681565b6040516001600160a01b039091168152602001610155565b6101b06101ab3660046113ec565b6102c7565b005b6101bb60025481565b604051908152602001610155565b600454610185906001600160a01b031681565b600554610185906001600160a01b031681565b6101b06101fd36600461143a565b610366565b6101b061038f565b600654610185906001600160a01b031681565b6101b061022b366004611457565b6103a3565b6000546001600160a01b0316610185565b61014961024f3660046114fd565b610475565b6101b061026236600461143a565b610529565b6101b06102753660046115ea565b61060b565b6101b06102883660046115ea565b6108b5565b6101b061029b3660046115ea565b610b23565b60015461014990600160a81b900460ff1681565b6101b06102c236600461143a565b610e85565b6102cf610f00565b6004546001600160a01b031615806102f057506005546001600160a01b0316155b8061030457506006546001600160a01b0316155b156103255760405160016220ee2d60e01b0319815260040160405180910390fd5b600254600003610348576040516372c7e25960e11b815260040160405180910390fd5b60018054911515600160a01b0260ff60a01b19909216919091179055565b61036e610f00565b600180546001600160a01b0319166001600160a01b03831617905550565b50565b610397610f00565b6103a16000610f5a565b565b6103ab610f00565b600154600160a81b900460ff16156103d6576040516317df678160e31b815260040160405180910390fd5b6001600160a01b03831615806103f357506001600160a01b038216155b8061040557506001600160a01b038116155b156104235760405163bec8d64160e01b815260040160405180910390fd5b6001805460ff60a81b1916600160a81b179055600480546001600160a01b039485166001600160a01b031991821617909155600580549385169382169390931790925560068054919093169116179055565b60008082858560405160200161048d939291906116b3565b604051602081830303815290604052905060006104fe82805190602001206040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01604051602081830303815290604052805190602001209050919050565b9050600061050c8289610faa565b6001546001600160a01b0391821691161498975050505050505050565b610531610f00565b6002541561055257604051630e87849960e21b815260040160405180910390fd5b6001600160a01b038116610579576040516321fc97c960e11b815260040160405180910390fd5b6000819050806001600160a01b031663aa192b216040518163ffffffff1660e01b81526004016020604051808303816000875af11580156105be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105e291906116e1565b6002819055600003610607576040516372c7e25960e11b815260040160405180910390fd5b5050565b83838383600160149054906101000a900460ff1661063c57604051632644396160e21b815260040160405180910390fd5b61068084848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250869250859150339050610475565b61069d57604051638baa579f60e01b815260040160405180910390fd5b60005b818110156108025760045433906001600160a01b0316636352211e8585858181106106cd576106cd6116fa565b905060200201356040518263ffffffff1660e01b81526004016106f291815260200190565b602060405180830381865afa15801561070f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107339190611710565b6001600160a01b03161461075a576040516359dc379f60e01b815260040160405180910390fd5b60036000848484818110610770576107706116fa565b602090810292909201358352508101919091526040016000205460ff16156107ab57604051631bd64ea560e01b815260040160405180910390fd5b6001600360008585858181106107c3576107c36116fa565b90506020020135815260200190815260200160002060006101000a81548160ff02191690831515021790555080806107fa90611743565b9150506106a0565b506040513390610815908890889061175c565b604051908190038120907f9f2d6403c0ea9925db709c74725b585c90423bd3bf4be9ef44a780a8ca5643cc90600090a360065460405163249723e960e11b81526001600160a01b039091169063492e47d29061087990899089903390600401611785565b600060405180830381600087803b15801561089357600080fd5b505af11580156108a7573d6000803e3d6000fd5b505050505050505050505050565b83838383600160149054906101000a900460ff166108e657604051632644396160e21b815260040160405180910390fd5b61092a84848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250869250859150339050610475565b61094757604051638baa579f60e01b815260040160405180910390fd5b60005b81811015610aac5760045433906001600160a01b0316636352211e858585818110610977576109776116fa565b905060200201356040518263ffffffff1660e01b815260040161099c91815260200190565b602060405180830381865afa1580156109b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109dd9190611710565b6001600160a01b031614610a04576040516359dc379f60e01b815260040160405180910390fd5b60036000848484818110610a1a57610a1a6116fa565b602090810292909201358352508101919091526040016000205460ff1615610a5557604051631bd64ea560e01b815260040160405180910390fd5b600160036000858585818110610a6d57610a6d6116fa565b90506020020135815260200190815260200160002060006101000a81548160ff0219169083151502179055508080610aa490611743565b91505061094a565b506040513390610abf908890889061175c565b604051908190038120907f32d0cbdf3dad73cc997f09da5a05a94895f5fe85dc85827745aadfbff874b54690600090a360055460405163249723e960e11b81526001600160a01b039091169063492e47d29061087990899089903390600401611785565b83838383600160149054906101000a900460ff16610b5457604051632644396160e21b815260040160405180910390fd5b610b9884848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250869250859150339050610475565b610bb557604051638baa579f60e01b815260040160405180910390fd5b60005b81811015610d1a5760045433906001600160a01b0316636352211e858585818110610be557610be56116fa565b905060200201356040518263ffffffff1660e01b8152600401610c0a91815260200190565b602060405180830381865afa158015610c27573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c4b9190611710565b6001600160a01b031614610c72576040516359dc379f60e01b815260040160405180910390fd5b60036000848484818110610c8857610c886116fa565b602090810292909201358352508101919091526040016000205460ff1615610cc357604051631bd64ea560e01b815260040160405180910390fd5b600160036000858585818110610cdb57610cdb6116fa565b90506020020135815260200190815260200160002060006101000a81548160ff0219169083151502179055508080610d1290611743565b915050610bb8565b506040513390610d2d908890889061175c565b604051908190038120907ff9c45a6f876b3d517dce7be4dd43bb0192285da872abd84217c1364d171065e290600090a36040513390610d6f908890889061175c565b604051908190038120907f9f2d6403c0ea9925db709c74725b585c90423bd3bf4be9ef44a780a8ca5643cc90600090a36040513390610db1908890889061175c565b604051908190038120907f32d0cbdf3dad73cc997f09da5a05a94895f5fe85dc85827745aadfbff874b54690600090a3610deb8686610fd0565b60065460405163249723e960e11b81526001600160a01b039091169063492e47d290610e1f90899089903390600401611785565b600060405180830381600087803b158015610e3957600080fd5b505af1158015610e4d573d6000803e3d6000fd5b505060055460405163249723e960e11b81526001600160a01b03909116925063492e47d2915061087990899089903390600401611785565b610e8d610f00565b6001600160a01b038116610ef75760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b61038c81610f5a565b6000546001600160a01b031633146103a15760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610eee565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000806000610fb98585611089565b91509150610fc6816110f7565b5090505b92915050565b60005b81811015611084576004546001600160a01b03166342842e0e3361dead868686818110611002576110026116fa565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b15801561105957600080fd5b505af115801561106d573d6000803e3d6000fd5b50505050808061107c90611743565b915050610fd3565b505050565b60008082516041036110bf5760208301516040840151606085015160001a6110b3878285856112ad565b945094505050506110f0565b82516040036110e857602083015160408401516110dd86838361139a565b9350935050506110f0565b506000905060025b9250929050565b600081600481111561110b5761110b6117b1565b036111135750565b6001816004811115611127576111276117b1565b036111745760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610eee565b6002816004811115611188576111886117b1565b036111d55760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610eee565b60038160048111156111e9576111e96117b1565b036112415760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610eee565b6004816004811115611255576112556117b1565b0361038c5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b6064820152608401610eee565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156112e45750600090506003611391565b8460ff16601b141580156112fc57508460ff16601c14155b1561130d5750600090506004611391565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015611361573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811661138a57600060019250925050611391565b9150600090505b94509492505050565b6000806001600160ff1b038316816113b760ff86901c601b6117c7565b90506113c5878288856112ad565b935093505050935093915050565b6000602082840312156113e557600080fd5b5035919050565b6000602082840312156113fe57600080fd5b8135801515811461140e57600080fd5b9392505050565b6001600160a01b038116811461038c57600080fd5b803561143581611415565b919050565b60006020828403121561144c57600080fd5b813561140e81611415565b60008060006060848603121561146c57600080fd5b833561147781611415565b9250602084013561148781611415565b9150604084013561149781611415565b809150509250925092565b634e487b7160e01b600052604160045260246000fd5b60008083601f8401126114ca57600080fd5b50813567ffffffffffffffff8111156114e257600080fd5b6020830191508360208260051b85010111156110f057600080fd5b6000806000806060858703121561151357600080fd5b843567ffffffffffffffff8082111561152b57600080fd5b818701915087601f83011261153f57600080fd5b813581811115611551576115516114a2565b604051601f8201601f19908116603f01168101908382118183101715611579576115796114a2565b816040528281528a602084870101111561159257600080fd5b8260208601602083013760006020848301015280985050505060208701359150808211156115bf57600080fd5b506115cc878288016114b8565b90945092506115df90506040860161142a565b905092959194509250565b6000806000806040858703121561160057600080fd5b843567ffffffffffffffff8082111561161857600080fd5b818701915087601f83011261162c57600080fd5b81358181111561163b57600080fd5b88602082850101111561164d57600080fd5b60209283019650945090860135908082111561166857600080fd5b50611675878288016114b8565b95989497509550505050565b81835260006001600160fb1b0383111561169a57600080fd5b8260051b80836020870137939093016020019392505050565b6001600160a01b03841681526040602082018190526000906116d89083018486611681565b95945050505050565b6000602082840312156116f357600080fd5b5051919050565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561172257600080fd5b815161140e81611415565b634e487b7160e01b600052601160045260246000fd5b6000600182016117555761175561172d565b5060010190565b60006001600160fb1b0383111561177257600080fd5b8260051b80858437919091019392505050565b604081526000611799604083018587611681565b905060018060a01b0383166020830152949350505050565b634e487b7160e01b600052602160045260246000fd5b80820180821115610fca57610fca61172d56fea2646970667358221220845b6ec6b55914377d43ec06663c0327d86f931725471d4c23e0781a72141f1264736f6c634300081000330000000000000000000000002bdb254079d55220bd093f9568b685c5af4da140

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101215760003560e01c80637ab4757d116100ad578063a8a5cad311610071578063a8a5cad314610267578063c7c3f2a21461027a578063c8daa2511461028d578063d4f986d7146102a0578063f2fde38b146102b457600080fd5b80637ab4757d1461020a57806384e7e3db1461021d5780638da5cb5b1461023057806391b7c74014610241578063a04d4e361461025457600080fd5b80632908afc9116100f45780632908afc9146101b25780632e146249146101c9578063693d33fe146101dc5780636c19e783146101ef578063715018a61461020257600080fd5b8063156cfedb1461012657806322f3e2d41461015e578063238ac933146101725780632750fc781461019d575b600080fd5b6101496101343660046113d3565b60036020526000908152604090205460ff1681565b60405190151581526020015b60405180910390f35b60015461014990600160a01b900460ff1681565b600154610185906001600160a01b031681565b6040516001600160a01b039091168152602001610155565b6101b06101ab3660046113ec565b6102c7565b005b6101bb60025481565b604051908152602001610155565b600454610185906001600160a01b031681565b600554610185906001600160a01b031681565b6101b06101fd36600461143a565b610366565b6101b061038f565b600654610185906001600160a01b031681565b6101b061022b366004611457565b6103a3565b6000546001600160a01b0316610185565b61014961024f3660046114fd565b610475565b6101b061026236600461143a565b610529565b6101b06102753660046115ea565b61060b565b6101b06102883660046115ea565b6108b5565b6101b061029b3660046115ea565b610b23565b60015461014990600160a81b900460ff1681565b6101b06102c236600461143a565b610e85565b6102cf610f00565b6004546001600160a01b031615806102f057506005546001600160a01b0316155b8061030457506006546001600160a01b0316155b156103255760405160016220ee2d60e01b0319815260040160405180910390fd5b600254600003610348576040516372c7e25960e11b815260040160405180910390fd5b60018054911515600160a01b0260ff60a01b19909216919091179055565b61036e610f00565b600180546001600160a01b0319166001600160a01b03831617905550565b50565b610397610f00565b6103a16000610f5a565b565b6103ab610f00565b600154600160a81b900460ff16156103d6576040516317df678160e31b815260040160405180910390fd5b6001600160a01b03831615806103f357506001600160a01b038216155b8061040557506001600160a01b038116155b156104235760405163bec8d64160e01b815260040160405180910390fd5b6001805460ff60a81b1916600160a81b179055600480546001600160a01b039485166001600160a01b031991821617909155600580549385169382169390931790925560068054919093169116179055565b60008082858560405160200161048d939291906116b3565b604051602081830303815290604052905060006104fe82805190602001206040517f19457468657265756d205369676e6564204d6573736167653a0a3332000000006020820152603c8101829052600090605c01604051602081830303815290604052805190602001209050919050565b9050600061050c8289610faa565b6001546001600160a01b0391821691161498975050505050505050565b610531610f00565b6002541561055257604051630e87849960e21b815260040160405180910390fd5b6001600160a01b038116610579576040516321fc97c960e11b815260040160405180910390fd5b6000819050806001600160a01b031663aa192b216040518163ffffffff1660e01b81526004016020604051808303816000875af11580156105be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105e291906116e1565b6002819055600003610607576040516372c7e25960e11b815260040160405180910390fd5b5050565b83838383600160149054906101000a900460ff1661063c57604051632644396160e21b815260040160405180910390fd5b61068084848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250869250859150339050610475565b61069d57604051638baa579f60e01b815260040160405180910390fd5b60005b818110156108025760045433906001600160a01b0316636352211e8585858181106106cd576106cd6116fa565b905060200201356040518263ffffffff1660e01b81526004016106f291815260200190565b602060405180830381865afa15801561070f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107339190611710565b6001600160a01b03161461075a576040516359dc379f60e01b815260040160405180910390fd5b60036000848484818110610770576107706116fa565b602090810292909201358352508101919091526040016000205460ff16156107ab57604051631bd64ea560e01b815260040160405180910390fd5b6001600360008585858181106107c3576107c36116fa565b90506020020135815260200190815260200160002060006101000a81548160ff02191690831515021790555080806107fa90611743565b9150506106a0565b506040513390610815908890889061175c565b604051908190038120907f9f2d6403c0ea9925db709c74725b585c90423bd3bf4be9ef44a780a8ca5643cc90600090a360065460405163249723e960e11b81526001600160a01b039091169063492e47d29061087990899089903390600401611785565b600060405180830381600087803b15801561089357600080fd5b505af11580156108a7573d6000803e3d6000fd5b505050505050505050505050565b83838383600160149054906101000a900460ff166108e657604051632644396160e21b815260040160405180910390fd5b61092a84848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250869250859150339050610475565b61094757604051638baa579f60e01b815260040160405180910390fd5b60005b81811015610aac5760045433906001600160a01b0316636352211e858585818110610977576109776116fa565b905060200201356040518263ffffffff1660e01b815260040161099c91815260200190565b602060405180830381865afa1580156109b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109dd9190611710565b6001600160a01b031614610a04576040516359dc379f60e01b815260040160405180910390fd5b60036000848484818110610a1a57610a1a6116fa565b602090810292909201358352508101919091526040016000205460ff1615610a5557604051631bd64ea560e01b815260040160405180910390fd5b600160036000858585818110610a6d57610a6d6116fa565b90506020020135815260200190815260200160002060006101000a81548160ff0219169083151502179055508080610aa490611743565b91505061094a565b506040513390610abf908890889061175c565b604051908190038120907f32d0cbdf3dad73cc997f09da5a05a94895f5fe85dc85827745aadfbff874b54690600090a360055460405163249723e960e11b81526001600160a01b039091169063492e47d29061087990899089903390600401611785565b83838383600160149054906101000a900460ff16610b5457604051632644396160e21b815260040160405180910390fd5b610b9884848080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250869250859150339050610475565b610bb557604051638baa579f60e01b815260040160405180910390fd5b60005b81811015610d1a5760045433906001600160a01b0316636352211e858585818110610be557610be56116fa565b905060200201356040518263ffffffff1660e01b8152600401610c0a91815260200190565b602060405180830381865afa158015610c27573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c4b9190611710565b6001600160a01b031614610c72576040516359dc379f60e01b815260040160405180910390fd5b60036000848484818110610c8857610c886116fa565b602090810292909201358352508101919091526040016000205460ff1615610cc357604051631bd64ea560e01b815260040160405180910390fd5b600160036000858585818110610cdb57610cdb6116fa565b90506020020135815260200190815260200160002060006101000a81548160ff0219169083151502179055508080610d1290611743565b915050610bb8565b506040513390610d2d908890889061175c565b604051908190038120907ff9c45a6f876b3d517dce7be4dd43bb0192285da872abd84217c1364d171065e290600090a36040513390610d6f908890889061175c565b604051908190038120907f9f2d6403c0ea9925db709c74725b585c90423bd3bf4be9ef44a780a8ca5643cc90600090a36040513390610db1908890889061175c565b604051908190038120907f32d0cbdf3dad73cc997f09da5a05a94895f5fe85dc85827745aadfbff874b54690600090a3610deb8686610fd0565b60065460405163249723e960e11b81526001600160a01b039091169063492e47d290610e1f90899089903390600401611785565b600060405180830381600087803b158015610e3957600080fd5b505af1158015610e4d573d6000803e3d6000fd5b505060055460405163249723e960e11b81526001600160a01b03909116925063492e47d2915061087990899089903390600401611785565b610e8d610f00565b6001600160a01b038116610ef75760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b61038c81610f5a565b6000546001600160a01b031633146103a15760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610eee565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000806000610fb98585611089565b91509150610fc6816110f7565b5090505b92915050565b60005b81811015611084576004546001600160a01b03166342842e0e3361dead868686818110611002576110026116fa565b6040516001600160e01b031960e088901b1681526001600160a01b03958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b15801561105957600080fd5b505af115801561106d573d6000803e3d6000fd5b50505050808061107c90611743565b915050610fd3565b505050565b60008082516041036110bf5760208301516040840151606085015160001a6110b3878285856112ad565b945094505050506110f0565b82516040036110e857602083015160408401516110dd86838361139a565b9350935050506110f0565b506000905060025b9250929050565b600081600481111561110b5761110b6117b1565b036111135750565b6001816004811115611127576111276117b1565b036111745760405162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e617475726500000000000000006044820152606401610eee565b6002816004811115611188576111886117b1565b036111d55760405162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e677468006044820152606401610eee565b60038160048111156111e9576111e96117b1565b036112415760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202773272076616c604482015261756560f01b6064820152608401610eee565b6004816004811115611255576112556117b1565b0361038c5760405162461bcd60e51b815260206004820152602260248201527f45434453413a20696e76616c6964207369676e6174757265202776272076616c604482015261756560f01b6064820152608401610eee565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08311156112e45750600090506003611391565b8460ff16601b141580156112fc57508460ff16601c14155b1561130d5750600090506004611391565b6040805160008082526020820180845289905260ff881692820192909252606081018690526080810185905260019060a0016020604051602081039080840390855afa158015611361573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811661138a57600060019250925050611391565b9150600090505b94509492505050565b6000806001600160ff1b038316816113b760ff86901c601b6117c7565b90506113c5878288856112ad565b935093505050935093915050565b6000602082840312156113e557600080fd5b5035919050565b6000602082840312156113fe57600080fd5b8135801515811461140e57600080fd5b9392505050565b6001600160a01b038116811461038c57600080fd5b803561143581611415565b919050565b60006020828403121561144c57600080fd5b813561140e81611415565b60008060006060848603121561146c57600080fd5b833561147781611415565b9250602084013561148781611415565b9150604084013561149781611415565b809150509250925092565b634e487b7160e01b600052604160045260246000fd5b60008083601f8401126114ca57600080fd5b50813567ffffffffffffffff8111156114e257600080fd5b6020830191508360208260051b85010111156110f057600080fd5b6000806000806060858703121561151357600080fd5b843567ffffffffffffffff8082111561152b57600080fd5b818701915087601f83011261153f57600080fd5b813581811115611551576115516114a2565b604051601f8201601f19908116603f01168101908382118183101715611579576115796114a2565b816040528281528a602084870101111561159257600080fd5b8260208601602083013760006020848301015280985050505060208701359150808211156115bf57600080fd5b506115cc878288016114b8565b90945092506115df90506040860161142a565b905092959194509250565b6000806000806040858703121561160057600080fd5b843567ffffffffffffffff8082111561161857600080fd5b818701915087601f83011261162c57600080fd5b81358181111561163b57600080fd5b88602082850101111561164d57600080fd5b60209283019650945090860135908082111561166857600080fd5b50611675878288016114b8565b95989497509550505050565b81835260006001600160fb1b0383111561169a57600080fd5b8260051b80836020870137939093016020019392505050565b6001600160a01b03841681526040602082018190526000906116d89083018486611681565b95945050505050565b6000602082840312156116f357600080fd5b5051919050565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561172257600080fd5b815161140e81611415565b634e487b7160e01b600052601160045260246000fd5b6000600182016117555761175561172d565b5060010190565b60006001600160fb1b0383111561177257600080fd5b8260051b80858437919091019392505050565b604081526000611799604083018587611681565b905060018060a01b0383166020830152949350505050565b634e487b7160e01b600052602160045260246000fd5b80820180821115610fca57610fca61172d56fea2646970667358221220845b6ec6b55914377d43ec06663c0327d86f931725471d4c23e0781a72141f1264736f6c63430008100033

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

0000000000000000000000002bdb254079d55220bd093f9568b685c5af4da140

-----Decoded View---------------
Arg [0] : signer_ (address): 0x2BdB254079d55220bd093f9568B685c5af4da140

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000002bdb254079d55220bd093f9568b685c5af4da140


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.