# LooksRare 合约代码解读（二）

By [xyyme.eth](https://paragraph.com/@xyyme) · 2022-06-27

---

我们继续来学习 LooksRare 的代码，[上篇文章](https://mirror.xyz/xyyme.eth/mlRnXcw-eg2Xeoctg54mDU08msmUt4LLnOy4-4WTQyo)中我们学习了它的主合约 `LooksRareExchange`，这篇文章我们着重于其它的辅助合约，包括各种管理合约以及交易策略合约等。

源码解读
----

### TransferSelectorNFT

上篇文章的最后，我们谈到了 NFT 的转账操作：

![NFT 转账](https://storage.googleapis.com/papyrus_images/b16ffcefcf28f8f61cd941917b8603213683aa98265732dc351de023dcc41ceb.png)

NFT 转账

可以看到，需要先根据 NFT 地址获取相应的转账管理器，然后采用对应的管理器来进行转账。其内部的实现为：

![获取 NFT 对应的转账管理合约](https://storage.googleapis.com/papyrus_images/f58cf5ac75db0dee4d5e980eb9eb8f57286629c80df13b85b437aa5e4b05a80e.png)

获取 NFT 对应的转账管理合约

这段代码中先查询该 NFT 有没有特定的转账管理器。如果没有，则利用 ERC165 规范，查询 NFT 合约实现了哪种规范（ERC721 或 ERC1155），然后使用对应的通用管理器。转账管理器本身的合约代码很简单，例如 ERC721 的转账代码为：

### TransferManagerERC721

![ERC721 转账管理器](https://storage.googleapis.com/papyrus_images/8667ae61fa5cbd17beace401bb3568e2774a584b0eced8bd3da014aac4575ea5.png)

ERC721 转账管理器

### Manager

`CurrencyManager`，`ExecutionManager` 这两个管理器合约内容比较简单，包含基本的 `add`，`remove`，`view` 等方法，我们这里不再介绍。

### RoyaltyFeeRegistry

该合约用于存储版税的相关信息，包括设置，读取等方法。

其中设置方法只能由 owner，即 `RoyaltyFeeSetter` 合约调用。

![版税数据结构](https://storage.googleapis.com/papyrus_images/592c351a1a748e82cf04fb3e9061692fc21ad072b3e2691ecd3ab4c29cffa3ce.png)

版税数据结构

![版税对应的相关方法](https://storage.googleapis.com/papyrus_images/2536cc15c6074833916a5263f81d8aa6a0d24194ce954e9a2e7a297eeeab75ab.png)

版税对应的相关方法

### RoyaltyFeeSetter

设置版税信息，可以理解为将上面的 `RoyaltyFeeRegistry` 合约包装了一层，这里是设置的入口。包含下面几个主要方法：

*   `updateRoyaltyInfoForCollectionIfAdmin`
    
*   `updateRoyaltyInfoForCollectionIfOwner`
    
*   `updateRoyaltyInfoForCollectionIfSetter`
    
*   `updateRoyaltyInfoForCollection`
    
*   `_updateRoyaltyInfoForCollectionIfOwnerOrAdmin`（内部方法，被上面的 `IfAdmin` 和 `IfOwner` 方法调用）
    

前四个方法均为设置版税功能，区别在于，前两个是由 NFT 的管理员设置，由于每个 NFT 合约的写法都不同，因此会区分 `admin`，`owner` 等角色。第三个方法是由前面设置版税时的 setter 设置。第四个是由 `RoyaltyFeeSetter` 合约本身的 owner 调用。最后一个内部方法调用上面的 `registry` 合约，进行设置操作。

我对这几个方法的理解是，如果 NFT 合约本身实现了 `owner` 或者 `admin` 方法，那么就有自主设置版税的权利。如果没有实现，可以找到系统管理员协助设置，此时同时会设置一个 setter 角色，以后 NFT 的版税就可以通过 setter 地址调用 `updateRoyaltyInfoForCollectionIfSetter` 来管理。系统更加推荐使用 setter 角色来管理版税。

我们来看看其中一个设置方法：

#### updateRoyaltyInfoForCollectionIfAdmin

![设置版税](https://storage.googleapis.com/papyrus_images/b826d765f481d7248fdca69eba1d9b3a116c39652b052c6ebd82f9ac0b3a1df9.png)

设置版税

逻辑比较简单。要求只有 NFT 的 admin 可以调用。我们看到第一步要求 NFT 不能实现 ERC2981，奇怪了，ERC2981 不就是版税的标准呢，为什么不能实现这个接口呢，我们后面会解答这个问题。

#### \_updateRoyaltyInfoForCollectionIfOwnerOrAdmin

![更新版税内部方法](https://storage.googleapis.com/papyrus_images/64c193dc8e3d992c2738d4e1e538ba9acef55fa938cd4380351e1e46c74348fb.png)

更新版税内部方法

### RoyaltyFeeManager

该合约是最外层的接口，主合约在这里获取版税信息，只有一个主要方法：

#### calculateRoyaltyFeeAndGetRecipient

![版税外层接口](https://storage.googleapis.com/papyrus_images/66e1c32e46cac513d86bc80a2dfd2ac7e6b3d474d5df267ecfc59ab0299a72b4.png)

版税外层接口

我们看到，首先要检查系统中是否设置了该 NFT 的版税信息，如果没有设置，再去检查 NFT 本身是否包含版税信息。反过来想，如果合约本身就已经包含了版税信息，那么我们就没有必要在系统中设置。这也就解答了我们前面提出的问题：在 `RoyaltyFeeSetter` 合约中设置版税时，要求 NFT 合约本身不能实现 ERC2981。因为实现了 ERC2981 的合约，我们直接使用其自身的版税信息即可，不必再次设置。

接下来我们看看交易策略，LooksRare 合约库中一共包含 5 个交易策略，分别是：

*   `StrategyStandardSaleForFixedPrice`，标准固定价格交易
    
*   `StrategyPrivateSale`，卖家指定的买家才能购买
    
*   `StrategyDutchAuction`，荷兰拍卖
    
*   `StrategyAnyItemFromCollectionForFixedPrice`，买家出价购买一个 NFT 合集中任意一项。例如，买家想购买 BAYC，任意一个都可以
    
*   `StrategyAnyItemInASetForFixedPrice`，买家出价购买一个 NFT 合集中某些特定 tokenId 中任意一项。例如，买家只想购买蓝色背景的 BAYC
    

我们回想一下，在上篇文章中我们看到每个 `match` 成单方法都会调用策略的方法来校验该交易是否有效。例如：

![调用策略方法](https://storage.googleapis.com/papyrus_images/d07be3a453aeea2923b9680d47b25dfbfaf64e31feddad599c99643bfe28d795.png)

调用策略方法

我们先提前了解一点，每个策略中都有两个主要方法：

*   `canExecuteTakerAsk`，校验 taker 卖单与 maker 买单能否有效匹配
    
*   `canExecuteTakerBid`，校验 taker 买单与 maker 卖单能否有效匹配
    

接下来我们分别来介绍每个策略的代码，看看他们的具体实现。

### StrategyStandardSaleForFixedPrice

最标准的买卖策略，固定价格，买单与卖单均指定 tokenId。

![标准策略](https://storage.googleapis.com/papyrus_images/fd29bf09da07fbd3447bd16cbc2b0f13ea39de3e72b93503c677b2e4dbf1bc97.png)

标准策略

可以看到标准策略中需要校验 `price`、`tokenId` 是否匹配，并检查时间戳是否有效，逻辑比较简单。只要满足这些规则，就是符合标准策略。

### StrategyPrivateSale

当卖家指定由某位固定的买家购买时，使用该策略。

![指定买家](https://storage.googleapis.com/papyrus_images/f69e1115bba48f11fb51a74b142eb161d7f80e90601897bacd9e6685abf68483.png)

指定买家

卖家指定买家，此时卖单挂单中会指定买家的地址，将其存放在 MakerOrder 的 `params` 字段。因为这个策略的执行只能由买家触发，所以 `canExecuteTakerAsk` 方法没有意义，需要返回 false。在下面的 `canExecuteTakerBid` 中，需要将卖家指定的买家地址从 `params` 中解析出来，然后进行校验，同时也要校验价格，tokenId，时间戳等信息。

### StrategyDutchAuction

荷兰拍卖，价格会不断下降，买家为主动方。

![荷兰拍卖](https://storage.googleapis.com/papyrus_images/a4cf969c51fba367d9088cabc82bc89af772fece53719b2a186b8509834f698d.png)

荷兰拍卖

荷兰拍卖同样由买家触发，因此 taker 卖单没有意义，`canExecuteTakerAsk` 需要返回 false。在 `canExecuteTakerBid` 方法中，根据开始价格，结束价格，拍卖时常来计算当前实时价格，最后对参数进行校验。

### StrategyAnyItemFromCollectionForFixedPrice

![买家购买任意一款](https://storage.googleapis.com/papyrus_images/898aa7034df7200a16b33dbbc1317b26a52b97c0b01f70db036c4d77a2666566.png)

买家购买任意一款

买家购买合集中任意一项均可，因此为买家挂单。此时卖家为 taker 主动方，因此 `canExecuteTakerBid` 没有意义，返回 false。我们看到，在 `canExecuteTakerAsk` 中仅仅校验了价格与时间，没有 tokenId，这是为何呢？因为买家购买任意一款均可，那么就不用指定 tokenId，只要价格与时间等信息匹配，任意一款 tokenId 都可以，因此这里不用校验。

### StrategyAnyItemInASetForFixedPrice

![买家购买某些特定 id](https://storage.googleapis.com/papyrus_images/51bc7f857f2a5f8512d853ee97bc760c4efe3f7608e01f29fc966ce66b85889a.png)

买家购买某些特定 id

买家指定购买某些特定的 tokenId，此时买家挂单，卖家为 taker 主动方，因此 `canExecuteTakerBid` 没有意义，返回 false。`canExecuteTakerAsk` 中利用了 Merkle Tree 的技术，maker 买单中的 `params` 字段存储所有想要购买 tokenId 合集的 Merkle Root，taker 卖单中的 `params` 存储了该 tokenId 对应的 Proof。最后通过 verify 校验 taker 卖单中的 tokenId 是否匹配。

总结
--

现在我们就已经介绍完了 LooksRare 的所有主要合约，是不是感觉还挺简单的。我个人认为 LooksRare 的文档和代码写得都比较简洁易懂，比较适合开发者来学习 NFT 市场的原理。希望大家能够结合代码库和我的文章，多理解几遍，必然会对自己的能力有一些提升。

LooksRare 代码系列文章
----------------

1.  [LooksRare 合约代码解读（一）](https://mirror.xyz/xyyme.eth/mlRnXcw-eg2Xeoctg54mDU08msmUt4LLnOy4-4WTQyo)
    
2.  [LooksRare 合约代码解读（二）](https://mirror.xyz/xyyme.eth/mdlzrw_UEl_ea6svtJ3zoF7gDdrnEp67hVDMr1hlvho)
    

关于我
---

欢迎[和我交流](https://linktr.ee/xyymeeth)

参考
--

[

LooksRare Exchange v1 Overview | LooksRare Docs
-----------------------------------------------

Understand the LooksRare blockchain architecture with the technical documentation for smart contracts of the exchange protocol.

https://docs.looksrare.org



](https://docs.looksrare.org/developers/looksrare-exchange-overview)

---

*Originally published on [xyyme.eth](https://paragraph.com/@xyyme/looksrare-2)*
