# MyPunks技术分享-可定制化的NFT

By [Xing](https://paragraph.com/@xing824) · 2022-03-10

---

最近在CryptoApes的DC里看见朋友分享的[MyPunks](https://twitter.com/MYPUNKofficial)项目，该项目定位是NFT2.0，即可定制化的NFT。因为比较新颖，抱着尝鲜的态度所以我就入坑了。

该项目分为两个NFT系列，一个是MyPunks Face（以下简称Face），一个是MyPunks Item（以下简称Item，就是眼镜、头发、口红、衣服等各种traits），貌似两个系列的所有元素均为Crypto Punks的设计元素。

鄙人本着对Crypto Punks的热爱，并且对该项目如何实现可定制化NFT这一目标十分好奇，故关注并购买了该项目的两个系列NFT，并自己定制的两个MyPunks。本文记录并分享一下该项目从技术上是如何实现定制NFT这一目标的。

![中年大叔style](https://storage.googleapis.com/papyrus_images/7bc0e95534914da99ff286fe1b9cef449ff29474c433d77a4f6b39b7b3d18a10.png)

中年大叔style

![东北二人转Style](https://storage.googleapis.com/papyrus_images/ee44a7c964ffa8419eff9450fff647a2ed7a4417f9ef48b45ecb90de8eab91b1.png)

东北二人转Style

NFT的定制过程
========

首先你需要购买至少各一个Face和Item。Face当初是每个地址可以免费mint 2个，而1个Item的公售价格是0.035E，截止到目前为止，Face已经全部mint完了，而Item还未mint完（就目前行情来说项目方可能会考虑降价）。

在拥有了Face和Item之后，即可登陆MyPunks[官网定制页面](https://mypunks.xyz/app/equip)进行定制，整个定制过程你需要做的就是：

1.  选择一个Face
    
2.  选择最多七个Item
    
3.  确认效果后进行确认即可（确认操作需要上链，上链之后发生什么见后文）
    

![定制界面](https://storage.googleapis.com/papyrus_images/b994885cd5e3cc890bad5ee17ef9d6d719805be57983a2104ad51097629bfa87.png)

定制界面

这里需要说明几点：

*   Face NFT是一个独立合约，Item NFT也是一个独立合约，所以两者都可以独立买卖
    
*   定制好的NFT实际上还是那个Face NFT，只不过将Item与Face绑定在一起了
    
*   定制好NFT后，你在OpenSea或者钱包里将看不见你那些已被使用了的Item，但你能看见这些Item在你的Face NFT上
    
*   定制好的NFT可以转移和卖出，但是卖出后已经装饰的Item也会一并转移，所以如果你准备给你的Face装饰多个Item的话，一定要挂高一些的价格
    
*   定制好的NFT也可以拆分（拆分也是一个上链操作），拆分后你又能在OpenSea或者钱包里看见你的Item NFT，然后根据自己的喜好重新组装
    

如何实现
====

定制NFT
-----

上文所述用Item去装饰Face这个操作需要上链，而整个上链过程从[Item的合约](https://etherscan.io/address/0x117c2e95aa1b1ead9db1e39ce494d9776c72a254#code)来看，就是将Item NFT转到Face NFT合约地址的一个过程。

![Item合约片段](https://storage.googleapis.com/papyrus_images/a8c0db1a5707201a75b2880ee34693c766fd796bb1709d73983499a673191dba.png)

Item合约片段

当你用Item去装饰Face的时候就是调用上图中Item合约里的stakeItem这个方法 ，该方法会将传入的所有Item NFT转移到Face这个合约中去（相当于质押），这些Item的Owner将会变成Face的合约地址，所以你从你的钱包里将看不到这些Item。

当调用Item合约中的safeTransferFrom方法发送Item到Face合约地址时，会去调用Face合约中的onERC721Received这个方法，该方法触发了Face合约去记录被装饰的Face都绑定了哪些Items。

![Face合约片段](https://storage.googleapis.com/papyrus_images/c1daf9cdb6af5e83a1098efb367ea81cacfe7c3186aa6f171c0bdfb5e4ae6f1a.png)

Face合约片段

上图中“items”这个map变量就记录了faceId对应绑定的itemId列表。这个“items”非常重要，相当于Face合约中不仅仅记录了你拥有哪些Face，并且还可以根据你拥有的Face得到你拥有了哪些Item。Item是与Face绑定的，这也就是为什么当你卖出或者转移了Face之后，所有已经绑定了的Item也会跟着被转移的原因。

以上过程就完成了NFT的定制：将Item从你的钱包转移至Face合约地址，同时在Face合约中记录该Face绑定了哪些Item。

定制NFT的Metadata
--------------

之前我们见到的大多数NFT的Metadata信息基本上都是存在IPFS上的（关于Metadata信息的科普建议看看鄙人[这篇文章](https://mirror.xyz/xing824.eth/O3hpbibMf9vLNz6p80YUriU8Bf3bEaJWvRL49FGAgAc)），因为所有的Metadata信息都预先知道，所以提前制作好上传到IPFS上，与此同时项目方一般会在合约里保留设置baseURI的权利以实现开盲盒等操作。

但对于MyPunks这种需要根据用户定制动态生成Metadata的情况，项目方的解决方案是采用HTTP方式通过中心化服务器生成，也就是说Face和Item的所属权上链，而定制NFT的Medata信息采用中心化方式动态返回。

![调用tokenURI方法](https://storage.googleapis.com/papyrus_images/f54f271124449d6a5d82fe561ca7e76033877adda9da9b2e13ad1481312fa26e.png)

调用tokenURI方法

如图所示，调用Face合约查询1172这个Face的tokenURI返回的是一个HTTP的API地址，MyPunks的中心化服务器可以根据链上1172这个Face绑定了哪些Item动态地返回相应的Metadata信息，从而让用户从OpenSea可以看到对应的图片及属性。

![OpenSea展示该Face NFT的Metadata信息](https://storage.googleapis.com/papyrus_images/cbc39266e927d4e9522f75fb5646c7fa7c149d78148495b0391a280e6ff5bda9.png)

OpenSea展示该Face NFT的Metadata信息

同时Face合约还提供了修改名字方法，除了可以定制自己NFT的样子之外，你还可以给自己的NFT定制专有的名字。

实际上鄙人不太喜欢HTTP方式去存储NFT的Metadata，因为这样项目方可以更容易且毫无察觉地修改Metadata。目前大多数NFT合约几乎都用IPFS，虽然去中心化存储不可以修改已存储的Metadata，但大多NFT合约也都会有留有Admin权限，只要Admin操作一次setBaseURI实际上也可以修改NFT指向的Metadta信息，从而修改NFT的Metadata（如果修改了可以在链上查到）。

MyPunks这个项目为了实现可定制化的NFT，将NFT的所有权上链，而metadata采用服务器动态生成的方式，鄙人认为还是可以接受。鄙人一贯的观点是，完全去中心化和完全中心化都是偏激的，重要的是需要达成的目标，具体实现目标的方式可以灵活调整。

如果非要使用去中心化方式存储，鄙人能想到的方案就是穷尽所有Face+Item组合的可能，将所有组合的metadata放到IPFS上，然后合约中根据Face+Item的组合去拼IPFS的tokenURI拿到Metadata，但是各种各样组合的数量实在是太多了。

抑或是像鄙人之前[这个文章中](https://mirror.xyz/xing824.eth/OlvKvj3k0M_g7d8SgmNdMYlthYI3LYWqdtsK1IX3mTM)说Pak的Censored项目方案一样，将Face和Item的图片数据存储到链上，然后根据Face+Item的组合在合约里动态地去拼装一个SVG图片，这个难度实际上也不小，同时存储的成本费用也不低。。。

这里同时也希望下一个定制化NFT的项目能有更好的Metadata动态生成的解决方案。

拆分NFT
-----

定制好的NFT因为有了上述的“items”变量存在，因此拆分也就变得容易了。拆分的过程实际上就是根据“items”存储的Face和Item的绑定信息，将Item从Face的合约地址转回到该Face的Owner钱包地址去。

![Face合约中的拆分代码](https://storage.googleapis.com/papyrus_images/82f75fd68aa5d0d3d250d9526bd374d6746c5c881bc700e2c3c5d240f61fcdce.png)

Face合约中的拆分代码

拆分是调用[Face合约](https://etherscan.io/address/0x327f25b05a291817fd10bab26053f0eb66c16158#readContract)中的withdraw方法，在维护好“items”这个变量状态之后，最终Item的转移实际上又是去调用的是[Item合约](https://etherscan.io/address/0x117c2e95aa1b1ead9db1e39ce494d9776c72a254#code)的“unstakeItem”方法

![Item合约中的解除质押代码](https://storage.googleapis.com/papyrus_images/cb9646c0ff5bb3e6e73b750969297d83bdbad442d55a89c53937644c42d8e686.png)

Item合约中的解除质押代码

上图是[Item合约](https://etherscan.io/address/0x117c2e95aa1b1ead9db1e39ce494d9776c72a254#code)中“unstakeItem”方法，该方法就是将这些Item转到这个Face的owner钱包地址去。

所以拆分后，你就可以在你的钱包地址里重新看见这些Item，并且开始新的定制再创作了。同时如果市场上没有你喜欢的Item出售，你也可以考虑购买一个包含你喜欢Item的MyPunk，买来整个MyPunks将其拆分，它上面的所有Item也就都属于你了。

最后
==

目前在NFT熊市，且项目同质化非常严重的市场环境下，MyPunks的创新和探索是值得鼓励和认可的。但目前看来市场的接受度并不是太高，很便宜的价格、很低的交易量，并且连Item都没mint完。即便如此鄙人还是觉得需要各个NFT项目方从更多方面去突破创新，来丰富NFT的生态以及扩宽NFT的边界，而不是一味地在10K形式的PFP上内卷。

利益相关：MyPunks这个项目比较新颖，所以鄙人购买了一些，已被深深套牢，虽然价格不贵钱也不多，但建议我的读者朋友们就别入坑了。如果是不差钱的大佬想尝试玩玩，也欢迎为鄙人接盘，哈哈。

---

*Originally published on [Xing](https://paragraph.com/@xing824/mypunks-nft)*
