# OpenSea合约深度解析——atomicMatch_ 篇

By [Joohhnnn](https://paragraph.com/@johnnft) · 2022-04-10

---

很多朋友在Opensea上购买NFT时，会发现自己的钱包正在调用一个名为Atomic Match\_的方法，正好这段时间做的项目需要和Opensea交互，研究了一下Opensea的合约，今天就从

atomicMatch\_开始，分析一下Opensea的合约源码，希望能够帮到大家。

![](https://storage.googleapis.com/papyrus_images/8951c83fa59a861ed2f9dd4a0822be9151432b8c25784d0a96993a1cc30dc430.png)

Opensea交互流程简介
-------------

### 1.NFT拥有者上架NFT

当用户初次使用opensea上架NFT时，会被要求初始化钱包（”lnitialize your wallet”），其本质是创建一个代理合约，做为下一步授权（”Approve this item for sale”）的目标。最后一步为签名（签名的信息为配对参数信息，且保存到Opensea的中心化服务器中）。

![](https://storage.googleapis.com/papyrus_images/c565b2490c58b72f53efc1ffde9426ca54dc213b574b1fd01e67678b8f5c64b0.png)

![](https://storage.googleapis.com/papyrus_images/30435152a9f87d6d8e9fa041f742520a1fa955648cc14d15809a54ff99efd661.png)

### 2.购买NFT

2.1 buy now 模式

当buyer点击buy now 对已经list的订单进行购买时，首先在前端获取order.buy部分,同时在Opnesea数据库获取order.sell部分并将其加入缓存，封装后作为参数调用atomicMatch\_方法，在方法内部确认订单可用且匹配后，通过调用代理合约来实现transferfrom方法。

![](https://storage.googleapis.com/papyrus_images/5b63d7ca4695f8d270e01b6bec5e7176b47e2aaa14c84c7c5d981842a8176285.png)

2.2 make offer 模式

make offer同理

![](https://storage.googleapis.com/papyrus_images/ae2d8f6d8cc07bda304ae9a6851d22e91a6411b50d480e2a5b356cd4ab6a8ce7.png)

atomicMatch\_详解
---------------

可以看到，atomicMatch\_在其中起到至关重要的作用，现在就让我们来看看这个方法究竟实现了哪些功能

![](https://storage.googleapis.com/papyrus_images/aba37dbd9ad6aeae67da87e5b655beb008f8f2759493fb8c42a43499e573e54f.png)

可以看到它的参数很多，但其本质只是将order.sell和order.buy集合到了一起。

**atomicMatch的四个参数分别为（买方order参数合集，买方签名vrs，卖方order参数合集，卖方签名vrs）**

我们从Order和Sig切入：

order：order结构体包含了如交换合约，订单创建者，订单获取者等大量和交易有关的数据（因篇幅原因不全部展示，可以到[区块链浏览器](https://etherscan.io/address/0x7f268357a8c2552623316e2562d90e642bb538e5#code)中获取，下同）

![](https://storage.googleapis.com/papyrus_images/67ec78e8c959b530302b6b76ea6ccc10f72209106671c21ff8b1513ee0db1b62.png)

Order信息存储在Opnesea的中心化服务器中，可以通过API获取

![](https://storage.googleapis.com/papyrus_images/733344d3148565aa29bc170ecb1e1dd0218cea91b545c1dedc21248393248c6a.png)

Sig：Sig结构体就简单很多，其主要作用是为了验证签名。

![](https://storage.googleapis.com/papyrus_images/99e2916c9bf864b55ee41c35ae242a99d3b0e175a339099f546c9816a1f742c9.png)

### atomicMatch主体部分分为两部分，第一部分是验证，第二部分是调用代理完成交换。

**1.验证**

1.1验证order参数

![主要通过validateOrderParameters来验证](https://storage.googleapis.com/papyrus_images/f03b7613f0930b2a8749d21f23e4b666345def5a03863222d574d667f413ce6a.png)

主要通过validateOrderParameters来验证

在这两个条件判断中，Opense逻辑是这样的， 如果是buy now模式，即buyer交易的发起者，在这里对buyer进行订单参数校验，对seller进行签名校验 如果是make offer模式，即seller是交易的发起者，在这里对seller进行订单参数校验，对buyer进行签名校验

![](https://storage.googleapis.com/papyrus_images/fcfc9bc9a6e1286bc385ae353c14efb038c23e65b08822c8337562d735e3a0ce.png)

validateOrderParameters 主要从四个方面来验证

1.当前合约是否为规定的交换合约

2.订单创建者地址是否为空

3.订单价格是否固定+是否在有效期内

4.判断费率是否正常

1.2 验证后通过orderCanMatch判断order.sell和order.buy的信息是否匹配

![比较数据是否一致](https://storage.googleapis.com/papyrus_images/97590561e5b528eeef276c949df1c4453a690081db371552289ecfd6e1575e8c.png)

比较数据是否一致

1.3验证calldate是否匹配

![](https://storage.googleapis.com/papyrus_images/e2f501aa81044df47e554527505e8f7e02f246874fc2363bd1578918db10a47c.png)

### 2转移NFT

在讲解代码前，先从流程见一下大概原理，方便大家理解。

首先获取由NFT拥有者创建的[代理合约](https://etherscan.io/address/0x1a1b846ba1f553915d61d6bcc73b013dd2a67ea6/advanced#code)（即获得NFT授权的合约）的实例，调用`代理合约`的[implement合约](https://etherscan.io/address/0xf9e266af4bca5890e2781812cc6a6e89495a79f2)的`proxy`方法，`proxy`方法指向并调用[target](https://etherscan.io/address/0xbaf2127b49fc93cbca6269fade0f7f31df4c88a7#code)合约，由`target`合约进行最后校验与token的转移。

2.1 获取`target`地址

![](https://storage.googleapis.com/papyrus_images/c1c5786efce7cab738180b6956b53f353eca4b7c21eb3aa8d57506f7bcf6cb37.png)

2.2 获取`代理合约`实例

![](https://storage.googleapis.com/papyrus_images/6bf95f1e6ba1fd2c6f7b9885caa031d289ab518fa044e1d054cff50f0a02e774.png)

![](https://storage.googleapis.com/papyrus_images/3ff32fb2e027e24b0e3cad94e6eb4471d1567ec882bd7fb7f4c891f04edddcbb.png)

2.3 获取包含`implement` `proxy`方法的`代理合约`实例

![](https://storage.googleapis.com/papyrus_images/541a57ad660fc2c031c2c70e37e7d2e4dd7f46758e1484225da6b343799b8745.png)

![](https://storage.googleapis.com/papyrus_images/322e8690aef85f18dd9939ac8322618a825b941dbca1a10f2a7918693170b0fb.png)

在这里要强调一下，有的朋友可能会有疑问，为什么这里明明是`implement` 的contract，为什么要传入`代理合约`的地址？ 这是因为`implement`合约并没有获取NFT的授权。又有朋友有疑问了，代理合约没有写transferFrom方法，或者调用方法，他是怎么做到去调用transferFrom的呢。_其实代理合约合约还真的写了，只不过在区块链浏览器上没办法显示出来。_

![](https://storage.googleapis.com/papyrus_images/e56b3fec43d01fced7927e48f4670b8da8c6cdc1ed97fa059d6aa6dd720ab984.png)

![](https://storage.googleapis.com/papyrus_images/a6064d61a4989e76169a6dde8a22f592631201d250367fed54299c7d4a7a939f.png)

这里运用了内联汇编的方法，调用implement的proxy方法。

新版的完整区块链浏览器显示，应该是这样的

![](https://storage.googleapis.com/papyrus_images/32bcae13a040968b3c692a16a1577a95ebf3b1035625544d0ef8cd30993cb0e1.png)

2.4将该签名的状态锁定

![](https://storage.googleapis.com/papyrus_images/e90417b218dd923b0b171054f611ef44b8ee0d4d3e001568bbe82622ba6d4838.png)

2.5转移费用

![](https://storage.googleapis.com/papyrus_images/cef033e4a7cf68a3285505ef8df40b90f82329e02e255bd2d49e730330f8178e.png)

2.6验证implement的地址和转移NFT`proxy`方法指向并调用[target](https://etherscan.io/address/0xbaf2127b49fc93cbca6269fade0f7f31df4c88a7#code)合约，由`target`合约进行最后校验与token的转移。

![](https://storage.googleapis.com/papyrus_images/76a6763852b0324afafe7c0042fad27750a94f5b791c4f454a40d40e8d353609.png)

proxy通过对contracts（msg.sender）的调用来判断目前调用该方法的地址是否为被注册为可调用地址

![](https://storage.googleapis.com/papyrus_images/adaf9d181061eb06f7ef06c8eba4e19bef11069beb2b738f5ac9503973a1ab19.png)

### 转移完NFT后提交event。 这就是整个atomicMatch\_执行流程。

**更多有关Opensea的内容，可能会在下期更新。**

discord：johnn#0104

---

*Originally published on [Joohhnnn](https://paragraph.com/@johnnft/opensea-atomicmatch)*
