Skip to content

Create an ERC721 contract

In this tutorial we are going to implement a subset of the functionality of an ERC721 contract in etch.

We will be using UInt256 for identifiers and the SHA256() function to generate the identifiers of the initial tokens.

We will need two records: an Address stating which tokens an address holds and a token record keeping track of the owner of the token.

For the first of these tasks, we will use the State object in etch, and for the second we will use ShardedState.

Initialisation function

Assuming that we have defined an owner and a total_supply, the initialise function will do three things:

  1. Generate a list of token ids.
  2. Create a record of each token owner.
  3. Create a record of the tokens that an owner has.

The dual relationship makes lookups efficient, but comes at the price of twice the book keeping.

First, create the list of token ids:

    // Genereating tokens
    var token_id = UInt256("hello world");

    for(i in 0:tokens.count())

        var hasher = SHA256();
        token_id =;
        tokens[i] = token_id;


Next, assign an owner:

    // Assigning owner
    var owner_state = ShardedState< Address >("tokens.owner");

    for(i in 0:tokens.count())

        var tid = tokens[i];
        owner_state.set(toString(tid), owner);


Finally, store the list of tokens on the creator's address:

    var objects_state = State< Array< UInt256 > >(owner);

    // Storing the tokens on the owners address


In this section we will focus on the functions which implement a wallet overview and token details view, namely balanceOf(owner: Address) : UInt256 and ownerOf(token_id: UInt256) : Address.

Both of these functions are short and easy to implement.

First, we make it possible to query the balance:

function balanceOf(owner: Address) : UInt256

    var objects_state = State< Array< UInt256 > >(owner);
    var tokens = objects_state.get( Array< UInt256 >(0) );
    var ret = UInt256( toUInt64(tokens.count()) );

    return ret;


Next, we make it possible to query the token owner:

function ownerOf(token_id: UInt256) : Address

    var owner_state = ShardedState< Address >("tokens.owner");
    return owner_state.get(toString(token_id)); 


With these two query functions, it is possible to implement an ERC721 wallet on top of the smart ledger.

We can also make several optimisations for these functions. For instance, by storing the number of tokens separately, we would not have to deserialise the full array.


The standard ERC721 contract has a number of different functions for transferring funds from one party to another. We will implement just one of these; they are all essentially variations of the same mechanism with more or less error checking built into them.

Implement a single transfer function:

function transferFrom(from: Address, to: Address, token_id: UInt256)

      panic("Invalid signature from owner.");

    var owner_state = ShardedState< Address >("tokens.owner");
    var owner = owner_state.get(toString(token_id));

    if(owner != from)
      panic("Owner does not actually own the token");

    var from_state   = State< Array< UInt256 > >(from);
    var from_objects = from_state.get( Array< UInt256 >(0) );
    var found = false;
    var position : Int32;

    for(i in 0:from_objects.count())
      var tid = from_objects[i];
      if(tid == token_id)
          panic("Contract broken - token is only supposed be represented once.");

        found = true;
        position = i;

      panic("Contract is fundamentally broken - owner has not been updated correctly");

    from_objects[position] = from_objects[from_objects.count() - 1];

    var to_state   = State< Array< UInt256 > >(to);
    var to_objects = to_state.get( Array< UInt256 >(0) );

    // updating sender

    // Updating receiver

    // Updating owner
    owner = to;
    owner_state.set(toString(token_id), owner);


The above implementation requires the sender to sign the transaction, but can be extended to also requiring the receiver to sign as well.

The full contract can be found here.