NFT交易所智能合约实现分析_第1页
NFT交易所智能合约实现分析_第2页
NFT交易所智能合约实现分析_第3页
NFT交易所智能合约实现分析_第4页
NFT交易所智能合约实现分析_第5页
已阅读5页,还剩29页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、NFT交易所智能合约实现分析.md2023/3/22NFT交易所智能合约实现分析NFT全称为Non-Fungible Tokens,即非同质化代币。信任阅读本文的读者也了解,NFT是目前区块链上最火应用之一。其交易所更是对NFT起到推波助澜的作用。本文就结合一个现有已开源的NFT交易所智能合约代码,解析其实现规律,挂念理解NFT交易所智能合约的实现。交易所基础功能分析交易所或许包含功能有:项目上架,发布商品,取消商品,达成交易等功能。功能项目上架发布商品取消商品达成交易说明登记NFT项目合约,使该合约下NFT能交易声明具体合约下NFT tokenid可交易取消具体合约下NFT tokenid交

2、易交易完成,转让NFT tokenid全部权,转账具体实例源码解析源码文件总览:文件Context.sol Ownable.sol ReentrancyGuard.sol EnumerableSet.sol IERC20.sol Address.sol SafeERC20.sol IERC165.sol IERC721.solIERC721Receiver.sol ERC721Holder.sol IWETH.sol BullsMarketplace.sol功能说明一笔交易上下文封装,猎取交易发起者以及交易数据合约全部者交易可重入把握可枚举集合ERC20协议接口,用来执行交易确认转账地址处理E

3、RC20转账封装ERC721协议标准相关ERC721协议接口,用于操作NFT转让ERC721协议接口IERC721Receiver实现接口交易所合约实现1 / 34NFT交易所智能合约实现分析.md2023/3/22接口说明关于为啥定义IERC20.sol、IERC721.sol等接口,是由于在交易所合约中需要调用其他合约。如NFT转让需要调用该合约中的转让接口,所以需要IERC721.sol;而交易中使用ERC20协议代币,其转账则需要调用IERC20.sol中接口。调用IERC721.sol接口示例:(极简化)function createAskOrder( address _collec

4、tion, uint _tokenId,uint _askPrice) / Transfer NFT to this contract IERC721(_collection).safeTransferFrom(address(msg.sender), address( this),_tokenId);在上述示例中,传入的_collection为某个NFT合约地址,通过IERC721(_collection)转换之后可以调用IERC721.sol中定义的safeTransferFrom接口。而_collection合约即为ERC721合约,则必定已实现safeTransferFrom接口,所以

5、实际调用到该合约的具体实现中。将_tokenId从当前交易发起者msg.sender转让给交易所合约地址this。Context.sol/ File: openzeppelin/contracts/utils/Context.sol/ SPDX-License-Identifier: MIT pragma solidity 0.8.0;/*dev Provides information about the current execution context, including thesender of the transaction and its data. While these ar

6、e generally availablevia msg.sender and msg.data, they should not be accessed in such a directmanner, since when dealing with meta-transactions the account sending andpaying for execution may not be the actual sender (as far as an applicationis concerned).*This contract is only required for intermed

7、iate, library-like contracts.*/abstract contract Context function _msgSender() internal view virtual returns (address) return msg.sender; / 返回交易发起者function _msgData() internal view virtual returns (bytes calldata) return msg.data; / 返回交易数据2 / 34NFT交易所智能合约实现分析.md2023/3/22Ownable.sol/ File: openzeppel

8、in/contracts/access/Ownable.sol pragma solidity 0.8.0;/*dev Contract module which provides a basic access control mechanism, wherethere is an account (an owner) that can be granted exclusive access tospecific functions.*By default, the owner account will be the one that deploys the contract. Thiscan

9、 later be changed with transferOwnership.*This module is used through inheritance. It will make available the modifieronlyOwner, which can be applied to your functions to restrict their use tothe owner.*/abstract contract Ownable is Context address private _owner;event OwnershipTransferred(address i

10、ndexed previousOwner, address indexed newOwner);/*dev Initializes the contract setting the deployer as the initial owner.*/ constructor() _setOwner(_msgSender(); / 创建合约时,设置_owner为创建着地址/* dev Returns the address of the current owner.*/function owner() public view virtual returns (address) return _own

11、er;/* dev Throws if called by any account other than the owner.*/ 检查当前交易发起者必需与合约全部者全都/ require函数推断第一个条件是否成立,假如不成立(也即发起者不为合约全部者)则报错/ 并提示Ownable: caller is not the ownermodifier onlyOwner() require(owner() = _msgSender(), Ownable: caller is not the owner);_;3 / 34NFT交易所智能合约实现分析.md2023/3/22/*dev Leaves

12、 the contract without owner. It will not be possible to callonlyOwner functions anymore. Can only be called by the current owner.*NOTE: Renouncing ownership will leave the contract without an owner,thereby removing any functionality that is only available to the owner.*/function renounceOwnership()

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

14、_setOwner(newOwner);function _setOwner(address newOwner) private address oldOwner = _owner;_owner = newOwner;emit OwnershipTransferred(oldOwner, newOwner);ReentrancyGuard.sol/ File: openzeppelin/contracts/security/ReentrancyGuard.sol pragma solidity 0.8.0;/*dev Contract module that helps prevent ree

15、ntrant calls to a function.*Inheriting from ReentrancyGuard will make the nonReentrant modifieravailable, which can be applied to functions to make sure there are no nested(reentrant) calls to them.*Note that because there is a single nonReentrant guard, functions marked asnonReentrant may not call

16、one another. This can be worked around by makingthose functions private, and then adding external nonReentrant entrypoints to them.*TIP: If you would like to learn more about reentrancy and alternative waysto protect against it, check out our blog post*/abstract contract ReentrancyGuard / Booleans a

17、re more expensive than uint or any type that takes up a full4 / 34NFT交易所智能合约实现分析.md2023/3/22/ word because each write operation emits an extra SLOAD to first read the/ slots contents, replace the bits taken up by the boolean, and then write/ back. This is the compilers defense against contract upgra

18、des and/ pointer aliasing, and it cannot be disabled./The values being non-zero value makes deployment a bit more expensive,/but in exchange the refund on every call to nonReentrant will be lowerin/amount. Since refunds are capped to a percentage of the total/transactions gas, it is best to keep the

19、m low in cases like this one,to/increase the likelihood of the full refund coming into effect.uintprivateconstant _NOT_ENTERED = 1;uintprivateconstant _ENTERED = 2;uintprivate_status;constructor() _status = _NOT_ENTERED;/*dev Prevents a contract from calling itself, directly or indirectly.Calling a

20、nonReentrant function from another nonReentrantfunction is not supported. It is possible to prevent this from happeningby making the nonReentrant function external, and make it call aprivate function that does the actual work.*/ 用于把握交易不行重入modifier nonReentrant() / On the first call to nonReentrant,

21、_notEntered will be true require(_status != _ENTERED, ReentrancyGuard: reentrant call);/ Any calls to nonReentrant after this point will fail_status = _ENTERED;_;/ By storing the original value once again, a refund is triggered_status = _NOT_ENTERED;EnumerableSet.sol/ File: openzeppelin/contracts/ut

22、ils/structs/EnumerableSet.sol pragma solidity 0.8.0;/*dev Library for managing*Sets have the following properties:5 / 34NFT交易所智能合约实现分析.md2023/3/22*- Elements are added, removed, and checked for existence in constant time* (O(1).- Elements are enumerated in O(n). No guarantees are made on the orderin

23、g.* contract Example / Add the library methodsusing EnumerableSet for EnumerableSet.AddressSet;*/ Declare a set state variableEnumerableSet.AddressSet private mySet;* * *As of v3.3.0, sets of type bytes32 (Bytes32Set), address (AddressSet)and uint (UintSet) are supported.*/library EnumerableSet / To

24、 implement this library for multiple types with as little code/ repetition as possible, we write it in terms of a generic Set type with/ bytes32 values./ The Set implementation uses private functions, and user-facing/ implementations (such as AddressSet) are just wrappers around the/ underlying Set.

25、/ This means that we can only create new EnumerableSets for types that fit/ in bytes32./ 可枚举集合/ _values 为集合,保存全部数据/ _indexes 为数据与其在集合中位置对应关系struct Set / Storage of set values bytes32 _values;/ Position of the value in the values array, plus 1 because index 0/ means a value is not in the set. mapping

26、(bytes32 = uint) _indexes;/*dev Add a value to a set. O(1).*Returns true if the value was added to the set, that is if it was notalready present.*/ 向集合中添加数据时,首先推断集合中是否已存在/ 否则添加到集合,并登记数据与其位置对应关系function _add(Set storage set, bytes32 value) private returns (bool) if (!_contains(set, value) set._values

27、.push(value);/ The value is stored at length-1, but we add 1 to all indexes/ and use 0 as a sentinel value set._indexesvalue = set._values.length; return true;6 / 34NFT交易所智能合约实现分析.md2023/3/22 else return false;/*dev Removes a value from a set. O(1).*Returns true if the value was removed from the set

28、, that is if it waspresent.*/function _remove(Set storage set, bytes32 value) private returns (bool) / We read and store the values index to prevent multiple reads from the same storage slotuint valueIndex = set._indexesvalue;if (valueIndex != 0) / Equivalent to contains(set, value)/ To delete an el

29、ement from the _values array in O(1), we swap the element to delete with the last one in/ the array, and then remove the last element (sometimes called as swap and pop)./ This modifies the order of the array, as noted in at.uint toDeleteIndex = valueIndex - 1; uint lastIndex = set._values.length - 1

30、;/ 删除数据为集合中间某个部分,将其与末尾数据进行交换if (lastIndex != toDeleteIndex) bytes32 lastvalue = set._valueslastIndex;/ Move the last value to the index where the value to delete is set._valuestoDeleteIndex = lastvalue;/ Update the index for the moved valueset._indexeslastvalue = valueIndex; / Replace lastvalues ind

31、ex to valueIndex/ Delete the slot where the moved value was stored set._values.pop();/ Delete the index for the deleted slot delete set._indexesvalue;return true; else return false;/*dev Returns true if the value is in the set. O(1).*/function _contains(Set storage set, bytes32 value) private view r

32、eturns (bool) 7 / 34NFT交易所智能合约实现分析.md2023/3/22return set._indexesvalue != 0;/*dev Returns the number of values on the set. O(1).*/function _length(Set storage set) private view returns (uint) return set._values.length;/*dev Returns the value stored at position index in the set. O(1).*Note that there

33、 are no guarantees on the ordering of values inside thearray, and it may change when more values are added or removed.*Requirements:*- index must be strictly less than length.*/function _at(Set storage set, uint index) private view returns (bytes32) return set._valuesindex;/ Bytes32Set struct Bytes3

34、2Set Set _inner;/*dev Add a value to a set. O(1).*Returns true if the value was added to the set, that is if it was notalready present.*/function add(Bytes32Set storage set, bytes32 value) internal returns (bool) return _add(set._inner, value);/*dev Removes a value from a set. O(1).*Returns true if

35、the value was removed from the set, that is if it waspresent.*/function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) return _remove(set._inner, value);/*dev Returns true if the value is in the set. O(1).*/function contains(Bytes32Set storage set, bytes32 value) internal view

36、 returns8 / 34NFT交易所智能合约实现分析.md2023/3/22(bool) return _contains(set._inner, value);/*dev Returns the number of values in the set. O(1).*/function length(Bytes32Set storage set) internal view returns (uint) return _length(set._inner);/*dev Returns the value stored at position index in the set. O(1).*

37、Note that there are no guarantees on the ordering of values inside thearray, and it may change when more values are added or removed.*Requirements:*- index must be strictly less than length.*/function at(Bytes32Set storage set, uint index) internal view returns (bytes32)return _at(set._inner, index)

38、;/ AddressSet struct AddressSet Set _inner;/*dev Add a value to a set. O(1).*Returns true if the value was added to the set, that is if it was notalready present.*/function add(AddressSet storage set, address value) internal returns (bool) return _add(set._inner, bytes32(uint(uint160(value);/*dev Re

39、moves a value from a set. O(1).*Returns true if the value was removed from the set, that is if it waspresent.*/function remove(AddressSet storage set, address value) internal returns (bool) return _remove(set._inner, bytes32(uint(uint160(value);/*dev Returns true if the value is in the set. O(1).9 /

40、 34NFT交易所智能合约实现分析.md2023/3/22*/function contains(AddressSet storage set, address value) internal view returns (bool) return _contains(set._inner, bytes32(uint(uint160(value);/*dev Returns the number of values in the set. O(1).*/function length(AddressSet storage set) internal view returns (uint) ret

41、urn _length(set._inner);/*dev Returns the value stored at position index in the set. O(1).*Note that there are no guarantees on the ordering of values inside thearray, and it may change when more values are added or removed.*Requirements:*- index must be strictly less than length.*/function at(Addre

42、ssSet storage set, uint index) internal view returns (address)return address(uint160(uint(_at(set._inner, index);/ UintSet struct UintSet Set _inner;/*dev Add a value to a set. O(1).*Returns true if the value was added to the set, that is if it was notalready present.*/function add(UintSet storage s

43、et, uint value) internal returns (bool) return _add(set._inner, bytes32(value);/*dev Removes a value from a set. O(1).*Returns true if the value was removed from the set, that is if it waspresent.*/function remove(UintSet storage set, uint value) internal returns (bool) return _remove(set._inner, by

44、tes32(value);10 / 34NFT交易所智能合约实现分析.md2023/3/22/*dev Returns true if the value is in the set. O(1).*/function contains(UintSet storage set, uint value) internal view returns (bool)return _contains(set._inner, bytes32(value);/*dev Returns the number of values on the set. O(1).*/function length(UintSet

45、 storage set) internal view returns (uint) return _length(set._inner);/*dev Returns the value stored at position index in the set. O(1).*Note that there are no guarantees on the ordering of values inside thearray, and it may change when more values are added or removed.*Requirements:*- index must be

46、 strictly less than length.*/function at(UintSet storage set, uint index) internal view returns (uint) return uint(_at(set._inner, index);IERC20.solIERC20.sol定义ERC20协议标准接口/ File: openzeppelin/contracts/token/ERC20/IERC20.sol pragma solidity 0.8.0;/* dev Interface of the ERC20 standard as defined in

47、the EIP.*/interface IERC20 /* dev Returns the amount of tokens in existence.*/function totalSupply() external view returns (uint);/* dev Returns the amount of tokens owned by account.*/function balanceOf(address account) external view returns (uint);11 / 34NFT交易所智能合约实现分析.md2023/3/22/*dev Moves amoun

48、t tokens from the callers account to recipient.*Returns a boolean value indicating whether the operation succeeded.*Emits a Transfer event.*/function transfer(address recipient, uint amount) external returns (bool);/*dev Returns the remaining number of tokens that spender will beallowed to spend on

49、behalf of owner through transferFrom. This iszero by default.*This value changes when approve or transferFrom are called.*/function allowance(address owner, address spender) external view returns (uint);/*dev Sets amount as the allowance of spender over the callers tokens.*Returns a boolean value in

50、dicating whether the operation succeeded.*IMPORTANT: Beware that changing an allowance with this method brings the riskthat someone may use both the old and the new allowance by unfortunatetransaction ordering. One possible solution to mitigate this racecondition is to first reduce the spenders allo

51、wance to 0 and set thedesired value afterwards*Emits an Approval event.*/function approve(address spender, uint amount) external returns (bool);/*dev Moves amount tokens from sender to recipient using theallowance mechanism. amount is then deducted from the callersallowance.*Returns a boolean value

52、indicating whether the operation succeeded.*Emits a Transfer event.*/function transferFrom( address sender, address recipient, uint amount) external returns (bool);/*dev Emitted when value tokens are moved from one account (from) toanother (to).*Note that value may be zero.12 / 34NFT交易所智能合约实现分析.md20

53、23/3/22*/event Transfer(address indexed from, address indexed to, uint value);/*dev Emitted when the allowance of a spender for an owner is set bya call to approve. value is the new allowance.*/event Approval(address indexed owner, address indexed spender, uint value);Address.sol/ File: openzeppelin

54、/contracts/utils/Address.sol pragma solidity 0.8.0;/*dev Collection of functions related to the address type*/library Address /*dev Returns true if account is a contract.*IMPORTANT* =It is unsafe to assume that an address for which this function returnsfalse is an externally-owned account (EOA) and

55、not a contract.*Among others, isContract will return false for the followingtypes of addresses:*- an externally-owned account- a contract in construction- an address where a contract will be created- an address where a contract lived, but was destroyed* =*/function isContract(address account) intern

56、al view returns (bool) / This method relies on extcodesize, which returns 0 for contracts in/ construction, since the code is only stored at the end of the/ constructor execution.uint size; assembly size := extcodesize(account)return size 0;/*dev Replacement for Soliditys transfer: sends amount wei

57、to13 / 34NFT交易所智能合约实现分析.md2023/3/22recipient, forwarding all available gas and reverting on errors.*/function sendValue(address payable recipient, uint amount) internal require(address(this).balance = amount, Address: insufficient balance);(bool success, ) = recipient.call value: amount (); require(

58、success, Address: unable to send value, recipient may havereverted);/*dev Performs a Solidity function call using a low level call. Aplain call is an unsafe replacement for a function call: use thisfunction instead.*If target reverts with a revert reason, it is bubbled up by thisfunction (like regul

59、ar Solidity function calls).*Requirements:*- target must be a contract.- calling target with data must not revert.*_Available since v3.1._*/function functionCall(address target, bytes memory data) internal returns (bytes memory) return functionCall(target, data, Address: low-level call failed);/*dev

60、 Same as xref-Address-functionCall-address-bytes-functionCall, but witherrorMessage as a fallback revert reason when target reverts.*_Available since v3.1._*/function functionCall( address target, bytes memory data,string memory errorMessage) internal returns (bytes memory) return functionCallWithVa

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论