ERC721 Wrapper

The ERC721 Wrapper contract allows for the wrapping of ERC721, and for the burning of Item-wrapped ERC721 to retrieve the original tokens.

Wrapped Item name and symbol

A wrapped ERC721 Item has the following metadata:

  • Name -> "ERC721 token wrapped name" + item

  • Symbol -> i"ERC721 token wrapped symbol"

Example

Wrapped Gods Unchained card:

  • name -> Gods Unchained Cards item

  • symbol -> iCARD

Wrapped CryptoKitties:

  • name -> CryptoKitties item

  • symbol -> iCK

Decimals

All Item-wrapped ERC721s always have 18 decimals, both as ERC1155 (using the Item Main Interface) and as ERC20 (using the Item Interoperable Interface).

Example

Wrapping 1 Bored Ape (which has no decimals) becomes 1000000000000000000 (1e18) wrapped Item Bored Ape.

Uniqueness

For the Item standard, there is a specific way to handle NFTs with a limited supply of one:

  • You can unwrap a 721 burning an amount of its wrapped Item between 0.51 and 1 in 18 decimals. If the total supply of the wrapped Item ranges from 0 to 0.51 no one can unwrap that 721.

  • When you wrap again that 721 token, you obtain 1e18-Wrapped Item total supply

In this way, we can guarantee that the original NFT will still be accessible and function as a unique token, but not be inflated.

Example

Unwrap:

1) 721 wrapped: Bored Ape id 1122

Bored Ape (id 1122) Wrapped Item totalSupply: 1e18

A wrapped Bored Ape Item holder can unwrap the Bored Ape (id 1122) burning at least 0.51e18 Bored Ape wrapped Items

2)

721 wrapped: Bored Ape id 2233 unreserved

Bored Ape (id 2233) Wrapped Item totalSupply: 0.8e18

A wrapped Bored Ape Item holder can unwrap the Bored Ape (id 2233) burning at least 0.51e18 Bored Ape wrapped Items

Rewrap:

1)

Bored Ape (id 1122) Wrapped Item totalSupply: 0.3e18

When someone wrap again the Bored Ape (id 1122) he obtains 0.7e18 Bored Ape Wrapped Item

2)

Bored Ape (id 2233) Wrapped Item totalSupply: 0

When someone wrap again the Bored Ape (id 2233) he obtains 1e18 Bored Ape Wrapped Item

Wrap an ERC721

Before wrapping your ERC721, make sure your token follows the ERC721 standard. In particular, make sure that your token:

  • integrates the standard IERC721 interface

  • has 0 decimals

  • has a transferFrom/safeTransferFrom function in order to wrap the token in a Wrapped Item

  • has a transferFrom/safeTransferFrom/transfer function in order to unwrap the Wrapped Item and get back the original 721 token

You can wrap your 721s in 2 ways:

  1. Using mintItems function -> only for tokens that have transferFrom

  2. By sending the token to the contract that implements onERC721Received using the safeTransferFrom

mintItems

To wrap an ERC721 using the mintItems function, the 721 token must have the transferFrom function. If the 721 token does not have transferFrom you can still wrap it by sending it with safeTransferFrom and so using the onERC721Received.

 function mintItems(CreateItem[] calldata createItemsInput) virtual override(Item, ItemProjection) external returns(uint256[] memory itemIds) {

The function takes as input:

  • struct CreateItem -> data for wrapping the ERC721

For each ERC721 you're wrapping, a CreateItem must be passed as follows:

  • struct Header -> composed of address host, string name, string symbol and string uri pass empty. These parameters are automatically populated by the contract. Look here for more info

  • bytes32 collection -> encoded ERC721 address of the token being wrapped

  • uint256 id -> id of original 721 token you're wrapping

  • address[] accounts -> address receiver of the Wrapped Item.

  • uint256[] amounts -> amounts being wrapped

The amounts[] array can specify the different amounts of the created wrapped Item to send to the receivers' addresses represented by the accounts[] array. Each position of the amounts array corresponds to the respective position of the accounts array and so the amounts[] and accounts[] arrays must have the same length. If an address in the accounts[] is passed as address(0), it automatically corresponds to the msg.sender address.

The amount(s) value(s) must be expressed in 18 decimals. It must be 1e18 if the current Wrapped Item totalSupply is 0, otherwise it must be 1e18-Wrapped Item total supply.

The output of the function represents the id(s) of the newly created wrapped Item(s).

Using the mintItems functions, different ERC721 tokens can be wrapped in a single transaction since you can pass multiple CreateItem structs.

onERC721Received

You can also use the safeTransferFrom sending the token to the Wrapper ERC721 contract invoking the onERC721Received function.

The data parameter of the safeTransferFrom function must contain an encoded value that represents two parameters:

  • Uint256[] values

  • Address[] receivers

The values[] array can specify different amounts of the created Item, with each amount to be sent to the receiver addresses in the accounts[] array; the positions of the amount and the receiver address must correspond.

The value(s) amount(s) must be expressed in 18 decimals, because they represent the amounts of the to-be-minted wrapped Items. It must be 1e18 if the current Wrapped Item totalSupply is 0, otherwise it must be 1e18-Wrapped Item total supply.

values and receivers work in the same way of amounts and accounts parameters of the mintItems function.

Unwrap Items

Burn

function burn(address account, uint256 itemId, uint256 amount, bytes memory data) override(Item, ItemProjection) public

The burn function can be used to burn a wrapped ERC821 Item amount and retrieve the relative amount of the original ERC721.

The function takes as input:

  • address account -> represents the address that holds the Item to burn. The address account can correspond to the msg.sender or not if the burn function is called from an approved operator address.

  • uint256 itemId -> represents the id of the wrapped Item to burn

  • uint256 amount ->represents the wrapped Item amount to burn

  • bytes data -> it is an encoded value and represents six parameters:

    • tokenAddress, the address of the original ERC721 token to get back

    • tokenId, the id of the original ERC721 token to get back

    • receiver, the address that will receive the original ERC721 after the burn. Pass address(0) to set receiver as msg.sender. It can even be an address different from the msg.sender

    • payload, an optional payload that can be executed with the safeTransferFrom function

    • safe, a boolean value that represents whether safeTransferFrom will be executed (true) or transferFrom/transfer will be executed (false)

    • withData, a boolean value that represents whether safeTransferFrom will be executed with the additional payload (true) or without one (false). If safe is false, transferFrom without a payload will be executed, regardless of how withData is populated.

(address tokenAddress, uint256 tokenId, address receiver, bytes memory payload, bool safe, bool withData) = abi.decode(data, (address, uint256, address, bytes, bool, bool));

Burn Batch

function burnBatch(address account, uint256[] calldata itemIds, uint256[] calldata amounts, bytes memory data) override(Item, ItemProjection) public

The burnBatch function can be used to burn multiple wrapped ERC721 Items amounts and retrieve the relative amounts of the original ERC721 tokens.

The function parameters are the same of the burn function with the following differences:

  • uint256[] itemId and uint256[] amount-> are arrays of values since you can unwrap multiple tokens at once

  • bytes data ->The data parameter in bytes format is an encoded value and represents a bytes[] (one for each Item involved in the operation) containing the six parameters explained above in the burn section.

Last updated