Deck ERC721

The ERC721 Deck contract allows for the wrapping of ERC721s as Items, and for the burning of Deck-items ERC721s to retrieve the original tokens.

Wrap

Before wrapping an ERC721 token as a Deck Item, make sure it is a standard ERC721. To be standard, it must:

  • integrate the standard IERC721 interface

  • have 0 decimals

  • have a transferFrom/safeTransferFrom function that allows for it to be wrapped as a Deck Item

  • have a transferFrom/safeTransferFrom/transfer function that allows it to be retrieved by wrapping a Deck Item

An ERC721 can be wrapped in two ways:

  1. By using the mintItems function (only for ERC721s that have a transferFrom function)

  2. By using the safeTransferFrom function to send the token to the ERC721 Deck Wrapper contract, which implements onERC721Received.

When wrapped, all ERC721s of the same token address generate the same shared Deck Item id. So, for example, if you wrap two Bored Apes, 2e18 Bored Ape Deck Items are minted, and they share the same Deck Item id.

mintItems

function mintItems(CreateItem[] calldata createItemsInput, bool[] calldata reserveArray) external returns(uint256[] memory itemIds);

This function has two inputs:

  • struct CreateItem -> data for wrapping the ERC721

  • bool[] reserveArrays -> boolean value that expresses whether the wrap is to be reserved (true) or unreserved (false). More on this below.

The lengths of CreateItem and reserveArrays must be the same; each CreateItem struct must correspond to its sequentially equivalent value in reserveArrays.

For each ERC721 being wrapped, a CreateItem struct must be passed as follows:

  • struct Header -> composed of address host, string name, string symbol and string uri. Pass this as empty; these parameters are automatically populated by the contract. See here for more info.

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

  • uint256 id -> id of the original ERC721 token being wrapped.

  • address[] accounts -> receiver address(es) of the Deck Item. Pass as address(0) to set as msg.sender, or pass as any other address(es).

  • uint256[] amounts -> 1e18 (i.e. 100000000000000000000000000).

Regarding accounts and amounts, 1e18 can be split to multiple receivers. The sum must be 1e18, and the accounts array and amounts lengths must be equal; each accounts value must correspond to its sequentially equivalent value in amounts.

Example

2 Bored Apes are wrapped as Deck Items; the first reserved, the second unreserved.

CreateItem1

  • Header -> - host: 0x00.. , - name: " ", symbol: " ", uri: " "

  • collection -> 0x000000000000000000000000bc4ca0eda7647a8ab7c2061c2e118a18a936f13d

  • id -> 1630

  • accounts -> 0x998093DF3d61dDDae8F4a84e02e12c78b3751cC4

  • amounts -> 100000000000000000000000000

CreateItem2:

  • Header -> - host: 0x00.. , - name: " ", symbol: " ", uri: " "

  • collection -> 0x000000000000000000000000bc4ca0eda7647a8ab7c2061c2e118a18a936f13d

  • id -> 6724

  • accounts -> 0x82465CB46506563f66285f18da7adD332e813A42

  • amounts -> 100000000000000000000000000

reserveArray: [true, false]

Using the mintItems function, multiple ERC721s of different token addresses can be wrapped in a single transaction by passing multiple CreateItem structs at once.

The mintItems function returns the created itemIds.

onERC721Received

An ERC721 can also be wrapped by using the safeTransferFrom function to send it to the ERC721 Deck Wrapper contract, which calls the onERC721Received function.

The data parameter of safeTransferFrom must contain the following encoded parameters:

  • Uint256[] values -> represents the amount of Deck Items (in 18 decimals) to send to each receiver address.

  • Address[] receivers -> addresses that will receive the Deck Item.

The lengths of values[] and receivers[] must be the same; each value in values[] must correspond to its sequentially equivalent value in receivers[].

  • Bool reserve -> boolean value that expresses whether the token wrap must be reserved (true) or unreserved (false). More on this below.

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

Example:

1 Gods Unchained card (id 81046035) is sent to be wrapped as a Deck Item with a reservation to the ERC721 Deck Wrapper contract, using safeTransferFrom with the following encoded data:

  • Uint256[] values -> 100000000000000000000000000

  • Address[] receivers -> 0x82465CB46506563f66285f18da7adD332e813A42

  • Bool reserve -> true

Reserve

When an ERC721 is wrapped as a Deck Item with a reservation, only the address that wrapped it (i.e. the msg.sender of the mintItems/safeTransferFrom function) can unwrap the Deck Item and retrieve it for the following 10 days (in blocks). A reservation is for a single ERC721 token.

Each reservation (ReserveData) corresponds to a struct:

struct ReserveData {
    address unwrapper;
    uint256 timeout;
}
  • address unwrapper -> msg.sender of the mintItems/safeTransferFrom function.

  • uint256 timeout -> blocks for which the token is reserved. Equal to block.number + reserveTimeInBlocks, where reserveTimeInBlocks is the number of blocks that are estimated to correspond to 10 days.

If, at any time during the reservation period, the unwrapper address transfers the Deck Item to another account, that account will be unable to unwrap it until the end of the 10 day reservation period, at which point it becomes unreserved and can be unwrapped by anyone.

Unlock Reservation A reservation can be ended without having to unwrap the token, by using the unlockReserves function:

function unlockReserves(address[] calldata tokenAddresses, uint256[] calldata tokenIds) external;
  • address[] tokenAddress -> address of the original ERC721 to unlock.

  • uint256[] tokenIds -> id of the original ERC721 to unlock.

unlockReserves can be used to unlock multiple reservations at once.

Unwrap

The unwrapping of Deck Items to retrieve the wrapped ERC721s can be done either in single mode, by using the burn function, or in batch mode, by using the burnBatch function.

These functions can be called by the Deck Item holder or by an approved operator address.

Burn

function burn(address account, uint256 itemId, uint256 amount, bytes memory data) override(Item, ItemProjection) public
  • address account -> address of the Deck Item holder.

  • uint256 itemId -> id of the Deck Item to burn.

  • uint256 amount -> amount of the Deck Item to burn.

  • bytes data -> data in bytes format that must contain the following encoded parameters:

- address tokenAddress -> token address of the wrapped ERC721.

- uint256 tokenId -> id of the wrapped ERC721.

- address receiver -> address that will receive the wrapped ERC721. Pass as address(0) to set as msg.sender, or pass as another address.

- bytes payload -> eventual optional data to perform a safeTransferFrom.

- bool safe -> boolean parameter to perform either a safeTransferFrom (true) or a transferFrom (false).

- bool withData -> boolean parameter to perform a safeTransferFrom either with data (true) or without data (false). In the first case, the payload is executed as data.

Example:

1 (in 18 decimals) Bored Ape Deck Item is burned to retrieve Bored Ape 1630.

  • account -> 0x998093DF3d61dDDae8F4a84e02e12c78b3751cC4

  • itemId -> id of the Bored Ape Deck Item; for example, 553791398095120659341456634

  • amount -> 100000000000000000000000000

  • data -> data = web3.eth.abi.encodeParameters( ["address", "uint256", "address", "bytes", "bool", "bool"], ["0xbc4ca0eda7647a8ab7c2061c2e118a18a936f13d", "1630", "0x998093DF3d61dDDae8F4a84e02e12c78b3751cC4", "0x", false, false] );

burnBatch

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

Using burnBatch, you can unwrap multiple Deck Items (even if they are of different Decks) at once. burnBatch can be called by the Deck Item holder or by an approved operator address.

The parameters are the same as those of the burn function, but with the following differences:

  • uint256[] itemId and uint256[] amount-> arrays of values, allowing you to unwrap multiple tokens at once.

  • bytes data ->the data parameter in bytes format is an encoded value that represents a bytes[] (one for each Item involved in the operation) containing the six parameters explained above in the burn section (tokenAddress, tokenId, receiver, payload, safe and withData).

Deck Items With a Total Supply <=1

Unwrap

If the total supply of a Deck Item ranges from 0.51 to 1 (in 18 decimals), the ERC721 can be unwrapped by burning an amount of Deck Items between 0.51 and 1 in 18 decimals.

This is contrast to the typical situation where the total supply >1, in which case 1e18 Deck Items must always be burned for each ERC721 to unwrap.

Examples:

1) Wrapped ERC721 Bored Ape id 1122 (unreserved)

Bored Ape Deck Items totalSupply 0.9e18

A holder of the token's Deck Item can unwrap the Bored Ape (id 1122) by burning at least 0.51e18 of the Deck Item.

2)

Wrapped ERC721 Bored Ape id1122, Bored Ape id 2233 (unreserved)

Bored Ape Deck Items totalSupply 0.6e18

A holder of the token's Deck Item can unwrap one of the two Bored Apes by burning at least 0.51e18 of the Deck Item.

If the total supply of a Deck Item ranges from 0 to 0.51, no one can unwrap the ERC721, because the Deck Item's totalSupply is <0.51.

Wrap

When you're going to wrap an ERC721 as a Deck Item and the Deck Item totalSupply is <1, 1e18-Deck Item total supply is obtained, and that amount must be passed in the amounts parameter of the mintItems/safeTransferFrom function when the ERC721 is wrapped again.

Examples:

1)

Bored Ape Deck Items totalSupply 0.3e18

When you wrap your Bored Ape, you obtain 0.7e18 of a Bored Ape Deck Item, and must pass 0.7e18 as amounts parameter of mintItems/safeTransferFrom.

2)

Bored Ape Deck Items totalSupply 0.1e18

When you wrap your Bored Ape, you obtain 0.9e18 of a Bored Ape Deck Item, and must pass 0.9e18 as amounts parameter of mintItems/safeTransferFrom.

Why Could a Deck Item's Total Supply Be <=1?

There are two main reasons.

  1. An address is either the first to wrap or the last to unwrap an ERC721 as a Deck Item, and as a result the Deck Item's totalSupply is equal to 1e18.

  2. Holders of a Deck Item burned some of them using the burn function of the Interoperable Item Interface (ERC20 face of the Item). Recall that an Item has two faces, allowing it to work simultaneously as an ERC1155 (using its Main Interface) and as an ERC20 (using its Interoperable Interface).

Last updated