Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
ERC721Marketplace
Compiler Version
v0.8.16+commit.07a7930e
Optimization Enabled:
Yes with 1000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; import {ERC721MarketplaceInternal} from "./ERC721MarketplaceInternal.sol"; import {ScapesMarketplaceStorage} from "./ScapesMarketplaceStorage.sol"; import {ERC721BaseInternal} from "../solidstate/ERC721BaseInternal.sol"; import {ScapesERC721MetadataStorage} from "../ScapesERC721MetadataStorage.sol"; import {IChild} from "../IChild.sol"; /// @title ERC721Marketplace /// @author akuti.eth, jalil.eth | scapes.eth /// @notice Adds a marketplace to ERC721 tokens that only takes royalties when tokens are sold at a gain. /// @dev A diamond facet that adds marketplace functionality to ERC721 tokens. contract ERC721Marketplace is ERC721BaseInternal, ERC721MarketplaceInternal { uint256 internal constant INITIAL_LAST_PRICE = 0.1 ether; /// @notice Get an exisiting current offer. function getOffer(uint256 tokenId) external view returns (ScapesMarketplaceStorage.Offer memory offer) { ScapesMarketplaceStorage.Layout storage d = ScapesMarketplaceStorage .layout(); offer = d.offers[tokenId]; if (offer.price == 0) revert ERC721Marketplace__NonExistentOffer(); } /// @notice List your token publicly. /// @dev Make an offer. Emits an {OfferCreated} event. An existing offer is replaced. function makeOffer(uint256 tokenId, uint80 price) external { // max price is 1_208_925 ETH _makeOffer(tokenId, price, address(0)); } /// @notice List multiple tokens publicly. /// @dev Batch make offers. Emits an {OfferCreated} event for each offer. Existing offers are replaced. function batchMakeOffer( uint256[] calldata tokenIds, uint80[] calldata prices ) external { if (tokenIds.length != prices.length) revert ERC721Marketplace__InvalidArguments(); uint256 length = tokenIds.length; for (uint256 i = 0; i < length; ) { _makeOffer(tokenIds[i], prices[i], address(0)); unchecked { i++; } } } /// @notice List your token privately for one address. /// @dev Make a private offer. Emits an {OfferCreated} event. An existing offer is replaced. function makeOfferTo( uint256 tokenId, uint80 price, address to ) external { _makeOffer(tokenId, price, to); } /// @notice List multiple tokens privately for given addresses. /// @dev Batch make private offers. Emits an {OfferCreated} event for each offer. Existing offers are replaced. function batchMakeOfferTo( uint256[] calldata tokenIds, uint80[] calldata prices, address[] calldata tos ) external { if (tokenIds.length != prices.length || tokenIds.length != tos.length) revert ERC721Marketplace__InvalidArguments(); uint256 length = tokenIds.length; for (uint256 i = 0; i < length; ) { _makeOffer(tokenIds[i], prices[i], tos[i]); unchecked { i++; } } } /// @notice Cancel an existing offer. /// @dev Allow approved operators to cancel an offer. Emits an {OfferWithdrawn} event. function cancelOffer(uint256 tokenId) public { if (!_isApprovedOrOwner(msg.sender, tokenId)) revert ERC721Base__NotOwnerOrApproved(); _cancelOffer(tokenId); } /// @notice Cancel multiple existing offers. /// @dev Allow approved operators to cancel existing offers. Emits an {OfferWithdrawn} event for each offer. function batchCancelOffer(uint256[] calldata tokenIds) external { uint256 length = tokenIds.length; for (uint256 i = 0; i < length; ) { cancelOffer(tokenIds[i]); unchecked { i++; } } } /// @notice Buy an offered item. /// @dev Buy an item that is offered publicly or to the sender. Emits a {Sale} event. function buy(uint256 tokenId) external payable { ScapesMarketplaceStorage.Offer memory offer = ScapesMarketplaceStorage .layout() .offers[tokenId]; if (offer.price > 0 && msg.value != offer.price) revert ERC721Marketplace__InvalidValue(); _buy(tokenId, offer); } /// @notice Buy multiple offered items. /// @dev Batch buy items that are offered publicly or to the sender. Emits a {Sale} event for each sale. function batchBuy(uint256[] calldata tokenIds) external payable { ScapesMarketplaceStorage.Layout storage d = ScapesMarketplaceStorage .layout(); uint256 totalCost; uint256 length = tokenIds.length; for (uint256 i = 0; i < length; ) { ScapesMarketplaceStorage.Offer memory offer = d.offers[tokenIds[i]]; totalCost += offer.price; if (msg.value < totalCost) revert ERC721Marketplace__InvalidValue(); _buy(tokenIds[i], offer); unchecked { i++; } } if (msg.value > totalCost) revert ERC721Marketplace__InvalidValue(); } /// @dev Logic of the buy function, check that item is offered, sent value /// is correct and caluclate correct fee to apply function _buy(uint256 tokenId, ScapesMarketplaceStorage.Offer memory offer) internal { uint256 price = offer.price; uint256 lastPrice = (offer.lastPrice == 0) ? INITIAL_LAST_PRICE : offer.lastPrice; if (price == 0) revert ERC721Marketplace__NonExistentOffer(); // If it is a private sale, make sure the buyer is the private sale recipient. if ( offer.specificBuyer != address(0) && offer.specificBuyer != msg.sender ) { revert ERC721Marketplace__NonExistentOffer(); } if (msg.value < offer.price) revert ERC721Marketplace__InvalidValue(); ScapesMarketplaceStorage.Layout storage d = ScapesMarketplaceStorage .layout(); // Keep track of the last price of the token. d.offers[tokenId].lastPrice = offer.price; // Close Offer d.offers[tokenId].price = 0; if (offer.specificBuyer != address(0)) d.offers[tokenId].specificBuyer = address(0); // Seller gets msg value - fees set as BPS. address seller = _ownerOf(tokenId); if (lastPrice < offer.price) { uint256 fullFeePrice = (10_000 * lastPrice) / (10_000 - d.bps); uint256 fee = price < fullFeePrice ? price - lastPrice : (price * d.bps) / 10_000; _transferEtherAndCheck(seller, price - fee); _transferEtherAndCheck(d.beneficiary, fee); } else { _transferEtherAndCheck(seller, msg.value); } _safeTransfer(seller, msg.sender, tokenId, ""); emit Sale(tokenId, seller, msg.sender, price); } function _transferEtherAndCheck(address receiver, uint256 value) internal { (bool sent, ) = payable(receiver).call{gas: 3_000, value: value}(""); if (!sent) revert ERC721Marketplace__PaymentFailed(); } /** * @inheritdoc ERC721BaseInternal */ function _afterTokenTransfer( address from, address to, uint256 tokenId ) internal virtual override(ERC721BaseInternal) { IChild(ScapesERC721MetadataStorage.layout().scapeBound).update( from, to, tokenId ); super._afterTokenTransfer(from, to, tokenId); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.8; /** * @title Map implementation with enumeration functions * @dev derived from https://github.com/OpenZeppelin/openzeppelin-contracts (MIT license) */ library EnumerableMap { error EnumerableMap__IndexOutOfBounds(); error EnumerableMap__NonExistentKey(); struct MapEntry { bytes32 _key; bytes32 _value; } struct Map { MapEntry[] _entries; // 1-indexed to allow 0 to signify nonexistence mapping(bytes32 => uint256) _indexes; } struct AddressToAddressMap { Map _inner; } struct UintToAddressMap { Map _inner; } function at( AddressToAddressMap storage map, uint256 index ) internal view returns (address, address) { (bytes32 key, bytes32 value) = _at(map._inner, index); return ( address(uint160(uint256(key))), address(uint160(uint256(value))) ); } function at( UintToAddressMap storage map, uint256 index ) internal view returns (uint256, address) { (bytes32 key, bytes32 value) = _at(map._inner, index); return (uint256(key), address(uint160(uint256(value)))); } function contains( AddressToAddressMap storage map, address key ) internal view returns (bool) { return _contains(map._inner, bytes32(uint256(uint160(key)))); } function contains( UintToAddressMap storage map, uint256 key ) internal view returns (bool) { return _contains(map._inner, bytes32(key)); } function length( AddressToAddressMap storage map ) internal view returns (uint256) { return _length(map._inner); } function length( UintToAddressMap storage map ) internal view returns (uint256) { return _length(map._inner); } function get( AddressToAddressMap storage map, address key ) internal view returns (address) { return address( uint160( uint256(_get(map._inner, bytes32(uint256(uint160(key))))) ) ); } function get( UintToAddressMap storage map, uint256 key ) internal view returns (address) { return address(uint160(uint256(_get(map._inner, bytes32(key))))); } function set( AddressToAddressMap storage map, address key, address value ) internal returns (bool) { return _set( map._inner, bytes32(uint256(uint160(key))), bytes32(uint256(uint160(value))) ); } function set( UintToAddressMap storage map, uint256 key, address value ) internal returns (bool) { return _set(map._inner, bytes32(key), bytes32(uint256(uint160(value)))); } function remove( AddressToAddressMap storage map, address key ) internal returns (bool) { return _remove(map._inner, bytes32(uint256(uint160(key)))); } function remove( UintToAddressMap storage map, uint256 key ) internal returns (bool) { return _remove(map._inner, bytes32(key)); } function toArray( AddressToAddressMap storage map ) internal view returns (address[] memory keysOut, address[] memory valuesOut) { uint256 len = map._inner._entries.length; keysOut = new address[](len); valuesOut = new address[](len); unchecked { for (uint256 i; i < len; ++i) { keysOut[i] = address( uint160(uint256(map._inner._entries[i]._key)) ); valuesOut[i] = address( uint160(uint256(map._inner._entries[i]._value)) ); } } } function toArray( UintToAddressMap storage map ) internal view returns (uint256[] memory keysOut, address[] memory valuesOut) { uint256 len = map._inner._entries.length; keysOut = new uint256[](len); valuesOut = new address[](len); unchecked { for (uint256 i; i < len; ++i) { keysOut[i] = uint256(map._inner._entries[i]._key); valuesOut[i] = address( uint160(uint256(map._inner._entries[i]._value)) ); } } } function keys( AddressToAddressMap storage map ) internal view returns (address[] memory keysOut) { uint256 len = map._inner._entries.length; keysOut = new address[](len); unchecked { for (uint256 i; i < len; ++i) { keysOut[i] = address( uint160(uint256(map._inner._entries[i]._key)) ); } } } function keys( UintToAddressMap storage map ) internal view returns (uint256[] memory keysOut) { uint256 len = map._inner._entries.length; keysOut = new uint256[](len); unchecked { for (uint256 i; i < len; ++i) { keysOut[i] = uint256(map._inner._entries[i]._key); } } } function values( AddressToAddressMap storage map ) internal view returns (address[] memory valuesOut) { uint256 len = map._inner._entries.length; valuesOut = new address[](len); unchecked { for (uint256 i; i < len; ++i) { valuesOut[i] = address( uint160(uint256(map._inner._entries[i]._value)) ); } } } function values( UintToAddressMap storage map ) internal view returns (address[] memory valuesOut) { uint256 len = map._inner._entries.length; valuesOut = new address[](len); unchecked { for (uint256 i; i < len; ++i) { valuesOut[i] = address( uint160(uint256(map._inner._entries[i]._value)) ); } } } function _at( Map storage map, uint256 index ) private view returns (bytes32, bytes32) { if (index >= map._entries.length) revert EnumerableMap__IndexOutOfBounds(); MapEntry storage entry = map._entries[index]; return (entry._key, entry._value); } function _contains( Map storage map, bytes32 key ) private view returns (bool) { return map._indexes[key] != 0; } function _length(Map storage map) private view returns (uint256) { return map._entries.length; } function _get(Map storage map, bytes32 key) private view returns (bytes32) { uint256 keyIndex = map._indexes[key]; if (keyIndex == 0) revert EnumerableMap__NonExistentKey(); unchecked { return map._entries[keyIndex - 1]._value; } } function _set( Map storage map, bytes32 key, bytes32 value ) private returns (bool) { uint256 keyIndex = map._indexes[key]; if (keyIndex == 0) { map._entries.push(MapEntry({ _key: key, _value: value })); map._indexes[key] = map._entries.length; return true; } else { unchecked { map._entries[keyIndex - 1]._value = value; } return false; } } function _remove(Map storage map, bytes32 key) private returns (bool) { uint256 keyIndex = map._indexes[key]; if (keyIndex != 0) { unchecked { MapEntry storage last = map._entries[map._entries.length - 1]; // move last entry to now-vacant index map._entries[keyIndex - 1] = last; map._indexes[last._key] = keyIndex; } // clear last index map._entries.pop(); delete map._indexes[key]; return true; } else { return false; } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.8; /** * @title Set implementation with enumeration functions * @dev derived from https://github.com/OpenZeppelin/openzeppelin-contracts (MIT license) */ library EnumerableSet { error EnumerableSet__IndexOutOfBounds(); struct Set { bytes32[] _values; // 1-indexed to allow 0 to signify nonexistence mapping(bytes32 => uint256) _indexes; } struct Bytes32Set { Set _inner; } struct AddressSet { Set _inner; } struct UintSet { Set _inner; } function at( Bytes32Set storage set, uint256 index ) internal view returns (bytes32) { return _at(set._inner, index); } function at( AddressSet storage set, uint256 index ) internal view returns (address) { return address(uint160(uint256(_at(set._inner, index)))); } function at( UintSet storage set, uint256 index ) internal view returns (uint256) { return uint256(_at(set._inner, index)); } function contains( Bytes32Set storage set, bytes32 value ) internal view returns (bool) { return _contains(set._inner, value); } function contains( AddressSet storage set, address value ) internal view returns (bool) { return _contains(set._inner, bytes32(uint256(uint160(value)))); } function contains( UintSet storage set, uint256 value ) internal view returns (bool) { return _contains(set._inner, bytes32(value)); } function indexOf( Bytes32Set storage set, bytes32 value ) internal view returns (uint256) { return _indexOf(set._inner, value); } function indexOf( AddressSet storage set, address value ) internal view returns (uint256) { return _indexOf(set._inner, bytes32(uint256(uint160(value)))); } function indexOf( UintSet storage set, uint256 value ) internal view returns (uint256) { return _indexOf(set._inner, bytes32(value)); } function length(Bytes32Set storage set) internal view returns (uint256) { return _length(set._inner); } function length(AddressSet storage set) internal view returns (uint256) { return _length(set._inner); } function length(UintSet storage set) internal view returns (uint256) { return _length(set._inner); } function add( Bytes32Set storage set, bytes32 value ) internal returns (bool) { return _add(set._inner, value); } function add( AddressSet storage set, address value ) internal returns (bool) { return _add(set._inner, bytes32(uint256(uint160(value)))); } function add(UintSet storage set, uint256 value) internal returns (bool) { return _add(set._inner, bytes32(value)); } function remove( Bytes32Set storage set, bytes32 value ) internal returns (bool) { return _remove(set._inner, value); } function remove( AddressSet storage set, address value ) internal returns (bool) { return _remove(set._inner, bytes32(uint256(uint160(value)))); } function remove( UintSet storage set, uint256 value ) internal returns (bool) { return _remove(set._inner, bytes32(value)); } function toArray( Bytes32Set storage set ) internal view returns (bytes32[] memory) { return set._inner._values; } function toArray( AddressSet storage set ) internal view returns (address[] memory) { bytes32[] storage values = set._inner._values; address[] storage array; assembly { array.slot := values.slot } return array; } function toArray( UintSet storage set ) internal view returns (uint256[] memory) { bytes32[] storage values = set._inner._values; uint256[] storage array; assembly { array.slot := values.slot } return array; } function _at( Set storage set, uint256 index ) private view returns (bytes32) { if (index >= set._values.length) revert EnumerableSet__IndexOutOfBounds(); return set._values[index]; } function _contains( Set storage set, bytes32 value ) private view returns (bool) { return set._indexes[value] != 0; } function _indexOf( Set storage set, bytes32 value ) private view returns (uint256) { unchecked { return set._indexes[value] - 1; } } function _length(Set storage set) private view returns (uint256) { return set._values.length; } function _add( Set storage set, bytes32 value ) private returns (bool status) { if (!_contains(set, value)) { set._values.push(value); set._indexes[value] = set._values.length; status = true; } } function _remove( Set storage set, bytes32 value ) private returns (bool status) { uint256 valueIndex = set._indexes[value]; if (valueIndex != 0) { unchecked { bytes32 last = set._values[set._values.length - 1]; // move last value to now-vacant index set._values[valueIndex - 1] = last; set._indexes[last] = valueIndex; } // clear last index set._values.pop(); delete set._indexes[value]; status = true; } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.8; /** * @title Partial ERC721 interface needed by internal functions */ interface IERC721Internal { event Transfer( address indexed from, address indexed to, uint256 indexed tokenId ); event Approval( address indexed owner, address indexed operator, uint256 indexed tokenId ); event ApprovalForAll( address indexed owner, address indexed operator, bool approved ); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.8; interface IERC721Receiver { function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.8; import { IERC721Internal } from '../../../interfaces/IERC721Internal.sol'; /** * @title ERC721 base interface */ interface IERC721BaseInternal is IERC721Internal { error ERC721Base__NotOwnerOrApproved(); error ERC721Base__SelfApproval(); error ERC721Base__BalanceQueryZeroAddress(); error ERC721Base__ERC721ReceiverNotImplemented(); error ERC721Base__InvalidOwner(); error ERC721Base__MintToZeroAddress(); error ERC721Base__NonExistentToken(); error ERC721Base__NotTokenOwner(); error ERC721Base__TokenAlreadyMinted(); error ERC721Base__TransferToZeroAddress(); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.8; import { UintUtils } from './UintUtils.sol'; library AddressUtils { using UintUtils for uint256; error AddressUtils__InsufficientBalance(); error AddressUtils__NotContract(); error AddressUtils__SendValueFailed(); function toString(address account) internal pure returns (string memory) { return uint256(uint160(account)).toHexString(20); } function isContract(address account) internal view returns (bool) { uint256 size; assembly { size := extcodesize(account) } return size > 0; } function sendValue(address payable account, uint256 amount) internal { (bool success, ) = account.call{ value: amount }(''); if (!success) revert AddressUtils__SendValueFailed(); } function functionCall( address target, bytes memory data ) internal returns (bytes memory) { return functionCall(target, data, 'AddressUtils: failed low-level call'); } function functionCall( address target, bytes memory data, string memory error ) internal returns (bytes memory) { return _functionCallWithValue(target, data, 0, error); } function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue( target, data, value, 'AddressUtils: failed low-level call with value' ); } function functionCallWithValue( address target, bytes memory data, uint256 value, string memory error ) internal returns (bytes memory) { if (value > address(this).balance) revert AddressUtils__InsufficientBalance(); return _functionCallWithValue(target, data, value, error); } /** * @notice execute arbitrary external call with limited gas usage and amount of copied return data * @dev derived from https://github.com/nomad-xyz/ExcessivelySafeCall (MIT License) * @param target recipient of call * @param gasAmount gas allowance for call * @param value native token value to include in call * @param maxCopy maximum number of bytes to copy from return data * @param data encoded call data * @return success whether call is successful * @return returnData copied return data */ function excessivelySafeCall( address target, uint256 gasAmount, uint256 value, uint16 maxCopy, bytes memory data ) internal returns (bool success, bytes memory returnData) { returnData = new bytes(maxCopy); assembly { // execute external call via assembly to avoid automatic copying of return data success := call( gasAmount, target, value, add(data, 0x20), mload(data), 0, 0 ) // determine whether to limit amount of data to copy let toCopy := returndatasize() if gt(toCopy, maxCopy) { toCopy := maxCopy } // store the length of the copied bytes mstore(returnData, toCopy) // copy the bytes from returndata[0:toCopy] returndatacopy(add(returnData, 0x20), 0, toCopy) } } function _functionCallWithValue( address target, bytes memory data, uint256 value, string memory error ) private returns (bytes memory) { if (!isContract(target)) revert AddressUtils__NotContract(); (bool success, bytes memory returnData) = target.call{ value: value }( data ); if (success) { return returnData; } else if (returnData.length > 0) { assembly { let returnData_size := mload(returnData) revert(add(32, returnData), returnData_size) } } else { revert(error); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.8; /** * @title utility functions for uint256 operations * @dev derived from https://github.com/OpenZeppelin/openzeppelin-contracts/ (MIT license) */ library UintUtils { error UintUtils__InsufficientHexLength(); bytes16 private constant HEX_SYMBOLS = '0123456789abcdef'; function add(uint256 a, int256 b) internal pure returns (uint256) { return b < 0 ? sub(a, -b) : a + uint256(b); } function sub(uint256 a, int256 b) internal pure returns (uint256) { return b < 0 ? add(a, -b) : a - uint256(b); } function toString(uint256 value) internal pure returns (string memory) { if (value == 0) { return '0'; } uint256 temp = value; uint256 digits; while (temp != 0) { digits++; temp /= 10; } bytes memory buffer = new bytes(digits); while (value != 0) { digits -= 1; buffer[digits] = bytes1(uint8(48 + uint256(value % 10))); value /= 10; } return string(buffer); } function toHexString(uint256 value) internal pure returns (string memory) { if (value == 0) { return '0x00'; } uint256 length = 0; for (uint256 temp = value; temp != 0; temp >>= 8) { unchecked { length++; } } return toHexString(value, length); } function toHexString( uint256 value, uint256 length ) internal pure returns (string memory) { bytes memory buffer = new bytes(2 * length + 2); buffer[0] = '0'; buffer[1] = 'x'; unchecked { for (uint256 i = 2 * length + 1; i > 1; --i) { buffer[i] = HEX_SYMBOLS[value & 0xf]; value >>= 4; } } if (value != 0) revert UintUtils__InsufficientHexLength(); return string(buffer); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; /** * @title ERC-721 Non-Fungible Token Standard, optional child extension * @dev See https://eips.ethereum.org/EIPS/eip-721 * * A child token does not store it's own token balances and does not support * minting, transfer, approval. All view methods are passed along to the * parent contract. */ interface IChild { error ERC721Child__InvalidCaller(); error ERC721Child__NonExistentToken(); error ERC721Child__ApprovalNotSupported(); error ERC721Child__TransferNotSupported(); /** * @dev Returns the parent collection. */ function parent() external view returns (address); /** * @dev Initialize token ownership by calling it from the parent contract. * * Only call this once in case the child contract after the parent contract. * Emits a {Transfer} event from ZeroAddress to current owner per token. */ function init(uint256 tokenIdStart, uint256 tokenIdEnd) external; /** * @dev Update token ownership from by calling it from the parent contract. * * Emits a {Transfer} event. */ function update( address from, address to, uint256 tokenId ) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; import {IERC721MarketplaceInternal} from "./IERC721MarketplaceInternal.sol"; import {ScapesMarketplaceStorage} from "./ScapesMarketplaceStorage.sol"; import {ERC721BaseInternal} from "../solidstate/ERC721BaseInternal.sol"; /// @title ERC721MarketplaceInternal /// @author akuti.eth, jalil.eth | scapes.eth /// @dev The internal logic of the ERC721Marketplace. abstract contract ERC721MarketplaceInternal is IERC721MarketplaceInternal, ERC721BaseInternal { /// @dev Make a new offer. Emits an {OfferCreated} event. function _makeOffer( uint256 tokenId, uint80 price, address to ) internal { if (price == 0) revert ERC721Marketplace__InvalidPrice(); if (!_isApprovedOrOwner(msg.sender, tokenId)) revert ERC721Base__NotOwnerOrApproved(); ScapesMarketplaceStorage.Offer storage offer = ScapesMarketplaceStorage .layout() .offers[tokenId]; offer.price = price; offer.specificBuyer = to; emit OfferCreated(tokenId, price, to); } /// @dev Revoke an active offer. Emits an {OfferWithdrawn} event. function _cancelOffer(uint256 tokenId) internal { ScapesMarketplaceStorage.Offer storage offer = ScapesMarketplaceStorage .layout() .offers[tokenId]; if (offer.price == 0) revert ERC721Marketplace__NonExistentOffer(); offer.price = 0; offer.specificBuyer = address(0); emit OfferWithdrawn(tokenId); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; import {IERC721BaseInternal} from "@solidstate/contracts/token/ERC721/base/IERC721BaseInternal.sol"; interface IERC721MarketplaceInternal is IERC721BaseInternal { error ERC721Marketplace__NonExistentOffer(); error ERC721Marketplace__InvalidArguments(); error ERC721Marketplace__PaymentFailed(); error ERC721Marketplace__InvalidValue(); error ERC721Marketplace__InvalidPrice(); event OfferCreated( uint256 indexed tokenId, uint256 indexed value, address indexed to ); event OfferWithdrawn(uint256 indexed tokenId); event Sale( uint256 indexed tokenId, address indexed from, address indexed to, uint256 value ); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; library ScapesMarketplaceStorage { bytes32 internal constant STORAGE_SLOT = keccak256("scapes.storage.Marketplace"); struct Offer { uint80 price; uint80 specificBuyerPrice; uint80 lastPrice; address specificBuyer; } struct Layout { address beneficiary; uint256 bps; mapping(uint256 => Offer) offers; } function layout() internal pure returns (Layout storage d) { bytes32 slot = STORAGE_SLOT; assembly { d.slot := slot } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.16; library ScapesERC721MetadataStorage { bytes32 internal constant STORAGE_SLOT = keccak256("scapes.storage.ERC721Metadata"); struct Layout { string name; string symbol; string description; string externalBaseURI; address scapeBound; } function layout() internal pure returns (Layout storage d) { bytes32 slot = STORAGE_SLOT; assembly { d.slot := slot } } }
// SPDX-License-Identifier: MIT // Based on solidstate @solidstate/contracts/token/ERC721/base/ERC721BaseInternal.sol // Changes made: // - store a holder balance instead of the individual tokens, this removes the // option to easily upgrade to ERC721Enumerable but lowers gas cost by ~45k per mint // - update balance in mint, transfer and burn functions separate balance for normal // tokens and merged tokens // - update balanceOf to return the combined balance // - add _afterTokenTransfer hook pragma solidity ^0.8.8; import {IERC721Receiver} from "@solidstate/contracts/interfaces/IERC721Receiver.sol"; import {EnumerableMap} from "@solidstate/contracts/data/EnumerableMap.sol"; import {EnumerableSet} from "@solidstate/contracts/data/EnumerableSet.sol"; import {AddressUtils} from "@solidstate/contracts/utils/AddressUtils.sol"; import {IERC721BaseInternal} from "@solidstate/contracts/token/ERC721/base/IERC721BaseInternal.sol"; import {ERC721BaseStorage} from "./ERC721BaseStorage.sol"; /** * @title Base ERC721 internal functions */ abstract contract ERC721BaseInternal is IERC721BaseInternal { using ERC721BaseStorage for ERC721BaseStorage.Layout; using AddressUtils for address; using EnumerableMap for EnumerableMap.UintToAddressMap; using EnumerableSet for EnumerableSet.UintSet; uint256 internal constant MERGES_TRESHOLD = 130_000; function _balanceOf(address account) internal view virtual returns (uint256) { if (account == address(0)) revert ERC721Base__BalanceQueryZeroAddress(); return ERC721BaseStorage.layout().holderBalances[account]; } function _balanceOfMerges(address account) internal view virtual returns (uint256) { if (account == address(0)) revert ERC721Base__BalanceQueryZeroAddress(); return ERC721BaseStorage.layout().holderBalancesMerges[account]; } function _ownerOf(uint256 tokenId) internal view virtual returns (address) { address owner = ERC721BaseStorage.layout().tokenOwners.get(tokenId); if (owner == address(0)) revert ERC721Base__InvalidOwner(); return owner; } function _getApproved(uint256 tokenId) internal view virtual returns (address) { ERC721BaseStorage.Layout storage l = ERC721BaseStorage.layout(); if (!l.exists(tokenId)) revert ERC721Base__NonExistentToken(); return l.tokenApprovals[tokenId]; } function _isApprovedForAll(address account, address operator) internal view virtual returns (bool) { return ERC721BaseStorage.layout().operatorApprovals[account][operator]; } function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) { if (!ERC721BaseStorage.layout().exists(tokenId)) revert ERC721Base__NonExistentToken(); address owner = _ownerOf(tokenId); return (spender == owner || _getApproved(tokenId) == spender || _isApprovedForAll(owner, spender)); } function _mint(address to, uint256 tokenId) internal virtual { if (to == address(0)) revert ERC721Base__MintToZeroAddress(); ERC721BaseStorage.Layout storage l = ERC721BaseStorage.layout(); if (l.exists(tokenId)) revert ERC721Base__TokenAlreadyMinted(); _beforeTokenTransfer(address(0), to, tokenId); unchecked { if (tokenId > MERGES_TRESHOLD) l.holderBalancesMerges[to] += 1; else l.holderBalances[to] += 1; } l.tokenOwners.set(tokenId, to); emit Transfer(address(0), to, tokenId); _afterTokenTransfer(address(0), to, tokenId); } function _safeMint(address to, uint256 tokenId) internal virtual { _safeMint(to, tokenId, ""); } function _safeMint( address to, uint256 tokenId, bytes memory data ) internal virtual { _mint(to, tokenId); if (!_checkOnERC721Received(address(0), to, tokenId, data)) revert ERC721Base__ERC721ReceiverNotImplemented(); } function _burn(uint256 tokenId) internal virtual { address owner = _ownerOf(tokenId); _beforeTokenTransfer(owner, address(0), tokenId); _approve(address(0), tokenId); ERC721BaseStorage.Layout storage l = ERC721BaseStorage.layout(); unchecked { if (tokenId > MERGES_TRESHOLD) l.holderBalancesMerges[owner] -= 1; else l.holderBalances[owner] -= 1; } l.tokenOwners.remove(tokenId); emit Transfer(owner, address(0), tokenId); _afterTokenTransfer(owner, address(0), tokenId); } function _transfer( address from, address to, uint256 tokenId ) internal virtual { if (_ownerOf(tokenId) != from) revert ERC721Base__NotTokenOwner(); if (to == address(0)) revert ERC721Base__TransferToZeroAddress(); _beforeTokenTransfer(from, to, tokenId); _approve(address(0), tokenId); ERC721BaseStorage.Layout storage l = ERC721BaseStorage.layout(); unchecked { if (tokenId > MERGES_TRESHOLD) { l.holderBalancesMerges[from] -= 1; l.holderBalancesMerges[to] += 1; } else { l.holderBalances[from] -= 1; l.holderBalances[to] += 1; } } l.tokenOwners.set(tokenId, to); emit Transfer(from, to, tokenId); _afterTokenTransfer(from, to, tokenId); } function _safeTransfer( address from, address to, uint256 tokenId, bytes memory data ) internal virtual { _transfer(from, to, tokenId); if (!_checkOnERC721Received(from, to, tokenId, data)) revert ERC721Base__ERC721ReceiverNotImplemented(); } function _approve(address operator, uint256 tokenId) internal virtual { ERC721BaseStorage.layout().tokenApprovals[tokenId] = operator; emit Approval(_ownerOf(tokenId), operator, tokenId); } function _checkOnERC721Received( address from, address to, uint256 tokenId, bytes memory data ) internal virtual returns (bool) { if (!to.isContract()) { return true; } bytes memory returnData = to.functionCall( abi.encodeWithSelector( IERC721Receiver(to).onERC721Received.selector, msg.sender, from, tokenId, data ), "ERC721: transfer to non ERC721Receiver implementer" ); bytes4 returnValue = abi.decode(returnData, (bytes4)); return returnValue == type(IERC721Receiver).interfaceId; } /** * @notice ERC721 hook, called before externally called approvals for processing of included message value * @param operator beneficiary of approval * @param tokenId id of transferred token * @param value message value */ function _handleApproveMessageValue( address operator, uint256 tokenId, uint256 value ) internal virtual {} /** * @notice ERC721 hook, called before externally called transfers for processing of included message value * @param from sender of token * @param to receiver of token * @param tokenId id of transferred token * @param value message value */ function _handleTransferMessageValue( address from, address to, uint256 tokenId, uint256 value ) internal virtual {} /** * @notice ERC721 hook, called before all transfers including mint and burn * @dev function should be overridden and new implementation must call super * @param from sender of token * @param to receiver of token * @param tokenId id of transferred token */ function _beforeTokenTransfer( address from, address to, uint256 tokenId ) internal virtual {} /** * @notice ERC721 hook, called after all transfers including mint and burn * @dev function should be overridden and new implementation must call super * @param from sender of token * @param to receiver of token * @param tokenId id of transferred token */ function _afterTokenTransfer( address from, address to, uint256 tokenId ) internal virtual {} }
// SPDX-License-Identifier: MIT // Based on solidstate @solidstate/contracts/token/ERC721/base/ERC721BaseStorage.sol // Changes made: // - replace holderTokens with holderBalances, this removes the // option to easily upgrade to ERC721Enumerable but lowers gas cost by ~45k per mint // - add holderBalancesMerges to separetly track the balance of merged scape tokens pragma solidity ^0.8.8; import {EnumerableMap} from "@solidstate/contracts/data/EnumerableMap.sol"; library ERC721BaseStorage { using EnumerableMap for EnumerableMap.UintToAddressMap; bytes32 internal constant STORAGE_SLOT = keccak256("scapes.storage.ERC721Base"); struct Layout { EnumerableMap.UintToAddressMap tokenOwners; mapping(address => uint256) holderBalances; mapping(address => uint256) holderBalancesMerges; mapping(uint256 => address) tokenApprovals; mapping(address => mapping(address => bool)) operatorApprovals; } function layout() internal pure returns (Layout storage l) { bytes32 slot = STORAGE_SLOT; assembly { l.slot := slot } } function exists(Layout storage l, uint256 tokenId) internal view returns (bool) { return l.tokenOwners.contains(tokenId); } function totalSupply(Layout storage l) internal view returns (uint256) { return l.tokenOwners.length(); } function tokenByIndex(Layout storage l, uint256 index) internal view returns (uint256) { (uint256 tokenId, ) = l.tokenOwners.at(index); return tokenId; } }
{ "optimizer": { "enabled": true, "runs": 1000 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"name":"AddressUtils__NotContract","type":"error"},{"inputs":[],"name":"ERC721Base__BalanceQueryZeroAddress","type":"error"},{"inputs":[],"name":"ERC721Base__ERC721ReceiverNotImplemented","type":"error"},{"inputs":[],"name":"ERC721Base__InvalidOwner","type":"error"},{"inputs":[],"name":"ERC721Base__MintToZeroAddress","type":"error"},{"inputs":[],"name":"ERC721Base__NonExistentToken","type":"error"},{"inputs":[],"name":"ERC721Base__NotOwnerOrApproved","type":"error"},{"inputs":[],"name":"ERC721Base__NotTokenOwner","type":"error"},{"inputs":[],"name":"ERC721Base__SelfApproval","type":"error"},{"inputs":[],"name":"ERC721Base__TokenAlreadyMinted","type":"error"},{"inputs":[],"name":"ERC721Base__TransferToZeroAddress","type":"error"},{"inputs":[],"name":"ERC721Marketplace__InvalidArguments","type":"error"},{"inputs":[],"name":"ERC721Marketplace__InvalidPrice","type":"error"},{"inputs":[],"name":"ERC721Marketplace__InvalidValue","type":"error"},{"inputs":[],"name":"ERC721Marketplace__NonExistentOffer","type":"error"},{"inputs":[],"name":"ERC721Marketplace__PaymentFailed","type":"error"},{"inputs":[],"name":"EnumerableMap__NonExistentKey","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"value","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OfferCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"OfferWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Sale","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":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"batchBuy","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"batchCancelOffer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"uint80[]","name":"prices","type":"uint80[]"}],"name":"batchMakeOffer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"uint80[]","name":"prices","type":"uint80[]"},{"internalType":"address[]","name":"tos","type":"address[]"}],"name":"batchMakeOfferTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"buy","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"cancelOffer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getOffer","outputs":[{"components":[{"internalType":"uint80","name":"price","type":"uint80"},{"internalType":"uint80","name":"specificBuyerPrice","type":"uint80"},{"internalType":"uint80","name":"lastPrice","type":"uint80"},{"internalType":"address","name":"specificBuyer","type":"address"}],"internalType":"struct ScapesMarketplaceStorage.Offer","name":"offer","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint80","name":"price","type":"uint80"}],"name":"makeOffer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint80","name":"price","type":"uint80"},{"internalType":"address","name":"to","type":"address"}],"name":"makeOfferTo","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b506118f7806100206000396000f3fe6080604052600436106100965760003560e01c806383e0de4511610069578063b8c4c4e31161004e578063b8c4c4e31461019c578063d96a094a146101bc578063ef706adf146101cf57600080fd5b806383e0de4514610169578063b03bfd171461017c57600080fd5b80634579268a1461009b5780634d6f011f14610107578063574aec59146101295780635d35ac4d14610149575b600080fd5b3480156100a757600080fd5b506100bb6100b636600461147e565b6101ef565b60408051825169ffffffffffffffffffff90811682526020808501518216908301528383015116818301526060928301516001600160a01b031692810192909252519081900360800190f35b34801561011357600080fd5b506101276101223660046114b6565b6102dc565b005b34801561013557600080fd5b506101276101443660046114f9565b6102ec565b34801561015557600080fd5b50610127610164366004611581565b6102fc565b61012761017736600461161b565b6103b6565b34801561018857600080fd5b5061012761019736600461165d565b6104f1565b3480156101a857600080fd5b506101276101b736600461161b565b610577565b6101276101ca36600461147e565b6105b2565b3480156101db57600080fd5b506101276101ea36600461147e565b61067d565b60408051608080820183526000808352602080840182905283850182905260609384018290528582527fcc410442a83ee5ff86205e8b7585832614e9498a8404ee01ae13793dea594dba815284822085519384018652805469ffffffffffffffffffff8082168087526a01000000000000000000008304821694870194909452600160a01b90910416958401959095526001909401546001600160a01b031692820192909252917fcc410442a83ee5ff86205e8b7585832614e9498a8404ee01ae13793dea594db891036102d657604051630f11ed4560e21b815260040160405180910390fd5b50919050565b6102e8828260006106b0565b5050565b6102f78383836106b0565b505050565b848314158061030b5750848114155b156103295760405163792d3a7360e01b815260040160405180910390fd5b8460005b818110156103ac576103a488888381811061034a5761034a6116c9565b90506020020135878784818110610363576103636116c9565b905060200201602081019061037891906116df565b86868581811061038a5761038a6116c9565b905060200201602081019061039f91906116fa565b6106b0565b60010161032d565b5050505050505050565b7fcc410442a83ee5ff86205e8b7585832614e9498a8404ee01ae13793dea594db8600082815b818110156104c85760008460020160008888858181106103fe576103fe6116c9565b602090810292909201358352508181019290925260409081016000208151608081018352815469ffffffffffffffffffff8082168084526a01000000000000000000008304821696840196909652600160a01b9091041692810192909252600101546001600160a01b03166060820152915061047a908561172b565b93508334101561049d57604051633c976a4360e21b815260040160405180910390fd5b6104bf8787848181106104b2576104b26116c9565b90506020020135826107ca565b506001016103dc565b50813411156104ea57604051633c976a4360e21b815260040160405180910390fd5b5050505050565b8281146105115760405163792d3a7360e01b815260040160405180910390fd5b8260005b8181101561056f57610567868683818110610532576105326116c9565b9050602002013585858481811061054b5761054b6116c9565b905060200201602081019061056091906116df565b60006106b0565b600101610515565b505050505050565b8060005b818110156105ac576105a4848483818110610598576105986116c9565b9050602002013561067d565b60010161057b565b50505050565b60008181527fcc410442a83ee5ff86205e8b7585832614e9498a8404ee01ae13793dea594dba60209081526040918290208251608081018452815469ffffffffffffffffffff8082168084526a01000000000000000000008304821695840195909552600160a01b9091041693810193909352600101546001600160a01b03166060830152158015906106555750806000015169ffffffffffffffffffff163414155b1561067357604051633c976a4360e21b815260040160405180910390fd5b6102e882826107ca565b6106873382610ab2565b6106a457604051632f5de44f60e01b815260040160405180910390fd5b6106ad81610b9a565b50565b8169ffffffffffffffffffff166000036106f6576040517f22c25eae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107003384610ab2565b61071d57604051632f5de44f60e01b815260040160405180910390fd5b60008381527fcc410442a83ee5ff86205e8b7585832614e9498a8404ee01ae13793dea594dba6020526040808220805469ffffffffffffffffffff191669ffffffffffffffffffff8616908117825560018201805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03871690811790915592519193909187917f1be7385e5a960aabd206224f90e23bb92719f1749fa15a10c0e39302eec9ab5891a450505050565b8051604082015169ffffffffffffffffffff9182169160009116156107ff57826040015169ffffffffffffffffffff16610809565b67016345785d8a00005b90508160000361082c57604051630f11ed4560e21b815260040160405180910390fd5b60608301516001600160a01b031615801590610855575060608301516001600160a01b03163314155b1561087357604051630f11ed4560e21b815260040160405180910390fd5b825169ffffffffffffffffffff163410156108a157604051633c976a4360e21b815260040160405180910390fd5b825160008581527fcc410442a83ee5ff86205e8b7585832614e9498a8404ee01ae13793dea594dba6020526040902080547fffff00000000000000000000ffffffffffffffffffff0000000000000000000016600160a01b69ffffffffffffffffffff9093169290920269ffffffffffffffffffff191691909117905560608301517fcc410442a83ee5ff86205e8b7585832614e9498a8404ee01ae13793dea594db8906001600160a01b0316156109825760008581526002820160205260409020600101805473ffffffffffffffffffffffffffffffffffffffff191690555b600061098d86610c57565b855190915069ffffffffffffffffffff16831015610a3757600082600101546127106109b9919061173e565b6109c585612710611751565b6109cf9190611770565b905060008186106109fc576127108460010154876109ed9190611751565b6109f79190611770565b610a06565b610a06858761173e565b9050610a1b83610a16838961173e565b610cc6565b8354610a30906001600160a01b031682610cc6565b5050610a41565b610a418134610cc6565b610a5c81338860405180602001604052806000815250610d57565b336001600160a01b0316816001600160a01b0316877f88863d5e20f64464b554931394e2e4b6f09c10015147215bf26b3ba5070acebe87604051610aa291815260200190565b60405180910390a4505050505050565b6000610ade7f24192aa1e930860a59219c92c01fd96c8fde79f41992dc1c72ae9cf26bb3bff583610da4565b610afb5760405163c1b843ef60e01b815260040160405180910390fd5b6000610b0683610c57565b9050806001600160a01b0316846001600160a01b03161480610b415750836001600160a01b0316610b3684610db7565b6001600160a01b0316145b80610b9057506001600160a01b0380821660009081527f24192aa1e930860a59219c92c01fd96c8fde79f41992dc1c72ae9cf26bb3bffa602090815260408083209388168352929052205460ff165b9150505b92915050565b60008181527fcc410442a83ee5ff86205e8b7585832614e9498a8404ee01ae13793dea594dba602052604081208054909169ffffffffffffffffffff9091169003610bf857604051630f11ed4560e21b815260040160405180910390fd5b805469ffffffffffffffffffff1916815560018101805473ffffffffffffffffffffffffffffffffffffffff1916905560405182907facbc44b7f46dc350c99fc0d9e5f61ed5c588cb4cdc6b69ea0deb0c5b28e5efc490600090a25050565b600080610c847f24192aa1e930860a59219c92c01fd96c8fde79f41992dc1c72ae9cf26bb3bff584610e1e565b90506001600160a01b038116610b94576040517f7e1a7d8b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000826001600160a01b0316610bb883604051600060405180830381858888f193505050503d8060008114610d17576040519150601f19603f3d011682016040523d82523d6000602084013e610d1c565b606091505b50509050806102f7576040517fe4415dce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610d62848484610e2a565b610d6e84848484610fb4565b6105ac576040517f9ff10cdd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610db083836110e1565b9392505050565b60007f24192aa1e930860a59219c92c01fd96c8fde79f41992dc1c72ae9cf26bb3bff5610de48184610da4565b610e015760405163c1b843ef60e01b815260040160405180910390fd5b60009283526004016020525060409020546001600160a01b031690565b6000610db083836110f9565b826001600160a01b0316610e3d82610c57565b6001600160a01b031614610e7d576040517f0f2db4ad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038216610ebd576040517f40311a0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ec8600082611176565b7f24192aa1e930860a59219c92c01fd96c8fde79f41992dc1c72ae9cf26bb3bff56201fbd0821115610f2a576001600160a01b038085166000908152600383016020526040808220805460001901905591851681522080546001019055610f5c565b6001600160a01b0380851660009081526002830160205260408082208054600019019055918516815220805460010190555b610f67818385611210565b5081836001600160a01b0316856001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a46105ac848484611226565b60006001600160a01b0384163b610fcd575060016110d9565b600061107863150b7a0260e01b33888787604051602401610ff194939291906117e2565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051806060016040528060328152602001611890603291396001600160a01b03881691906112d7565b9050600081806020019051810190611090919061181e565b7fffffffff00000000000000000000000000000000000000000000000000000000167f150b7a020000000000000000000000000000000000000000000000000000000014925050505b949350505050565b60008181526001830160205260408120541515610db0565b6000818152600183016020526040812054808203611143576040517ff551fb1400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83600001600182038154811061115b5761115b6116c9565b90600052602060002090600202016001015491505092915050565b60008181527f24192aa1e930860a59219c92c01fd96c8fde79f41992dc1c72ae9cf26bb3bff960205260409020805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03841690811790915581906111d782610c57565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b60006110d984846001600160a01b0385166112e6565b7f4ca5b6536be965df5a6498d1883a57f2ca8946e5bd14e05eafa6e36d0ceffcd16004908101546040517f8ce516da0000000000000000000000000000000000000000000000000000000081526001600160a01b0386811693820193909352848316602482015260448101849052911690638ce516da90606401600060405180830381600087803b1580156112ba57600080fd5b505af11580156112ce573d6000803e3d6000fd5b50505050505050565b60606110d98484600085611385565b600082815260018401602052604081205480820361134d575050604080518082018252838152602080820184815286546001818101895560008981528481209551600290930290950191825591519082015586548684528188019092529290912055610db0565b82856000016001830381548110611366576113666116c9565b9060005260206000209060020201600101819055506000915050610db0565b6060843b6113bf576040517f89c35afc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080866001600160a01b031685876040516113db9190611860565b60006040518083038185875af1925050503d8060008114611418576040519150601f19603f3d011682016040523d82523d6000602084013e61141d565b606091505b509150915081156114315791506110d99050565b8051156114415780518082602001fd5b836040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611475919061187c565b60405180910390fd5b60006020828403121561149057600080fd5b5035919050565b803569ffffffffffffffffffff811681146114b157600080fd5b919050565b600080604083850312156114c957600080fd5b823591506114d960208401611497565b90509250929050565b80356001600160a01b03811681146114b157600080fd5b60008060006060848603121561150e57600080fd5b8335925061151e60208501611497565b915061152c604085016114e2565b90509250925092565b60008083601f84011261154757600080fd5b50813567ffffffffffffffff81111561155f57600080fd5b6020830191508360208260051b850101111561157a57600080fd5b9250929050565b6000806000806000806060878903121561159a57600080fd5b863567ffffffffffffffff808211156115b257600080fd5b6115be8a838b01611535565b909850965060208901359150808211156115d757600080fd5b6115e38a838b01611535565b909650945060408901359150808211156115fc57600080fd5b5061160989828a01611535565b979a9699509497509295939492505050565b6000806020838503121561162e57600080fd5b823567ffffffffffffffff81111561164557600080fd5b61165185828601611535565b90969095509350505050565b6000806000806040858703121561167357600080fd5b843567ffffffffffffffff8082111561168b57600080fd5b61169788838901611535565b909650945060208701359150808211156116b057600080fd5b506116bd87828801611535565b95989497509550505050565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156116f157600080fd5b610db082611497565b60006020828403121561170c57600080fd5b610db0826114e2565b634e487b7160e01b600052601160045260246000fd5b80820180821115610b9457610b94611715565b81810381811115610b9457610b94611715565b600081600019048311821515161561176b5761176b611715565b500290565b60008261178d57634e487b7160e01b600052601260045260246000fd5b500490565b60005b838110156117ad578181015183820152602001611795565b50506000910152565b600081518084526117ce816020860160208601611792565b601f01601f19169290920160200192915050565b60006001600160a01b0380871683528086166020840152508360408301526080606083015261181460808301846117b6565b9695505050505050565b60006020828403121561183057600080fd5b81517fffffffff0000000000000000000000000000000000000000000000000000000081168114610db057600080fd5b60008251611872818460208701611792565b9190910192915050565b602081526000610db060208301846117b656fe4552433732313a207472616e7366657220746f206e6f6e20455243373231526563656976657220696d706c656d656e746572a2646970667358221220f7420dd88d408d7cea7b261db4f2e96bc1649c669d63951732df77385ff346bc64736f6c63430008100033
Deployed Bytecode
0x6080604052600436106100965760003560e01c806383e0de4511610069578063b8c4c4e31161004e578063b8c4c4e31461019c578063d96a094a146101bc578063ef706adf146101cf57600080fd5b806383e0de4514610169578063b03bfd171461017c57600080fd5b80634579268a1461009b5780634d6f011f14610107578063574aec59146101295780635d35ac4d14610149575b600080fd5b3480156100a757600080fd5b506100bb6100b636600461147e565b6101ef565b60408051825169ffffffffffffffffffff90811682526020808501518216908301528383015116818301526060928301516001600160a01b031692810192909252519081900360800190f35b34801561011357600080fd5b506101276101223660046114b6565b6102dc565b005b34801561013557600080fd5b506101276101443660046114f9565b6102ec565b34801561015557600080fd5b50610127610164366004611581565b6102fc565b61012761017736600461161b565b6103b6565b34801561018857600080fd5b5061012761019736600461165d565b6104f1565b3480156101a857600080fd5b506101276101b736600461161b565b610577565b6101276101ca36600461147e565b6105b2565b3480156101db57600080fd5b506101276101ea36600461147e565b61067d565b60408051608080820183526000808352602080840182905283850182905260609384018290528582527fcc410442a83ee5ff86205e8b7585832614e9498a8404ee01ae13793dea594dba815284822085519384018652805469ffffffffffffffffffff8082168087526a01000000000000000000008304821694870194909452600160a01b90910416958401959095526001909401546001600160a01b031692820192909252917fcc410442a83ee5ff86205e8b7585832614e9498a8404ee01ae13793dea594db891036102d657604051630f11ed4560e21b815260040160405180910390fd5b50919050565b6102e8828260006106b0565b5050565b6102f78383836106b0565b505050565b848314158061030b5750848114155b156103295760405163792d3a7360e01b815260040160405180910390fd5b8460005b818110156103ac576103a488888381811061034a5761034a6116c9565b90506020020135878784818110610363576103636116c9565b905060200201602081019061037891906116df565b86868581811061038a5761038a6116c9565b905060200201602081019061039f91906116fa565b6106b0565b60010161032d565b5050505050505050565b7fcc410442a83ee5ff86205e8b7585832614e9498a8404ee01ae13793dea594db8600082815b818110156104c85760008460020160008888858181106103fe576103fe6116c9565b602090810292909201358352508181019290925260409081016000208151608081018352815469ffffffffffffffffffff8082168084526a01000000000000000000008304821696840196909652600160a01b9091041692810192909252600101546001600160a01b03166060820152915061047a908561172b565b93508334101561049d57604051633c976a4360e21b815260040160405180910390fd5b6104bf8787848181106104b2576104b26116c9565b90506020020135826107ca565b506001016103dc565b50813411156104ea57604051633c976a4360e21b815260040160405180910390fd5b5050505050565b8281146105115760405163792d3a7360e01b815260040160405180910390fd5b8260005b8181101561056f57610567868683818110610532576105326116c9565b9050602002013585858481811061054b5761054b6116c9565b905060200201602081019061056091906116df565b60006106b0565b600101610515565b505050505050565b8060005b818110156105ac576105a4848483818110610598576105986116c9565b9050602002013561067d565b60010161057b565b50505050565b60008181527fcc410442a83ee5ff86205e8b7585832614e9498a8404ee01ae13793dea594dba60209081526040918290208251608081018452815469ffffffffffffffffffff8082168084526a01000000000000000000008304821695840195909552600160a01b9091041693810193909352600101546001600160a01b03166060830152158015906106555750806000015169ffffffffffffffffffff163414155b1561067357604051633c976a4360e21b815260040160405180910390fd5b6102e882826107ca565b6106873382610ab2565b6106a457604051632f5de44f60e01b815260040160405180910390fd5b6106ad81610b9a565b50565b8169ffffffffffffffffffff166000036106f6576040517f22c25eae00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6107003384610ab2565b61071d57604051632f5de44f60e01b815260040160405180910390fd5b60008381527fcc410442a83ee5ff86205e8b7585832614e9498a8404ee01ae13793dea594dba6020526040808220805469ffffffffffffffffffff191669ffffffffffffffffffff8616908117825560018201805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03871690811790915592519193909187917f1be7385e5a960aabd206224f90e23bb92719f1749fa15a10c0e39302eec9ab5891a450505050565b8051604082015169ffffffffffffffffffff9182169160009116156107ff57826040015169ffffffffffffffffffff16610809565b67016345785d8a00005b90508160000361082c57604051630f11ed4560e21b815260040160405180910390fd5b60608301516001600160a01b031615801590610855575060608301516001600160a01b03163314155b1561087357604051630f11ed4560e21b815260040160405180910390fd5b825169ffffffffffffffffffff163410156108a157604051633c976a4360e21b815260040160405180910390fd5b825160008581527fcc410442a83ee5ff86205e8b7585832614e9498a8404ee01ae13793dea594dba6020526040902080547fffff00000000000000000000ffffffffffffffffffff0000000000000000000016600160a01b69ffffffffffffffffffff9093169290920269ffffffffffffffffffff191691909117905560608301517fcc410442a83ee5ff86205e8b7585832614e9498a8404ee01ae13793dea594db8906001600160a01b0316156109825760008581526002820160205260409020600101805473ffffffffffffffffffffffffffffffffffffffff191690555b600061098d86610c57565b855190915069ffffffffffffffffffff16831015610a3757600082600101546127106109b9919061173e565b6109c585612710611751565b6109cf9190611770565b905060008186106109fc576127108460010154876109ed9190611751565b6109f79190611770565b610a06565b610a06858761173e565b9050610a1b83610a16838961173e565b610cc6565b8354610a30906001600160a01b031682610cc6565b5050610a41565b610a418134610cc6565b610a5c81338860405180602001604052806000815250610d57565b336001600160a01b0316816001600160a01b0316877f88863d5e20f64464b554931394e2e4b6f09c10015147215bf26b3ba5070acebe87604051610aa291815260200190565b60405180910390a4505050505050565b6000610ade7f24192aa1e930860a59219c92c01fd96c8fde79f41992dc1c72ae9cf26bb3bff583610da4565b610afb5760405163c1b843ef60e01b815260040160405180910390fd5b6000610b0683610c57565b9050806001600160a01b0316846001600160a01b03161480610b415750836001600160a01b0316610b3684610db7565b6001600160a01b0316145b80610b9057506001600160a01b0380821660009081527f24192aa1e930860a59219c92c01fd96c8fde79f41992dc1c72ae9cf26bb3bffa602090815260408083209388168352929052205460ff165b9150505b92915050565b60008181527fcc410442a83ee5ff86205e8b7585832614e9498a8404ee01ae13793dea594dba602052604081208054909169ffffffffffffffffffff9091169003610bf857604051630f11ed4560e21b815260040160405180910390fd5b805469ffffffffffffffffffff1916815560018101805473ffffffffffffffffffffffffffffffffffffffff1916905560405182907facbc44b7f46dc350c99fc0d9e5f61ed5c588cb4cdc6b69ea0deb0c5b28e5efc490600090a25050565b600080610c847f24192aa1e930860a59219c92c01fd96c8fde79f41992dc1c72ae9cf26bb3bff584610e1e565b90506001600160a01b038116610b94576040517f7e1a7d8b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000826001600160a01b0316610bb883604051600060405180830381858888f193505050503d8060008114610d17576040519150601f19603f3d011682016040523d82523d6000602084013e610d1c565b606091505b50509050806102f7576040517fe4415dce00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610d62848484610e2a565b610d6e84848484610fb4565b6105ac576040517f9ff10cdd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610db083836110e1565b9392505050565b60007f24192aa1e930860a59219c92c01fd96c8fde79f41992dc1c72ae9cf26bb3bff5610de48184610da4565b610e015760405163c1b843ef60e01b815260040160405180910390fd5b60009283526004016020525060409020546001600160a01b031690565b6000610db083836110f9565b826001600160a01b0316610e3d82610c57565b6001600160a01b031614610e7d576040517f0f2db4ad00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600160a01b038216610ebd576040517f40311a0900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ec8600082611176565b7f24192aa1e930860a59219c92c01fd96c8fde79f41992dc1c72ae9cf26bb3bff56201fbd0821115610f2a576001600160a01b038085166000908152600383016020526040808220805460001901905591851681522080546001019055610f5c565b6001600160a01b0380851660009081526002830160205260408082208054600019019055918516815220805460010190555b610f67818385611210565b5081836001600160a01b0316856001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60405160405180910390a46105ac848484611226565b60006001600160a01b0384163b610fcd575060016110d9565b600061107863150b7a0260e01b33888787604051602401610ff194939291906117e2565b604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050604051806060016040528060328152602001611890603291396001600160a01b03881691906112d7565b9050600081806020019051810190611090919061181e565b7fffffffff00000000000000000000000000000000000000000000000000000000167f150b7a020000000000000000000000000000000000000000000000000000000014925050505b949350505050565b60008181526001830160205260408120541515610db0565b6000818152600183016020526040812054808203611143576040517ff551fb1400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b83600001600182038154811061115b5761115b6116c9565b90600052602060002090600202016001015491505092915050565b60008181527f24192aa1e930860a59219c92c01fd96c8fde79f41992dc1c72ae9cf26bb3bff960205260409020805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b03841690811790915581906111d782610c57565b6001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45050565b60006110d984846001600160a01b0385166112e6565b7f4ca5b6536be965df5a6498d1883a57f2ca8946e5bd14e05eafa6e36d0ceffcd16004908101546040517f8ce516da0000000000000000000000000000000000000000000000000000000081526001600160a01b0386811693820193909352848316602482015260448101849052911690638ce516da90606401600060405180830381600087803b1580156112ba57600080fd5b505af11580156112ce573d6000803e3d6000fd5b50505050505050565b60606110d98484600085611385565b600082815260018401602052604081205480820361134d575050604080518082018252838152602080820184815286546001818101895560008981528481209551600290930290950191825591519082015586548684528188019092529290912055610db0565b82856000016001830381548110611366576113666116c9565b9060005260206000209060020201600101819055506000915050610db0565b6060843b6113bf576040517f89c35afc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080866001600160a01b031685876040516113db9190611860565b60006040518083038185875af1925050503d8060008114611418576040519150601f19603f3d011682016040523d82523d6000602084013e61141d565b606091505b509150915081156114315791506110d99050565b8051156114415780518082602001fd5b836040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611475919061187c565b60405180910390fd5b60006020828403121561149057600080fd5b5035919050565b803569ffffffffffffffffffff811681146114b157600080fd5b919050565b600080604083850312156114c957600080fd5b823591506114d960208401611497565b90509250929050565b80356001600160a01b03811681146114b157600080fd5b60008060006060848603121561150e57600080fd5b8335925061151e60208501611497565b915061152c604085016114e2565b90509250925092565b60008083601f84011261154757600080fd5b50813567ffffffffffffffff81111561155f57600080fd5b6020830191508360208260051b850101111561157a57600080fd5b9250929050565b6000806000806000806060878903121561159a57600080fd5b863567ffffffffffffffff808211156115b257600080fd5b6115be8a838b01611535565b909850965060208901359150808211156115d757600080fd5b6115e38a838b01611535565b909650945060408901359150808211156115fc57600080fd5b5061160989828a01611535565b979a9699509497509295939492505050565b6000806020838503121561162e57600080fd5b823567ffffffffffffffff81111561164557600080fd5b61165185828601611535565b90969095509350505050565b6000806000806040858703121561167357600080fd5b843567ffffffffffffffff8082111561168b57600080fd5b61169788838901611535565b909650945060208701359150808211156116b057600080fd5b506116bd87828801611535565b95989497509550505050565b634e487b7160e01b600052603260045260246000fd5b6000602082840312156116f157600080fd5b610db082611497565b60006020828403121561170c57600080fd5b610db0826114e2565b634e487b7160e01b600052601160045260246000fd5b80820180821115610b9457610b94611715565b81810381811115610b9457610b94611715565b600081600019048311821515161561176b5761176b611715565b500290565b60008261178d57634e487b7160e01b600052601260045260246000fd5b500490565b60005b838110156117ad578181015183820152602001611795565b50506000910152565b600081518084526117ce816020860160208601611792565b601f01601f19169290920160200192915050565b60006001600160a01b0380871683528086166020840152508360408301526080606083015261181460808301846117b6565b9695505050505050565b60006020828403121561183057600080fd5b81517fffffffff0000000000000000000000000000000000000000000000000000000081168114610db057600080fd5b60008251611872818460208701611792565b9190910192915050565b602081526000610db060208301846117b656fe4552433732313a207472616e7366657220746f206e6f6e20455243373231526563656976657220696d706c656d656e746572a2646970667358221220f7420dd88d408d7cea7b261db4f2e96bc1649c669d63951732df77385ff346bc64736f6c63430008100033
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 35 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
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.