Skip to main content

Create a UTXO-based token system

caution

This example dapp may be deprecated. Thus, it may not function correctly with the latest versions of postchain, rell, and postchain-client.

As an exercise, we can also implement a Bitcoin-style token system.

We first define an unspent transaction output structure:

entity utxo {
pubkey;
amount: integer;
}

Then define the transfer operation that roughly follows Bitcoin transaction structure -- it has a list of inputs and outputs:

operation transfer (inputs: list<utxo>, output_pubkeys: list<pubkey>, output_amounts: list<integer>) {
var input_sum = 0;
for (an_utxo in inputs) {
require(op_context.is_signer(an_utxo.pubkey));
input_sum += an_utxo.amount;
delete utxo@{utxo == an_utxo};
}
var output_sum = 0;
require(output_pubkeys.size() == output_amounts.size());
for (out_index in range(output_pubkeys.size())) {
output_sum += output_amounts[out_index];
create utxo (output_pubkeys[out_index],
output_amounts[out_index]);
}
require(output_sum <= input_sum);
}

There are quite a lot of new constructs used in this example:

  • list<...> is, obviously, a collection. Besides lists, Rell also supports set and map
  • in list<utxo> utxo object references are physically implemented using integer identifiers which are used internally
  • an_utxo.pubkey accesses an attribute of an object, which is a database query identical to utxo@{utxo==an_utxo} (pubkey)
  • variable type is automatically inferred from expression used for initialization. One can also write it like var output_sum : integer = 0;
  • delete operation accepts a relational expression which identifies objects
  • .size() method can be used get the size of a collection
  • for (... in ...) works both for collections and for ranges of integer values
  • [] is used to refer to an element of a collection
tip

A front-end client together with a similar UTXO implementation to the preceding example can be found here.

Note that we perform checks as we go. This is OK because Rell is transactional: if a requirement fails or an error is generated, the whole operation (in fact, the entire transaction) is rolled back. Rell is typically used with a GTX transaction format that supports multiple signers and operations per transaction. Thus it can easily support Bitcoin-style multi-input transactions, atomic token swaps, multi-sig, etc.

Now a bit about the delete operator. Isn't it strange to enable the deletion of data from a blockchain?!

Here we aren't deleting data "from a blockchain", we're removing entries from the current blockchain state. This is precisely how it works in a Bitcoin node -- once entries in an unspent transaction output set are spent, they're deleted. A typical Bitcoin node doesn't keep track of spent transaction outputs.

A system based on Rell (Postchain or Chromia) works in exactly the same way: raw information about transactions and operations is preserved in a blockchain. The database contains both raw blockchain transactions and processed current state. The current state is what a Rell programmer can work with: he is allowed to do destructive updates and delete entries. These operations don't affect the raw blockchain.