Devcon2, an Ethereum conference for researchers and developers, took place in Shanghai, China from September 19-21, 2016. In addition to hearing about the latest developments in the burgeoning Ethereum world, attendees had the opportunity to participate in one of the first NFT experiments.
On the first morning of the conference, Piper Merriam deployed a contract for the Devcon2 token. Over the course of the conference, people were given the opportunity to receive a token upon providing a public address and an identifying string. After three days, minting was automatically disabled, and a total of 231 tokens were held in 231 distinct addresses.
This early experiment paved the way for what would come to be known as the Proof of Attendance Protocol, or POAP.
Nonfungibility and ERC20
An interesting aspect of the Devcon2 token is that it is ERC20 compliant despite being nonfungible. This is achieved by enforcing certain constraints:
- The balance of an address serves as the token ID.
- Transfers are not allowed into an address with a nonzero balance.
The system was creative but also difficult to work with. In fact, two months after Devcon2, Piper deployed a revised token contract and instructed holders on how to upgrade their tokens.
Only 40 or so holders opted to upgrade. Those who did ended up with ownership in both the original and the revised contracts. The project seemed to fizzle out after that. In my opinion, the original token is more of a collectors item, so I decided to focus on that one.
I wrote an ERC-721 wrapper contract, so that holders of the original tokens can display and trade them as collectibles on the NFT marketplaces. You can view the tokens that have been wrapped on OpenSea.
Instructions for wrapping and unwrapping are as follows.
Suppose you want to wrap a Devcon2 token that is held in address A. Further, let’s call the address of the wrapper contract W.
Step 1: In the original contract, call balanceOf(A) to get the token ID. Let’s call this ID i.
Step 2: In the original contract, call approve(W, i). This gives the wrapper permission to transfer the token. (Note that there are two approve functions. You should use the one that takes a uint256 as its second parameter.)
Step 3: In the wrapper contract, call Wrap() to create a box for the token and have it be placed in the box. In exchange, you will be issued an ERC-721 token.
Now, suppose that you hold the ERC-721 version of token i in address A, and you want to exchange it for the original token.
Step 1: Call isTokenOwner(A) in the original contract to make sure you don’t already hold an original token in that address. (Only one original token is allowed per address.)
Step 2: Call Unwrap(i) in the wrapper contract. This causes the ERC-721 token to be burned, and the corresponding original token will be transferred from its box to your address.
A Word of Warning
As usual, I tried my best to write a flawless wrapper contract, but I can provide no guarantees. Dealing with old projects and wrappers is for advanced users only. Proceed at your own risk!