ETH Price: $3,247.75 (+2.42%)
Gas: 2 Gwei

Contract

0xAbEffb353dae4A177057e9a3e4A663386cF54758
 
Transaction Hash
Method
Block
From
To
Unstake Batch203810412024-07-25 4:01:3531 hrs ago1721880095IN
0xAbEffb35...86cF54758
0 ETH0.001406324.96142288
Unstake Batch203517892024-07-21 2:01:115 days ago1721527271IN
0xAbEffb35...86cF54758
0 ETH0.000237081.98467653
Unstake Batch202887362024-07-12 6:49:2314 days ago1720766963IN
0xAbEffb35...86cF54758
0 ETH0.000692095.7937585
Unstake Batch202149422024-07-01 23:25:5924 days ago1719876359IN
0xAbEffb35...86cF54758
0 ETH0.002386552
Unstake Batch202131812024-07-01 17:32:2324 days ago1719855143IN
0xAbEffb35...86cF54758
0 ETH0.00238288
Unstake201789312024-06-26 22:45:5929 days ago1719441959IN
0xAbEffb35...86cF54758
0 ETH0.000592615
Unstake201789212024-06-26 22:43:5929 days ago1719441839IN
0xAbEffb35...86cF54758
0 ETH0.000592615
Unstake Batch201346112024-06-20 18:05:1135 days ago1718906711IN
0xAbEffb35...86cF54758
0 ETH0.0019793712.60867265
Unstake Batch201319882024-06-20 9:16:4736 days ago1718875007IN
0xAbEffb35...86cF54758
0 ETH0.0010326912.10581811
Unstake Batch200018512024-06-02 4:48:4754 days ago1717303727IN
0xAbEffb35...86cF54758
0 ETH0.000973325
Unstake Batch199920712024-05-31 20:02:4755 days ago1717185767IN
0xAbEffb35...86cF54758
0 ETH0.001148217.54240347
Unstake199722382024-05-29 1:27:4758 days ago1716946067IN
0xAbEffb35...86cF54758
0 ETH0.0015407913
Unstake199721882024-05-29 1:17:4758 days ago1716945467IN
0xAbEffb35...86cF54758
0 ETH0.000908988
Unstake Batch199356972024-05-23 22:55:2363 days ago1716504923IN
0xAbEffb35...86cF54758
0 ETH0.0030057311.76311854
Unstake Batch198850432024-05-16 20:52:4770 days ago1715892767IN
0xAbEffb35...86cF54758
0 ETH0.000330053.8691244
Unstake Batch198850202024-05-16 20:48:1170 days ago1715892491IN
0xAbEffb35...86cF54758
0 ETH0.000345784.05340979
Unstake Batch198850072024-05-16 20:45:3570 days ago1715892335IN
0xAbEffb35...86cF54758
0 ETH0.000314843.91570456
Unstake Batch198849802024-05-16 20:40:1170 days ago1715892011IN
0xAbEffb35...86cF54758
0 ETH0.000330163.87036169
Unstake Batch198849572024-05-16 20:35:2370 days ago1715891723IN
0xAbEffb35...86cF54758
0 ETH0.00035574.16976124
Unstake Batch198849512024-05-16 20:34:1170 days ago1715891651IN
0xAbEffb35...86cF54758
0 ETH0.000361694.24246669
Unstake Batch198849392024-05-16 20:31:4770 days ago1715891507IN
0xAbEffb35...86cF54758
0 ETH0.000466544.55809683
Unstake Batch198842592024-05-16 18:14:5970 days ago1715883299IN
0xAbEffb35...86cF54758
0 ETH0.000640837.51220714
Unstake Batch198841922024-05-16 18:01:2370 days ago1715882483IN
0xAbEffb35...86cF54758
0 ETH0.000742518.70418747
Unstake Batch198838732024-05-16 16:56:5970 days ago1715878619IN
0xAbEffb35...86cF54758
0 ETH0.000844629.90698138
Unstake Batch198838302024-05-16 16:48:1170 days ago1715878091IN
0xAbEffb35...86cF54758
0 ETH0.000740159.20525378
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
NFTStaking

Compiler Version
v0.8.7+commit.e28d00a7

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 5 : NFTStaking.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.7;

import "../interfaces/ERC20Spec.sol";
import "../interfaces/ERC721Spec.sol";
import "../utils/AccessControl.sol";

/**
 * @title NFT Staking
 *
 * @notice Enables NFT staking for a given NFT smart contract defined on deployment
 *
 * @notice Doesn't introduce any rewards, just tracks the stake/unstake dates for each
 *      token/owner, this data will be used later on to process the rewards
 */
contract NFTStaking is AccessControl {
	/**
	 * @dev Main staking data structure keeping track of a stake,
	 *      used in `tokenStakes` array mapping
	 */
	struct StakeData {
		/**
		 * @dev Who owned and staked the token, who will be the token
		 *      returned to once unstaked
		 */
		address owner;

		/**
		 * @dev When the token was staked and transferred from the owner,
		 *      unix timestamp
		 */
		uint32 stakedOn;

		/**
		 * @dev When token was unstaked and returned back to the owner,
		 *      unix timestamp
		 * @dev Zero value means the token is still staked
		 */
		uint32 unstakedOn;
	}

	/**
	 * @dev Auxiliary data structure to help iterate over NFT owner stakes,
	 *      used in `userStakes` array mapping
	 */
	struct StakeIndex {
		/**
		 * @dev Staked token ID
		 */
		uint32 tokenId;

		/**
		 * @dev Where to look for main staking data `StakeData`
		 *      in `tokenStakes` array mapping
		 */
		uint32 index;
	}

	/**
	 * @dev NFT smart contract to stake/unstake tokens of
	 */
	address public immutable targetContract;

	/**
	 * @notice For each token ID stores the history of its stakes,
	 *      last element of the history may be "open" (unstakedOn = 0),
	 *      meaning the token is still staked and is ot be returned to the `owner`
	 *
	 * @dev Maps token ID => StakeData[]
	 */
	mapping(uint32 => StakeData[]) public tokenStakes;

	/**
	 * @notice For each owner address stores the links to its stakes,
	 *      the link is represented as StakeIndex data struct
	 *
	 * @dev Maps owner address => StakeIndex[]
	 */
	mapping(address => StakeIndex[]) public userStakes;

	/**
	 * @dev Enables staking, stake(), stakeBatch()
	 */
	uint32 public constant FEATURE_STAKING = 0x0000_0001;

	/**
	 * @dev Enables unstaking, unstake(), unstakeBatch()
	 */
	uint32 public constant FEATURE_UNSTAKING = 0x0000_0002;

	/**
	 * @notice People do mistake and may send tokens by mistake; since
	 *      staking contract is not designed to accept the tokens directly,
	 *      it allows the rescue manager to "rescue" such lost tokens
	 *
	 * @notice Rescue manager is responsible for "rescuing" ERC20/ERC721 tokens
	 *      accidentally sent to the smart contract
	 *
	 * @dev Role ROLE_RESCUE_MANAGER allows withdrawing non-staked ERC20/ERC721
	 *      tokens stored on the smart contract balance
	 */
	uint32 public constant ROLE_RESCUE_MANAGER = 0x0001_0000;

	/**
	 * @dev Fired in stake(), stakeBatch()
	 *
	 * @param _by token owner, tx executor
	 * @param _tokenId token ID staked and transferred into the smart contract
	 * @param _when unix timestamp of when staking happened
	 */
	event Staked(address indexed _by, uint32 indexed _tokenId, uint32 _when);

	/**
	 * @dev Fired in unstake(), unstakeBatch()
	 *
	 * @param _by token owner, tx executor
	 * @param _tokenId token ID unstaked and transferred back to owner
	 * @param _when unix timestamp of when unstaking happened
	 */
	event Unstaked(address indexed _by, uint32 indexed _tokenId, uint32 _when);

	/**
	 * @dev Creates/deploys NFT staking contract bound to the already deployed
	 *      target NFT ERC721 smart contract to be staked
	 *
	 * @param _nft address of the deployed NFT smart contract instance
	 */
	constructor(address _nft) {
		// verify input is set
		require(_nft != address(0), "target contract is not set");

		// verify input is valid smart contract of the expected interface
		require(ERC165(_nft).supportsInterface(type(ERC721).interfaceId), "unexpected target type");

		// setup smart contract internal state
		targetContract = _nft;
	}

	/**
	 * @notice How many times a particular token was staked
	 *
	 * @dev Used to iterate `tokenStakes(tokenId, i)`, `i < numStakes(tokenId)`
	 *
	 * @param tokenId token ID to query number of times staked for
	 * @return number of times token was staked
	 */
	function numStakes(uint32 tokenId) public view returns(uint256) {
		// just read the array length and return it
		return tokenStakes[tokenId].length;
	}

	/**
	 * @notice How many stakes a particular address has done
	 *
	 * @dev Used to iterate `userStakes(owner, i)`, `i < numStakes(owner)`
	 *
	 * @param owner an address to query number of times it staked
	 * @return number of times a particular address has staked
	 */
	function numStakes(address owner) public view returns(uint256) {
		// just read the array length and return it
		return userStakes[owner].length;
	}

	/**
	 * @notice Determines if the token is currently staked or not
	 *
	 * @param tokenId token ID to check state for
	 * @return true if token is staked, false otherwise
	 */
	function isStaked(uint32 tokenId) public view returns(bool) {
		// get an idea of current stakes for the token
		uint256 n = tokenStakes[tokenId].length;

		// evaluate based on the last stake element in the array
		return n > 0 && tokenStakes[tokenId][n - 1].unstakedOn == 0;
	}

	/**
	 * @notice Stakes the NFT; the token is transferred from its owner to the staking contract;
	 *      token must be owned by the tx executor and be transferable by staking contract
	 *
	 * @param tokenId token ID to stake
	 */
	function stake(uint32 tokenId) public {
		// verify staking is enabled
		require(isFeatureEnabled(FEATURE_STAKING), "staking is disabled");

		// get an idea of current stakes for the token
		uint256 n = tokenStakes[tokenId].length;

		// verify the token is not currently staked
		require(n == 0 || tokenStakes[tokenId][n - 1].unstakedOn != 0, "already staked");

		// verify token belongs to the address which executes staking
		require(ERC721(targetContract).ownerOf(tokenId) == msg.sender, "access denied");

		// transfer the token from owner into the staking contract
		ERC721(targetContract).transferFrom(msg.sender, address(this), tokenId);

		// current timestamp to be set as `stakedOn`
		uint32 stakedOn = now32();

		// save token stake data
		tokenStakes[tokenId].push(StakeData({
			owner: msg.sender,
			stakedOn: stakedOn,
			unstakedOn: 0
		}));

		// save token stake index
		userStakes[msg.sender].push(StakeIndex({
			tokenId: tokenId,
			index: uint32(n)
		}));

		// emit an event
		emit Staked(msg.sender, tokenId, stakedOn);
	}

	/**
	 * @notice Stakes several NFTs; tokens are transferred from their owner to the staking contract;
	 *      tokens must be owned by the tx executor and be transferable by staking contract
	 *
	 * @param tokenIds token IDs to stake
	 */
	function stakeBatch(uint32[] memory tokenIds) public {
		// iterate the collection passed
		for(uint256 i = 0; i < tokenIds.length; i++) {
			// and stake each token one by one
			stake(tokenIds[i]);
		}
	}

	/**
	 * @notice Unstakes the NFT; the token is transferred from staking contract back
	 *      its previous owner
	 *
	 * @param tokenId token ID to unstake
	 */
	function unstake(uint32 tokenId) public {
		// verify staking is enabled
		require(isFeatureEnabled(FEATURE_UNSTAKING), "unstaking is disabled");

		// get an idea of current stakes for the token
		uint256 n = tokenStakes[tokenId].length;

		// verify the token is not currently staked
		require(n != 0, "not staked");
		require(tokenStakes[tokenId][n - 1].unstakedOn == 0, "already unstaked");

		// verify token belongs to the address which executes unstaking
		require(tokenStakes[tokenId][n - 1].owner == msg.sender, "access denied");

		// current timestamp to be set as `unstakedOn`
		uint32 unstakedOn = now32();

		// update token stake data
		tokenStakes[tokenId][n - 1].unstakedOn = unstakedOn;

		// transfer the token back to owner
		ERC721(targetContract).transferFrom(address(this), msg.sender, tokenId);

		// emit an event
		emit Unstaked(msg.sender, tokenId, unstakedOn);
	}

	/**
	 * @notice Unstakes several NFTs; tokens are transferred from staking contract back
	 *      their previous owner
	 *
	 * @param tokenIds token IDs to unstake
	 */
	function unstakeBatch(uint32[] memory tokenIds) public {
		// iterate the collection passed
		for(uint256 i = 0; i < tokenIds.length; i++) {
			// and unstake each token one by one
			unstake(tokenIds[i]);
		}
	}

	/**
	 * @dev Restricted access function to rescue accidentally sent ERC20 tokens,
	 *      the tokens are rescued via `transfer` function call on the
	 *      contract address specified and with the parameters specified:
	 *      `_contract.transfer(_to, _value)`
	 *
	 * @dev Requires executor to have `ROLE_RESCUE_MANAGER` permission
	 *
	 * @param _contract smart contract address to execute `transfer` function on
	 * @param _to to address in `transfer(_to, _value)`
	 * @param _value value to transfer in `transfer(_to, _value)`
	 */
	function rescueErc20(address _contract, address _to, uint256 _value) public {
		// verify the access permission
		require(isSenderInRole(ROLE_RESCUE_MANAGER), "access denied");

		// perform the transfer as requested, without any checks
		ERC20(_contract).transfer(_to, _value);
	}

	/**
	 * @dev Restricted access function to rescue accidentally sent ERC721 tokens,
	 *      the tokens are rescued via `transferFrom` function call on the
	 *      contract address specified and with the parameters specified:
	 *      `_contract.transferFrom(this, _to, _tokenId)`
	 *
	 * @dev Requires executor to have `ROLE_RESCUE_MANAGER` permission
	 *
	 * @param _contract smart contract address to execute `transferFrom` function on
	 * @param _to to address in `transferFrom(this, _to, _tokenId)`
	 * @param _tokenId token ID to transfer in `transferFrom(this, _to, _tokenId)`
	 */
	function rescueErc721(address _contract, address _to, uint256 _tokenId) public {
		// verify the access permission
		require(isSenderInRole(ROLE_RESCUE_MANAGER), "access denied");

		// verify the NFT is not staked
		require(_contract != targetContract || !isStaked(uint32(_tokenId)), "token is staked");

		// perform the transfer as requested, without any checks
		ERC721(_contract).transferFrom(address(this), _to, _tokenId);
	}

	/**
	 * @dev Testing time-dependent functionality may be difficult;
	 *      we override time in the helper test smart contract (mock)
	 *
	 * @return `block.timestamp` in mainnet, custom values in testnets (if overridden)
	 */
	function now32() public view virtual returns (uint32) {
		// return current block timestamp
		return uint32(block.timestamp);
	}
}

File 2 of 5 : ERC20Spec.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.7;

/**
 * @title EIP-20: ERC-20 Token Standard
 *
 * @notice The ERC-20 (Ethereum Request for Comments 20), proposed by Fabian Vogelsteller in November 2015,
 *      is a Token Standard that implements an API for tokens within Smart Contracts.
 *
 * @notice It provides functionalities like to transfer tokens from one account to another,
 *      to get the current token balance of an account and also the total supply of the token available on the network.
 *      Besides these it also has some other functionalities like to approve that an amount of
 *      token from an account can be spent by a third party account.
 *
 * @notice If a Smart Contract implements the following methods and events it can be called an ERC-20 Token
 *      Contract and, once deployed, it will be responsible to keep track of the created tokens on Ethereum.
 *
 * @notice See https://ethereum.org/en/developers/docs/standards/tokens/erc-20/
 * @notice See https://eips.ethereum.org/EIPS/eip-20
 */
interface ERC20 {
	/**
	 * @dev Fired in transfer(), transferFrom() to indicate that token transfer happened
	 *
	 * @param from an address tokens were consumed from
	 * @param to an address tokens were sent to
	 * @param value number of tokens transferred
	 */
	event Transfer(address indexed from, address indexed to, uint256 value);

	/**
	 * @dev Fired in approve() to indicate an approval event happened
	 *
	 * @param owner an address which granted a permission to transfer
	 *      tokens on its behalf
	 * @param spender an address which received a permission to transfer
	 *      tokens on behalf of the owner `_owner`
	 * @param value amount of tokens granted to transfer on behalf
	 */
	event Approval(address indexed owner, address indexed spender, uint256 value);

	/**
	 * @return name of the token (ex.: USD Coin)
	 */
	// OPTIONAL - This method can be used to improve usability,
	// but interfaces and other contracts MUST NOT expect these values to be present.
	// function name() external view returns (string memory);

	/**
	 * @return symbol of the token (ex.: USDC)
	 */
	// OPTIONAL - This method can be used to improve usability,
	// but interfaces and other contracts MUST NOT expect these values to be present.
	// function symbol() external view returns (string memory);

	/**
	 * @dev Returns the number of decimals used to get its user representation.
	 *      For example, if `decimals` equals `2`, a balance of `505` tokens should
	 *      be displayed to a user as `5,05` (`505 / 10 ** 2`).
	 *
	 * @dev Tokens usually opt for a value of 18, imitating the relationship between
	 *      Ether and Wei. This is the value {ERC20} uses, unless this function is
	 *      overridden;
	 *
	 * @dev NOTE: This information is only used for _display_ purposes: it in
	 *      no way affects any of the arithmetic of the contract, including
	 *      {IERC20-balanceOf} and {IERC20-transfer}.
	 *
	 * @return token decimals
	 */
	// OPTIONAL - This method can be used to improve usability,
	// but interfaces and other contracts MUST NOT expect these values to be present.
	// function decimals() external view returns (uint8);

	/**
	 * @return the amount of tokens in existence
	 */
	function totalSupply() external view returns (uint256);

	/**
	 * @notice Gets the balance of a particular address
	 *
	 * @param _owner the address to query the the balance for
	 * @return balance an amount of tokens owned by the address specified
	 */
	function balanceOf(address _owner) external view returns (uint256 balance);

	/**
	 * @notice Transfers some tokens to an external address or a smart contract
	 *
	 * @dev Called by token owner (an address which has a
	 *      positive token balance tracked by this smart contract)
	 * @dev Throws on any error like
	 *      * insufficient token balance or
	 *      * incorrect `_to` address:
	 *          * zero address or
	 *          * self address or
	 *          * smart contract which doesn't support ERC20
	 *
	 * @param _to an address to transfer tokens to,
	 *      must be either an external address or a smart contract,
	 *      compliant with the ERC20 standard
	 * @param _value amount of tokens to be transferred,, zero
	 *      value is allowed
	 * @return success true on success, throws otherwise
	 */
	function transfer(address _to, uint256 _value) external returns (bool success);

	/**
	 * @notice Transfers some tokens on behalf of address `_from' (token owner)
	 *      to some other address `_to`
	 *
	 * @dev Called by token owner on his own or approved address,
	 *      an address approved earlier by token owner to
	 *      transfer some amount of tokens on its behalf
	 * @dev Throws on any error like
	 *      * insufficient token balance or
	 *      * incorrect `_to` address:
	 *          * zero address or
	 *          * same as `_from` address (self transfer)
	 *          * smart contract which doesn't support ERC20
	 *
	 * @param _from token owner which approved caller (transaction sender)
	 *      to transfer `_value` of tokens on its behalf
	 * @param _to an address to transfer tokens to,
	 *      must be either an external address or a smart contract,
	 *      compliant with the ERC20 standard
	 * @param _value amount of tokens to be transferred,, zero
	 *      value is allowed
	 * @return success true on success, throws otherwise
	 */
	function transferFrom(address _from, address _to, uint256 _value) external returns (bool success);

	/**
	 * @notice Approves address called `_spender` to transfer some amount
	 *      of tokens on behalf of the owner (transaction sender)
	 *
	 * @dev Transaction sender must not necessarily own any tokens to grant the permission
	 *
	 * @param _spender an address approved by the caller (token owner)
	 *      to spend some tokens on its behalf
	 * @param _value an amount of tokens spender `_spender` is allowed to
	 *      transfer on behalf of the token owner
	 * @return success true on success, throws otherwise
	 */
	function approve(address _spender, uint256 _value) external returns (bool success);

	/**
	 * @notice Returns the amount which _spender is still allowed to withdraw from _owner.
	 *
	 * @dev A function to check an amount of tokens owner approved
	 *      to transfer on its behalf by some other address called "spender"
	 *
	 * @param _owner an address which approves transferring some tokens on its behalf
	 * @param _spender an address approved to transfer some tokens on behalf
	 * @return remaining an amount of tokens approved address `_spender` can transfer on behalf
	 *      of token owner `_owner`
	 */
	function allowance(address _owner, address _spender) external view returns (uint256 remaining);
}

File 3 of 5 : ERC721Spec.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.7;

import "./ERC165Spec.sol";

/**
 * @title ERC-721 Non-Fungible Token Standard
 *
 * @notice See https://eips.ethereum.org/EIPS/eip-721
 *
 * @dev Solidity issue #3412: The ERC721 interfaces include explicit mutability guarantees for each function.
 *      Mutability guarantees are, in order weak to strong: payable, implicit nonpayable, view, and pure.
 *      Implementation MUST meet the mutability guarantee in this interface and MAY meet a stronger guarantee.
 *      For example, a payable function in this interface may be implemented as nonpayable
 *      (no state mutability specified) in implementing contract.
 *      It is expected a later Solidity release will allow stricter contract to inherit from this interface,
 *      but current workaround is that we edit this interface to add stricter mutability before inheriting:
 *      we have removed all "payable" modifiers.
 *
 * @dev The ERC-165 identifier for this interface is 0x80ac58cd.
 *
 * @author William Entriken, Dieter Shirley, Jacob Evans, Nastassia Sachs
 */
interface ERC721 is ERC165 {
	/// @dev This emits when ownership of any NFT changes by any mechanism.
	///  This event emits when NFTs are created (`from` == 0) and destroyed
	///  (`to` == 0). Exception: during contract creation, any number of NFTs
	///  may be created and assigned without emitting Transfer. At the time of
	///  any transfer, the approved address for that NFT (if any) is reset to none.
	event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);

	/// @dev This emits when the approved address for an NFT is changed or
	///  reaffirmed. The zero address indicates there is no approved address.
	///  When a Transfer event emits, this also indicates that the approved
	///  address for that NFT (if any) is reset to none.
	event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);

	/// @dev This emits when an operator is enabled or disabled for an owner.
	///  The operator can manage all NFTs of the owner.
	event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);

	/// @notice Count all NFTs assigned to an owner
	/// @dev NFTs assigned to the zero address are considered invalid, and this
	///  function throws for queries about the zero address.
	/// @param _owner An address for whom to query the balance
	/// @return The number of NFTs owned by `_owner`, possibly zero
	function balanceOf(address _owner) external view returns (uint256);

	/// @notice Find the owner of an NFT
	/// @dev NFTs assigned to zero address are considered invalid, and queries
	///  about them do throw.
	/// @param _tokenId The identifier for an NFT
	/// @return The address of the owner of the NFT
	function ownerOf(uint256 _tokenId) external view returns (address);

	/// @notice Transfers the ownership of an NFT from one address to another address
	/// @dev Throws unless `msg.sender` is the current owner, an authorized
	///  operator, or the approved address for this NFT. Throws if `_from` is
	///  not the current owner. Throws if `_to` is the zero address. Throws if
	///  `_tokenId` is not a valid NFT. When transfer is complete, this function
	///  checks if `_to` is a smart contract (code size > 0). If so, it calls
	///  `onERC721Received` on `_to` and throws if the return value is not
	///  `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.
	/// @param _from The current owner of the NFT
	/// @param _to The new owner
	/// @param _tokenId The NFT to transfer
	/// @param _data Additional data with no specified format, sent in call to `_to`
	function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes calldata _data) external /*payable*/;

	/// @notice Transfers the ownership of an NFT from one address to another address
	/// @dev This works identically to the other function with an extra data parameter,
	///  except this function just sets data to "".
	/// @param _from The current owner of the NFT
	/// @param _to The new owner
	/// @param _tokenId The NFT to transfer
	function safeTransferFrom(address _from, address _to, uint256 _tokenId) external /*payable*/;

	/// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
	///  TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE
	///  THEY MAY BE PERMANENTLY LOST
	/// @dev Throws unless `msg.sender` is the current owner, an authorized
	///  operator, or the approved address for this NFT. Throws if `_from` is
	///  not the current owner. Throws if `_to` is the zero address. Throws if
	///  `_tokenId` is not a valid NFT.
	/// @param _from The current owner of the NFT
	/// @param _to The new owner
	/// @param _tokenId The NFT to transfer
	function transferFrom(address _from, address _to, uint256 _tokenId) external /*payable*/;

	/// @notice Change or reaffirm the approved address for an NFT
	/// @dev The zero address indicates there is no approved address.
	///  Throws unless `msg.sender` is the current NFT owner, or an authorized
	///  operator of the current owner.
	/// @param _approved The new approved NFT controller
	/// @param _tokenId The NFT to approve
	function approve(address _approved, uint256 _tokenId) external /*payable*/;

	/// @notice Enable or disable approval for a third party ("operator") to manage
	///  all of `msg.sender`'s assets
	/// @dev Emits the ApprovalForAll event. The contract MUST allow
	///  multiple operators per owner.
	/// @param _operator Address to add to the set of authorized operators
	/// @param _approved True if the operator is approved, false to revoke approval
	function setApprovalForAll(address _operator, bool _approved) external;

	/// @notice Get the approved address for a single NFT
	/// @dev Throws if `_tokenId` is not a valid NFT.
	/// @param _tokenId The NFT to find the approved address for
	/// @return The approved address for this NFT, or the zero address if there is none
	function getApproved(uint256 _tokenId) external view returns (address);

	/// @notice Query if an address is an authorized operator for another address
	/// @param _owner The address that owns the NFTs
	/// @param _operator The address that acts on behalf of the owner
	/// @return True if `_operator` is an approved operator for `_owner`, false otherwise
	function isApprovedForAll(address _owner, address _operator) external view returns (bool);
}

/// @dev Note: the ERC-165 identifier for this interface is 0x150b7a02.
interface ERC721TokenReceiver {
	/// @notice Handle the receipt of an NFT
	/// @dev The ERC721 smart contract calls this function on the recipient
	///  after a `transfer`. This function MAY throw to revert and reject the
	///  transfer. Return of other than the magic value MUST result in the
	///  transaction being reverted.
	///  Note: the contract address is always the message sender.
	/// @param _operator The address which called `safeTransferFrom` function
	/// @param _from The address which previously owned the token
	/// @param _tokenId The NFT identifier which is being transferred
	/// @param _data Additional data with no specified format
	/// @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
	///  unless throwing
	function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes calldata _data) external returns(bytes4);
}

/**
 * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
 *
 * @notice See https://eips.ethereum.org/EIPS/eip-721
 *
 * @dev The ERC-165 identifier for this interface is 0x5b5e139f.
 *
 * @author William Entriken, Dieter Shirley, Jacob Evans, Nastassia Sachs
 */
interface ERC721Metadata is ERC721 {
	/// @notice A descriptive name for a collection of NFTs in this contract
	function name() external view returns (string memory _name);

	/// @notice An abbreviated name for NFTs in this contract
	function symbol() external view returns (string memory _symbol);

	/// @notice A distinct Uniform Resource Identifier (URI) for a given asset.
	/// @dev Throws if `_tokenId` is not a valid NFT. URIs are defined in RFC
	///  3986. The URI may point to a JSON file that conforms to the "ERC721
	///  Metadata JSON Schema".
	function tokenURI(uint256 _tokenId) external view returns (string memory);
}

/**
 * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
 *
 * @notice See https://eips.ethereum.org/EIPS/eip-721
 *
 * @dev The ERC-165 identifier for this interface is 0x780e9d63.
 *
 * @author William Entriken, Dieter Shirley, Jacob Evans, Nastassia Sachs
 */
interface ERC721Enumerable is ERC721 {
	/// @notice Count NFTs tracked by this contract
	/// @return A count of valid NFTs tracked by this contract, where each one of
	///  them has an assigned and queryable owner not equal to the zero address
	function totalSupply() external view returns (uint256);

	/// @notice Enumerate valid NFTs
	/// @dev Throws if `_index` >= `totalSupply()`.
	/// @param _index A counter less than `totalSupply()`
	/// @return The token identifier for the `_index`th NFT,
	///  (sort order not specified)
	function tokenByIndex(uint256 _index) external view returns (uint256);

	/// @notice Enumerate NFTs assigned to an owner
	/// @dev Throws if `_index` >= `balanceOf(_owner)` or if
	///  `_owner` is the zero address, representing invalid NFTs.
	/// @param _owner An address where we are interested in NFTs owned by them
	/// @param _index A counter less than `balanceOf(_owner)`
	/// @return The token identifier for the `_index`th NFT assigned to `_owner`,
	///   (sort order not specified)
	function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256);
}

File 4 of 5 : AccessControl.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.7;

/**
 * @title Access Control List
 *
 * @notice Access control smart contract provides an API to check
 *      if specific operation is permitted globally and/or
 *      if particular user has a permission to execute it.
 *
 * @notice It deals with two main entities: features and roles.
 *
 * @notice Features are designed to be used to enable/disable specific
 *      functions (public functions) of the smart contract for everyone.
 * @notice User roles are designed to restrict access to specific
 *      functions (restricted functions) of the smart contract to some users.
 *
 * @notice Terms "role", "permissions" and "set of permissions" have equal meaning
 *      in the documentation text and may be used interchangeably.
 * @notice Terms "permission", "single permission" implies only one permission bit set.
 *
 * @notice Access manager is a special role which allows to grant/revoke other roles.
 *      Access managers can only grant/revoke permissions which they have themselves.
 *      As an example, access manager with no other roles set can only grant/revoke its own
 *      access manager permission and nothing else.
 *
 * @notice Access manager permission should be treated carefully, as a super admin permission:
 *      Access manager with even no other permission can interfere with another account by
 *      granting own access manager permission to it and effectively creating more powerful
 *      permission set than its own.
 *
 * @dev Both current and OpenZeppelin AccessControl implementations feature a similar API
 *      to check/know "who is allowed to do this thing".
 * @dev Zeppelin implementation is more flexible:
 *      - it allows setting unlimited number of roles, while current is limited to 256 different roles
 *      - it allows setting an admin for each role, while current allows having only one global admin
 * @dev Current implementation is more lightweight:
 *      - it uses only 1 bit per role, while Zeppelin uses 256 bits
 *      - it allows setting up to 256 roles at once, in a single transaction, while Zeppelin allows
 *        setting only one role in a single transaction
 *
 * @dev This smart contract is designed to be inherited by other
 *      smart contracts which require access control management capabilities.
 *
 * @dev Access manager permission has a bit 255 set.
 *      This bit must not be used by inheriting contracts for any other permissions/features.
 */
contract AccessControl {
	/**
	 * @notice Access manager is responsible for assigning the roles to users,
	 *      enabling/disabling global features of the smart contract
	 * @notice Access manager can add, remove and update user roles,
	 *      remove and update global features
	 *
	 * @dev Role ROLE_ACCESS_MANAGER allows modifying user roles and global features
	 * @dev Role ROLE_ACCESS_MANAGER has single bit at position 255 enabled
	 */
	uint256 public constant ROLE_ACCESS_MANAGER = 0x8000000000000000000000000000000000000000000000000000000000000000;

	/**
	 * @dev Bitmask representing all the possible permissions (super admin role)
	 * @dev Has all the bits are enabled (2^256 - 1 value)
	 */
	uint256 private constant FULL_PRIVILEGES_MASK = type(uint256).max; // before 0.8.0: uint256(-1) overflows to 0xFFFF...

	/**
	 * @notice Privileged addresses with defined roles/permissions
	 * @notice In the context of ERC20/ERC721 tokens these can be permissions to
	 *      allow minting or burning tokens, transferring on behalf and so on
	 *
	 * @dev Maps user address to the permissions bitmask (role), where each bit
	 *      represents a permission
	 * @dev Bitmask 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
	 *      represents all possible permissions
	 * @dev 'This' address mapping represents global features of the smart contract
	 */
	mapping(address => uint256) public userRoles;

	/**
	 * @dev Fired in updateRole() and updateFeatures()
	 *
	 * @param _by operator which called the function
	 * @param _to address which was granted/revoked permissions
	 * @param _requested permissions requested
	 * @param _actual permissions effectively set
	 */
	event RoleUpdated(address indexed _by, address indexed _to, uint256 _requested, uint256 _actual);

	/**
	 * @notice Creates an access control instance,
	 *      setting contract creator to have full privileges
	 */
	constructor() {
		// contract creator has full privileges
		userRoles[msg.sender] = FULL_PRIVILEGES_MASK;
	}

	/**
	 * @notice Retrieves globally set of features enabled
	 *
	 * @dev Effectively reads userRoles role for the contract itself
	 *
	 * @return 256-bit bitmask of the features enabled
	 */
	function features() public view returns(uint256) {
		// features are stored in 'this' address  mapping of `userRoles` structure
		return userRoles[address(this)];
	}

	/**
	 * @notice Updates set of the globally enabled features (`features`),
	 *      taking into account sender's permissions
	 *
	 * @dev Requires transaction sender to have `ROLE_ACCESS_MANAGER` permission
	 * @dev Function is left for backward compatibility with older versions
	 *
	 * @param _mask bitmask representing a set of features to enable/disable
	 */
	function updateFeatures(uint256 _mask) public {
		// delegate call to `updateRole`
		updateRole(address(this), _mask);
	}

	/**
	 * @notice Updates set of permissions (role) for a given user,
	 *      taking into account sender's permissions.
	 *
	 * @dev Setting role to zero is equivalent to removing an all permissions
	 * @dev Setting role to `FULL_PRIVILEGES_MASK` is equivalent to
	 *      copying senders' permissions (role) to the user
	 * @dev Requires transaction sender to have `ROLE_ACCESS_MANAGER` permission
	 *
	 * @param operator address of a user to alter permissions for or zero
	 *      to alter global features of the smart contract
	 * @param role bitmask representing a set of permissions to
	 *      enable/disable for a user specified
	 */
	function updateRole(address operator, uint256 role) public {
		// caller must have a permission to update user roles
		require(isSenderInRole(ROLE_ACCESS_MANAGER), "access denied");

		// evaluate the role and reassign it
		userRoles[operator] = evaluateBy(msg.sender, userRoles[operator], role);

		// fire an event
		emit RoleUpdated(msg.sender, operator, role, userRoles[operator]);
	}

	/**
	 * @notice Determines the permission bitmask an operator can set on the
	 *      target permission set
	 * @notice Used to calculate the permission bitmask to be set when requested
	 *     in `updateRole` and `updateFeatures` functions
	 *
	 * @dev Calculated based on:
	 *      1) operator's own permission set read from userRoles[operator]
	 *      2) target permission set - what is already set on the target
	 *      3) desired permission set - what do we want set target to
	 *
	 * @dev Corner cases:
	 *      1) Operator is super admin and its permission set is `FULL_PRIVILEGES_MASK`:
	 *        `desired` bitset is returned regardless of the `target` permission set value
	 *        (what operator sets is what they get)
	 *      2) Operator with no permissions (zero bitset):
	 *        `target` bitset is returned regardless of the `desired` value
	 *        (operator has no authority and cannot modify anything)
	 *
	 * @dev Example:
	 *      Consider an operator with the permissions bitmask     00001111
	 *      is about to modify the target permission set          01010101
	 *      Operator wants to set that permission set to          00110011
	 *      Based on their role, an operator has the permissions
	 *      to update only lowest 4 bits on the target, meaning that
	 *      high 4 bits of the target set in this example is left
	 *      unchanged and low 4 bits get changed as desired:      01010011
	 *
	 * @param operator address of the contract operator which is about to set the permissions
	 * @param target input set of permissions to operator is going to modify
	 * @param desired desired set of permissions operator would like to set
	 * @return resulting set of permissions given operator will set
	 */
	function evaluateBy(address operator, uint256 target, uint256 desired) public view returns(uint256) {
		// read operator's permissions
		uint256 p = userRoles[operator];

		// taking into account operator's permissions,
		// 1) enable the permissions desired on the `target`
		target |= p & desired;
		// 2) disable the permissions desired on the `target`
		target &= FULL_PRIVILEGES_MASK ^ (p & (FULL_PRIVILEGES_MASK ^ desired));

		// return calculated result
		return target;
	}

	/**
	 * @notice Checks if requested set of features is enabled globally on the contract
	 *
	 * @param required set of features to check against
	 * @return true if all the features requested are enabled, false otherwise
	 */
	function isFeatureEnabled(uint256 required) public view returns(bool) {
		// delegate call to `__hasRole`, passing `features` property
		return __hasRole(features(), required);
	}

	/**
	 * @notice Checks if transaction sender `msg.sender` has all the permissions required
	 *
	 * @param required set of permissions (role) to check against
	 * @return true if all the permissions requested are enabled, false otherwise
	 */
	function isSenderInRole(uint256 required) public view returns(bool) {
		// delegate call to `isOperatorInRole`, passing transaction sender
		return isOperatorInRole(msg.sender, required);
	}

	/**
	 * @notice Checks if operator has all the permissions (role) required
	 *
	 * @param operator address of the user to check role for
	 * @param required set of permissions (role) to check
	 * @return true if all the permissions requested are enabled, false otherwise
	 */
	function isOperatorInRole(address operator, uint256 required) public view returns(bool) {
		// delegate call to `__hasRole`, passing operator's permissions (role)
		return __hasRole(userRoles[operator], required);
	}

	/**
	 * @dev Checks if role `actual` contains all the permissions required `required`
	 *
	 * @param actual existent role
	 * @param required required role
	 * @return true if actual has required role (all permissions), false otherwise
	 */
	function __hasRole(uint256 actual, uint256 required) internal pure returns(bool) {
		// check the bitmask for the role required and return the result
		return actual & required == required;
	}
}

File 5 of 5 : ERC165Spec.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.7;

/**
 * @title ERC-165 Standard Interface Detection
 *
 * @dev Interface of the ERC165 standard, as defined in the
 *       https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * @dev Implementers can declare support of contract interfaces,
 *      which can then be queried by others.
 *
 * @author Christian Reitwießner, Nick Johnson, Fabian Vogelsteller, Jordi Baylina, Konrad Feldmeier, William Entriken
 */
interface ERC165 {
	/**
	 * @notice Query if a contract implements an interface
	 *
	 * @dev Interface identification is specified in ERC-165.
	 *      This function uses less than 30,000 gas.
	 *
	 * @param interfaceID The interface identifier, as specified in ERC-165
	 * @return `true` if the contract implements `interfaceID` and
	 *      `interfaceID` is not 0xffffffff, `false` otherwise
	 */
	function supportsInterface(bytes4 interfaceID) external view returns (bool);
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_nft","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_by","type":"address"},{"indexed":true,"internalType":"address","name":"_to","type":"address"},{"indexed":false,"internalType":"uint256","name":"_requested","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_actual","type":"uint256"}],"name":"RoleUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_by","type":"address"},{"indexed":true,"internalType":"uint32","name":"_tokenId","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"_when","type":"uint32"}],"name":"Staked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_by","type":"address"},{"indexed":true,"internalType":"uint32","name":"_tokenId","type":"uint32"},{"indexed":false,"internalType":"uint32","name":"_when","type":"uint32"}],"name":"Unstaked","type":"event"},{"inputs":[],"name":"FEATURE_STAKING","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEATURE_UNSTAKING","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ROLE_ACCESS_MANAGER","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ROLE_RESCUE_MANAGER","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"target","type":"uint256"},{"internalType":"uint256","name":"desired","type":"uint256"}],"name":"evaluateBy","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"features","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"required","type":"uint256"}],"name":"isFeatureEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"required","type":"uint256"}],"name":"isOperatorInRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"required","type":"uint256"}],"name":"isSenderInRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"tokenId","type":"uint32"}],"name":"isStaked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"now32","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"numStakes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"tokenId","type":"uint32"}],"name":"numStakes","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_contract","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"rescueErc20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_contract","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"rescueErc721","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"tokenId","type":"uint32"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32[]","name":"tokenIds","type":"uint32[]"}],"name":"stakeBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"targetContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"","type":"uint32"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokenStakes","outputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint32","name":"stakedOn","type":"uint32"},{"internalType":"uint32","name":"unstakedOn","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint32","name":"tokenId","type":"uint32"}],"name":"unstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32[]","name":"tokenIds","type":"uint32[]"}],"name":"unstakeBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_mask","type":"uint256"}],"name":"updateFeatures","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"role","type":"uint256"}],"name":"updateRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"userRoles","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"userStakes","outputs":[{"internalType":"uint32","name":"tokenId","type":"uint32"},{"internalType":"uint32","name":"index","type":"uint32"}],"stateMutability":"view","type":"function"}]

60a06040523480156200001157600080fd5b50604051620013f8380380620013f883398101604081905262000034916200018a565b33600090815260208190526040902060001990556001600160a01b038116620000a45760405162461bcd60e51b815260206004820152601a60248201527f74617267657420636f6e7472616374206973206e6f742073657400000000000060448201526064015b60405180910390fd5b6040516301ffc9a760e01b81526380ac58cd60e01b60048201526001600160a01b038216906301ffc9a79060240160206040518083038186803b158015620000eb57600080fd5b505afa15801562000100573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001269190620001bc565b620001745760405162461bcd60e51b815260206004820152601660248201527f756e65787065637465642074617267657420747970650000000000000000000060448201526064016200009b565b60601b6001600160601b031916608052620001e0565b6000602082840312156200019d57600080fd5b81516001600160a01b0381168114620001b557600080fd5b9392505050565b600060208284031215620001cf57600080fd5b81518015158114620001b557600080fd5b60805160601c6111dd6200021b60003960008181610324015281816104350152818161074f015281816108160152610bcc01526111dd6000f3fe608060405234801561001057600080fd5b50600436106101735760003560e01c8063809ee57d116100de578063c688d69311610097578063e60999ab11610071578063e60999ab146103c3578063f13b42fe146103c9578063f822d5aa146103dc578063fcc2c078146103ef57600080fd5b8063c688d6931461035e578063d5bb7f6714610371578063db6d98df1461038457600080fd5b8063809ee57d146102ab578063a69cb327146102be578063ae5b102e146102d1578063ae682e2e146102e4578063b5d5b5fa146102ef578063bd90df701461031f57600080fd5b80633a90b569116101305780633a90b56914610214578063490b7b9a1461023a57806355a38f2814610242578063725f36261461025557806374d5e100146102785780637fcfb7c21461029857600080fd5b806316ce9f0c14610178578063243feb991461018d5780632b521416146101a05780632d17f8bc146101c45780633467e9e1146101e3578063366d4f881461020c575b600080fd5b61018b610186366004610f17565b610402565b005b61018b61019b366004610f17565b610525565b306000908152602081905260409020545b6040519081526020015b60405180910390f35b6101ce6201000081565b60405163ffffffff90911681526020016101bb565b6101b16101f1366004610edd565b6001600160a01b031660009081526002602052604090205490565b6101ce600281565b6101b16102223660046110c0565b63ffffffff1660009081526001602052604090205490565b6101ce600181565b61018b610250366004610fb9565b6105d5565b6102686102633660046110a7565b610619565b60405190151581526020016101bb565b6101b1610286366004610edd565b60006020819052908152604090205481565b61018b6102a63660046110c0565b610634565b61018b6102b93660046110c0565b6109ba565b61018b6102cc366004610fb9565b610c6c565b61018b6102df366004610f58565b610cac565b6101b1600160ff1b81565b6103026102fd366004610f58565b610d56565b6040805163ffffffff9384168152929091166020830152016101bb565b6103467f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016101bb565b61026861036c366004610f58565b610d97565b61018b61037f3660046110a7565b610dbc565b6103976103923660046110db565b610dc9565b604080516001600160a01b03909416845263ffffffff92831660208501529116908201526060016101bb565b426101ce565b6102686103d73660046110c0565b610e19565b6101b16103ea366004610f84565b610e8d565b6102686103fd3660046110a7565b610eb8565b61040e62010000610eb8565b6104335760405162461bcd60e51b815260040161042a906110f7565b60405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b031614158061047a575061047881610e19565b155b6104b85760405162461bcd60e51b815260206004820152600f60248201526e1d1bdad95b881a5cc81cdd185ad959608a1b604482015260640161042a565b6040516323b872dd60e01b81523060048201526001600160a01b038381166024830152604482018390528416906323b872dd90606401600060405180830381600087803b15801561050857600080fd5b505af115801561051c573d6000803e3d6000fd5b50505050505050565b61053162010000610eb8565b61054d5760405162461bcd60e51b815260040161042a906110f7565b60405163a9059cbb60e01b81526001600160a01b0383811660048301526024820183905284169063a9059cbb90604401602060405180830381600087803b15801561059757600080fd5b505af11580156105ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105cf9190611085565b50505050565b60005b8151811015610615576106038282815181106105f6576105f6611166565b6020026020010151610634565b8061060d81611135565b9150506105d8565b5050565b30600090815260208190526040812054821682145b92915050565b61063e6001610619565b6106805760405162461bcd60e51b81526020600482015260136024820152721cdd185ada5b99c81a5cc8191a5cd8589b1959606a1b604482015260640161042a565b63ffffffff81166000908152600160205260409020548015806106ed575063ffffffff82166000908152600160208190526040909120906106c1908361111e565b815481106106d1576106d1611166565b600091825260209091200154600160c01b900463ffffffff1615155b61072a5760405162461bcd60e51b815260206004820152600e60248201526d185b1c9958591e481cdd185ad95960921b604482015260640161042a565b6040516331a9108f60e11b815263ffffffff8316600482015233906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690636352211e9060240160206040518083038186803b15801561079157600080fd5b505afa1580156107a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107c99190610efa565b6001600160a01b0316146107ef5760405162461bcd60e51b815260040161042a906110f7565b6040516323b872dd60e01b815233600482015230602482015263ffffffff831660448201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906323b872dd90606401600060405180830381600087803b15801561086257600080fd5b505af1158015610876573d6000803e3d6000fd5b5050505060006108834290565b63ffffffff8085166000818152600160208181526040808420815160608101835233808252888a16828601908152828501888152845480890186559489528689209351939094018054915194518b16600160c01b0263ffffffff60c01b19958c16600160a01b026001600160c01b03199093166001600160a01b03959095169490941791909117939093169190911790915580855260028352818520825180840184528781528b891681860190815282549687018355918752939095209251929093018054945187166401000000000267ffffffffffffffff1990951692909616919091179290921790935551929350917f8d014b746c7fb511963855f62ef66b6859e8ce4e0524803ad565394fca8a8779906109ad90859063ffffffff91909116815260200190565b60405180910390a3505050565b6109c46002610619565b610a085760405162461bcd60e51b81526020600482015260156024820152741d5b9cdd185ada5b99c81a5cc8191a5cd8589b1959605a1b604482015260640161042a565b63ffffffff811660009081526001602052604090205480610a585760405162461bcd60e51b815260206004820152600a6024820152691b9bdd081cdd185ad95960b21b604482015260640161042a565b63ffffffff8216600090815260016020819052604090912090610a7b908361111e565b81548110610a8b57610a8b611166565b600091825260209091200154600160c01b900463ffffffff1615610ae45760405162461bcd60e51b815260206004820152601060248201526f185b1c9958591e481d5b9cdd185ad95960821b604482015260640161042a565b63ffffffff821660009081526001602081905260409091203391610b08908461111e565b81548110610b1857610b18611166565b6000918252602090912001546001600160a01b031614610b4a5760405162461bcd60e51b815260040161042a906110f7565b63ffffffff821660009081526001602081905260409091204291829190610b71908561111e565b81548110610b8157610b81611166565b6000918252602090912001805463ffffffff60c01b1916600160c01b63ffffffff938416021790556040516323b872dd60e01b815230600482015233602482015290841660448201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906323b872dd90606401600060405180830381600087803b158015610c1857600080fd5b505af1158015610c2c573d6000803e3d6000fd5b505060405163ffffffff8481168252861692503391507f1559f9d134d7761c724b694e7080cc95b2950bd40608ca802f85fcc0b23c586c906020016109ad565b60005b815181101561061557610c9a828281518110610c8d57610c8d611166565b60200260200101516109ba565b80610ca481611135565b915050610c6f565b610cb9600160ff1b610eb8565b610cd55760405162461bcd60e51b815260040161042a906110f7565b6001600160a01b038216600090815260208190526040902054610cfa90339083610e8d565b6001600160a01b03831660008181526020818152604091829020849055815185815290810193909352909133917f5a10526456f5116c0b7b80582c217d666243fd51b6a2d92c8011e601c2462e5f910160405180910390a35050565b60026020528160005260406000208181548110610d7257600080fd5b60009182526020909120015463ffffffff808216935064010000000090910416905082565b6001600160a01b038216600090815260208190526040812054821682145b9392505050565b610dc63082610cac565b50565b60016020528160005260406000208181548110610de557600080fd5b6000918252602090912001546001600160a01b038116925063ffffffff600160a01b820481169250600160c01b9091041683565b63ffffffff81166000908152600160205260408120548015801590610db5575063ffffffff8316600090815260016020819052604090912090610e5c908361111e565b81548110610e6c57610e6c611166565b600091825260209091200154600160c01b900463ffffffff16159392505050565b6001600160a01b03929092166000908152602081905260409020546000198084188216189216171690565b600061062e3383610d97565b803563ffffffff81168114610ed857600080fd5b919050565b600060208284031215610eef57600080fd5b8135610db581611192565b600060208284031215610f0c57600080fd5b8151610db581611192565b600080600060608486031215610f2c57600080fd5b8335610f3781611192565b92506020840135610f4781611192565b929592945050506040919091013590565b60008060408385031215610f6b57600080fd5b8235610f7681611192565b946020939093013593505050565b600080600060608486031215610f9957600080fd5b8335610fa481611192565b95602085013595506040909401359392505050565b60006020808385031215610fcc57600080fd5b823567ffffffffffffffff80821115610fe457600080fd5b818501915085601f830112610ff857600080fd5b81358181111561100a5761100a61117c565b8060051b604051601f19603f8301168101818110858211171561102f5761102f61117c565b604052828152858101935084860182860187018a101561104e57600080fd5b600095505b838610156110785761106481610ec4565b855260019590950194938601938601611053565b5098975050505050505050565b60006020828403121561109757600080fd5b81518015158114610db557600080fd5b6000602082840312156110b957600080fd5b5035919050565b6000602082840312156110d257600080fd5b610db582610ec4565b600080604083850312156110ee57600080fd5b610f7683610ec4565b6020808252600d908201526c1858d8d95cdcc819195b9a5959609a1b604082015260600190565b60008282101561113057611130611150565b500390565b600060001982141561114957611149611150565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114610dc657600080fdfea26469706673582212207cdb496931f82b95d6b28fbbd143a992dfe26c8284a53304f3494d110ec876dd64736f6c63430008070033000000000000000000000000dd70af84ba86f29bf437756b655110d134b5651c

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101735760003560e01c8063809ee57d116100de578063c688d69311610097578063e60999ab11610071578063e60999ab146103c3578063f13b42fe146103c9578063f822d5aa146103dc578063fcc2c078146103ef57600080fd5b8063c688d6931461035e578063d5bb7f6714610371578063db6d98df1461038457600080fd5b8063809ee57d146102ab578063a69cb327146102be578063ae5b102e146102d1578063ae682e2e146102e4578063b5d5b5fa146102ef578063bd90df701461031f57600080fd5b80633a90b569116101305780633a90b56914610214578063490b7b9a1461023a57806355a38f2814610242578063725f36261461025557806374d5e100146102785780637fcfb7c21461029857600080fd5b806316ce9f0c14610178578063243feb991461018d5780632b521416146101a05780632d17f8bc146101c45780633467e9e1146101e3578063366d4f881461020c575b600080fd5b61018b610186366004610f17565b610402565b005b61018b61019b366004610f17565b610525565b306000908152602081905260409020545b6040519081526020015b60405180910390f35b6101ce6201000081565b60405163ffffffff90911681526020016101bb565b6101b16101f1366004610edd565b6001600160a01b031660009081526002602052604090205490565b6101ce600281565b6101b16102223660046110c0565b63ffffffff1660009081526001602052604090205490565b6101ce600181565b61018b610250366004610fb9565b6105d5565b6102686102633660046110a7565b610619565b60405190151581526020016101bb565b6101b1610286366004610edd565b60006020819052908152604090205481565b61018b6102a63660046110c0565b610634565b61018b6102b93660046110c0565b6109ba565b61018b6102cc366004610fb9565b610c6c565b61018b6102df366004610f58565b610cac565b6101b1600160ff1b81565b6103026102fd366004610f58565b610d56565b6040805163ffffffff9384168152929091166020830152016101bb565b6103467f000000000000000000000000dd70af84ba86f29bf437756b655110d134b5651c81565b6040516001600160a01b0390911681526020016101bb565b61026861036c366004610f58565b610d97565b61018b61037f3660046110a7565b610dbc565b6103976103923660046110db565b610dc9565b604080516001600160a01b03909416845263ffffffff92831660208501529116908201526060016101bb565b426101ce565b6102686103d73660046110c0565b610e19565b6101b16103ea366004610f84565b610e8d565b6102686103fd3660046110a7565b610eb8565b61040e62010000610eb8565b6104335760405162461bcd60e51b815260040161042a906110f7565b60405180910390fd5b7f000000000000000000000000dd70af84ba86f29bf437756b655110d134b5651c6001600160a01b0316836001600160a01b031614158061047a575061047881610e19565b155b6104b85760405162461bcd60e51b815260206004820152600f60248201526e1d1bdad95b881a5cc81cdd185ad959608a1b604482015260640161042a565b6040516323b872dd60e01b81523060048201526001600160a01b038381166024830152604482018390528416906323b872dd90606401600060405180830381600087803b15801561050857600080fd5b505af115801561051c573d6000803e3d6000fd5b50505050505050565b61053162010000610eb8565b61054d5760405162461bcd60e51b815260040161042a906110f7565b60405163a9059cbb60e01b81526001600160a01b0383811660048301526024820183905284169063a9059cbb90604401602060405180830381600087803b15801561059757600080fd5b505af11580156105ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105cf9190611085565b50505050565b60005b8151811015610615576106038282815181106105f6576105f6611166565b6020026020010151610634565b8061060d81611135565b9150506105d8565b5050565b30600090815260208190526040812054821682145b92915050565b61063e6001610619565b6106805760405162461bcd60e51b81526020600482015260136024820152721cdd185ada5b99c81a5cc8191a5cd8589b1959606a1b604482015260640161042a565b63ffffffff81166000908152600160205260409020548015806106ed575063ffffffff82166000908152600160208190526040909120906106c1908361111e565b815481106106d1576106d1611166565b600091825260209091200154600160c01b900463ffffffff1615155b61072a5760405162461bcd60e51b815260206004820152600e60248201526d185b1c9958591e481cdd185ad95960921b604482015260640161042a565b6040516331a9108f60e11b815263ffffffff8316600482015233906001600160a01b037f000000000000000000000000dd70af84ba86f29bf437756b655110d134b5651c1690636352211e9060240160206040518083038186803b15801561079157600080fd5b505afa1580156107a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107c99190610efa565b6001600160a01b0316146107ef5760405162461bcd60e51b815260040161042a906110f7565b6040516323b872dd60e01b815233600482015230602482015263ffffffff831660448201527f000000000000000000000000dd70af84ba86f29bf437756b655110d134b5651c6001600160a01b0316906323b872dd90606401600060405180830381600087803b15801561086257600080fd5b505af1158015610876573d6000803e3d6000fd5b5050505060006108834290565b63ffffffff8085166000818152600160208181526040808420815160608101835233808252888a16828601908152828501888152845480890186559489528689209351939094018054915194518b16600160c01b0263ffffffff60c01b19958c16600160a01b026001600160c01b03199093166001600160a01b03959095169490941791909117939093169190911790915580855260028352818520825180840184528781528b891681860190815282549687018355918752939095209251929093018054945187166401000000000267ffffffffffffffff1990951692909616919091179290921790935551929350917f8d014b746c7fb511963855f62ef66b6859e8ce4e0524803ad565394fca8a8779906109ad90859063ffffffff91909116815260200190565b60405180910390a3505050565b6109c46002610619565b610a085760405162461bcd60e51b81526020600482015260156024820152741d5b9cdd185ada5b99c81a5cc8191a5cd8589b1959605a1b604482015260640161042a565b63ffffffff811660009081526001602052604090205480610a585760405162461bcd60e51b815260206004820152600a6024820152691b9bdd081cdd185ad95960b21b604482015260640161042a565b63ffffffff8216600090815260016020819052604090912090610a7b908361111e565b81548110610a8b57610a8b611166565b600091825260209091200154600160c01b900463ffffffff1615610ae45760405162461bcd60e51b815260206004820152601060248201526f185b1c9958591e481d5b9cdd185ad95960821b604482015260640161042a565b63ffffffff821660009081526001602081905260409091203391610b08908461111e565b81548110610b1857610b18611166565b6000918252602090912001546001600160a01b031614610b4a5760405162461bcd60e51b815260040161042a906110f7565b63ffffffff821660009081526001602081905260409091204291829190610b71908561111e565b81548110610b8157610b81611166565b6000918252602090912001805463ffffffff60c01b1916600160c01b63ffffffff938416021790556040516323b872dd60e01b815230600482015233602482015290841660448201527f000000000000000000000000dd70af84ba86f29bf437756b655110d134b5651c6001600160a01b0316906323b872dd90606401600060405180830381600087803b158015610c1857600080fd5b505af1158015610c2c573d6000803e3d6000fd5b505060405163ffffffff8481168252861692503391507f1559f9d134d7761c724b694e7080cc95b2950bd40608ca802f85fcc0b23c586c906020016109ad565b60005b815181101561061557610c9a828281518110610c8d57610c8d611166565b60200260200101516109ba565b80610ca481611135565b915050610c6f565b610cb9600160ff1b610eb8565b610cd55760405162461bcd60e51b815260040161042a906110f7565b6001600160a01b038216600090815260208190526040902054610cfa90339083610e8d565b6001600160a01b03831660008181526020818152604091829020849055815185815290810193909352909133917f5a10526456f5116c0b7b80582c217d666243fd51b6a2d92c8011e601c2462e5f910160405180910390a35050565b60026020528160005260406000208181548110610d7257600080fd5b60009182526020909120015463ffffffff808216935064010000000090910416905082565b6001600160a01b038216600090815260208190526040812054821682145b9392505050565b610dc63082610cac565b50565b60016020528160005260406000208181548110610de557600080fd5b6000918252602090912001546001600160a01b038116925063ffffffff600160a01b820481169250600160c01b9091041683565b63ffffffff81166000908152600160205260408120548015801590610db5575063ffffffff8316600090815260016020819052604090912090610e5c908361111e565b81548110610e6c57610e6c611166565b600091825260209091200154600160c01b900463ffffffff16159392505050565b6001600160a01b03929092166000908152602081905260409020546000198084188216189216171690565b600061062e3383610d97565b803563ffffffff81168114610ed857600080fd5b919050565b600060208284031215610eef57600080fd5b8135610db581611192565b600060208284031215610f0c57600080fd5b8151610db581611192565b600080600060608486031215610f2c57600080fd5b8335610f3781611192565b92506020840135610f4781611192565b929592945050506040919091013590565b60008060408385031215610f6b57600080fd5b8235610f7681611192565b946020939093013593505050565b600080600060608486031215610f9957600080fd5b8335610fa481611192565b95602085013595506040909401359392505050565b60006020808385031215610fcc57600080fd5b823567ffffffffffffffff80821115610fe457600080fd5b818501915085601f830112610ff857600080fd5b81358181111561100a5761100a61117c565b8060051b604051601f19603f8301168101818110858211171561102f5761102f61117c565b604052828152858101935084860182860187018a101561104e57600080fd5b600095505b838610156110785761106481610ec4565b855260019590950194938601938601611053565b5098975050505050505050565b60006020828403121561109757600080fd5b81518015158114610db557600080fd5b6000602082840312156110b957600080fd5b5035919050565b6000602082840312156110d257600080fd5b610db582610ec4565b600080604083850312156110ee57600080fd5b610f7683610ec4565b6020808252600d908201526c1858d8d95cdcc819195b9a5959609a1b604082015260600190565b60008282101561113057611130611150565b500390565b600060001982141561114957611149611150565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160a01b0381168114610dc657600080fdfea26469706673582212207cdb496931f82b95d6b28fbbd143a992dfe26c8284a53304f3494d110ec876dd64736f6c63430008070033

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

000000000000000000000000dd70af84ba86f29bf437756b655110d134b5651c

-----Decoded View---------------
Arg [0] : _nft (address): 0xDd70AF84BA86F29bf437756B655110D134b5651C

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000dd70af84ba86f29bf437756b655110d134b5651c


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.