Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
20475935 | 126 days ago | Contract Creation | 0 ETH |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Source Code Verified (Exact Match)
Contract Name:
BT404MirrorOG
Compiler Version
v0.8.26+commit.8a97fa7a
Optimization Enabled:
Yes with 1000 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import {IERC721Metadata} from "../external/IERC721Metadata.sol"; import {BT404Mirror} from "../BT404Mirror.sol"; import {BT404MirrorWrapper} from "../BT404MirrorWrapper.sol"; import {UUPSUpgradeable} from "solady/utils/UUPSUpgradeable.sol"; import {OwnableRoles} from "solady/auth/OwnableRoles.sol"; contract BT404MirrorOG is BT404MirrorWrapper, UUPSUpgradeable { /// @dev The role that can upgrade the implementation. /// Keep it the same as the base contract. uint256 private constant _UPGRADE_MANAGER_ROLE = 1 << 61; // init with `address(1)` to prevent double-initializing constructor() payable BT404MirrorWrapper() { _initializeBT404MirrorWrapper(address(1), address(1), 0, 0); } modifier onlyUpgradeRole() { _checkUpgradeRole(); _; } function _checkUpgradeRole() internal view { if (!OwnableRoles(baseERC20()).hasAnyRole(msg.sender, _UPGRADE_MANAGER_ROLE)) { revert Unauthorized(); } } function _authorizeUpgrade(address) internal override onlyUpgradeRole {} function initialize(address _baseERC721, uint256 _startBaseId, uint256 _endBaseId) public payable { // if deployer was set, can not initialize again if (_getBT404NFTStorage().deployer != address(0)) revert Unauthorized(); _initializeBT404MirrorWrapper(msg.sender, _baseERC721, _startBaseId, _endBaseId); } function tokenURI(uint256 tokenId) public view override returns (string memory result) { IERC721Metadata base = IERC721Metadata(baseERC721()); try base.tokenURI(tokenId) returns (string memory res) { return res; } catch (bytes memory) { return super.tokenURI(tokenId); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Metadata.sol) pragma solidity ^0.8.22; import {IERC721} from "./IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Metadata is IERC721 { /** * @dev Returns the token collection name. */ function name() external view returns (string memory); /** * @dev Returns the token collection symbol. */ function symbol() external view returns (string memory); /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) external view returns (string memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; /// @title BT404Mirror /// @notice BT404Mirror provides an interface for interacting with the /// NFT tokens in a BT404 implementation. /// /// @author FlooringLab /// @author Modified from DN404(https://github.com/Vectorized/dn404/src/DN404Mirror.sol) /// /// @dev Note: /// - The ERC721 data is stored in the base BT404 contract. contract BT404Mirror { /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/ /* EVENTS */ /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/ /// @dev Emitted when token `id` is transferred from `from` to `to`. event Transfer(address indexed from, address indexed to, uint256 indexed id); /// @dev Emitted when `owner` enables `account` to manage the `id` token. event Approval(address indexed owner, address indexed account, uint256 indexed id); /// @dev Emitted when `owner` enables or disables `operator` to manage all of their tokens. event ApprovalForAll(address indexed owner, address indexed operator, bool isApproved); /// @dev The ownership is transferred from `oldOwner` to `newOwner`. /// This is for marketplace signaling purposes. This contract has a `pullOwner()` /// function that will sync the owner from the base contract. event OwnershipTransferred(address indexed oldOwner, address indexed newOwner); /// @dev Emitted when `owner` lock or unlock token `id`. event UpdateLockState(address indexed owner, uint256 indexed id, bool lockStatus); /// @dev Emitted when token `idX` and `idY` exchanged. event Exchange(uint256 indexed idX, uint256 indexed idY, uint256 exchangeFee); /// @dev Emitted when token `id` offered for sale. event Offer(uint256 indexed id, address indexed to, uint256 minPrice, address offerToken); /// @dev Emitted when token `id` offered for sale. event CancelOffer(uint256 indexed id, address indexed owner); /// @dev Emitted when token `id` offered for sale. event Bid(uint256 indexed id, address indexed from, uint256 price, address bidToken); /// @dev Emitted when token `id` offered for sale. event CancelBid(uint256 indexed id, address indexed from); /// @dev Emitted when token `id` bought. event Bought( uint256 indexed id, address indexed from, address indexed to, uint256 price, address token, address maker ); /// @dev `keccak256(bytes("Transfer(address,address,uint256)"))`. uint256 internal constant _TRANSFER_EVENT_SIGNATURE = 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef; /// @dev `keccak256(bytes("Approval(address,address,uint256)"))`. uint256 internal constant _APPROVAL_EVENT_SIGNATURE = 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925; /// @dev `keccak256(bytes("ApprovalForAll(address,address,bool)"))`. uint256 internal constant _APPROVAL_FOR_ALL_EVENT_SIGNATURE = 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31; /// @dev `keccak256(bytes("UpdateLockState(address,uint256,bool)"))`. uint256 internal constant _UPDATE_LOCK_STATE_EVENT_SIGNATURE = 0xcc3a1bd7e528af8582cd3578d82ae22e309de7c3663c9d0fa5b5ce79c1a346ac; /// @dev `keccak256(bytes("Exchange(uint256,uint256,uint256)"))` uint256 internal constant _EXCHANGE_EVENT_SIGNATURE = 0xbc43d7c0945f5a13a7bfa8ca7309e55f903f01d66c38c6d1353fe7ff9335d776; /// @dev `keccak256(bytes("Offer(uint256,address,uint256,address)"))` uint256 private constant _OFFER_EVENT_SIGNATURE = 0xc56f8610599b5a39311e36563ef3386394748f787ef5efc116d960d77def8050; /// @dev `keccak256(bytes("CancelOffer(uint256,address)"))` uint256 private constant _CANCEL_OFFER_EVENT_SIGNATURE = 0xc4caef7e3533865382e608c341581a5e2a1b0d1ac37b0aaf58023ccd4eedfd8e; /// @dev `keccak256(bytes("Bid(uint256,address,uint256,address)"))` uint256 private constant _BID_EVENT_SIGNATURE = 0xec85e6e86fabc4c703529b570fb5eb567dad69ddbf7901bc0fd28b38b93de7f3; /// @dev `keccak256(bytes("CancelBid(uint256,address)"))` uint256 private constant _CANCEL_BID_EVENT_SIGNATURE = 0x874afcdd5e90b2329b3c1601e613dcdc6abb6deb62ce61339a8337b48c053e51; /// @dev `keccak256(bytes("Bought(uint256,address,address,uint256,address,address)"))` uint256 private constant _BOUGHT_EVENT_SIGNATURE = 0xd9882bc1ac8e78c918b907fa0ff79cc9d866091c5eb450ebed79e9d147541d5b; /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/ /* CUSTOM ERRORS */ /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/ /// @dev Thrown when a call for an NFT function did not originate /// from the base BT404 contract. error SenderNotBase(); /// @dev Thrown when a call for an NFT function did not originate from the deployer. error SenderNotDeployer(); /// @dev Thrown when transferring an NFT to a contract address that /// does not implement ERC721Receiver. error TransferToNonERC721ReceiverImplementer(); /// @dev Thrown when linking to the BT404 base contract and the /// BT404 supportsInterface check fails or the call reverts. error CannotLink(); /// @dev Thrown when a linkMirrorContract call is received and the /// NFT mirror contract has already been linked to a BT404 base contract. error AlreadyLinked(); /// @dev Thrown when retrieving the base BT404 address when a link has not /// been established. error NotLinked(); /// @dev The caller is not authorized to call the function. error Unauthorized(); /// @dev Unauthorized reentrant call. error Reentrancy(); /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/ /* STORAGE */ /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/ /// @dev Struct contain the NFT mirror contract storage. struct BT404NFTStorage { address baseERC20; bool locked; address deployer; address owner; } /// @dev Returns a storage pointer for BT404NFTStorage. function _getBT404NFTStorage() internal pure virtual returns (BT404NFTStorage storage $) { /// @solidity memory-safe-assembly assembly { // `uint72(bytes9(keccak256("DN404_MIRROR_STORAGE")))`. $.slot := 0x3602298b8c10b01230 // Truncate to 9 bytes to reduce bytecode size. } } /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/ /* REENTRANCY GUARD */ /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/ /// @dev Guards a function from reentrancy. modifier nonReentrant() virtual { BT404NFTStorage storage $ = _getBT404NFTStorage(); if ($.locked) revert Reentrancy(); $.locked = true; _; $.locked = false; } /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/ /* CONSTRUCTOR */ /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/ constructor(address deployer) { // For non-proxies, we will store the deployer so that only the deployer can // link the base contract. _getBT404NFTStorage().deployer = deployer; } function _initializeBT404Mirror(address deployer) internal { // For non-proxies, we will store the deployer so that only the deployer can // link the base contract. _getBT404NFTStorage().deployer = deployer; } /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/ /* ERC721 OPERATIONS */ /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/ /// @dev Returns the token collection name from the base BT404 contract. function name() public view virtual returns (string memory result) { return _readString(0x06fdde03, 0); // `name()`. } /// @dev Returns the token collection symbol from the base BT404 contract. function symbol() public view virtual returns (string memory result) { return _readString(0x95d89b41, 0); // `symbol()`. } /// @dev Returns the Uniform Resource Identifier (URI) for token `id` from /// the base BT404 contract. function tokenURI(uint256 id) public view virtual returns (string memory result) { return _readString(0xc87b56dd, id); // `tokenURI()`. } /// @dev Returns the total NFT supply from the base BT404 contract. function totalSupply() public view virtual returns (uint256 result) { return _readWord(0xe2c79281, 0, 0); // `totalNFTSupply()`. } /// @dev Returns the number of NFT tokens owned by `nftOwner` from the base BT404 contract. /// /// Requirements: /// - `nftOwner` must not be the zero address. function balanceOf(address nftOwner) public view virtual returns (uint256 result) { return _readWord(0xf5b100ea, uint160(nftOwner), 0); // `balanceOfNFT(address)`. } /// @dev Returns the owner of token `id` from the base BT404 contract. /// /// Requirements: /// - Token `id` must exist. function ownerOf(uint256 id) public view virtual returns (address result) { return address(uint160(_readWord(0x6352211e, id, 0))); // `ownerOf(uint256)`. } /// @dev Returns the owner of token `id` from the base BT404 contract. /// Returns `address(0)` instead of reverting if the token does not exist. function ownerAt(uint256 id) public view virtual returns (address result) { return address(uint160(_readWord(0x24359879, id, 0))); // `ownerAt(uint256)`. } /// @dev Sets `spender` as the approved account to manage token `id` in /// the base BT404 contract. /// /// Requirements: /// - Token `id` must exist. /// - The caller must be the owner of the token, /// or an approved operator for the token owner. /// /// Emits an {Approval} event. function approve(address spender, uint256 id) public virtual { address base = baseERC20(); /// @solidity memory-safe-assembly assembly { spender := shr(96, shl(96, spender)) let m := mload(0x40) mstore(0x00, 0xd10b6e0c) // `approveNFT(address,uint256,address)`. mstore(0x20, spender) mstore(0x40, id) mstore(0x60, caller()) if iszero( and( gt(returndatasize(), 0x1f), call(gas(), base, callvalue(), 0x1c, 0x64, 0x00, 0x20) ) ) { returndatacopy(m, 0x00, returndatasize()) revert(m, returndatasize()) } mstore(0x40, m) // Restore the free memory pointer. mstore(0x60, 0) // Restore the zero pointer. // Emit the {Approval} event. log4(codesize(), 0x00, _APPROVAL_EVENT_SIGNATURE, shr(96, mload(0x0c)), spender, id) } } /// @dev Returns the account approved to manage token `id` from /// the base BT404 contract. /// /// Requirements: /// - Token `id` must exist. function getApproved(uint256 id) public view virtual returns (address) { return address(uint160(_readWord(0x081812fc, id, 0))); // `getApproved(uint256)`. } /// @dev Sets whether `operator` is approved to manage the tokens of the caller in /// the base BT404 contract. /// /// Emits an {ApprovalForAll} event. function setApprovalForAll(address operator, bool approved) public virtual { address base = baseERC20(); /// @solidity memory-safe-assembly assembly { operator := shr(96, shl(96, operator)) let m := mload(0x40) mstore(0x00, 0x813500fc) // `setApprovalForAll(address,bool,address)`. mstore(0x20, operator) mstore(0x40, iszero(iszero(approved))) mstore(0x60, caller()) if iszero( and(eq(mload(0x00), 1), call(gas(), base, callvalue(), 0x1c, 0x64, 0x00, 0x20)) ) { returndatacopy(m, 0x00, returndatasize()) revert(m, returndatasize()) } // Emit the {ApprovalForAll} event. // The `approved` value is already at 0x40. log3(0x40, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, caller(), operator) mstore(0x40, m) // Restore the free memory pointer. mstore(0x60, 0) // Restore the zero pointer. } } /// @dev Returns whether `operator` is approved to manage the tokens of `nftOwner` from /// the base BT404 contract. function isApprovedForAll(address nftOwner, address operator) public view virtual returns (bool result) { // `isApprovedForAll(address,address)`. return _readWord(0xe985e9c5, uint160(nftOwner), uint160(operator)) != 0; } /// @dev Returns the owned token ids of `account` from the base BT404 contract. function ownedIds(address account, uint256 begin, uint256 end) public view virtual returns (uint256[] memory) { return _ownedIds(account, begin, end, false); } /// @dev Returns the locked token ids of `account` from the base BT404 contract. function lockedIds(address account, uint256 begin, uint256 end) public view virtual returns (uint256[] memory) { return _ownedIds(account, begin, end, true); } /// @dev Transfers token `id` from `from` to `to`. /// /// Requirements: /// /// - Token `id` must exist. /// - `from` must be the owner of the token. /// - `to` cannot be the zero address. /// - The caller must be the owner of the token, or be approved to manage the token. /// /// Emits a {Transfer} event. function transferFrom(address from, address to, uint256 id) public virtual { address base = baseERC20(); /// @solidity memory-safe-assembly assembly { from := shr(96, shl(96, from)) to := shr(96, shl(96, to)) let m := mload(0x40) mstore(m, 0xe5eb36c8) // `transferFromNFT(address,address,uint256,address)`. mstore(add(m, 0x20), from) mstore(add(m, 0x40), to) mstore(add(m, 0x60), id) mstore(add(m, 0x80), caller()) if iszero( and(eq(mload(m), 1), call(gas(), base, callvalue(), add(m, 0x1c), 0x84, m, 0x20)) ) { returndatacopy(m, 0x00, returndatasize()) revert(m, returndatasize()) } // Emit the `from` unlock event. mstore(m, 0x00) log3(m, 0x20, _UPDATE_LOCK_STATE_EVENT_SIGNATURE, from, id) // Emit the {Transfer} event. log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, from, to, id) // Emit the `to` lock event mstore(m, 0x01) log3(m, 0x20, _UPDATE_LOCK_STATE_EVENT_SIGNATURE, to, id) } } /// @dev Equivalent to `safeTransferFrom(from, to, id, "")`. function safeTransferFrom(address from, address to, uint256 id) public virtual { transferFrom(from, to, id); if (_hasCode(to)) _checkOnERC721Received(from, to, id, ""); } /// @dev Transfers token `id` from `from` to `to`. /// /// Requirements: /// /// - Token `id` must exist. /// - `from` must be the owner of the token. /// - `to` cannot be the zero address. /// - The caller must be the owner of the token, or be approved to manage the token. /// - 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 id, bytes calldata data) public virtual { transferFrom(from, to, id); if (_hasCode(to)) _checkOnERC721Received(from, to, id, data); } function updateLockState(uint256[] memory ids, bool lock) public virtual { address base = baseERC20(); (bool success, bytes memory result) = base.call( abi.encodeWithSignature( "setNFTLockState(uint256,uint256[])", uint256(uint160(msg.sender)) << 96 | (lock ? 1 : 0), ids ) ); // @solidity memory-safe-assembly assembly { if iszero(and(eq(mload(add(result, 0x20)), 1), success)) { revert(add(result, 0x20), mload(result)) } let idLen := mload(ids) mstore(0x00, lock) for { let s := add(ids, 0x20) let end := add(s, shl(5, idLen)) } iszero(eq(s, end)) { s := add(s, 0x20) } { log3(0x00, 0x20, _UPDATE_LOCK_STATE_EVENT_SIGNATURE, caller(), mload(s)) } } } function exchange(uint256 idX, uint256 idY) public virtual returns (uint256 exchangeFee) { address base = baseERC20(); /// @solidity memory-safe-assembly assembly { let m := mload(0x40) mstore(0x00, 0x2c5966af) // `exchangeNFT(uint256,uint256,address)`. mstore(0x20, idX) mstore(0x40, idY) mstore(0x60, caller()) if iszero( and( gt(returndatasize(), 0x5F), call(gas(), base, callvalue(), 0x1c, 0x64, 0x00, 0x60) ) ) { returndatacopy(m, 0x00, returndatasize()) revert(m, returndatasize()) } // store return value let x := mload(0x00) let y := mload(0x20) exchangeFee := mload(0x40) // Emit the {Transfer} event. log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, x, y, idX) log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, y, caller(), idY) // Emit the {Exchange} event. log3(0x40, 0x20, _EXCHANGE_EVENT_SIGNATURE, idX, idY) // Emit the `caller` lock event. mstore(0x40, 0x01) log3(0x40, 0x20, _UPDATE_LOCK_STATE_EVENT_SIGNATURE, caller(), idY) mstore(0x40, m) // Restore the free memory pointer. mstore(0x60, 0) // Restore the zero pointer. } } struct NFTOrder { uint256 id; uint256 price; address token; address trader; } function offerForSale(NFTOrder[] memory orders) public virtual nonReentrant { _callBaseRetWord( abi.encodeWithSignature( "offerForSale(address,(uint256,uint256,address,address)[])", msg.sender, orders ) ); /// @solidity memory-safe-assembly assembly { for { let s := add(orders, add(0x20, shl(5, mload(orders)))) let end := add(s, mul(0x80, mload(orders))) } iszero(eq(s, end)) { s := add(s, 0x80) } { log3(add(s, 0x20), 0x40, _OFFER_EVENT_SIGNATURE, mload(s), mload(add(s, 0x60))) } } } function acceptOffer(NFTOrder[] memory orders) public payable virtual nonReentrant { _callBaseRetWord( abi.encodeWithSignature( "acceptOffer(address,(uint256,uint256,address,address)[])", msg.sender, orders ) ); /// @solidity memory-safe-assembly assembly { for { let s := add(orders, add(0x20, shl(5, mload(orders)))) let end := add(s, mul(0x80, mload(orders))) } iszero(eq(s, end)) { s := add(s, 0x80) } { let from := mload(add(s, 0x60)) mstore(0x00, 0x01) log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, from, caller(), mload(s)) log3(0x00, 0x20, _UPDATE_LOCK_STATE_EVENT_SIGNATURE, caller(), mload(s)) log4(add(s, 0x20), 0x60, _BOUGHT_EVENT_SIGNATURE, mload(s), from, caller()) } } } function cancelOffer(uint256[] memory ids) public virtual nonReentrant { _callBaseRetWord(abi.encodeWithSignature("cancelOffer(address,uint256[])", msg.sender, ids)); /// @solidity memory-safe-assembly assembly { for { let s := add(ids, 0x20) let end := add(s, shl(5, mload(ids))) } iszero(eq(s, end)) { s := add(s, 0x20) } { log3(codesize(), 0x00, _CANCEL_OFFER_EVENT_SIGNATURE, mload(s), caller()) } } } function bidForBuy(NFTOrder[] memory orders) public payable virtual nonReentrant { _callBaseRetWord( abi.encodeWithSignature( "bidForBuy(address,(uint256,uint256,address,address)[])", msg.sender, orders ) ); /// @solidity memory-safe-assembly assembly { for { let s := add(orders, add(0x20, shl(5, mload(orders)))) let end := add(s, mul(0x80, mload(orders))) } iszero(eq(s, end)) { s := add(s, 0x80) } { log3(add(s, 0x20), 0x40, _BID_EVENT_SIGNATURE, mload(s), caller()) } } } function acceptBid(NFTOrder[] memory orders) public virtual nonReentrant { _callBaseRetWord( abi.encodeWithSignature( "acceptBid(address,(uint256,uint256,address,address)[])", msg.sender, orders ) ); /// @solidity memory-safe-assembly assembly { for { let s := add(orders, add(0x20, shl(5, mload(orders)))) let end := add(s, mul(0x80, mload(orders))) } iszero(eq(s, end)) { s := add(s, 0x80) } { let to := mload(add(s, 0x60)) mstore(0x00, 0x01) log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, caller(), to, mload(s)) log3(0x00, 0x20, _UPDATE_LOCK_STATE_EVENT_SIGNATURE, to, mload(s)) log4(add(s, 0x20), 0x60, _BOUGHT_EVENT_SIGNATURE, mload(s), caller(), to) } } } function cancelBid(uint256[] memory ids) public virtual nonReentrant { _callBaseRetWord(abi.encodeWithSignature("cancelBid(address,uint256[])", msg.sender, ids)); /// @solidity memory-safe-assembly assembly { for { let s := add(ids, 0x20) let end := add(s, shl(5, mload(ids))) } iszero(eq(s, end)) { s := add(s, 0x20) } { log3(codesize(), 0x00, _CANCEL_BID_EVENT_SIGNATURE, mload(s), caller()) } } } /// @dev Returns true if this contract implements the interface defined by `interfaceId`. /// See: https://eips.ethereum.org/EIPS/eip-165 /// This function call must use less than 30000 gas. function supportsInterface(bytes4 interfaceId) public view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { let s := shr(224, interfaceId) // ERC165: 0x01ffc9a7, ERC721: 0x80ac58cd, ERC721Metadata: 0x5b5e139f. result := or(or(eq(s, 0x01ffc9a7), eq(s, 0x80ac58cd)), eq(s, 0x5b5e139f)) } } /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/ /* OWNER SYNCING OPERATIONS */ /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/ /// @dev Returns the `owner` of the contract, for marketplace signaling purposes. function owner() public view virtual returns (address) { return _getBT404NFTStorage().owner; } /// @dev Permissionless function to pull the owner from the base BT404 contract /// if it implements ownable, for marketplace signaling purposes. function pullOwner() public virtual { address newOwner; address base = baseERC20(); /// @solidity memory-safe-assembly assembly { mstore(0x00, 0x8da5cb5b) // `owner()`. if and(gt(returndatasize(), 0x1f), staticcall(gas(), base, 0x1c, 0x04, 0x00, 0x20)) { newOwner := shr(96, mload(0x0c)) } } BT404NFTStorage storage $ = _getBT404NFTStorage(); address oldOwner = $.owner; if (oldOwner != newOwner) { $.owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } } /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/ /* MIRROR OPERATIONS */ /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/ /// @dev Returns the address of the base BT404 contract. function baseERC20() public view virtual returns (address base) { base = _getBT404NFTStorage().baseERC20; if (base == address(0)) revert NotLinked(); } /// @dev Fallback modifier to execute calls from the base BT404 contract. modifier bt404NFTFallback() virtual { BT404NFTStorage storage $ = _getBT404NFTStorage(); uint256 fnSelector = _calldataload(0x00) >> 224; // `logTransfer(uint256[])`. if (fnSelector == 0x263c69d6) { if (msg.sender != $.baseERC20) revert SenderNotBase(); /// @solidity memory-safe-assembly assembly { // When returndatacopy copies 1 or more out-of-bounds bytes, it reverts. returndatacopy(0x00, returndatasize(), lt(calldatasize(), 0x20)) let o := add(0x24, calldataload(0x04)) // Packed logs offset. returndatacopy(0x00, returndatasize(), lt(calldatasize(), o)) let end := add(o, shl(5, calldataload(sub(o, 0x20)))) returndatacopy(0x00, returndatasize(), lt(calldatasize(), end)) for {} iszero(eq(o, end)) { o := add(0x20, o) } { let d := calldataload(o) // Entry in the packed logs. let a := shr(96, d) // The address. let b := and(1, d) // Whether it is a burn. log4( codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, mul(a, b), // `from`. mul(a, iszero(b)), // `to`. shr(168, shl(160, d)) // `id`. ) } mstore(0x00, 0x01) return(0x00, 0x20) } } // `logDirectTransfer(address,address,uint256[])`. if (fnSelector == 0x144027d3) { if (msg.sender != $.baseERC20) revert SenderNotBase(); /// @solidity memory-safe-assembly assembly { let from := calldataload(0x04) let to := calldataload(0x24) let o := add(0x24, calldataload(0x44)) // Direct logs offset. let end := add(o, shl(5, calldataload(sub(o, 0x20)))) for {} iszero(eq(o, end)) { o := add(0x20, o) } { log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, from, to, calldataload(o)) } mstore(0x00, 0x01) return(0x00, 0x20) } } // `linkMirrorContract(address)`. if (fnSelector == 0x0f4599e5) { if ($.deployer != address(0)) { if (address(uint160(_calldataload(0x04))) != $.deployer) { revert SenderNotDeployer(); } } if ($.baseERC20 != address(0)) revert AlreadyLinked(); $.baseERC20 = msg.sender; /// @solidity memory-safe-assembly assembly { mstore(0x00, 0x01) return(0x00, 0x20) } } _; } /// @dev Fallback function for calls from base BT404 contract. fallback() external payable virtual bt404NFTFallback {} receive() external payable virtual {} /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/ /* PRIVATE HELPERS */ /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/ /// @dev Helper to read owned ids of a account from the base BT404 contract function _ownedIds(address account, uint256 begin, uint256 end, bool locked) private view returns (uint256[] memory result) { address base = baseERC20(); /// @solidity memory-safe-assembly assembly { result := mload(0x40) mstore(0x00, 0xf9b4b328) // `ownedIds(uint256,uint256,uint256)`. mstore(0x20, or(shl(96, account), iszero(iszero(locked)))) mstore(0x40, begin) mstore(0x60, end) if iszero(staticcall(gas(), base, 0x1c, 0x64, 0x00, 0x00)) { returndatacopy(result, 0x00, returndatasize()) revert(result, returndatasize()) } returndatacopy(0x00, 0x00, 0x20) // Copy the offset of the array in returndata. returndatacopy(result, mload(0x00), 0x20) // Copy the length of the array. returndatacopy(add(result, 0x20), add(mload(0x00), 0x20), shl(5, mload(result))) // Copy the array elements. mstore(0x40, add(add(result, 0x20), shl(5, mload(result)))) // Allocate memory. mstore(0x60, 0) // Restore the zero pointer. } } /// @dev Helper to read a string from the base BT404 contract. function _readString(uint256 fnSelector, uint256 arg0) private view returns (string memory result) { address base = baseERC20(); /// @solidity memory-safe-assembly assembly { result := mload(0x40) mstore(0x00, fnSelector) mstore(0x20, arg0) if iszero(staticcall(gas(), base, 0x1c, 0x24, 0x00, 0x00)) { returndatacopy(result, 0x00, returndatasize()) revert(result, returndatasize()) } returndatacopy(0x00, 0x00, 0x20) // Copy the offset of the string in returndata. returndatacopy(result, mload(0x00), 0x20) // Copy the length of the string. returndatacopy(add(result, 0x20), add(mload(0x00), 0x20), mload(result)) // Copy the string. mstore(0x40, add(add(result, 0x20), mload(result))) // Allocate memory. } } /// @dev Helper to read a word from the base BT404 contract. function _readWord(uint256 fnSelector, uint256 arg0, uint256 arg1) private view returns (uint256 result) { address base = baseERC20(); /// @solidity memory-safe-assembly assembly { let m := mload(0x40) mstore(0x00, fnSelector) mstore(0x20, arg0) mstore(0x40, arg1) if iszero( and(gt(returndatasize(), 0x1f), staticcall(gas(), base, 0x1c, 0x44, 0x00, 0x20)) ) { returndatacopy(m, 0x00, returndatasize()) revert(m, returndatasize()) } mstore(0x40, m) // Restore the free memory pointer. result := mload(0x00) } } /// @dev Helper to call a function and return a word value. function _callBaseRetWord(bytes memory _calldata) private returns (uint256 result) { address base = baseERC20(); /// @solidity memory-safe-assembly assembly { let m := mload(0x40) if iszero( and( gt(returndatasize(), 0x1f), call( gas(), base, callvalue(), add(_calldata, 0x20), mload(_calldata), 0x00, 0x20 ) ) ) { returndatacopy(m, 0x00, returndatasize()) revert(m, returndatasize()) } mstore(0x40, m) // Restore the free memory pointer. mstore(0x60, 0) // Restore the zero pointer. result := mload(0x00) } } /// @dev Returns the calldata value at `offset`. function _calldataload(uint256 offset) private pure returns (uint256 value) { /// @solidity memory-safe-assembly assembly { value := calldataload(offset) } } /// @dev Returns if `a` has bytecode of non-zero length. function _hasCode(address a) private view returns (bool result) { /// @solidity memory-safe-assembly assembly { result := extcodesize(a) // Can handle dirty upper bits. } } /// @dev Perform a call to invoke {IERC721Receiver-onERC721Received} on `to`. /// Reverts if the target does not support the function correctly. function _checkOnERC721Received(address from, address to, uint256 id, bytes memory data) private { /// @solidity memory-safe-assembly assembly { // Prepare the calldata. let m := mload(0x40) let onERC721ReceivedSelector := 0x150b7a02 mstore(m, onERC721ReceivedSelector) mstore(add(m, 0x20), caller()) // The `operator`, which is always `msg.sender`. mstore(add(m, 0x40), shr(96, shl(96, from))) mstore(add(m, 0x60), id) mstore(add(m, 0x80), 0x80) let n := mload(data) mstore(add(m, 0xa0), n) if n { pop(staticcall(gas(), 4, add(data, 0x20), n, add(m, 0xc0), n)) } // Revert if the call reverts. if iszero(call(gas(), to, 0, add(m, 0x1c), add(n, 0xa4), m, 0x20)) { if returndatasize() { // Bubble up the revert if the call reverts. returndatacopy(m, 0x00, returndatasize()) revert(m, returndatasize()) } } // Load the returndata and compare it. if iszero(eq(mload(m), shl(224, onERC721ReceivedSelector))) { mstore(0x00, 0xd1a57ed6) // `TransferToNonERC721ReceiverImplementer()`. revert(0x1c, 0x04) } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.22; import "./BT404Mirror.sol"; import {IERC721} from "./external/IERC721.sol"; /// @title BT404MirrorWrapper /// @notice BT404MirrorWrapper provides an interface for wrapping legacy ERC721 /// NFT tokens in a BT404 implementation. contract BT404MirrorWrapper is BT404Mirror { /// @dev Thrown when the nft ids is empty. error EmptyNFTIds(); /// @dev Thrown when the nft id is out of the range. error InvalidIdInRange(); /// @dev Struct contain the wrapped ERC721 contract. struct BT404WNFTStorage { address baseERC721; // Indicates the start of the range (inclusive). uint256 startBaseId; // Indicates the end of the range (inclusive). uint256 endBaseId; } /// @dev Returns a storage pointer for BT404WNFTStorage. function _getBT404WNFTStorage() internal pure virtual returns (BT404WNFTStorage storage $) { /// @solidity memory-safe-assembly assembly { // `uint72(bytes9(keccak256("BT404_MIRROR_WRAPPER_STORAGE")))`. $.slot := 0x2ab3f28a60db472ee6 // Truncate to 9 bytes to reduce bytecode size. } } /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/ /* CONSTRUCTOR */ /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/ /// @dev Prefer to use the proxy and initialization process. constructor() payable BT404Mirror(msg.sender) {} function _initializeBT404MirrorWrapper( address deployer, address baseERC721_, uint256 startBaseId_, uint256 endBaseId_ ) internal { _initializeBT404Mirror(deployer); BT404WNFTStorage storage $ = _getBT404WNFTStorage(); $.baseERC721 = baseERC721_; $.startBaseId = startBaseId_; $.endBaseId = endBaseId_; } /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/ /* ERC721 Wrapper OPERATIONS */ /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/ /// @dev Wrap the original NFTs. /// `msg.sender` receives the wrapped BT404 NFTs and the corresponding amount of ERC20 tokens. function wrapBatch(uint256[] memory ids) public virtual { wrapBatch(ids, false); } /// @dev Wrap the original NFTs. /// `msg.sender` receives the wrapped BT404 NFTs along with the corresponding amount of ERC20 tokens. /// Lock the BT404 NFTs to prevent transfer via `ERC20.transfer`. function wrapBatch(uint256[] memory ids, bool lock) public virtual { if (ids.length == 0) revert EmptyNFTIds(); BT404WNFTStorage storage $ = _getBT404WNFTStorage(); IERC721 base721 = IERC721($.baseERC721); (uint256 startBaseId, uint256 endBaseId) = ($.startBaseId, $.endBaseId); for (uint256 i; i < ids.length;) { uint256 id = ids[i]; _checkInvalidIdInRange(startBaseId, endBaseId, id); base721.transferFrom(msg.sender, address(this), id); unchecked { ++i; } } address base = baseERC20(); (bool success, bytes memory result) = base.call( abi.encodeWithSignature( "mintNFT(uint256,uint256[])", uint256(uint160(msg.sender)) << 96 | (lock ? 1 : 0), ids ) ); // @solidity memory-safe-assembly assembly { if iszero(and(eq(mload(add(result, 0x20)), 1), success)) { revert(add(result, 0x20), mload(result)) } let idLen := mload(ids) mstore(0x00, lock) for { let s := add(ids, 0x20) let end := add(s, shl(5, idLen)) } iszero(eq(s, end)) { s := add(s, 0x20) } { // Emit the {Transfer} event. log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, 0, caller(), mload(s)) // Emit the {UpdateLockState} event. if lock { log3(0x00, 0x20, _UPDATE_LOCK_STATE_EVENT_SIGNATURE, caller(), mload(s)) } } } } /// @dev Unwrap the original NFTs. `msg.sender` receives the original ERC721 NFTs. /// Burn the BT404 NFTs and corresponding ERC20 Tokens. function unwrapBatch(uint256[] memory ids) public virtual { if (ids.length == 0) revert EmptyNFTIds(); address base = baseERC20(); (bool success, bytes memory result) = base.call(abi.encodeWithSignature("burnNFT(address,uint256[])", msg.sender, ids)); // @solidity memory-safe-assembly assembly { if iszero(and(eq(mload(add(result, 0x20)), 1), success)) { revert(add(result, 0x20), mload(result)) } let idLen := mload(ids) for { let s := add(ids, 0x20) let end := add(s, shl(5, idLen)) } iszero(eq(s, end)) { s := add(s, 0x20) } { // Don't emit the {UpdateLockState} event, as the NFTs already are burned. // Emit the {Transfer} event. log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, caller(), 0, mload(s)) } } IERC721 base721 = IERC721(baseERC721()); for (uint256 i; i < ids.length;) { base721.safeTransferFrom(address(this), msg.sender, ids[i]); unchecked { ++i; } } } function baseERC721() public view virtual returns (address) { return _getBT404WNFTStorage().baseERC721; } /** * @dev Always returns `this.onERC721Received.selector`. */ function onERC721Received(address, address, uint256, bytes memory) public pure virtual returns (bytes4) { return this.onERC721Received.selector; } function _checkInvalidIdInRange(uint256 startBaseId, uint256 endBaseId, uint256 id) internal pure { if ((startBaseId | endBaseId) > 0) { if (id < startBaseId || endBaseId < id) { revert InvalidIdInRange(); } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice UUPS proxy mixin. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/UUPSUpgradeable.sol) /// @author Modified from OpenZeppelin /// (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/proxy/utils/UUPSUpgradeable.sol) /// /// Note: /// - This implementation is intended to be used with ERC1967 proxies. /// See: `LibClone.deployERC1967` and related functions. /// - This implementation is NOT compatible with legacy OpenZeppelin proxies /// which do not store the implementation at `_ERC1967_IMPLEMENTATION_SLOT`. abstract contract UUPSUpgradeable { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The upgrade failed. error UpgradeFailed(); /// @dev The call is from an unauthorized call context. error UnauthorizedCallContext(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* IMMUTABLES */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev For checking if the context is a delegate call. uint256 private immutable __self = uint256(uint160(address(this))); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Emitted when the proxy's implementation is upgraded. event Upgraded(address indexed implementation); /// @dev `keccak256(bytes("Upgraded(address)"))`. uint256 private constant _UPGRADED_EVENT_SIGNATURE = 0xbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The ERC-1967 storage slot for the implementation in the proxy. /// `uint256(keccak256("eip1967.proxy.implementation")) - 1`. bytes32 internal constant _ERC1967_IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* UUPS OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Please override this function to check if `msg.sender` is authorized /// to upgrade the proxy to `newImplementation`, reverting if not. /// ``` /// function _authorizeUpgrade(address) internal override onlyOwner {} /// ``` function _authorizeUpgrade(address newImplementation) internal virtual; /// @dev Returns the storage slot used by the implementation, /// as specified in [ERC1822](https://eips.ethereum.org/EIPS/eip-1822). /// /// Note: The `notDelegated` modifier prevents accidental upgrades to /// an implementation that is a proxy contract. function proxiableUUID() public view virtual notDelegated returns (bytes32) { // This function must always return `_ERC1967_IMPLEMENTATION_SLOT` to comply with ERC1967. return _ERC1967_IMPLEMENTATION_SLOT; } /// @dev Upgrades the proxy's implementation to `newImplementation`. /// Emits a {Upgraded} event. /// /// Note: Passing in empty `data` skips the delegatecall to `newImplementation`. function upgradeToAndCall(address newImplementation, bytes calldata data) public payable virtual onlyProxy { _authorizeUpgrade(newImplementation); /// @solidity memory-safe-assembly assembly { newImplementation := shr(96, shl(96, newImplementation)) // Clears upper 96 bits. mstore(0x01, 0x52d1902d) // `proxiableUUID()`. let s := _ERC1967_IMPLEMENTATION_SLOT // Check if `newImplementation` implements `proxiableUUID` correctly. if iszero(eq(mload(staticcall(gas(), newImplementation, 0x1d, 0x04, 0x01, 0x20)), s)) { mstore(0x01, 0x55299b49) // `UpgradeFailed()`. revert(0x1d, 0x04) } // Emit the {Upgraded} event. log2(codesize(), 0x00, _UPGRADED_EVENT_SIGNATURE, newImplementation) sstore(s, newImplementation) // Updates the implementation. // Perform a delegatecall to `newImplementation` if `data` is non-empty. if data.length { // Forwards the `data` to `newImplementation` via delegatecall. let m := mload(0x40) calldatacopy(m, data.offset, data.length) if iszero(delegatecall(gas(), newImplementation, m, data.length, codesize(), 0x00)) { // Bubble up the revert if the call reverts. returndatacopy(m, 0x00, returndatasize()) revert(m, returndatasize()) } } } } /// @dev Requires that the execution is performed through a proxy. modifier onlyProxy() { uint256 s = __self; /// @solidity memory-safe-assembly assembly { // To enable use cases with an immutable default implementation in the bytecode, // (see: ERC6551Proxy), we don't require that the proxy address must match the // value stored in the implementation slot, which may not be initialized. if eq(s, address()) { mstore(0x00, 0x9f03a026) // `UnauthorizedCallContext()`. revert(0x1c, 0x04) } } _; } /// @dev Requires that the execution is NOT performed via delegatecall. /// This is the opposite of `onlyProxy`. modifier notDelegated() { uint256 s = __self; /// @solidity memory-safe-assembly assembly { if iszero(eq(s, address())) { mstore(0x00, 0x9f03a026) // `UnauthorizedCallContext()`. revert(0x1c, 0x04) } } _; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import {Ownable} from "./Ownable.sol"; /// @notice Simple single owner and multiroles authorization mixin. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) /// @dev While the ownable portion follows [EIP-173](https://eips.ethereum.org/EIPS/eip-173) /// for compatibility, the nomenclature for the 2-step ownership handover and roles /// may be unique to this codebase. abstract contract OwnableRoles is Ownable { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The `user`'s roles is updated to `roles`. /// Each bit of `roles` represents whether the role is set. event RolesUpdated(address indexed user, uint256 indexed roles); /// @dev `keccak256(bytes("RolesUpdated(address,uint256)"))`. uint256 private constant _ROLES_UPDATED_EVENT_SIGNATURE = 0x715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The role slot of `user` is given by: /// ``` /// mstore(0x00, or(shl(96, user), _ROLE_SLOT_SEED)) /// let roleSlot := keccak256(0x00, 0x20) /// ``` /// This automatically ignores the upper bits of the `user` in case /// they are not clean, as well as keep the `keccak256` under 32-bytes. /// /// Note: This is equivalent to `uint32(bytes4(keccak256("_OWNER_SLOT_NOT")))`. uint256 private constant _ROLE_SLOT_SEED = 0x8b78c6d8; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Overwrite the roles directly without authorization guard. function _setRoles(address user, uint256 roles) internal virtual { /// @solidity memory-safe-assembly assembly { mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, user) // Store the new value. sstore(keccak256(0x0c, 0x20), roles) // Emit the {RolesUpdated} event. log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), roles) } } /// @dev Updates the roles directly without authorization guard. /// If `on` is true, each set bit of `roles` will be turned on, /// otherwise, each set bit of `roles` will be turned off. function _updateRoles(address user, uint256 roles, bool on) internal virtual { /// @solidity memory-safe-assembly assembly { mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, user) let roleSlot := keccak256(0x0c, 0x20) // Load the current value. let current := sload(roleSlot) // Compute the updated roles if `on` is true. let updated := or(current, roles) // Compute the updated roles if `on` is false. // Use `and` to compute the intersection of `current` and `roles`, // `xor` it with `current` to flip the bits in the intersection. if iszero(on) { updated := xor(current, and(current, roles)) } // Then, store the new value. sstore(roleSlot, updated) // Emit the {RolesUpdated} event. log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), updated) } } /// @dev Grants the roles directly without authorization guard. /// Each bit of `roles` represents the role to turn on. function _grantRoles(address user, uint256 roles) internal virtual { _updateRoles(user, roles, true); } /// @dev Removes the roles directly without authorization guard. /// Each bit of `roles` represents the role to turn off. function _removeRoles(address user, uint256 roles) internal virtual { _updateRoles(user, roles, false); } /// @dev Throws if the sender does not have any of the `roles`. function _checkRoles(uint256 roles) internal view virtual { /// @solidity memory-safe-assembly assembly { // Compute the role slot. mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, caller()) // Load the stored value, and if the `and` intersection // of the value and `roles` is zero, revert. if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { mstore(0x00, 0x82b42900) // `Unauthorized()`. revert(0x1c, 0x04) } } } /// @dev Throws if the sender is not the owner, /// and does not have any of the `roles`. /// Checks for ownership first, then lazily checks for roles. function _checkOwnerOrRoles(uint256 roles) internal view virtual { /// @solidity memory-safe-assembly assembly { // If the caller is not the stored owner. // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`. if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) { // Compute the role slot. mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, caller()) // Load the stored value, and if the `and` intersection // of the value and `roles` is zero, revert. if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { mstore(0x00, 0x82b42900) // `Unauthorized()`. revert(0x1c, 0x04) } } } } /// @dev Throws if the sender does not have any of the `roles`, /// and is not the owner. /// Checks for roles first, then lazily checks for ownership. function _checkRolesOrOwner(uint256 roles) internal view virtual { /// @solidity memory-safe-assembly assembly { // Compute the role slot. mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, caller()) // Load the stored value, and if the `and` intersection // of the value and `roles` is zero, revert. if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) { // If the caller is not the stored owner. // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`. if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) { mstore(0x00, 0x82b42900) // `Unauthorized()`. revert(0x1c, 0x04) } } } } /// @dev Convenience function to return a `roles` bitmap from an array of `ordinals`. /// This is meant for frontends like Etherscan, and is therefore not fully optimized. /// Not recommended to be called on-chain. /// Made internal to conserve bytecode. Wrap it in a public function if needed. function _rolesFromOrdinals(uint8[] memory ordinals) internal pure returns (uint256 roles) { /// @solidity memory-safe-assembly assembly { for { let i := shl(5, mload(ordinals)) } i { i := sub(i, 0x20) } { // We don't need to mask the values of `ordinals`, as Solidity // cleans dirty upper bits when storing variables into memory. roles := or(shl(mload(add(ordinals, i)), 1), roles) } } } /// @dev Convenience function to return an array of `ordinals` from the `roles` bitmap. /// This is meant for frontends like Etherscan, and is therefore not fully optimized. /// Not recommended to be called on-chain. /// Made internal to conserve bytecode. Wrap it in a public function if needed. function _ordinalsFromRoles(uint256 roles) internal pure returns (uint8[] memory ordinals) { /// @solidity memory-safe-assembly assembly { // Grab the pointer to the free memory. ordinals := mload(0x40) let ptr := add(ordinals, 0x20) let o := 0 // The absence of lookup tables, De Bruijn, etc., here is intentional for // smaller bytecode, as this function is not meant to be called on-chain. for { let t := roles } 1 {} { mstore(ptr, o) // `shr` 5 is equivalent to multiplying by 0x20. // Push back into the ordinals array if the bit is set. ptr := add(ptr, shl(5, and(t, 1))) o := add(o, 1) t := shr(o, roles) if iszero(t) { break } } // Store the length of `ordinals`. mstore(ordinals, shr(5, sub(ptr, add(ordinals, 0x20)))) // Allocate the memory. mstore(0x40, ptr) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC UPDATE FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Allows the owner to grant `user` `roles`. /// If the `user` already has a role, then it will be an no-op for the role. function grantRoles(address user, uint256 roles) public payable virtual onlyOwner { _grantRoles(user, roles); } /// @dev Allows the owner to remove `user` `roles`. /// If the `user` does not have a role, then it will be an no-op for the role. function revokeRoles(address user, uint256 roles) public payable virtual onlyOwner { _removeRoles(user, roles); } /// @dev Allow the caller to remove their own roles. /// If the caller does not have a role, then it will be an no-op for the role. function renounceRoles(uint256 roles) public payable virtual { _removeRoles(msg.sender, roles); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC READ FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the roles of `user`. function rolesOf(address user) public view virtual returns (uint256 roles) { /// @solidity memory-safe-assembly assembly { // Compute the role slot. mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, user) // Load the stored value. roles := sload(keccak256(0x0c, 0x20)) } } /// @dev Returns whether `user` has any of `roles`. function hasAnyRole(address user, uint256 roles) public view virtual returns (bool) { return rolesOf(user) & roles != 0; } /// @dev Returns whether `user` has all of `roles`. function hasAllRoles(address user, uint256 roles) public view virtual returns (bool) { return rolesOf(user) & roles == roles; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MODIFIERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Marks a function as only callable by an account with `roles`. modifier onlyRoles(uint256 roles) virtual { _checkRoles(roles); _; } /// @dev Marks a function as only callable by the owner or by an account /// with `roles`. Checks for ownership first, then lazily checks for roles. modifier onlyOwnerOrRoles(uint256 roles) virtual { _checkOwnerOrRoles(roles); _; } /// @dev Marks a function as only callable by an account with `roles` /// or the owner. Checks for roles first, then lazily checks for ownership. modifier onlyRolesOrOwner(uint256 roles) virtual { _checkRolesOrOwner(roles); _; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ROLE CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // IYKYK uint256 internal constant _ROLE_0 = 1 << 0; uint256 internal constant _ROLE_1 = 1 << 1; uint256 internal constant _ROLE_2 = 1 << 2; uint256 internal constant _ROLE_3 = 1 << 3; uint256 internal constant _ROLE_4 = 1 << 4; uint256 internal constant _ROLE_5 = 1 << 5; uint256 internal constant _ROLE_6 = 1 << 6; uint256 internal constant _ROLE_7 = 1 << 7; uint256 internal constant _ROLE_8 = 1 << 8; uint256 internal constant _ROLE_9 = 1 << 9; uint256 internal constant _ROLE_10 = 1 << 10; uint256 internal constant _ROLE_11 = 1 << 11; uint256 internal constant _ROLE_12 = 1 << 12; uint256 internal constant _ROLE_13 = 1 << 13; uint256 internal constant _ROLE_14 = 1 << 14; uint256 internal constant _ROLE_15 = 1 << 15; uint256 internal constant _ROLE_16 = 1 << 16; uint256 internal constant _ROLE_17 = 1 << 17; uint256 internal constant _ROLE_18 = 1 << 18; uint256 internal constant _ROLE_19 = 1 << 19; uint256 internal constant _ROLE_20 = 1 << 20; uint256 internal constant _ROLE_21 = 1 << 21; uint256 internal constant _ROLE_22 = 1 << 22; uint256 internal constant _ROLE_23 = 1 << 23; uint256 internal constant _ROLE_24 = 1 << 24; uint256 internal constant _ROLE_25 = 1 << 25; uint256 internal constant _ROLE_26 = 1 << 26; uint256 internal constant _ROLE_27 = 1 << 27; uint256 internal constant _ROLE_28 = 1 << 28; uint256 internal constant _ROLE_29 = 1 << 29; uint256 internal constant _ROLE_30 = 1 << 30; uint256 internal constant _ROLE_31 = 1 << 31; uint256 internal constant _ROLE_32 = 1 << 32; uint256 internal constant _ROLE_33 = 1 << 33; uint256 internal constant _ROLE_34 = 1 << 34; uint256 internal constant _ROLE_35 = 1 << 35; uint256 internal constant _ROLE_36 = 1 << 36; uint256 internal constant _ROLE_37 = 1 << 37; uint256 internal constant _ROLE_38 = 1 << 38; uint256 internal constant _ROLE_39 = 1 << 39; uint256 internal constant _ROLE_40 = 1 << 40; uint256 internal constant _ROLE_41 = 1 << 41; uint256 internal constant _ROLE_42 = 1 << 42; uint256 internal constant _ROLE_43 = 1 << 43; uint256 internal constant _ROLE_44 = 1 << 44; uint256 internal constant _ROLE_45 = 1 << 45; uint256 internal constant _ROLE_46 = 1 << 46; uint256 internal constant _ROLE_47 = 1 << 47; uint256 internal constant _ROLE_48 = 1 << 48; uint256 internal constant _ROLE_49 = 1 << 49; uint256 internal constant _ROLE_50 = 1 << 50; uint256 internal constant _ROLE_51 = 1 << 51; uint256 internal constant _ROLE_52 = 1 << 52; uint256 internal constant _ROLE_53 = 1 << 53; uint256 internal constant _ROLE_54 = 1 << 54; uint256 internal constant _ROLE_55 = 1 << 55; uint256 internal constant _ROLE_56 = 1 << 56; uint256 internal constant _ROLE_57 = 1 << 57; uint256 internal constant _ROLE_58 = 1 << 58; uint256 internal constant _ROLE_59 = 1 << 59; uint256 internal constant _ROLE_60 = 1 << 60; uint256 internal constant _ROLE_61 = 1 << 61; uint256 internal constant _ROLE_62 = 1 << 62; uint256 internal constant _ROLE_63 = 1 << 63; uint256 internal constant _ROLE_64 = 1 << 64; uint256 internal constant _ROLE_65 = 1 << 65; uint256 internal constant _ROLE_66 = 1 << 66; uint256 internal constant _ROLE_67 = 1 << 67; uint256 internal constant _ROLE_68 = 1 << 68; uint256 internal constant _ROLE_69 = 1 << 69; uint256 internal constant _ROLE_70 = 1 << 70; uint256 internal constant _ROLE_71 = 1 << 71; uint256 internal constant _ROLE_72 = 1 << 72; uint256 internal constant _ROLE_73 = 1 << 73; uint256 internal constant _ROLE_74 = 1 << 74; uint256 internal constant _ROLE_75 = 1 << 75; uint256 internal constant _ROLE_76 = 1 << 76; uint256 internal constant _ROLE_77 = 1 << 77; uint256 internal constant _ROLE_78 = 1 << 78; uint256 internal constant _ROLE_79 = 1 << 79; uint256 internal constant _ROLE_80 = 1 << 80; uint256 internal constant _ROLE_81 = 1 << 81; uint256 internal constant _ROLE_82 = 1 << 82; uint256 internal constant _ROLE_83 = 1 << 83; uint256 internal constant _ROLE_84 = 1 << 84; uint256 internal constant _ROLE_85 = 1 << 85; uint256 internal constant _ROLE_86 = 1 << 86; uint256 internal constant _ROLE_87 = 1 << 87; uint256 internal constant _ROLE_88 = 1 << 88; uint256 internal constant _ROLE_89 = 1 << 89; uint256 internal constant _ROLE_90 = 1 << 90; uint256 internal constant _ROLE_91 = 1 << 91; uint256 internal constant _ROLE_92 = 1 << 92; uint256 internal constant _ROLE_93 = 1 << 93; uint256 internal constant _ROLE_94 = 1 << 94; uint256 internal constant _ROLE_95 = 1 << 95; uint256 internal constant _ROLE_96 = 1 << 96; uint256 internal constant _ROLE_97 = 1 << 97; uint256 internal constant _ROLE_98 = 1 << 98; uint256 internal constant _ROLE_99 = 1 << 99; uint256 internal constant _ROLE_100 = 1 << 100; uint256 internal constant _ROLE_101 = 1 << 101; uint256 internal constant _ROLE_102 = 1 << 102; uint256 internal constant _ROLE_103 = 1 << 103; uint256 internal constant _ROLE_104 = 1 << 104; uint256 internal constant _ROLE_105 = 1 << 105; uint256 internal constant _ROLE_106 = 1 << 106; uint256 internal constant _ROLE_107 = 1 << 107; uint256 internal constant _ROLE_108 = 1 << 108; uint256 internal constant _ROLE_109 = 1 << 109; uint256 internal constant _ROLE_110 = 1 << 110; uint256 internal constant _ROLE_111 = 1 << 111; uint256 internal constant _ROLE_112 = 1 << 112; uint256 internal constant _ROLE_113 = 1 << 113; uint256 internal constant _ROLE_114 = 1 << 114; uint256 internal constant _ROLE_115 = 1 << 115; uint256 internal constant _ROLE_116 = 1 << 116; uint256 internal constant _ROLE_117 = 1 << 117; uint256 internal constant _ROLE_118 = 1 << 118; uint256 internal constant _ROLE_119 = 1 << 119; uint256 internal constant _ROLE_120 = 1 << 120; uint256 internal constant _ROLE_121 = 1 << 121; uint256 internal constant _ROLE_122 = 1 << 122; uint256 internal constant _ROLE_123 = 1 << 123; uint256 internal constant _ROLE_124 = 1 << 124; uint256 internal constant _ROLE_125 = 1 << 125; uint256 internal constant _ROLE_126 = 1 << 126; uint256 internal constant _ROLE_127 = 1 << 127; uint256 internal constant _ROLE_128 = 1 << 128; uint256 internal constant _ROLE_129 = 1 << 129; uint256 internal constant _ROLE_130 = 1 << 130; uint256 internal constant _ROLE_131 = 1 << 131; uint256 internal constant _ROLE_132 = 1 << 132; uint256 internal constant _ROLE_133 = 1 << 133; uint256 internal constant _ROLE_134 = 1 << 134; uint256 internal constant _ROLE_135 = 1 << 135; uint256 internal constant _ROLE_136 = 1 << 136; uint256 internal constant _ROLE_137 = 1 << 137; uint256 internal constant _ROLE_138 = 1 << 138; uint256 internal constant _ROLE_139 = 1 << 139; uint256 internal constant _ROLE_140 = 1 << 140; uint256 internal constant _ROLE_141 = 1 << 141; uint256 internal constant _ROLE_142 = 1 << 142; uint256 internal constant _ROLE_143 = 1 << 143; uint256 internal constant _ROLE_144 = 1 << 144; uint256 internal constant _ROLE_145 = 1 << 145; uint256 internal constant _ROLE_146 = 1 << 146; uint256 internal constant _ROLE_147 = 1 << 147; uint256 internal constant _ROLE_148 = 1 << 148; uint256 internal constant _ROLE_149 = 1 << 149; uint256 internal constant _ROLE_150 = 1 << 150; uint256 internal constant _ROLE_151 = 1 << 151; uint256 internal constant _ROLE_152 = 1 << 152; uint256 internal constant _ROLE_153 = 1 << 153; uint256 internal constant _ROLE_154 = 1 << 154; uint256 internal constant _ROLE_155 = 1 << 155; uint256 internal constant _ROLE_156 = 1 << 156; uint256 internal constant _ROLE_157 = 1 << 157; uint256 internal constant _ROLE_158 = 1 << 158; uint256 internal constant _ROLE_159 = 1 << 159; uint256 internal constant _ROLE_160 = 1 << 160; uint256 internal constant _ROLE_161 = 1 << 161; uint256 internal constant _ROLE_162 = 1 << 162; uint256 internal constant _ROLE_163 = 1 << 163; uint256 internal constant _ROLE_164 = 1 << 164; uint256 internal constant _ROLE_165 = 1 << 165; uint256 internal constant _ROLE_166 = 1 << 166; uint256 internal constant _ROLE_167 = 1 << 167; uint256 internal constant _ROLE_168 = 1 << 168; uint256 internal constant _ROLE_169 = 1 << 169; uint256 internal constant _ROLE_170 = 1 << 170; uint256 internal constant _ROLE_171 = 1 << 171; uint256 internal constant _ROLE_172 = 1 << 172; uint256 internal constant _ROLE_173 = 1 << 173; uint256 internal constant _ROLE_174 = 1 << 174; uint256 internal constant _ROLE_175 = 1 << 175; uint256 internal constant _ROLE_176 = 1 << 176; uint256 internal constant _ROLE_177 = 1 << 177; uint256 internal constant _ROLE_178 = 1 << 178; uint256 internal constant _ROLE_179 = 1 << 179; uint256 internal constant _ROLE_180 = 1 << 180; uint256 internal constant _ROLE_181 = 1 << 181; uint256 internal constant _ROLE_182 = 1 << 182; uint256 internal constant _ROLE_183 = 1 << 183; uint256 internal constant _ROLE_184 = 1 << 184; uint256 internal constant _ROLE_185 = 1 << 185; uint256 internal constant _ROLE_186 = 1 << 186; uint256 internal constant _ROLE_187 = 1 << 187; uint256 internal constant _ROLE_188 = 1 << 188; uint256 internal constant _ROLE_189 = 1 << 189; uint256 internal constant _ROLE_190 = 1 << 190; uint256 internal constant _ROLE_191 = 1 << 191; uint256 internal constant _ROLE_192 = 1 << 192; uint256 internal constant _ROLE_193 = 1 << 193; uint256 internal constant _ROLE_194 = 1 << 194; uint256 internal constant _ROLE_195 = 1 << 195; uint256 internal constant _ROLE_196 = 1 << 196; uint256 internal constant _ROLE_197 = 1 << 197; uint256 internal constant _ROLE_198 = 1 << 198; uint256 internal constant _ROLE_199 = 1 << 199; uint256 internal constant _ROLE_200 = 1 << 200; uint256 internal constant _ROLE_201 = 1 << 201; uint256 internal constant _ROLE_202 = 1 << 202; uint256 internal constant _ROLE_203 = 1 << 203; uint256 internal constant _ROLE_204 = 1 << 204; uint256 internal constant _ROLE_205 = 1 << 205; uint256 internal constant _ROLE_206 = 1 << 206; uint256 internal constant _ROLE_207 = 1 << 207; uint256 internal constant _ROLE_208 = 1 << 208; uint256 internal constant _ROLE_209 = 1 << 209; uint256 internal constant _ROLE_210 = 1 << 210; uint256 internal constant _ROLE_211 = 1 << 211; uint256 internal constant _ROLE_212 = 1 << 212; uint256 internal constant _ROLE_213 = 1 << 213; uint256 internal constant _ROLE_214 = 1 << 214; uint256 internal constant _ROLE_215 = 1 << 215; uint256 internal constant _ROLE_216 = 1 << 216; uint256 internal constant _ROLE_217 = 1 << 217; uint256 internal constant _ROLE_218 = 1 << 218; uint256 internal constant _ROLE_219 = 1 << 219; uint256 internal constant _ROLE_220 = 1 << 220; uint256 internal constant _ROLE_221 = 1 << 221; uint256 internal constant _ROLE_222 = 1 << 222; uint256 internal constant _ROLE_223 = 1 << 223; uint256 internal constant _ROLE_224 = 1 << 224; uint256 internal constant _ROLE_225 = 1 << 225; uint256 internal constant _ROLE_226 = 1 << 226; uint256 internal constant _ROLE_227 = 1 << 227; uint256 internal constant _ROLE_228 = 1 << 228; uint256 internal constant _ROLE_229 = 1 << 229; uint256 internal constant _ROLE_230 = 1 << 230; uint256 internal constant _ROLE_231 = 1 << 231; uint256 internal constant _ROLE_232 = 1 << 232; uint256 internal constant _ROLE_233 = 1 << 233; uint256 internal constant _ROLE_234 = 1 << 234; uint256 internal constant _ROLE_235 = 1 << 235; uint256 internal constant _ROLE_236 = 1 << 236; uint256 internal constant _ROLE_237 = 1 << 237; uint256 internal constant _ROLE_238 = 1 << 238; uint256 internal constant _ROLE_239 = 1 << 239; uint256 internal constant _ROLE_240 = 1 << 240; uint256 internal constant _ROLE_241 = 1 << 241; uint256 internal constant _ROLE_242 = 1 << 242; uint256 internal constant _ROLE_243 = 1 << 243; uint256 internal constant _ROLE_244 = 1 << 244; uint256 internal constant _ROLE_245 = 1 << 245; uint256 internal constant _ROLE_246 = 1 << 246; uint256 internal constant _ROLE_247 = 1 << 247; uint256 internal constant _ROLE_248 = 1 << 248; uint256 internal constant _ROLE_249 = 1 << 249; uint256 internal constant _ROLE_250 = 1 << 250; uint256 internal constant _ROLE_251 = 1 << 251; uint256 internal constant _ROLE_252 = 1 << 252; uint256 internal constant _ROLE_253 = 1 << 253; uint256 internal constant _ROLE_254 = 1 << 254; uint256 internal constant _ROLE_255 = 1 << 255; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.22; /** * @dev Required interface of an ERC-721 compliant contract. */ interface IERC721 { /** * @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); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Simple single owner authorization mixin. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) /// /// @dev Note: /// This implementation does NOT auto-initialize the owner to `msg.sender`. /// You MUST call the `_initializeOwner` in the constructor / initializer. /// /// While the ownable portion follows /// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility, /// the nomenclature for the 2-step ownership handover may be unique to this codebase. abstract contract Ownable { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The caller is not authorized to call the function. error Unauthorized(); /// @dev The `newOwner` cannot be the zero address. error NewOwnerIsZeroAddress(); /// @dev The `pendingOwner` does not have a valid handover request. error NoHandoverRequest(); /// @dev Cannot double-initialize. error AlreadyInitialized(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The ownership is transferred from `oldOwner` to `newOwner`. /// This event is intentionally kept the same as OpenZeppelin's Ownable to be /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173), /// despite it not being as lightweight as a single argument event. event OwnershipTransferred(address indexed oldOwner, address indexed newOwner); /// @dev An ownership handover to `pendingOwner` has been requested. event OwnershipHandoverRequested(address indexed pendingOwner); /// @dev The ownership handover to `pendingOwner` has been canceled. event OwnershipHandoverCanceled(address indexed pendingOwner); /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`. uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE = 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0; /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`. uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE = 0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d; /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`. uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE = 0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The owner slot is given by: /// `bytes32(~uint256(uint32(bytes4(keccak256("_OWNER_SLOT_NOT")))))`. /// It is intentionally chosen to be a high value /// to avoid collision with lower slots. /// The choice of manual storage layout is to enable compatibility /// with both regular and upgradeable contracts. bytes32 internal constant _OWNER_SLOT = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927; /// The ownership handover slot of `newOwner` is given by: /// ``` /// mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED)) /// let handoverSlot := keccak256(0x00, 0x20) /// ``` /// It stores the expiry timestamp of the two-step ownership handover. uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Override to return true to make `_initializeOwner` prevent double-initialization. function _guardInitializeOwner() internal pure virtual returns (bool guard) {} /// @dev Initializes the owner directly without authorization guard. /// This function must be called upon initialization, /// regardless of whether the contract is upgradeable or not. /// This is to enable generalization to both regular and upgradeable contracts, /// and to save gas in case the initial owner is not the caller. /// For performance reasons, this function will not check if there /// is an existing owner. function _initializeOwner(address newOwner) internal virtual { if (_guardInitializeOwner()) { /// @solidity memory-safe-assembly assembly { let ownerSlot := _OWNER_SLOT if sload(ownerSlot) { mstore(0x00, 0x0dc149f0) // `AlreadyInitialized()`. revert(0x1c, 0x04) } // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Store the new value. sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner)))) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner) } } else { /// @solidity memory-safe-assembly assembly { // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Store the new value. sstore(_OWNER_SLOT, newOwner) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner) } } } /// @dev Sets the owner directly without authorization guard. function _setOwner(address newOwner) internal virtual { if (_guardInitializeOwner()) { /// @solidity memory-safe-assembly assembly { let ownerSlot := _OWNER_SLOT // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner) // Store the new value. sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner)))) } } else { /// @solidity memory-safe-assembly assembly { let ownerSlot := _OWNER_SLOT // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner) // Store the new value. sstore(ownerSlot, newOwner) } } } /// @dev Throws if the sender is not the owner. function _checkOwner() internal view virtual { /// @solidity memory-safe-assembly assembly { // If the caller is not the stored owner, revert. if iszero(eq(caller(), sload(_OWNER_SLOT))) { mstore(0x00, 0x82b42900) // `Unauthorized()`. revert(0x1c, 0x04) } } } /// @dev Returns how long a two-step ownership handover is valid for in seconds. /// Override to return a different value if needed. /// Made internal to conserve bytecode. Wrap it in a public function if needed. function _ownershipHandoverValidFor() internal view virtual returns (uint64) { return 48 * 3600; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC UPDATE FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Allows the owner to transfer the ownership to `newOwner`. function transferOwnership(address newOwner) public payable virtual onlyOwner { /// @solidity memory-safe-assembly assembly { if iszero(shl(96, newOwner)) { mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`. revert(0x1c, 0x04) } } _setOwner(newOwner); } /// @dev Allows the owner to renounce their ownership. function renounceOwnership() public payable virtual onlyOwner { _setOwner(address(0)); } /// @dev Request a two-step ownership handover to the caller. /// The request will automatically expire in 48 hours (172800 seconds) by default. function requestOwnershipHandover() public payable virtual { unchecked { uint256 expires = block.timestamp + _ownershipHandoverValidFor(); /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to `expires`. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x20), expires) // Emit the {OwnershipHandoverRequested} event. log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller()) } } } /// @dev Cancels the two-step ownership handover to the caller, if any. function cancelOwnershipHandover() public payable virtual { /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to 0. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x20), 0) // Emit the {OwnershipHandoverCanceled} event. log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller()) } } /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`. /// Reverts if there is no existing ownership handover requested by `pendingOwner`. function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner { /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to 0. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, pendingOwner) let handoverSlot := keccak256(0x0c, 0x20) // If the handover does not exist, or has expired. if gt(timestamp(), sload(handoverSlot)) { mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`. revert(0x1c, 0x04) } // Set the handover slot to 0. sstore(handoverSlot, 0) } _setOwner(pendingOwner); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC READ FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the owner of the contract. function owner() public view virtual returns (address result) { /// @solidity memory-safe-assembly assembly { result := sload(_OWNER_SLOT) } } /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`. function ownershipHandoverExpiresAt(address pendingOwner) public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { // Compute the handover slot. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, pendingOwner) // Load the handover slot. result := sload(keccak256(0x0c, 0x20)) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MODIFIERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Marks a function as only callable by the owner. modifier onlyOwner() virtual { _checkOwner(); _; } }
{ "remappings": [ "forge-std/=test/utils/forge-std/", "murky/=lib/murky/", "solady/=lib/solady/src/", "@openzeppelin-upgradeable/=lib/openzeppelin-contracts-upgradeable/", "@openzeppelin/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/", "permit2/=lib/permit2/src/", "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", "@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/", "ds-test/=lib/forge-std/lib/ds-test/src/", "erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/", "forge-gas-snapshot/=lib/permit2/lib/forge-gas-snapshot/src/", "forge-std/=lib/forge-std/src/", "halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/", "murky/=lib/murky/", "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/", "openzeppelin-contracts/=lib/murky/lib/openzeppelin-contracts/", "solady/=lib/solady/src/", "solmate/=lib/permit2/lib/solmate/" ], "optimizer": { "enabled": true, "runs": 1000 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "cancun", "viaIR": false, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"payable","type":"constructor"},{"inputs":[],"name":"AlreadyLinked","type":"error"},{"inputs":[],"name":"CannotLink","type":"error"},{"inputs":[],"name":"EmptyNFTIds","type":"error"},{"inputs":[],"name":"InvalidIdInRange","type":"error"},{"inputs":[],"name":"NotLinked","type":"error"},{"inputs":[],"name":"Reentrancy","type":"error"},{"inputs":[],"name":"SenderNotBase","type":"error"},{"inputs":[],"name":"SenderNotDeployer","type":"error"},{"inputs":[],"name":"TransferToNonERC721ReceiverImplementer","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"UnauthorizedCallContext","type":"error"},{"inputs":[],"name":"UpgradeFailed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"isApproved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"},{"indexed":false,"internalType":"address","name":"bidToken","type":"address"}],"name":"Bid","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"},{"indexed":false,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"address","name":"maker","type":"address"}],"name":"Bought","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"}],"name":"CancelBid","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"}],"name":"CancelOffer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"idX","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"idY","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"exchangeFee","type":"uint256"}],"name":"Exchange","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"minPrice","type":"uint256"},{"indexed":false,"internalType":"address","name":"offerToken","type":"address"}],"name":"Offer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"bool","name":"lockStatus","type":"bool"}],"name":"UpdateLockState","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"stateMutability":"payable","type":"fallback"},{"inputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"trader","type":"address"}],"internalType":"struct BT404Mirror.NFTOrder[]","name":"orders","type":"tuple[]"}],"name":"acceptBid","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"trader","type":"address"}],"internalType":"struct BT404Mirror.NFTOrder[]","name":"orders","type":"tuple[]"}],"name":"acceptOffer","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"nftOwner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseERC20","outputs":[{"internalType":"address","name":"base","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseERC721","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"trader","type":"address"}],"internalType":"struct BT404Mirror.NFTOrder[]","name":"orders","type":"tuple[]"}],"name":"bidForBuy","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"cancelBid","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"cancelOffer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"idX","type":"uint256"},{"internalType":"uint256","name":"idY","type":"uint256"}],"name":"exchange","outputs":[{"internalType":"uint256","name":"exchangeFee","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_baseERC721","type":"address"},{"internalType":"uint256","name":"_startBaseId","type":"uint256"},{"internalType":"uint256","name":"_endBaseId","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"nftOwner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"begin","type":"uint256"},{"internalType":"uint256","name":"end","type":"uint256"}],"name":"lockedIds","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"result","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"price","type":"uint256"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"trader","type":"address"}],"internalType":"struct BT404Mirror.NFTOrder[]","name":"orders","type":"tuple[]"}],"name":"offerForSale","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"begin","type":"uint256"},{"internalType":"uint256","name":"end","type":"uint256"}],"name":"ownedIds","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"ownerAt","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pullOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"result","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"result","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"unwrapBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"bool","name":"lock","type":"bool"}],"name":"updateLockState","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"wrapBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"bool","name":"lock","type":"bool"}],"name":"wrapBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60a060405230608052683602298b8c10b01231805460016001600160a01b0319918216338316178117909255682ab3f28a60db472ee6805490911690911790555f682ab3f28a60db472ee7819055682ab3f28a60db472ee85560805161286e6100775f395f8181610ecd0152610fae015261286e5ff3fe608060405260043610610252575f3560e01c8063680a9f1f11610137578063a444be1f116100af578063c87b56dd1161007e578063d4b7eac311610063578063d4b7eac3146108ec578063e5583c0f1461090b578063e985e9c51461092a57610259565b8063c87b56dd146108ae578063ccf0e515146108cd57610259565b8063a444be1f1461083e578063b313f05a14610851578063b88d4fde14610870578063bf598e1e1461088f57610259565b80637ec824181161010657806395d89b41116100eb57806395d89b41146107f757806397e5311c1461080b578063a22cb4651461081f57610259565b80637ec82418146107b35780638da5cb5b146107d257610259565b8063680a9f1f146107415780636cef16e61461076d57806370a08231146107815780637a1ac61e146107a057610259565b806324359879116101ca5780634ae9617c1161019957806352d1902d1161017e57806352d1902d146106ef578063616b95e8146107035780636352211e1461072257610259565b80634ae9617c146106bd5780634f1ef286146106dc57610259565b8063243598791461064d57806325d4fe1a1461066c57806342842e0e1461068b578063442f085d146106aa57610259565b8063095ea7b311610221578063150b7a0211610206578063150b7a021461059857806318160ddd1461060c57806323b872dd1461062e57610259565b8063095ea7b31461055a57806312553e201461057957610259565b806301ffc9a71461048c57806306fdde03146104dd578063081812fc146104fe57806308b327421461053557610259565b3661025957005b683602298b8c10b012305f3560e01c63263c69d681900361031e5781546001600160a01b0316331461029e57604051631b1e598960e11b815260040160405180910390fd5b602036103d5f3e6004356024018036103d5f3e602081033560051b81018036103d5f3e5b8082146103135781358060601c816001168260a01b60a81c811583028284027fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f38a45050508160200191506102c2565b505060015f5260205ff35b8063144027d3036103b15781546001600160a01b0316331461035357604051631b1e598960e11b815260040160405180910390fd5b600435602435604435602401602081033560051b81015b8082146103a457813583857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f38a481602001915061036a565b5050505060015f5260205ff35b80630f4599e50361048a5760018201546001600160a01b0316156104205760018201546001600160a01b03166004356001600160a01b031614610420576040517fc59ec47a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81546001600160a01b031615610462576040517fbf656a4600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b815473ffffffffffffffffffffffffffffffffffffffff19163317825560015f908152602090f35b005b348015610497575f80fd5b506104c86104a6366004612079565b6301ffc9a760e09190911c9081146380ac58cd821417635b5e139f9091141790565b60405190151581526020015b60405180910390f35b3480156104e8575f80fd5b506104f1610949565b6040516104d491906120b8565b348015610509575f80fd5b5061051d6105183660046120ed565b61095e565b6040516001600160a01b0390911681526020016104d4565b348015610540575f80fd5b50682ab3f28a60db472ee6546001600160a01b031661051d565b348015610565575f80fd5b5061048a61057436600461211f565b610974565b348015610584575f80fd5b5061048a610593366004612242565b6109f4565b3480156105a3575f80fd5b506105db6105b236600461229b565b7f150b7a0200000000000000000000000000000000000000000000000000000000949350505050565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681526020016104d4565b348015610617575f80fd5b50610620610a01565b6040519081526020016104d4565b348015610639575f80fd5b5061048a61064836600461233a565b610a11565b348015610658575f80fd5b5061051d6106673660046120ed565b610af2565b348015610677575f80fd5b5061048a610686366004612242565b610b02565b348015610696575f80fd5b5061048a6106a536600461233a565b610bfc565b61048a6106b8366004612374565b610c2d565b3480156106c8575f80fd5b5061048a6106d7366004612374565b610d7c565b61048a6106ea366004612492565b610ecb565b3480156106fa575f80fd5b50610620610fab565b34801561070e575f80fd5b5061048a61071d366004612242565b611008565b34801561072d575f80fd5b5061051d61073c3660046120ed565b6110f2565b34801561074c575f80fd5b5061076061075b3660046124e1565b611102565b6040516104d4919061254b565b348015610778575f80fd5b5061048a611119565b34801561078c575f80fd5b5061062061079b36600461255d565b6111d4565b61048a6107ae3660046124e1565b6111ed565b3480156107be575f80fd5b5061048a6107cd366004612583565b611282565b3480156107dd575f80fd5b50683602298b8c10b01232546001600160a01b031661051d565b348015610802575f80fd5b506104f16113c6565b348015610816575f80fd5b5061051d6113d6565b34801561082a575f80fd5b5061048a6108393660046125d2565b611424565b61048a61084c366004612374565b6114a1565b34801561085c575f80fd5b5061048a61086b366004612583565b611595565b34801561087b575f80fd5b5061048a61088a3660046125fc565b611815565b34801561089a575f80fd5b506107606108a93660046124e1565b611868565b3480156108b9575f80fd5b506104f16108c83660046120ed565b611876565b3480156108d8575f80fd5b5061048a6108e7366004612374565b611956565b3480156108f7575f80fd5b50610620610906366004612666565b611a4e565b348015610916575f80fd5b5061048a610925366004612242565b611b49565b348015610935575f80fd5b506104c8610944366004612686565b611d68565b60606109596306fdde035f611d93565b905090565b5f61096e63081812fc835f611de9565b92915050565b5f61097d6113d6565b90508260601b60601c925060405163d10b6e0c5f5283602052826040523360605260205f6064601c34865af1601f3d11166109ba573d5f823e3d81fd5b80604052505f6060528183600c5160601c7f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f38a4505050565b6109fe815f611595565b50565b5f61095963e2c792815f80611de9565b5f610a1a6113d6565b90508360601b60601c93508260601b60601c925060405163e5eb36c881528460208201528360408201528260608201523360808201526020816084601c840134865af1600182511416610a6f573d5f823e3d81fd5b5f815282857fcc3a1bd7e528af8582cd3578d82ae22e309de7c3663c9d0fa5b5ce79c1a346ac602084a38284867fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f38a46001815282847fcc3a1bd7e528af8582cd3578d82ae22e309de7c3663c9d0fa5b5ce79c1a346ac602084a35050505050565b5f61096e6324359879835f611de9565b683602298b8c10b012308054600160a01b900460ff1615610b365760405163558a1e0360e11b815260040160405180910390fd5b805460ff60a01b1916600160a01b178155604051610ba690610b5e90339085906024016126b7565b60408051601f198184030181529190526020810180516001600160e01b03167f2da2a85900000000000000000000000000000000000000000000000000000000179052611e2c565b5060208201825160051b81015b808214610bec573382517fc4caef7e3533865382e608c341581a5e2a1b0d1ac37b0aaf58023ccd4eedfd8e5f38a3602082019150610bb3565b5050805460ff60a01b1916905550565b610c07838383610a11565b813b15610c2857610c2883838360405180602001604052805f815250611e6a565b505050565b683602298b8c10b012308054600160a01b900460ff1615610c615760405163558a1e0360e11b815260040160405180910390fd5b805460ff60a01b1916600160a01b178155604051610cd190610c8990339085906024016126d8565b60408051601f198184030181529190526020810180516001600160e01b03167f53ffa07100000000000000000000000000000000000000000000000000000000179052611e2c565b50815160051b6020018201825160800281015b808214610bec57606082015160015f52825133827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f38a48251337fcc3a1bd7e528af8582cd3578d82ae22e309de7c3663c9d0fa5b5ce79c1a346ac60205fa3338184517fd9882bc1ac8e78c918b907fa0ff79cc9d866091c5eb450ebed79e9d147541d5b606060208801a450608082019150610ce4565b683602298b8c10b012308054600160a01b900460ff1615610db05760405163558a1e0360e11b815260040160405180910390fd5b805460ff60a01b1916600160a01b178155604051610e2090610dd890339085906024016126d8565b60408051601f198184030181529190526020810180516001600160e01b03167fb6ebe10300000000000000000000000000000000000000000000000000000000179052611e2c565b50815160051b6020018201825160800281015b808214610bec57606082015160015f52825181337fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f38a48251817fcc3a1bd7e528af8582cd3578d82ae22e309de7c3663c9d0fa5b5ce79c1a346ac60205fa3803384517fd9882bc1ac8e78c918b907fa0ff79cc9d866091c5eb450ebed79e9d147541d5b606060208801a450608082019150610e33565b7f0000000000000000000000000000000000000000000000000000000000000000308103610f0057639f03a0265f526004601cfd5b610f0984611eeb565b8360601b60601c93506352d1902d6001527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80602060016004601d895afa5114610f5b576355299b496001526004601dfd5b847fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f38a28490558115610fa557604051828482375f388483885af4610fa3573d5f823e3d81fd5b505b50505050565b5f7f0000000000000000000000000000000000000000000000000000000000000000308114610fe157639f03a0265f526004601cfd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc91505090565b683602298b8c10b012308054600160a01b900460ff161561103c5760405163558a1e0360e11b815260040160405180910390fd5b805460ff60a01b1916600160a01b1781556040516110ac9061106490339085906024016126b7565b60408051601f198184030181529190526020810180516001600160e01b03167fa38beee100000000000000000000000000000000000000000000000000000000179052611e2c565b5060208201825160051b81015b808214610bec573382517f874afcdd5e90b2329b3c1601e613dcdc6abb6deb62ce61339a8337b48c053e515f38a36020820191506110b9565b5f61096e636352211e835f611de9565b60606111118484846001611ef3565b949350505050565b5f806111236113d6565b9050638da5cb5b5f5260205f6004601c845afa601f3d11161561114957600c5160601c91505b683602298b8c10b0123254683602298b8c10b01230906001600160a01b039081169084168114610fa55760028201805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0386811691821790925560405190918316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a350505050565b5f61096e63f5b100ea836001600160a01b03165f611de9565b683602298b8c10b01231546001600160a01b03161561121e576040516282b42960e81b815260040160405180910390fd5b683602298b8c10b0123180543373ffffffffffffffffffffffffffffffffffffffff1991821617909155682ab3f28a60db472ee680549091166001600160a01b039490941693909317909255682ab3f28a60db472ee755682ab3f28a60db472ee855565b5f61128b6113d6565b90505f80826001600160a01b0316846112a4575f6112a7565b60015b60ff166060336001600160a01b0316901b17866040516024016112cb929190612766565b60408051601f198184030181529181526020820180516001600160e01b03167fb79cc1bd0000000000000000000000000000000000000000000000000000000017905251611319919061277e565b5f604051808303815f865af19150503d805f8114611352576040519150601f19603f3d011682016040523d82523d5f602084013e611357565b606091505b50915091508160016020830151141661137257805160208201fd5b8451845f52602086018160051b81015b8082146113bc578151337fcc3a1bd7e528af8582cd3578d82ae22e309de7c3663c9d0fa5b5ce79c1a346ac60205fa3602082019150611382565b5050505050505050565b60606109596395d89b415f611d93565b683602298b8c10b01230546001600160a01b031680611421576040517f5b2a47ae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b90565b5f61142d6113d6565b90508260601b60601c925060405163813500fc5f52836020528215156040523360605260205f6064601c34865af160015f51141661146d573d5f823e3d81fd5b83337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160206040a360405250505f60605250565b683602298b8c10b012308054600160a01b900460ff16156114d55760405163558a1e0360e11b815260040160405180910390fd5b805460ff60a01b1916600160a01b178155604051611545906114fd90339085906024016126d8565b60408051601f198184030181529190526020810180516001600160e01b03167fb5a1305b00000000000000000000000000000000000000000000000000000000179052611e2c565b50815160051b6020018201825160800281015b808214610bec573382517fec85e6e86fabc4c703529b570fb5eb567dad69ddbf7901bc0fd28b38b93de7f3604060208601a3608082019150611558565b81515f036115b657604051632cc45dcf60e01b815260040160405180910390fd5b682ab3f28a60db472ee68054682ab3f28a60db472ee754682ab3f28a60db472ee8546001600160a01b03909216915f5b865181101561169d575f87828151811061160257611602612794565b60200260200101519050611617848483611f68565b6040517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018290526001600160a01b038616906323b872dd906064015f604051808303815f87803b15801561167b575f80fd5b505af115801561168d573d5f803e3d5ffd5b50505050816001019150506115e6565b505f6116a76113d6565b90505f80826001600160a01b0316886116c0575f6116c3565b60015b60ff166060336001600160a01b0316901b178a6040516024016116e7929190612766565b60408051601f198184030181529181526020820180516001600160e01b03167f3e0446a10000000000000000000000000000000000000000000000000000000017905251611735919061277e565b5f604051808303815f865af19150503d805f811461176e576040519150601f19603f3d011682016040523d82523d5f602084013e611773565b606091505b50915091508160016020830151141661178e57805160208201fd5b8851885f5260208a018160051b81015b808214611807578151335f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f38a48a156117fc578151337fcc3a1bd7e528af8582cd3578d82ae22e309de7c3663c9d0fa5b5ce79c1a346ac60205fa35b60208201915061179e565b505050505050505050505050565b611820858585610a11565b833b15610fa357610fa385858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611e6a92505050565b60606111118484845f611ef3565b60605f611893682ab3f28a60db472ee6546001600160a01b031690565b6040517fc87b56dd000000000000000000000000000000000000000000000000000000008152600481018590529091506001600160a01b0382169063c87b56dd906024015f60405180830381865afa92505050801561191357506040513d5f823e601f3d908101601f1916820160405261191091908101906127a8565b60015b61194f573d808015611940576040519150601f19603f3d011682016040523d82523d5f602084013e611945565b606091505b5061111184611fb4565b9392505050565b683602298b8c10b012308054600160a01b900460ff161561198a5760405163558a1e0360e11b815260040160405180910390fd5b805460ff60a01b1916600160a01b1781556040516119fa906119b290339085906024016126d8565b60408051601f198184030181529190526020810180516001600160e01b03167f73e63d8900000000000000000000000000000000000000000000000000000000179052611e2c565b50815160051b6020018201825160800281015b808214610bec57606082015182517fc56f8610599b5a39311e36563ef3386394748f787ef5efc116d960d77def8050604060208601a3608082019150611a0d565b5f80611a586113d6565b9050604051632c5966af5f5284602052836040523360605260605f6064601c34865af1605f3d1116611a8c573d5f823e3d81fd5b5f5160205160405194508681837fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f38a48533827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f38a4505083857fbc43d7c0945f5a13a7bfa8ca7309e55f903f01d66c38c6d1353fe7ff9335d77660206040a3600160405283337fcc3a1bd7e528af8582cd3578d82ae22e309de7c3663c9d0fa5b5ce79c1a346ac60206040a3604052505f60605292915050565b80515f03611b6a57604051632cc45dcf60e01b815260040160405180910390fd5b5f611b736113d6565b90505f80826001600160a01b03163385604051602401611b949291906126b7565b60408051601f198184030181529181526020820180516001600160e01b03167f86529a610000000000000000000000000000000000000000000000000000000017905251611be2919061277e565b5f604051808303815f865af19150503d805f8114611c1b576040519150601f19603f3d011682016040523d82523d5f602084013e611c20565b606091505b509150915081600160208301511416611c3b57805160208201fd5b8351602085018160051b81015b808214611c825781515f337fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f38a4602082019150611c48565b5050505f611ca0682ab3f28a60db472ee6546001600160a01b031690565b90505f5b8551811015611d6057816001600160a01b03166342842e0e3033898581518110611cd057611cd0612794565b60209081029190910101516040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b03938416600482015292909116602483015260448201526064015f604051808303815f87803b158015611d3f575f80fd5b505af1158015611d51573d5f803e3d5ffd5b50505050806001019050611ca4565b505050505050565b5f611d8a63e985e9c5846001600160a01b0316846001600160a01b0316611de9565b15159392505050565b60605f611d9e6113d6565b90506040519150835f52826020525f806024601c845afa611dc1573d5f833e3d82fd5b60205f803e60205f51833e815160205f5101602084013e815160208301016040525092915050565b5f80611df36113d6565b9050604051855f52846020528360405260205f6044601c855afa601f3d1116611e1e573d5f823e3d81fd5b60405250505f519392505050565b5f80611e366113d6565b905060405160205f85516020870134865af1601f3d1116611e59573d5f823e3d81fd5b60405250505f606081905251919050565b60405163150b7a028082523360208301528560601b60601c604083015283606083015260808083015282518060a08401528015611eb1578060c08401826020870160045afa505b60208360a48301601c86015f8a5af1611ed2573d15611ed2573d5f843e3d83fd5b508060e01b825114611d605763d1a57ed65f526004601cfd5b6109fe611fc4565b60605f611efe6113d6565b9050604051915063f9b4b3285f528215158660601b1760205284604052836060525f806064601c845afa611f34573d5f833e3d82fd5b60205f803e60205f51833e815160051b60205f5101602084013e815160051b60208301016040525f60605250949350505050565b82821715610c285782811080611f7d57508082105b15610c28576040517fafaa46a500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606061096e63c87b56dd83611d93565b611fcc6113d6565b6040517f514e62fc00000000000000000000000000000000000000000000000000000000815233600482015267200000000000000060248201526001600160a01b03919091169063514e62fc90604401602060405180830381865afa158015612037573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061205b919061281d565b612077576040516282b42960e81b815260040160405180910390fd5b565b5f60208284031215612089575f80fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461194f575f80fd5b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b5f602082840312156120fd575f80fd5b5035919050565b80356001600160a01b038116811461211a575f80fd5b919050565b5f8060408385031215612130575f80fd5b61213983612104565b946020939093013593505050565b634e487b7160e01b5f52604160045260245ffd5b6040516080810167ffffffffffffffff8111828210171561217e5761217e612147565b60405290565b604051601f8201601f1916810167ffffffffffffffff811182821017156121ad576121ad612147565b604052919050565b5f67ffffffffffffffff8211156121ce576121ce612147565b5060051b60200190565b5f82601f8301126121e7575f80fd5b81356121fa6121f5826121b5565b612184565b8082825260208201915060208360051b86010192508583111561221b575f80fd5b602085015b83811015612238578035835260209283019201612220565b5095945050505050565b5f60208284031215612252575f80fd5b813567ffffffffffffffff811115612268575f80fd5b611111848285016121d8565b5f67ffffffffffffffff82111561228d5761228d612147565b50601f01601f191660200190565b5f805f80608085870312156122ae575f80fd5b6122b785612104565b93506122c560208601612104565b925060408501359150606085013567ffffffffffffffff8111156122e7575f80fd5b8501601f810187136122f7575f80fd5b80356123056121f582612274565b818152886020838501011115612319575f80fd5b816020840160208301375f6020838301015280935050505092959194509250565b5f805f6060848603121561234c575f80fd5b61235584612104565b925061236360208501612104565b929592945050506040919091013590565b5f60208284031215612384575f80fd5b813567ffffffffffffffff81111561239a575f80fd5b8201601f810184136123aa575f80fd5b80356123b86121f5826121b5565b8082825260208201915060208360071b8501019250868311156123d9575f80fd5b6020840193505b8284101561244357608084880312156123f7575f80fd5b6123ff61215b565b843581526020808601359082015261241960408601612104565b604082015261242a60608601612104565b60608201528252608093909301926020909101906123e0565b9695505050505050565b5f8083601f84011261245d575f80fd5b50813567ffffffffffffffff811115612474575f80fd5b60208301915083602082850101111561248b575f80fd5b9250929050565b5f805f604084860312156124a4575f80fd5b6124ad84612104565b9250602084013567ffffffffffffffff8111156124c8575f80fd5b6124d48682870161244d565b9497909650939450505050565b5f805f606084860312156124f3575f80fd5b6124fc84612104565b95602085013595506040909401359392505050565b5f8151808452602084019350602083015f5b82811015612541578151865260209586019590910190600101612523565b5093949350505050565b602081525f61194f6020830184612511565b5f6020828403121561256d575f80fd5b61194f82612104565b80151581146109fe575f80fd5b5f8060408385031215612594575f80fd5b823567ffffffffffffffff8111156125aa575f80fd5b6125b6858286016121d8565b92505060208301356125c781612576565b809150509250929050565b5f80604083850312156125e3575f80fd5b6125ec83612104565b915060208301356125c781612576565b5f805f805f60808688031215612610575f80fd5b61261986612104565b945061262760208701612104565b935060408601359250606086013567ffffffffffffffff811115612649575f80fd5b6126558882890161244d565b969995985093965092949392505050565b5f8060408385031215612677575f80fd5b50508035926020909101359150565b5f8060408385031215612697575f80fd5b6126a083612104565b91506126ae60208401612104565b90509250929050565b6001600160a01b0383168152604060208201525f6111116040830184612511565b5f604082016001600160a01b0385168352604060208401528084518083526060850191506020860192505f5b8181101561275a57835180518452602081015160208501526001600160a01b0360408201511660408501526001600160a01b03606082015116606085015250608083019250602084019350600181019050612704565b50909695505050505050565b828152604060208201525f6111116040830184612511565b5f82518060208501845e5f920191825250919050565b634e487b7160e01b5f52603260045260245ffd5b5f602082840312156127b8575f80fd5b815167ffffffffffffffff8111156127ce575f80fd5b8201601f810184136127de575f80fd5b80516127ec6121f582612274565b818152856020838501011115612800575f80fd5b8160208401602083015e5f91810160200191909152949350505050565b5f6020828403121561282d575f80fd5b815161194f8161257656fea264697066735822122054a57c64c26e053d19f5872d49112243a685b25cb8dcfc3a9bed5307fd152a0964736f6c634300081a0033
Deployed Bytecode
0x608060405260043610610252575f3560e01c8063680a9f1f11610137578063a444be1f116100af578063c87b56dd1161007e578063d4b7eac311610063578063d4b7eac3146108ec578063e5583c0f1461090b578063e985e9c51461092a57610259565b8063c87b56dd146108ae578063ccf0e515146108cd57610259565b8063a444be1f1461083e578063b313f05a14610851578063b88d4fde14610870578063bf598e1e1461088f57610259565b80637ec824181161010657806395d89b41116100eb57806395d89b41146107f757806397e5311c1461080b578063a22cb4651461081f57610259565b80637ec82418146107b35780638da5cb5b146107d257610259565b8063680a9f1f146107415780636cef16e61461076d57806370a08231146107815780637a1ac61e146107a057610259565b806324359879116101ca5780634ae9617c1161019957806352d1902d1161017e57806352d1902d146106ef578063616b95e8146107035780636352211e1461072257610259565b80634ae9617c146106bd5780634f1ef286146106dc57610259565b8063243598791461064d57806325d4fe1a1461066c57806342842e0e1461068b578063442f085d146106aa57610259565b8063095ea7b311610221578063150b7a0211610206578063150b7a021461059857806318160ddd1461060c57806323b872dd1461062e57610259565b8063095ea7b31461055a57806312553e201461057957610259565b806301ffc9a71461048c57806306fdde03146104dd578063081812fc146104fe57806308b327421461053557610259565b3661025957005b683602298b8c10b012305f3560e01c63263c69d681900361031e5781546001600160a01b0316331461029e57604051631b1e598960e11b815260040160405180910390fd5b602036103d5f3e6004356024018036103d5f3e602081033560051b81018036103d5f3e5b8082146103135781358060601c816001168260a01b60a81c811583028284027fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f38a45050508160200191506102c2565b505060015f5260205ff35b8063144027d3036103b15781546001600160a01b0316331461035357604051631b1e598960e11b815260040160405180910390fd5b600435602435604435602401602081033560051b81015b8082146103a457813583857fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f38a481602001915061036a565b5050505060015f5260205ff35b80630f4599e50361048a5760018201546001600160a01b0316156104205760018201546001600160a01b03166004356001600160a01b031614610420576040517fc59ec47a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b81546001600160a01b031615610462576040517fbf656a4600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b815473ffffffffffffffffffffffffffffffffffffffff19163317825560015f908152602090f35b005b348015610497575f80fd5b506104c86104a6366004612079565b6301ffc9a760e09190911c9081146380ac58cd821417635b5e139f9091141790565b60405190151581526020015b60405180910390f35b3480156104e8575f80fd5b506104f1610949565b6040516104d491906120b8565b348015610509575f80fd5b5061051d6105183660046120ed565b61095e565b6040516001600160a01b0390911681526020016104d4565b348015610540575f80fd5b50682ab3f28a60db472ee6546001600160a01b031661051d565b348015610565575f80fd5b5061048a61057436600461211f565b610974565b348015610584575f80fd5b5061048a610593366004612242565b6109f4565b3480156105a3575f80fd5b506105db6105b236600461229b565b7f150b7a0200000000000000000000000000000000000000000000000000000000949350505050565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681526020016104d4565b348015610617575f80fd5b50610620610a01565b6040519081526020016104d4565b348015610639575f80fd5b5061048a61064836600461233a565b610a11565b348015610658575f80fd5b5061051d6106673660046120ed565b610af2565b348015610677575f80fd5b5061048a610686366004612242565b610b02565b348015610696575f80fd5b5061048a6106a536600461233a565b610bfc565b61048a6106b8366004612374565b610c2d565b3480156106c8575f80fd5b5061048a6106d7366004612374565b610d7c565b61048a6106ea366004612492565b610ecb565b3480156106fa575f80fd5b50610620610fab565b34801561070e575f80fd5b5061048a61071d366004612242565b611008565b34801561072d575f80fd5b5061051d61073c3660046120ed565b6110f2565b34801561074c575f80fd5b5061076061075b3660046124e1565b611102565b6040516104d4919061254b565b348015610778575f80fd5b5061048a611119565b34801561078c575f80fd5b5061062061079b36600461255d565b6111d4565b61048a6107ae3660046124e1565b6111ed565b3480156107be575f80fd5b5061048a6107cd366004612583565b611282565b3480156107dd575f80fd5b50683602298b8c10b01232546001600160a01b031661051d565b348015610802575f80fd5b506104f16113c6565b348015610816575f80fd5b5061051d6113d6565b34801561082a575f80fd5b5061048a6108393660046125d2565b611424565b61048a61084c366004612374565b6114a1565b34801561085c575f80fd5b5061048a61086b366004612583565b611595565b34801561087b575f80fd5b5061048a61088a3660046125fc565b611815565b34801561089a575f80fd5b506107606108a93660046124e1565b611868565b3480156108b9575f80fd5b506104f16108c83660046120ed565b611876565b3480156108d8575f80fd5b5061048a6108e7366004612374565b611956565b3480156108f7575f80fd5b50610620610906366004612666565b611a4e565b348015610916575f80fd5b5061048a610925366004612242565b611b49565b348015610935575f80fd5b506104c8610944366004612686565b611d68565b60606109596306fdde035f611d93565b905090565b5f61096e63081812fc835f611de9565b92915050565b5f61097d6113d6565b90508260601b60601c925060405163d10b6e0c5f5283602052826040523360605260205f6064601c34865af1601f3d11166109ba573d5f823e3d81fd5b80604052505f6060528183600c5160601c7f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f38a4505050565b6109fe815f611595565b50565b5f61095963e2c792815f80611de9565b5f610a1a6113d6565b90508360601b60601c93508260601b60601c925060405163e5eb36c881528460208201528360408201528260608201523360808201526020816084601c840134865af1600182511416610a6f573d5f823e3d81fd5b5f815282857fcc3a1bd7e528af8582cd3578d82ae22e309de7c3663c9d0fa5b5ce79c1a346ac602084a38284867fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f38a46001815282847fcc3a1bd7e528af8582cd3578d82ae22e309de7c3663c9d0fa5b5ce79c1a346ac602084a35050505050565b5f61096e6324359879835f611de9565b683602298b8c10b012308054600160a01b900460ff1615610b365760405163558a1e0360e11b815260040160405180910390fd5b805460ff60a01b1916600160a01b178155604051610ba690610b5e90339085906024016126b7565b60408051601f198184030181529190526020810180516001600160e01b03167f2da2a85900000000000000000000000000000000000000000000000000000000179052611e2c565b5060208201825160051b81015b808214610bec573382517fc4caef7e3533865382e608c341581a5e2a1b0d1ac37b0aaf58023ccd4eedfd8e5f38a3602082019150610bb3565b5050805460ff60a01b1916905550565b610c07838383610a11565b813b15610c2857610c2883838360405180602001604052805f815250611e6a565b505050565b683602298b8c10b012308054600160a01b900460ff1615610c615760405163558a1e0360e11b815260040160405180910390fd5b805460ff60a01b1916600160a01b178155604051610cd190610c8990339085906024016126d8565b60408051601f198184030181529190526020810180516001600160e01b03167f53ffa07100000000000000000000000000000000000000000000000000000000179052611e2c565b50815160051b6020018201825160800281015b808214610bec57606082015160015f52825133827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f38a48251337fcc3a1bd7e528af8582cd3578d82ae22e309de7c3663c9d0fa5b5ce79c1a346ac60205fa3338184517fd9882bc1ac8e78c918b907fa0ff79cc9d866091c5eb450ebed79e9d147541d5b606060208801a450608082019150610ce4565b683602298b8c10b012308054600160a01b900460ff1615610db05760405163558a1e0360e11b815260040160405180910390fd5b805460ff60a01b1916600160a01b178155604051610e2090610dd890339085906024016126d8565b60408051601f198184030181529190526020810180516001600160e01b03167fb6ebe10300000000000000000000000000000000000000000000000000000000179052611e2c565b50815160051b6020018201825160800281015b808214610bec57606082015160015f52825181337fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f38a48251817fcc3a1bd7e528af8582cd3578d82ae22e309de7c3663c9d0fa5b5ce79c1a346ac60205fa3803384517fd9882bc1ac8e78c918b907fa0ff79cc9d866091c5eb450ebed79e9d147541d5b606060208801a450608082019150610e33565b7f0000000000000000000000000000000011420846a00c2d14a548b81c1709d162308103610f0057639f03a0265f526004601cfd5b610f0984611eeb565b8360601b60601c93506352d1902d6001527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80602060016004601d895afa5114610f5b576355299b496001526004601dfd5b847fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f38a28490558115610fa557604051828482375f388483885af4610fa3573d5f823e3d81fd5b505b50505050565b5f7f0000000000000000000000000000000011420846a00c2d14a548b81c1709d162308114610fe157639f03a0265f526004601cfd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc91505090565b683602298b8c10b012308054600160a01b900460ff161561103c5760405163558a1e0360e11b815260040160405180910390fd5b805460ff60a01b1916600160a01b1781556040516110ac9061106490339085906024016126b7565b60408051601f198184030181529190526020810180516001600160e01b03167fa38beee100000000000000000000000000000000000000000000000000000000179052611e2c565b5060208201825160051b81015b808214610bec573382517f874afcdd5e90b2329b3c1601e613dcdc6abb6deb62ce61339a8337b48c053e515f38a36020820191506110b9565b5f61096e636352211e835f611de9565b60606111118484846001611ef3565b949350505050565b5f806111236113d6565b9050638da5cb5b5f5260205f6004601c845afa601f3d11161561114957600c5160601c91505b683602298b8c10b0123254683602298b8c10b01230906001600160a01b039081169084168114610fa55760028201805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b0386811691821790925560405190918316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a350505050565b5f61096e63f5b100ea836001600160a01b03165f611de9565b683602298b8c10b01231546001600160a01b03161561121e576040516282b42960e81b815260040160405180910390fd5b683602298b8c10b0123180543373ffffffffffffffffffffffffffffffffffffffff1991821617909155682ab3f28a60db472ee680549091166001600160a01b039490941693909317909255682ab3f28a60db472ee755682ab3f28a60db472ee855565b5f61128b6113d6565b90505f80826001600160a01b0316846112a4575f6112a7565b60015b60ff166060336001600160a01b0316901b17866040516024016112cb929190612766565b60408051601f198184030181529181526020820180516001600160e01b03167fb79cc1bd0000000000000000000000000000000000000000000000000000000017905251611319919061277e565b5f604051808303815f865af19150503d805f8114611352576040519150601f19603f3d011682016040523d82523d5f602084013e611357565b606091505b50915091508160016020830151141661137257805160208201fd5b8451845f52602086018160051b81015b8082146113bc578151337fcc3a1bd7e528af8582cd3578d82ae22e309de7c3663c9d0fa5b5ce79c1a346ac60205fa3602082019150611382565b5050505050505050565b60606109596395d89b415f611d93565b683602298b8c10b01230546001600160a01b031680611421576040517f5b2a47ae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b90565b5f61142d6113d6565b90508260601b60601c925060405163813500fc5f52836020528215156040523360605260205f6064601c34865af160015f51141661146d573d5f823e3d81fd5b83337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160206040a360405250505f60605250565b683602298b8c10b012308054600160a01b900460ff16156114d55760405163558a1e0360e11b815260040160405180910390fd5b805460ff60a01b1916600160a01b178155604051611545906114fd90339085906024016126d8565b60408051601f198184030181529190526020810180516001600160e01b03167fb5a1305b00000000000000000000000000000000000000000000000000000000179052611e2c565b50815160051b6020018201825160800281015b808214610bec573382517fec85e6e86fabc4c703529b570fb5eb567dad69ddbf7901bc0fd28b38b93de7f3604060208601a3608082019150611558565b81515f036115b657604051632cc45dcf60e01b815260040160405180910390fd5b682ab3f28a60db472ee68054682ab3f28a60db472ee754682ab3f28a60db472ee8546001600160a01b03909216915f5b865181101561169d575f87828151811061160257611602612794565b60200260200101519050611617848483611f68565b6040517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018290526001600160a01b038616906323b872dd906064015f604051808303815f87803b15801561167b575f80fd5b505af115801561168d573d5f803e3d5ffd5b50505050816001019150506115e6565b505f6116a76113d6565b90505f80826001600160a01b0316886116c0575f6116c3565b60015b60ff166060336001600160a01b0316901b178a6040516024016116e7929190612766565b60408051601f198184030181529181526020820180516001600160e01b03167f3e0446a10000000000000000000000000000000000000000000000000000000017905251611735919061277e565b5f604051808303815f865af19150503d805f811461176e576040519150601f19603f3d011682016040523d82523d5f602084013e611773565b606091505b50915091508160016020830151141661178e57805160208201fd5b8851885f5260208a018160051b81015b808214611807578151335f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f38a48a156117fc578151337fcc3a1bd7e528af8582cd3578d82ae22e309de7c3663c9d0fa5b5ce79c1a346ac60205fa35b60208201915061179e565b505050505050505050505050565b611820858585610a11565b833b15610fa357610fa385858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611e6a92505050565b60606111118484845f611ef3565b60605f611893682ab3f28a60db472ee6546001600160a01b031690565b6040517fc87b56dd000000000000000000000000000000000000000000000000000000008152600481018590529091506001600160a01b0382169063c87b56dd906024015f60405180830381865afa92505050801561191357506040513d5f823e601f3d908101601f1916820160405261191091908101906127a8565b60015b61194f573d808015611940576040519150601f19603f3d011682016040523d82523d5f602084013e611945565b606091505b5061111184611fb4565b9392505050565b683602298b8c10b012308054600160a01b900460ff161561198a5760405163558a1e0360e11b815260040160405180910390fd5b805460ff60a01b1916600160a01b1781556040516119fa906119b290339085906024016126d8565b60408051601f198184030181529190526020810180516001600160e01b03167f73e63d8900000000000000000000000000000000000000000000000000000000179052611e2c565b50815160051b6020018201825160800281015b808214610bec57606082015182517fc56f8610599b5a39311e36563ef3386394748f787ef5efc116d960d77def8050604060208601a3608082019150611a0d565b5f80611a586113d6565b9050604051632c5966af5f5284602052836040523360605260605f6064601c34865af1605f3d1116611a8c573d5f823e3d81fd5b5f5160205160405194508681837fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f38a48533827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f38a4505083857fbc43d7c0945f5a13a7bfa8ca7309e55f903f01d66c38c6d1353fe7ff9335d77660206040a3600160405283337fcc3a1bd7e528af8582cd3578d82ae22e309de7c3663c9d0fa5b5ce79c1a346ac60206040a3604052505f60605292915050565b80515f03611b6a57604051632cc45dcf60e01b815260040160405180910390fd5b5f611b736113d6565b90505f80826001600160a01b03163385604051602401611b949291906126b7565b60408051601f198184030181529181526020820180516001600160e01b03167f86529a610000000000000000000000000000000000000000000000000000000017905251611be2919061277e565b5f604051808303815f865af19150503d805f8114611c1b576040519150601f19603f3d011682016040523d82523d5f602084013e611c20565b606091505b509150915081600160208301511416611c3b57805160208201fd5b8351602085018160051b81015b808214611c825781515f337fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f38a4602082019150611c48565b5050505f611ca0682ab3f28a60db472ee6546001600160a01b031690565b90505f5b8551811015611d6057816001600160a01b03166342842e0e3033898581518110611cd057611cd0612794565b60209081029190910101516040517fffffffff0000000000000000000000000000000000000000000000000000000060e086901b1681526001600160a01b03938416600482015292909116602483015260448201526064015f604051808303815f87803b158015611d3f575f80fd5b505af1158015611d51573d5f803e3d5ffd5b50505050806001019050611ca4565b505050505050565b5f611d8a63e985e9c5846001600160a01b0316846001600160a01b0316611de9565b15159392505050565b60605f611d9e6113d6565b90506040519150835f52826020525f806024601c845afa611dc1573d5f833e3d82fd5b60205f803e60205f51833e815160205f5101602084013e815160208301016040525092915050565b5f80611df36113d6565b9050604051855f52846020528360405260205f6044601c855afa601f3d1116611e1e573d5f823e3d81fd5b60405250505f519392505050565b5f80611e366113d6565b905060405160205f85516020870134865af1601f3d1116611e59573d5f823e3d81fd5b60405250505f606081905251919050565b60405163150b7a028082523360208301528560601b60601c604083015283606083015260808083015282518060a08401528015611eb1578060c08401826020870160045afa505b60208360a48301601c86015f8a5af1611ed2573d15611ed2573d5f843e3d83fd5b508060e01b825114611d605763d1a57ed65f526004601cfd5b6109fe611fc4565b60605f611efe6113d6565b9050604051915063f9b4b3285f528215158660601b1760205284604052836060525f806064601c845afa611f34573d5f833e3d82fd5b60205f803e60205f51833e815160051b60205f5101602084013e815160051b60208301016040525f60605250949350505050565b82821715610c285782811080611f7d57508082105b15610c28576040517fafaa46a500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606061096e63c87b56dd83611d93565b611fcc6113d6565b6040517f514e62fc00000000000000000000000000000000000000000000000000000000815233600482015267200000000000000060248201526001600160a01b03919091169063514e62fc90604401602060405180830381865afa158015612037573d5f803e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061205b919061281d565b612077576040516282b42960e81b815260040160405180910390fd5b565b5f60208284031215612089575f80fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461194f575f80fd5b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b5f602082840312156120fd575f80fd5b5035919050565b80356001600160a01b038116811461211a575f80fd5b919050565b5f8060408385031215612130575f80fd5b61213983612104565b946020939093013593505050565b634e487b7160e01b5f52604160045260245ffd5b6040516080810167ffffffffffffffff8111828210171561217e5761217e612147565b60405290565b604051601f8201601f1916810167ffffffffffffffff811182821017156121ad576121ad612147565b604052919050565b5f67ffffffffffffffff8211156121ce576121ce612147565b5060051b60200190565b5f82601f8301126121e7575f80fd5b81356121fa6121f5826121b5565b612184565b8082825260208201915060208360051b86010192508583111561221b575f80fd5b602085015b83811015612238578035835260209283019201612220565b5095945050505050565b5f60208284031215612252575f80fd5b813567ffffffffffffffff811115612268575f80fd5b611111848285016121d8565b5f67ffffffffffffffff82111561228d5761228d612147565b50601f01601f191660200190565b5f805f80608085870312156122ae575f80fd5b6122b785612104565b93506122c560208601612104565b925060408501359150606085013567ffffffffffffffff8111156122e7575f80fd5b8501601f810187136122f7575f80fd5b80356123056121f582612274565b818152886020838501011115612319575f80fd5b816020840160208301375f6020838301015280935050505092959194509250565b5f805f6060848603121561234c575f80fd5b61235584612104565b925061236360208501612104565b929592945050506040919091013590565b5f60208284031215612384575f80fd5b813567ffffffffffffffff81111561239a575f80fd5b8201601f810184136123aa575f80fd5b80356123b86121f5826121b5565b8082825260208201915060208360071b8501019250868311156123d9575f80fd5b6020840193505b8284101561244357608084880312156123f7575f80fd5b6123ff61215b565b843581526020808601359082015261241960408601612104565b604082015261242a60608601612104565b60608201528252608093909301926020909101906123e0565b9695505050505050565b5f8083601f84011261245d575f80fd5b50813567ffffffffffffffff811115612474575f80fd5b60208301915083602082850101111561248b575f80fd5b9250929050565b5f805f604084860312156124a4575f80fd5b6124ad84612104565b9250602084013567ffffffffffffffff8111156124c8575f80fd5b6124d48682870161244d565b9497909650939450505050565b5f805f606084860312156124f3575f80fd5b6124fc84612104565b95602085013595506040909401359392505050565b5f8151808452602084019350602083015f5b82811015612541578151865260209586019590910190600101612523565b5093949350505050565b602081525f61194f6020830184612511565b5f6020828403121561256d575f80fd5b61194f82612104565b80151581146109fe575f80fd5b5f8060408385031215612594575f80fd5b823567ffffffffffffffff8111156125aa575f80fd5b6125b6858286016121d8565b92505060208301356125c781612576565b809150509250929050565b5f80604083850312156125e3575f80fd5b6125ec83612104565b915060208301356125c781612576565b5f805f805f60808688031215612610575f80fd5b61261986612104565b945061262760208701612104565b935060408601359250606086013567ffffffffffffffff811115612649575f80fd5b6126558882890161244d565b969995985093965092949392505050565b5f8060408385031215612677575f80fd5b50508035926020909101359150565b5f8060408385031215612697575f80fd5b6126a083612104565b91506126ae60208401612104565b90509250929050565b6001600160a01b0383168152604060208201525f6111116040830184612511565b5f604082016001600160a01b0385168352604060208401528084518083526060850191506020860192505f5b8181101561275a57835180518452602081015160208501526001600160a01b0360408201511660408501526001600160a01b03606082015116606085015250608083019250602084019350600181019050612704565b50909695505050505050565b828152604060208201525f6111116040830184612511565b5f82518060208501845e5f920191825250919050565b634e487b7160e01b5f52603260045260245ffd5b5f602082840312156127b8575f80fd5b815167ffffffffffffffff8111156127ce575f80fd5b8201601f810184136127de575f80fd5b80516127ec6121f582612274565b818152856020838501011115612800575f80fd5b8160208401602083015e5f91810160200191909152949350505050565b5f6020828403121561282d575f80fd5b815161194f8161257656fea264697066735822122054a57c64c26e053d19f5872d49112243a685b25cb8dcfc3a9bed5307fd152a0964736f6c634300081a0033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.