Tangible Tokenization on Tezos

Mike Radin
The Cryptonomic Aperiodical
4 min readAug 1, 2019

--

Tokenization is one of the blockchain use-cases with the most up-take in real-world applications. Similar to securitization in traditional finance, tokenization brings the concept of partial ownership to blockchains. Specifically in the Tezos space there have been several high profile announcements in recent months about tokenization efforts on this blockchain. Earlier this month Serokell proposed an implementation of the FA1.2 standard for asset representation on the chain.

We’re eager to see further developments in the space, for example the on-going Dexter effort from camlCase that would bring decentralized trading of tokenized assets. In the meantime there are meaningful applications for the Managed Ledger (the name of the Serokell contract) and ConseilJS provides all the building blocks for it. In this article we implement an interface for this contract that can then be used to create user applications.

What follows is a tutorial for deploying and interacting with the token contract using ConseilJS 0.2.7 and Typescript.

Issuance and Allocation

Creating a token on the blockchain amounts to deploying the contract with the appropriate initial state. In the example below, the default storage specifies tz1WpPzK6NwWVTJcXqFvYmoA6msQeVy1YP6z as the manager, token state is set to active with False, finally the initial token supply is 0. Note that creating a contract with non-zero initial supply and an empty holder map will result in an orphaned amount that cannot be assigned to an account.

'Pair {} (Pair "tz1WpPzK6NwWVTJcXqFvYmoA6msQeVy1YP6z" (Pair False 0))';

The full deployment function might look like this.

async function deployContract(tezosNode: string, keyStore: KeyStore): Promise<OperationResult> {
const code = ``; // full contract code
const storage = ‘Pair {} (Pair 'tz1WpPzK6NwWVTJcXqFvYmoA6msQeVy1YP6z' (Pair False 0))’;
return await TezosNodeWriter.sendContractOriginationOperation(tezosNode, keyStore, 0, undefined, false, true, 15000000, ‘’, 5392, 144382, code, storage, TezosParameterFormat.Michelson);
}

Once the contract is deployed, the administrator can perform several operations including issuance and allocation. In the example above the token was created with an empty initial holder list and zero balance. The administrator can mint tokens to a target address as follows:

async function mint(target: string, amount: number): Promise<OperationResult> {
const tezosNode = ''; // https://...
const contractAddress = ''; // KT1...
const keyStore = {}; // admin KeyStore
const parameter = `Right (Right (Right (Right (Right (Right (Right (Right (Left (Pair "${target}" amount)))))))))`; return await TezosNodeWriter.sendContractInvocationOperation(tezosNode, keyStore, contractAddress, 0, 150000, '', 5392, 144382, parameter, TezosParameterFormat.Michelson);
}

Exchange

Two methods of value exchange are available to token holders: active and passive. The active path involves immediate transfer between two accounts as presented below under transfer. Passive transfer approves an address for withdrawal for up to some limit. An approved account can make multiple withdrawals from a source account until the allowance limit is reached.

The token administrator can also perform the transfer action with elevated privileges — they can invoke a transfer between any account pair.

async function transfer(source: string, target: string, amount: number): Promise<OperationResult> {
const tezosNode = ''; // https://...
const contractAddress = ''; // KT1...
const keyStore = {}; // admin KeyStore
const parameter = `Left (Pair "${source}" (Pair "${target}" value))`; return await TezosNodeWriter.sendContractInvocationOperation(tezosNode, keyStore, contractAddress, 0, 150000, '', 5392, 144382, parameter, TezosParameterFormat.Michelson);
}
async function approve(target: string, amount: number): Promise<OperationResult> {
const tezosNode = ''; // https://...
const contractAddress = ''; // KT1...
const keyStore = {}; // admin KeyStore
const parameter = `Right (Left (Pair "${target}" value))`; return await TezosNodeWriter.sendContractInvocationOperation(tezosNode, keyStore, contractAddress, 0, 150000, '', 5392, 144382, parameter, TezosParameterFormat.Michelson);
}

Maintenance Operations

Token administrator can perform several other operations, examples of which are given below. An admin can burn token value from any account participating in the contract resulting in a reduction of overall supply in addition to the debit against the affected account. They can also pause the contract which would result in rejection of standard user operations. Administrator actions will continue to be evaluated even on a paused token ledger. Note, to pause a token call the function with True, to activate it with False. Finally an administrator can reassign the admin function to a different account.

async function pause(pause: boolean): Promise<OperationResult> {
const tezosNode = ''; // https://...
const contractAddress = ''; // KT1...
const keyStore = {}; // admin KeyStore
const input = String(pause).charAt(0).toUpperCase() + String(pause).slice(1);
const parameter = `Right (Right (Right (Right (Right (Left input )))))`;
return await TezosNodeWriter.sendContractInvocationOperation(tezosNode, keyStore, contractAddress, 0, 150000, '', 5392, 144382, parameter, TezosParameterFormat.Michelson);
}
async function burn(target: string, amount: number): Promise<operationResult> {
const tezosNode = ''; // https://...
const contractAddress = ''; // KT1...
const keyStore = {}; // admin KeyStore
const parameter = `Right (Right (Right (Right (Right (Right (Right (Right (Right (Pair "${target}" amount)))))))))`; return await TezosNodeWriter.sendContractInvocationOperation(tezosNode, keyStore, contractAddress, 0, 150000, '', 5392, 144382, parameter, TezosParameterFormat.Michelson);
}
async function setAdministrator(administrator: string): Promise<operationResult> {
const tezosNode = ''; // https://...
const contractAddress = ''; // KT1...
const keyStore = {}; // admin KeyStore
const parameter = `Right (Right (Right (Right (Right (Right (Left "${administrator}"))))))`; return await TezosNodeWriter.sendContractInvocationOperation(tezosNode, keyStore, contractAddress, 0, 150000, '', 5392, 144382, parameter, TezosParameterFormat.Michelson);
}

Further Developments

All of the above is enabled by ConseilJS, which is one of the core libraries powering our own products. An effort to integrate both deployment and interaction with tokens on Tezos following the FA1.2 standard into the Galleon Wallet is underway. Not only will this provide retail access to tokens issued by institutions, but also democratize access to the technology allowing individual chain participants to do the same.

I would also be remiss not to mention Arronax which would be useful to both debug the development and investigate the use of these contracts. Here’s a report showing at some of the test contracts that were deployed during the development of FA1.2.

As always we stand by our code and would like to hear you feedback and questions in our developer channel on Riot.

We have also developed an interactive demo of this contract. It is available on GitHub in beta form.

--

--