# LooksRare 合约代码解读（一）

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

---

最近研究了 LooksRare 的[合约代码](https://github.com/LooksRare/contracts-exchange-v1)，他们的代码写得比较简单易懂，同时文档内容也比较丰富。学习了几天，基本算是把整个合约代码都研究明白了，因此写篇文章来做做笔记，同时也希望能够帮助到有需要的朋友。

系统架构
----

### 名词解释

*   `ask` 代表卖家卖出，`bid` 代表买家买入。
    
*   `maker` 代表主动挂单的人，例如卖家主动挂单卖 NFT ，此时卖家为 maker。或者买家对某 NFT 出价，此时买家为 maker。
    
*   `taker` 代表撮合完成订单的人，例如买家看到某 NFT 的价格合适，对其买入，此时买家为 taker。或者卖家看到某买家的出价合适，对其卖出，此时卖家为 taker。
    

结合上面的描述，合约中一共有四个角色，分别是：

*   `makerAsk`，挂单的卖家
    
*   `makerBid`，出价的买家
    
*   `takerAsk`，撮合完成订单的卖家
    
*   `takerBid`，撮合完成订单的买家
    

### 链下

挂单（出价）行为是在链下完成的，即 `maker` 操作不上链，只是在链下签名。

### 链上

成单行为是在链上完成的，即 `taker` 操作上链。因此代码中只有成单，没有挂单的逻辑。

### 合约架构

*   `LooksRareExchange`，主合约，用户的所有操作都在这里
    
*   管理合约
    
    *   `CurrencyManager`，管理协议支持的支付币种
        
    *   `ExecutionManager`，管理协议支持的交易策略
        
    *   `RoyaltyFeeManager`，管理 NFT 对应的版税信息
        
    *   TransferManager，均继承于 `ITransferManagerNFT`
        
        *   `TransferManagerERC721`，执行 ERC-721 的转移操作（使用 `safeTransferFrom`）
            
        *   `TransferManagerERC1155`，执行 ERC-1155 的转移操作
            
        *   `TransferManagerNonCompliantERC721`，执行 ERC-721 的转移操作（**不**使用 `safeTransferFrom`，而是 `transferFrom`）
            
*   `OrderTypes`，包含 `MakerOrder` 与 `TakerOrder` 的订单数据结构
    
*   `TransferSelectorNFT`，管理 NFT 对应的 TransferManager
    
*   交易策略合约
    
    *   `StrategyStandardSaleForFixedPrice`，标准固定价格交易
        
    *   `StrategyPrivateSale`，卖家指定的买家才能购买
        
    *   `StrategyDutchAuction`，荷兰拍卖
        
    *   `StrategyAnyItemFromCollectionForFixedPrice`，买家出价购买一个 NFT 合集中任意一项。例如，买家想购买 BAYC，任意一个都可以
        
    *   `StrategyAnyItemInASetForFixedPrice`，买家出价购买一个 NFT 合集中某些特定 tokenId 中任意一项。例如，买家只想购买蓝色背景的 BAYC
        
*   `RoyaltyFeeRegistry`，设置 NFT 的版税信息，存储版税信息
    
*   `RoyaltyFeeSetter`，设置 NFT 的版税信息，该合约为入口，调用上面的合约
    

看到这么多合约，是不是已经晕了。不用怕，我们要关心的只有 `LooksRareExchange` 合约，其他的合约都是为了它服务的。

源码解读
----

> 注：由于 Mirror 的排版原因，长代码的阅读性很差，因此为了统一起见，所有代码将会截图展示。同时，只着重于主要业务逻辑，对于例如 setter 等比较简单的部分，不再介绍。

### OrderTypes

包含 `MakerOrder` 与 `TakerOrder`，分别为：

![订单数据结构](https://storage.googleapis.com/papyrus_images/b4998f620990a39d5269ac0d8994ed5097f567221d0bdb8a130bbffa750d0791.png)

订单数据结构

### LooksRareExchange

![nonce 数据结构](https://storage.googleapis.com/papyrus_images/900ae735cdddfde843a32d34dfda52fcc342ceaa3bea08083ccaa1950a791bfe.png)

nonce 数据结构

![取消订单](https://storage.googleapis.com/papyrus_images/f3b71f35bbf9f8238d7d6e281096f2125d0284f88f9291d6c66388e1fcbd7fdd.png)

取消订单

我们知道，挂单是在通过签名在链下进行的，每个挂单都包含 nonce。但是如果要取消订单，必须要上链，为什么呢？因为在成单的时候，要用到挂单的签名信息，而一旦签名了，签名信息是一直存在的。即使链下再怎么操作，链上也可以把这份签名拿过来用。因此 maker 需要在链上将这个 nonce 的订单取消，让其在链上失效。这样即使有人拿着签名信息来用，那么在链上这个 nonce 的订单已经失效了。

对于上面两个函数，`cancelAllOrdersForSender` 属于一刀切，传入一个 nonce，该 nonce 以下的订单就全部失效。`cancelMultipleMakerOrders` 则是传入特定的 nonce 列表，只有这些 nonce 的订单失效。

#### matchAskWithTakerBidUsingETHAndWETH

买家发起撮合，使用 WETH 购买

![买家使用 WETH 购买](https://storage.googleapis.com/papyrus_images/d5613d452e73ef6507f8153dfc014c7d3c02c07e50883c031de6962854717ec2.png)

买家使用 WETH 购买

#### matchAskWithTakerBid

买家发起撮合，使用指定币种（makerAsk.currency）购买

![买家使用非 WETH 币种购买](https://storage.googleapis.com/papyrus_images/0259659fe34dd265117f2b6532050cd03d37da9b628f47ef28a88632730a497b.png)

买家使用非 WETH 币种购买

可以看到上面两个函数的逻辑大同小异，区别比较大的地方就是使用 WETH 购买的函数中，需要对 `msg.value` 以及 ETH 的转换进行处理。

#### matchBidWithTakerAsk

卖家发起撮合

![卖家卖出](https://storage.googleapis.com/papyrus_images/acd2d47f182158ce8dbac6b5fb0efc4ac2a1d253b2a382ca25f332c75eedffc1.png)

卖家卖出

可以看到，与上一个方法也是大同小异，只是方向不同。

用户所有的操作就是这些，我们再来小结一下：

*   `cancelAllOrdersForSender` → 取消指定 nonce 以下所有订单
    
*   `cancelMultipleMakerOrders` → 批量取消指定订单
    
*   `matchAskWithTakerBidUsingETHAndWETH` → 买家发起撮合，使用 WETH 购买
    
*   `matchAskWithTakerBid` → 买家发起撮合，使用指定币种(makerAsk.currency)购买
    
*   `matchBidWithTakerAsk` → 卖家发起撮合
    

读懂这些逻辑，我们就已经掌握了 LooksRare 合约的核心内容。

接下来，我们看看几个重要的内部函数。

#### \_transferFeesAndFunds

分发买家的款项（非 ETH 支付）

![分发买家的款项（非 ETH 支付）](https://storage.googleapis.com/papyrus_images/470e9116ed20c436419354d797491ddafa9494f983c4bc6866694dfd07c9b09f.png)

分发买家的款项（非 ETH 支付）

#### \_transferFeesAndFundsWithWETH

分发买家的款项（WETH 支付）

![分发买家的款项（WETH 支付）](https://storage.googleapis.com/papyrus_images/cbe9d7d477eef10ddb321ff20c28bf128d358fae2bc8e31a82a07e6ce46c57ab.png)

分发买家的款项（WETH 支付）

我们可以看到，上面两个函数的内容基本相同，主要逻辑都是对买家的款项进行了分发，计算了协议费用和版税费用，最后将剩余款项转给卖家。

还记得我们前面看到的 `MakerOrder` 中的 `minPercentageToAsk` 字段吗，当时看是不是有点迷茫，这个字段是什么意思？因为有版税和协议费用的存在，且它俩都是变量，可能卖家在挂单之后，各种费用的值被管理员修改了，那么在挂单的时候就需要设置一个最小可接受的值，如果最后盈利的数量小于该值，那么就不交易了，类似于 DEX 中滑点的概念。

注意到两个函数最大的区别就是转账这块，在非 ETH 函数中，使用的是 `safeTransferFrom`，而在 ETH 函数中，使用的是 `safeTransfer`。因为一个是 ERC20，一个是原生货币，后者在调用函数的同时就已经转入款项了。同时这也是为什么我们前面的入口函数那里，ETH 支付的函数需要对 `msg.value` 进行处理，而 ERC20 不需要这一步。

#### \_transferNonFungibleToken

转账 NFT

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

转账 NFT

由于目前 NFT 流行的标准有 ERC-721 和 ERC-1155，两者的转账方法略有不同。因此，这里会根据 NFT 合集对应的标准，选取相应的转账管理器来进行转账。转账管理器的内部逻辑其实很简单，我们后面再介绍，这里先着重于主逻辑。

#### \_validateOrder

校验订单信息

![校验订单信息](https://storage.googleapis.com/papyrus_images/7367469218c771cc735f8643b719b8fb07ff9644e014dfffb54a1a49a4a468cb.png)

校验订单信息

这里，先校验订单的 nonce 是否有效，我们最开始看到的两个关于 nonce 的数据结构可以用来验证。然后再根据 maker 的签名和 makerOrder 的哈希值来判断其是否为正确的订单信息，这里利用了 EIP-712 的相关内容，不熟悉的朋友可以看看我之前的写的这篇[文章](https://mirror.xyz/xyyme.eth/cJX3zqiiUg2dxB1nmbXbDcQ1DSdajHP5iNgBc6wEZz4)。

小结
--

到这里，所有的主逻辑我们就已经看完了，是不是还算比较简单。

我们先休息一下，没有完全看懂的朋友可以再多看两遍消化一下。这篇文章就先介绍到这里，看完这篇我们基本上就已经对 LooksRare 的主要逻辑了解了个大概了。剩下的合约基本上都是辅助合约了，例如各种管理器合约，我们放在下篇文章介绍。

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)*
