WantedVault

Description:

Multi-signature wallet contract requiring multiple confirmations for transaction execution.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "WantedVault.sol": {
      "content": "// SPDX-License-Identifier: MIT\r
pragma solidity ^0.8.29;\r
\r
 //            _       __            __           __     \r
 //           | |     / /___ _____  / /____  ____/ /      \r
 //           | | /| / / __ `/ __ \/ __/ _ \/ __  /       \r
 //           | |/ |/ / /_/ / / / / /_/  __/ /_/ /        \r
 //           |__/|__/\__,_/_/ /_/\__/\___/\__,_/         \r
 //              _    _____   __  ____  ______\r
 //             | |  / /   | / / / / / /_  __/\r
 //             | | / / /| |/ / / / /   / /   \r
 //             | |/ / ___ / /_/ / /___/ /    \r
 //             |___/_/  |_\____/_____/_/                                     \r
 //    \r
 // Creator: MadV0x\r
 // Deployer: Syntetik Labs\r
\r
import { IERC721 } from "@openzeppelin/contracts/token/ERC721/IERC721.sol";\r
import { ReentrancyGuard } from "@openzeppelin/contracts/security/ReentrancyGuard.sol";\r
import { IERC721Receiver } from "lib/openzeppelin-contracts/contracts/token/ERC721/IERC721Receiver.sol";\r
import { Ownable } from ".deps/npm/@openzeppelin/contracts/access/Ownable.sol";\r
\r
/**\r
* @title  WANTED Cyborgs - Vesting Vault.\r
* @notice Implements immutable vesting schedules for WANTED NFTs premint Allocations.\r
*         Multibeneficiaries with cliffs and linear monthly releases.\r
* @dev    Implements IERC721Receiver to receive ERC721 NFTs from a contract safely.\r
*/\r
\r
contract WantedVault is ReentrancyGuard, IERC721Receiver, Ownable {\r
    IERC721 public WANTEDcontract; \r
\r
    /// @notice beneficiaries group\r
    address public ArtistWallet;\r
    address public OperationsWallet;\r
    address public TreasuryWallet;\r
    address public MarketingWallet ; \r
   \r
    /// @notice Global vesting start timestamp (set at deployment)\r
    uint256 public vestingStart;\r
\r
    uint256 constant SECONDS_IN_A_MONTH = 2592000; // 30 days = 2592000 sec\r
    uint256 constant cliff = 3 * SECONDS_IN_A_MONTH;\r
\r
    /**\r
     * @dev Vesting config for a beneficiary\r
     * @param beneficiary: The account allowed to claim NFTs from this schedule.\r
     * @param fromId: First tokenId allocated to the beneficiary.\r
     * @param toId: Last tokenId allocated to the beneficiary.\r
     * @param cliff: The delay (in seconds) before vesting starts.\r
     * @param perMonth: Number of NFTs released per month after cliff.\r
     */\r
    struct Schedule {\r
        address beneficiary;\r
        uint256 fromId;\r
        uint256 toId;\r
        uint256 cliff; \r
        uint256 perMonth; \r
    }\r
\r
    Schedule[] internal schedules;\r
\r
    /// @dev Marks whether a specific tokenId has been claimed.\r
    mapping(uint256 => bool) public claimed;\r
\r
    /// @dev Tracks how many NFTs each beneficiary has claimed.\r
    mapping(address => uint256) public claimedCount;\r
\r
    /// @dev Tracks whether a token has been deposited into the vault.\r
    mapping(uint256 => bool) public deposited;\r
\r
    /// @notice Emitted when an account claims a batch of NFTs.\r
    /// @param beneficiary The account that claimed NFTs.\r
    /// @param count Number of NFTs claimed.\r
    /// @param tokenIds List of tokenIds claimed.\r
    event BatchClaimed(address indexed beneficiary, uint256 count, uint256[] tokenIds);\r
\r
    constructor(address _wantedContract) Ownable(msg.sender) {\r
        WANTEDcontract = IERC721(_wantedContract);\r
\r
        ArtistWallet = 0xEC4bB69B40cC3Bb44a7c903A3A06a3203Ac41E42;\r
        OperationsWallet = 0x451e5d30Fa83e19A35A2A01E55Ff1D2630968352;\r
        TreasuryWallet = 0x9d953ecd8782c7D589365736335305e98df1e6cC;\r
        MarketingWallet = 0xE4d96514386B650B165Ff67DcCe2484113AEB65e;\r
\r
        // Define vesting schedules per beneficiary\r
        schedules.push(Schedule(ArtistWallet, 1, 100, cliff, 3)); // 3 months cliff, 3 per month (40 months)\r
        schedules.push(Schedule(OperationsWallet, 101, 300, 2*cliff, 6)); // 6 months cliff, 6 per month (40 months)\r
        schedules.push(Schedule(TreasuryWallet, 301, 600, 2*cliff, 9)); // 6 months cliff, 9 per month (40 months)\r
        schedules.push(Schedule(MarketingWallet, 601, 1000, cliff, 11)); // 3 months cliff, 11 per month (40 months)\r
    }\r
\r
    /**\r
     * @notice Allows a beneficiary to claim all eligible NFTs at once based on their vesting schedule.\r
     * \r
     * @dev \r
     * - A "Schedule" defines the vesting conditions for a beneficiary (fromId, toId, cliff, perMonth).\r
     * - This function enforces a time-based cliff and linear monthly vesting.\r
     * - Calculates how many NFTs the caller is allowed to claim at this point in time.\r
     * - Transfers only deposited and unclaimed tokenIds within the beneficiary’s allowed range.\r
     * - Updates claim tracking to prevent double-claims.\r
     *\r
     * Requirements:\r
     * - Caller must be a registered beneficiary with a valid schedule.\r
     * - The cliff period must have passed.\r
     * - At least one unclaimed token must be available based on elapsed time.\r
     * - Token must have been previously deposited and not yet claimed.\r
     *\r
     * Emits:\r
     * - {BatchClaimed} with number of tokens claimed and their token IDs.\r
     */\r
    function batchClaimAll() external nonReentrant {\r
        Schedule memory schedule = getSchedule(msg.sender);\r
        require(schedule.beneficiary != address(0), "Not beneficiary");\r
\r
        uint256 timePassed = block.timestamp - vestingStart;\r
        require(timePassed >= schedule.cliff, "Cliff not reached");\r
\r
        uint256 periods = (timePassed - schedule.cliff) / SECONDS_IN_A_MONTH;\r
        uint256 totalClaimable = periods * schedule.perMonth;\r
        uint256 maxClaimable = schedule.toId - schedule.fromId + 1;\r
        if (totalClaimable >= maxClaimable) {totalClaimable = maxClaimable;}\r
        uint256 toClaim = totalClaimable - claimedCount[msg.sender];\r
        require(toClaim > 0, "Nothing to claim");\r
\r
        uint256 claimedNow = 0;\r
        uint256[] memory batch = new uint256[](toClaim);\r
\r
        for (uint256 tokenId = schedule.fromId; tokenId <= schedule.toId && claimedNow < toClaim; tokenId++) {\r
            if (!claimed[tokenId] && deposited[tokenId]) {\r
                claimed[tokenId] = true;\r
                WANTEDcontract.safeTransferFrom(address(this), msg.sender, tokenId);\r
                batch[claimedNow] = tokenId;\r
                claimedNow++;\r
            }\r
        }\r
\r
        require(claimedNow > 0, "No eligible tokens");\r
        claimedCount[msg.sender] += claimedNow;\r
        emit BatchClaimed(msg.sender, claimedNow, batch);\r
    }\r
\r
    /**\r
     * @notice Allows a beneficiary to claim an amount of unvested NFTs.\r
     * \r
     * @dev \r
     * - A "Schedule" defines the vesting conditions for a beneficiary (fromId, toId, cliff, perMonth).\r
     * - This function enforces a time-based cliff and linear monthly vesting.\r
     * - Verifies the amount asked is unvested and claimable.\r
     * - Transfers the claimed amount of unvested tokenIds to the beneficiary.\r
     * - Updates claim tracking to prevent double-claims.\r
     *\r
     * Requirements:\r
     * - Caller must be a registered beneficiary with a valid schedule.\r
     * - The cliff period must have passed.\r
     * - At least one unclaimed token must be available based on elapsed time.\r
     * - Token must have been previously deposited and not yet claimed.\r
     * - Amount claimed should not be higher than the unvested NFTs amount.\r
     *\r
     * Emits:\r
     * - {BatchClaimed} with number of tokens claimed and their token IDs.\r
     *\r
     * @param amountToClaim The number of NFTs the beneficiary wants to claim.\r
     */\r
    function claimAmount(uint256 amountToClaim) external nonReentrant {\r
        Schedule memory schedule = getSchedule(msg.sender);\r
        require(schedule.beneficiary != address(0), "Not beneficiary");\r
\r
        uint256 timePassed = block.timestamp - vestingStart;\r
        require(timePassed >= schedule.cliff, "Cliff not reached");\r
\r
        uint256 periods = (timePassed - schedule.cliff) / SECONDS_IN_A_MONTH;\r
        uint256 totalClaimable = periods * schedule.perMonth;\r
        uint256 maxClaimable = schedule.toId - schedule.fromId + 1;\r
        \r
        if (totalClaimable >= maxClaimable) {totalClaimable = maxClaimable;}\r
        \r
        uint256 toClaim = totalClaimable - claimedCount[msg.sender];\r
        require(toClaim > 0, "Nothing to claim");\r
        require(amountToClaim <= toClaim, "Amount > Available");\r
\r
        uint256 claimedNow = 0;\r
        uint256[] memory batch = new uint256[](amountToClaim);\r
\r
        for (uint256 tokenId = schedule.fromId; tokenId <= schedule.toId && claimedNow < amountToClaim; tokenId++) {\r
            if (!claimed[tokenId] && deposited[tokenId]) {\r
                claimed[tokenId] = true;\r
                WANTEDcontract.safeTransferFrom(address(this), msg.sender, tokenId);\r
                batch[claimedNow] = tokenId;\r
                claimedNow++;\r
            }\r
        }\r
\r
        require(claimedNow > 0, "No eligible tokens");\r
        claimedCount[msg.sender] += claimedNow;\r
        emit BatchClaimed(msg.sender, claimedNow, batch);\r
    }\r
\r
    /**\r
     * @notice Returns the vesting schedule assigned to a specific beneficiary.\r
     *\r
     * @dev \r
     * - Iterates over all defined schedules to find the one matching the given account.\r
     * - If found, returns the full Schedule struct (includes range, cliff, and monthly vesting rate).\r
     * - If not found, returns an empty Schedule (beneficiary = address(0)).\r
     *\r
     * @param account The address for which to retrieve the schedule.\r
     * @return The Schedule struct associated with the address, or a zeroed struct if none exists.\r
     */\r
    function getSchedule(address account) public view returns (Schedule memory) {\r
        for (uint256 i = 0; i < schedules.length; i++) {\r
            if (schedules[i].beneficiary == account) {\r
                return schedules[i];\r
            }\r
        }\r
        return Schedule(address(0), 0, 0, 0, 0);\r
    }\r
\r
    /**\r
     * @notice Calculates how many NFTs a beneficiary is currently eligible to claim.\r
     *\r
     * @dev \r
     * - Returns 0 if the account is not assigned a schedule or the cliff period hasn't passed.\r
     * - Computes how many full vesting periods (months) have passed since the cliff.\r
     * - Multiplies passed periods by the per-month vesting rate.\r
     * - Caps the total claimable to the maximum NFTs assigned in the vesting schedule.\r
     * - Subtracts the number of NFTs already claimed to get the final claimable amount.\r
     *\r
     * @param account The address of the beneficiary.\r
     * @return Number of NFTs currently available to be claimed by the beneficiary.\r
     */\r
    function getClaimable(address account) external view returns (uint256) {\r
        Schedule memory schedule = getSchedule(account);\r
\r
        if (\r
            schedule.beneficiary == address(0) ||\r
            block.timestamp < vestingStart + schedule.cliff\r
        ) {\r
            return 0;\r
        }\r
\r
        uint256 elapsed = block.timestamp - vestingStart - schedule.cliff;\r
        uint256 periods = elapsed / SECONDS_IN_A_MONTH;\r
        uint256 totalClaimable = periods * schedule.perMonth;\r
\r
        uint256 maxClaimable = schedule.toId - schedule.fromId + 1;\r
        if (totalClaimable > maxClaimable) {\r
            totalClaimable = maxClaimable;\r
        }\r
\r
        uint256 alreadyClaimed = claimedCount[account];\r
        if (alreadyClaimed >= totalClaimable) { return 0; }\r
\r
        return totalClaimable - alreadyClaimed;\r
    }\r
\r
    /**\r
    * @notice Returns the remaining time and timestamp until the next vesting unlock.\r
    * @dev \r
    * - Calculates how many full vesting periods (months) have elapsed since `vestingStart`.\r
    * - If all 40 (37 + 3 cliff) vesting periods have passed, returns 0 indicating vesting is complete.\r
    *\r
    * @return timeRemaining Seconds remaining until the next unlock or 0 if complete.\r
    */\r
    function timeBeforeNextUnlock() external view returns (uint256) {\r
\r
        uint256 timePassed = block.timestamp - vestingStart;\r
        uint256 periods = timePassed / SECONDS_IN_A_MONTH;\r
\r
        if (timePassed <= cliff) {\r
            return cliff - timePassed;\r
        }\r
\r
        if (periods >= 40) {\r
            // Vesting complete: no more unlocks\r
            return (0);\r
        }\r
\r
        uint256 nextUnlockTime = vestingStart + (periods + 1) * SECONDS_IN_A_MONTH;\r
        uint256 timeRemaining = nextUnlockTime - block.timestamp;\r
\r
        return timeRemaining;\r
    }\r
\r
    /**\r
     * @notice Updates the wallet address associated with the artist.\r
     *\r
     * @dev \r
     * - Only callable by the contract owner.\r
     * - Reverts if the new address is the zero address.\r
     * - Internally calls `_updateBeneficiary()` to handle bookkeeping or external integrations.\r
     * - Updates the `ArtistWallet` state variable to the new address.\r
     *\r
     * @param newWallet The new address to be set as the artist's wallet.\r
     */\r
    function updateArtistWallet(address newWallet) external onlyOwner {\r
        require(newWallet != address(0), "Invalid address");\r
        _updateBeneficiary(ArtistWallet, newWallet);\r
        ArtistWallet = newWallet;\r
    }\r
\r
    /**\r
     * @notice Updates the wallet address designated for operations.\r
     *\r
     * @dev \r
     * - Only callable by the contract owner.\r
     * - Reverts if the new wallet address is the zero address.\r
     * - Calls `_updateBeneficiary()` to handle necessary state updates or mappings.\r
     * - Updates the `OperationsWallet` state variable to the new address.\r
     *\r
     * @param newWallet The new wallet address to assign for operations-related funds or permissions.\r
     */\r
    function updateOperationsWallet(address newWallet) external onlyOwner {\r
        require(newWallet != address(0), "Invalid address");\r
        _updateBeneficiary(OperationsWallet, newWallet);\r
        OperationsWallet = newWallet;\r
    }\r
\r
    /**\r
     * @notice Updates the wallet address designated for Treasury.\r
     *\r
     * @dev \r
     * - Only callable by the contract owner.\r
     * - Reverts if the new wallet address is the zero address.\r
     * - Calls `_updateBeneficiary()` to handle necessary state updates or mappings.\r
     * - Updates the `TreasuryWallet` state variable to the new address.\r
     *\r
     * @param newWallet The new wallet address to assign for Treasury-related funds or permissions.\r
     */\r
    function updateTreasuryWallet(address newWallet) external onlyOwner {\r
        require(newWallet != address(0), "Invalid address");\r
        _updateBeneficiary(TreasuryWallet, newWallet);\r
        TreasuryWallet = newWallet;\r
    }\r
\r
    /**\r
     * @notice Updates the wallet address designated for Marketing.\r
     *\r
     * @dev \r
     * - Only callable by the contract owner.\r
     * - Reverts if the new wallet address is the zero address.\r
     * - Calls `_updateBeneficiary()` to handle necessary state updates or mappings.\r
     * - Updates the `MarketingsWallet` state variable to the new address.\r
     *\r
     * @param newWallet The new wallet address to assign for Marketing-related funds or permissions.\r
     */\r
    function updateMarketingWallet(address newWallet) external onlyOwner {\r
        require(newWallet != address(0), "Invalid address");\r
        _updateBeneficiary(MarketingWallet, newWallet);\r
        MarketingWallet = newWallet;\r
    }\r
\r
    /**\r
     * @dev Internal utility to update the beneficiary address within a vesting schedule.\r
     *\r
     * @dev\r
     * - Iterates through all existing schedules.\r
     * - If a schedule is found for `oldAddr`, it updates the beneficiary to `newAddr`.\r
     * - Transfers the claimed count to the new address.\r
     * - Resets the claimed count for the old address to zero.\r
     * - Stops after the first match (assuming unique beneficiaries).\r
     *\r
     * @param oldAddr The previous beneficiary address to be replaced.\r
     * @param newAddr The new address to assign as beneficiary.\r
     */\r
    function _updateBeneficiary(address oldAddr, address newAddr) private {\r
        for (uint256 i = 0; i < schedules.length; i++) {\r
            if (schedules[i].beneficiary == oldAddr) {\r
                schedules[i].beneficiary = newAddr;\r
                claimedCount[newAddr] = claimedCount[oldAddr];\r
                claimedCount[oldAddr] = 0;\r
                break;\r
            }\r
        }\r
    }\r
\r
    /**\r
     * @notice Handles the receipt of a WANTED ERC721 token.\r
     * @dev This function is automatically called when an ERC721 token is transferred\r
     *      to this contract via `safeTransferFrom`. It:\r
     *      - Ensures the token comes from the expected WANTED contract.\r
     *      - Validates the tokenId is within an acceptable range.\r
     *      - Flags the token as deposited for future vesting logic.\r
     *      - Initializes the vesting start time if this is the first token received.\r
     *\r
     * @param tokenId The unique ID of the token being received.\r
     * @return Selector confirming the token was received correctly.\r
     */\r
    function onERC721Received(\r
        address /* operator */,\r
        address /* from */,\r
        uint256 tokenId,\r
        bytes calldata /* data */\r
    ) external override returns (bytes4) {\r
        require(msg.sender == address(WANTEDcontract), "Only accepts WANTED NFTs from contract");\r
        require(tokenId <= 1000, "Invalid tokenId");  \r
        deposited[tokenId] = true;\r
\r
        // vestingStart on first deposit\r
        if (vestingStart == 0) {\r
            vestingStart = block.timestamp;\r
        }\r
\r
        return this.onERC721Received.selector;\r
    }\r
\r
}"
    },
    ".deps/npm/@openzeppelin/contracts/access/Ownable.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {Context} from "../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.
 *
 * The initial owner is set to the address provided by the deployer. 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;

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

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

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @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 {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public payable 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 {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _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);
    }
}
"
    },
    "lib/openzeppelin-contracts/contracts/token/ERC721/IERC721Receiver.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)

pragma solidity ^0.8.0;

/**
 * @title ERC721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC721 asset contracts.
 */
interface IERC721Receiver {
    /**
     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
     * by `operator` from `from`, this function is called.
     *
     * It must return its Solidity selector to confirm the token transfer.
     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
     *
     * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
     */
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}
"
    },
    "@openzeppelin/contracts/security/ReentrancyGuard.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be _NOT_ENTERED
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == _ENTERED;
    }
}
"
    },
    "@openzeppelin/contracts/token/ERC721/IERC721.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/ERC721/IERC721.sol)

pragma solidity >=0.6.2;

import {IERC165} from "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC-721 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 ERC-721 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: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC-721
     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
     * understand this adds an external call which potentially creates a reentrancy vulnerability.
     *
     * 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 address zero.
     *
     * 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);
}
"
    },
    "@openzeppelin/contracts/utils/introspection/IERC165.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)

pragma solidity >=0.4.16;

/**
 * @dev Interface of the ERC-165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[ERC].
 *
 * 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[ERC 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);
}
"
    },
    ".deps/npm/@openzeppelin/contracts/utils/Context.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @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;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}
"
    }
  },
  "settings": {
    "optimizer": {
      "enabled": true,
      "runs": 200
    },
    "outputSelection": {
      "*": {
        "*": [
          "evm.bytecode",
          "evm.deployedBytecode",
          "devdoc",
          "userdoc",
          "metadata",
          "abi"
        ]
      }
    },
    "remappings": []
  }
}}

Tags:
ERC721, ERC165, Multisig, Non-Fungible, Upgradeable, Multi-Signature, Factory|addr:0xd1088b5002bcb7f6f75e39114c7daea6fbc90ff0|verified:true|block:23621211|tx:0xc55209d6cde13ee38205ab08497584f278eb0b6914dd4b3220263c40a6c639f3|first_check:1761035967

Submitted on: 2025-10-21 10:39:29

Comments

Log in to comment.

No comments yet.