# LooksRare 合约代码解读(二) **Published by:** [xyyme.eth](https://paragraph.com/@xyyme/) **Published on:** 2022-06-27 **URL:** https://paragraph.com/@xyyme/looksrare-2 ## Content 我们继续来学习 LooksRare 的代码,上篇文章中我们学习了它的主合约 LooksRareExchange,这篇文章我们着重于其它的辅助合约,包括各种管理合约以及交易策略合约等。源码解读TransferSelectorNFT上篇文章的最后,我们谈到了 NFT 的转账操作:NFT 转账可以看到,需要先根据 NFT 地址获取相应的转账管理器,然后采用对应的管理器来进行转账。其内部的实现为:获取 NFT 对应的转账管理合约这段代码中先查询该 NFT 有没有特定的转账管理器。如果没有,则利用 ERC165 规范,查询 NFT 合约实现了哪种规范(ERC721 或 ERC1155),然后使用对应的通用管理器。转账管理器本身的合约代码很简单,例如 ERC721 的转账代码为:TransferManagerERC721ERC721 转账管理器ManagerCurrencyManager,ExecutionManager 这两个管理器合约内容比较简单,包含基本的 add,remove,view 等方法,我们这里不再介绍。RoyaltyFeeRegistry该合约用于存储版税的相关信息,包括设置,读取等方法。 其中设置方法只能由 owner,即 RoyaltyFeeSetter 合约调用。版税数据结构版税对应的相关方法RoyaltyFeeSetter设置版税信息,可以理解为将上面的 RoyaltyFeeRegistry 合约包装了一层,这里是设置的入口。包含下面几个主要方法:updateRoyaltyInfoForCollectionIfAdminupdateRoyaltyInfoForCollectionIfOwnerupdateRoyaltyInfoForCollectionIfSetterupdateRoyaltyInfoForCollection_updateRoyaltyInfoForCollectionIfOwnerOrAdmin(内部方法,被上面的 IfAdmin 和 IfOwner 方法调用)前四个方法均为设置版税功能,区别在于,前两个是由 NFT 的管理员设置,由于每个 NFT 合约的写法都不同,因此会区分 admin,owner 等角色。第三个方法是由前面设置版税时的 setter 设置。第四个是由 RoyaltyFeeSetter 合约本身的 owner 调用。最后一个内部方法调用上面的 registry 合约,进行设置操作。 我对这几个方法的理解是,如果 NFT 合约本身实现了 owner 或者 admin 方法,那么就有自主设置版税的权利。如果没有实现,可以找到系统管理员协助设置,此时同时会设置一个 setter 角色,以后 NFT 的版税就可以通过 setter 地址调用 updateRoyaltyInfoForCollectionIfSetter 来管理。系统更加推荐使用 setter 角色来管理版税。 我们来看看其中一个设置方法:updateRoyaltyInfoForCollectionIfAdmin设置版税逻辑比较简单。要求只有 NFT 的 admin 可以调用。我们看到第一步要求 NFT 不能实现 ERC2981,奇怪了,ERC2981 不就是版税的标准呢,为什么不能实现这个接口呢,我们后面会解答这个问题。_updateRoyaltyInfoForCollectionIfOwnerOrAdmin更新版税内部方法RoyaltyFeeManager该合约是最外层的接口,主合约在这里获取版税信息,只有一个主要方法:calculateRoyaltyFeeAndGetRecipient版税外层接口我们看到,首先要检查系统中是否设置了该 NFT 的版税信息,如果没有设置,再去检查 NFT 本身是否包含版税信息。反过来想,如果合约本身就已经包含了版税信息,那么我们就没有必要在系统中设置。这也就解答了我们前面提出的问题:在 RoyaltyFeeSetter 合约中设置版税时,要求 NFT 合约本身不能实现 ERC2981。因为实现了 ERC2981 的合约,我们直接使用其自身的版税信息即可,不必再次设置。 接下来我们看看交易策略,LooksRare 合约库中一共包含 5 个交易策略,分别是:StrategyStandardSaleForFixedPrice,标准固定价格交易StrategyPrivateSale,卖家指定的买家才能购买StrategyDutchAuction,荷兰拍卖StrategyAnyItemFromCollectionForFixedPrice,买家出价购买一个 NFT 合集中任意一项。例如,买家想购买 BAYC,任意一个都可以StrategyAnyItemInASetForFixedPrice,买家出价购买一个 NFT 合集中某些特定 tokenId 中任意一项。例如,买家只想购买蓝色背景的 BAYC我们回想一下,在上篇文章中我们看到每个 match 成单方法都会调用策略的方法来校验该交易是否有效。例如:调用策略方法我们先提前了解一点,每个策略中都有两个主要方法:canExecuteTakerAsk,校验 taker 卖单与 maker 买单能否有效匹配canExecuteTakerBid,校验 taker 买单与 maker 卖单能否有效匹配接下来我们分别来介绍每个策略的代码,看看他们的具体实现。StrategyStandardSaleForFixedPrice最标准的买卖策略,固定价格,买单与卖单均指定 tokenId。标准策略可以看到标准策略中需要校验 price、tokenId 是否匹配,并检查时间戳是否有效,逻辑比较简单。只要满足这些规则,就是符合标准策略。StrategyPrivateSale当卖家指定由某位固定的买家购买时,使用该策略。指定买家卖家指定买家,此时卖单挂单中会指定买家的地址,将其存放在 MakerOrder 的 params 字段。因为这个策略的执行只能由买家触发,所以 canExecuteTakerAsk 方法没有意义,需要返回 false。在下面的 canExecuteTakerBid 中,需要将卖家指定的买家地址从 params 中解析出来,然后进行校验,同时也要校验价格,tokenId,时间戳等信息。StrategyDutchAuction荷兰拍卖,价格会不断下降,买家为主动方。荷兰拍卖荷兰拍卖同样由买家触发,因此 taker 卖单没有意义,canExecuteTakerAsk 需要返回 false。在 canExecuteTakerBid 方法中,根据开始价格,结束价格,拍卖时常来计算当前实时价格,最后对参数进行校验。StrategyAnyItemFromCollectionForFixedPrice买家购买任意一款买家购买合集中任意一项均可,因此为买家挂单。此时卖家为 taker 主动方,因此 canExecuteTakerBid 没有意义,返回 false。我们看到,在 canExecuteTakerAsk 中仅仅校验了价格与时间,没有 tokenId,这是为何呢?因为买家购买任意一款均可,那么就不用指定 tokenId,只要价格与时间等信息匹配,任意一款 tokenId 都可以,因此这里不用校验。StrategyAnyItemInASetForFixedPrice买家购买某些特定 id买家指定购买某些特定的 tokenId,此时买家挂单,卖家为 taker 主动方,因此 canExecuteTakerBid 没有意义,返回 false。canExecuteTakerAsk 中利用了 Merkle Tree 的技术,maker 买单中的 params 字段存储所有想要购买 tokenId 合集的 Merkle Root,taker 卖单中的 params 存储了该 tokenId 对应的 Proof。最后通过 verify 校验 taker 卖单中的 tokenId 是否匹配。总结现在我们就已经介绍完了 LooksRare 的所有主要合约,是不是感觉还挺简单的。我个人认为 LooksRare 的文档和代码写得都比较简洁易懂,比较适合开发者来学习 NFT 市场的原理。希望大家能够结合代码库和我的文章,多理解几遍,必然会对自己的能力有一些提升。LooksRare 代码系列文章LooksRare 合约代码解读(一)LooksRare 合约代码解读(二)关于我欢迎和我交流参考LooksRare Exchange v1 Overview | LooksRare DocsUnderstand the LooksRare blockchain architecture with the technical documentation for smart contracts of the exchange protocol.https://docs.looksrare.org ## Publication Information - [xyyme.eth](https://paragraph.com/@xyyme/): Publication homepage - [All Posts](https://paragraph.com/@xyyme/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@xyyme): Subscribe to updates - [Twitter](https://twitter.com/xyymeeth): Follow on Twitter