[Proposal] Minimal UDT Implementation and Extensions

We have had several threads about UDT on CKB, like Approach to Designing a User Defined Token Standard on CKB: Part 1, and Discussion on UDT Standard Evaluation Criterion. Here is a minimal UDT implementation proposal according to previous discussions.

ERC20 Standard

First of all, ERC20 standard defines a interface, not an implementation, which means developers have to deploy a new ERC20 compitable smart contract for every new token. According to previous suggestion, the UDT standard we are talking about should be an implementation, which means all tokens share the same basic script code.

// Grabbed from: https://github.com/ethereum/EIPs/issues/20
contract ERC20 {
   function totalSupply();
   function balanceOf(address _owner);
   function transfer(address _to, uint _value);
   function transferFrom(address _from, address _to, uint _value);
   function approve(address _spender, uint _value);
   function allowance(address _owner, address _spender);

This is a standard ERC20 interface. We can split these functions into three catalogs, hidden constructor function, totalSupply for token management; balanceOf and transfer for daily use; approve, allowance and transferFrom for authorization.

Actually, a minimal UDT implementation has to cover token creation and token transferring functions. dApp developers can use extensions for other functions, like future management and authorization.

Minimal UDT on CKB

This UDT proposal only supports two basic actions (what an action is?) in this minimal UDT implementation. These two actions handle the state transition of two kinds of cells.

# actions
Action create:
    input: [capacity_cell, ...]
    output: [info_cell, balance_cell]

Action transfer:
    input: [balance_cell, ...]
    output: [balance_cell, ...]

# cells
Cell info_cell:
    data: /* infomation including supply, decimal, symbol, full name, operator, ...*/
    type: {code: minimal_udt, args: uuid_for_udt}
    lock: /*operator defined*/

Cell balance_cell:
    data: /* 64bit UDT amount*/
    type: {code: minimal_udt, args: uuid_for_udt}
    lock: /*user defined*/

Anyone can initiate create action to create a new UDT on CKB, with basic token parameters in witness to define the name, symbol, initial supply, decimal of the new UDT. And this minimal_udt type guarantees the unique uuid for every kind of UDT, and guarantees the balance consistency.

Extensions to the UDT Implementation

This UDT implementation can be extended with custom lock scripts and corresponding cells. Here are several examples.

Token management extension

/* Add mint and burn fucntions: 
    - setup info_cell's lock to operator defined lock 
    - operator unlocks info_cell to modify it
    - unlock rules are user-defined, like 2-of-3 multisig or token holder vote.

// actions
Action mint:
    input: [info_cell]
    output: [info_cell, balance_cell, ...]

Action burn:
    input: [info_cell, balance_cell, ...]
    output: [info_cell, balance_cell]


One can also use new lock script to achieve ERC20 approve, transfer_from functions.

/* approve_logic description:
  - grantor could fully control this cell
  - grantee could be either a lock script or a type script
    - lock script: grantee must provide the unlock witness to the lock script to consume this cell.
    - type script: the TX that consume this cell must contains an output with specific type script.
  - approve_parameters consists of grantor, grantee and allowance amount.

// actions
Action approve:
    input: [balance_cell, ...]
    output: [balance_with_approve_cell, ...]

Action transfer_from:
    input: [balance_with_approve_cell]
    output: [balance_with_approve_cell, balance_cell, ...]

// cells
Cell balance_with_approve_cell: /*standard udt cell with specific lock*/
    data: /* 64bit UDT amount*/
    type: {code: minimal_udt, args: uuid_for_udt}
    lock: {code: approve_logic, args: approve_parameters}

Atomic swap

/* Alice use 100 A tokens to exchange 10 B tokens.
  - Alice create a balance_cell_pending to describe her intention
  - Bob consume the balance_cell_pending with 10 B tokens and send the 100 A tokens to himself.

  lock atomic_swap_logic:
  - Alice could fully control this cell
  - Any TX consumed this cell (except Alice herself initialized) must follow these rules:
    -  There are 10 B tokens in output with lock = Alice's lock

// actions
Action ask:
    input: [balance_cell_A, ...]
    output: [balance_cell_pending]

Action bid:
    input: [balance_cell_pending, balance_cell_B]
    output: [balance_cell_A, balance_cell_B]

// cells
Cell balance_cell_pending: /*standard udt cell with specific lock*/
    data: /* 64bit UDT amount*/
    type: {code: minimal_udt, args: uuid_for_udt}
    lock: {code: atomic_swap_logic, args: swap_parameters}


IMO, this minimal UDT model could cover most of token usage scenarios, if new lock scripts and new kinds of cells provided by 3rd party. The community provides this minimal UDT implementation on CKB, and leave the extensions to the dApp developers.