Discussion on the compatibility of different token standards

There are multiple different implementations of the Dfinity token (Fungible Token and Non-Fungible Token) standards and no consensus can be formed. This will be detrimental to the development of Defi on IC network.

IC Canister’s methods are not allowed polymorphism, which creates a barrier to token compatibility.

Is it possible to form a specification for different standards to be compatible with each other and achieve compatibility without intrusion?

I’m thinking about an idea and working on some examples.

Idea:

main interface implements a standard scheme using the method names of ERC20. The optional compatibility interface implements self/other standard schemes with the method names plus the standard name prefix xxx_.

standard method

Returns the list of supported token standards, in lowercase letters, separated by “; ”. The format is similar to “main standard; compatible standard 1; compatible standard 2”. E.g. “dip20; drc20”, “dft”.


standard: () -> (text) query;

Main interface

Use the method names of ERC20 to define the main interface.

For example:

name: () -> (text) query;
symbol: () -> (text) query;
decimals: () -> (nat8) query;
totalSupply: () -> (nat) query;
balanceOf: (...) -> (...) query;
transfer: (...) -> (...);
transferFrom: (...) -> (...);
approve: (...) -> (...);
allowance: (...) -> (...);
...

Optional compatibility interface

Use the method names prefixed with standard name “xxx_” to define the compatibility interfaces.

For example 1:

dip20_name: () -> (text) query;
dip20_symbol: () -> (text) query;
dip20_decimals: () -> (nat8) query;
dip20_totalSupply: () -> (nat) query;
dip20_balanceOf: (...) -> (...) query;
dip20_transfer: (...) -> (...);
dip20_transferFrom: (...) -> (...);
dip20_approve: (...) -> (...);
dip20_allowance: (...) -> (...);
...

For example 2:

dft_name: () -> (text) query;
dft_symbol: () -> (text) query;
dft_decimals: () -> (nat8) query;
dft_totalSupply: () -> (nat) query;
dft_balanceOf: (...) -> (...) query;
dft_transfer: (...) -> (...);
dft_transferFrom: (...) -> (...);
dft_approve: (...) -> (...);
dft_allowance: (...) -> (...);
...

Single-standard compatibility example

standard: () -> (text) query; // “drc20”

// drc20
name: () -> (text) query;
symbol: () -> (text) query;
decimals: () -> (nat8) query;
totalSupply: () -> (nat) query;
balanceOf: (...) -> (...) query;
transfer: (...) -> (...);
transferFrom: (...) -> (...);
approve: (...) -> (...);
allowance: (...) -> (...);
...

// drc20 (Compatibility aliases)
drc20_name: () -> (text) query;
drc20_symbol: () -> (text) query;
drc20_decimals: () -> (nat8) query;
drc20_totalSupply: () -> (nat) query;
drc20_balanceOf: (...) -> (...) query;
drc20_transfer: (...) -> (...);
drc20_transferFrom: (...) -> (...);
drc20_approve: (...) -> (...);
drc20_allowance: (...) -> (...);
...

Multi-standard compatibility example

standard: () -> (text) query; // “dft; drc20”

// dft
name: () -> (text) query;
symbol: () -> (text) query;
decimals: () -> (nat8) query;
totalSupply: () -> (nat) query;
balanceOf: (...) -> (...) query;
transfer: (...) -> (...);
transferFrom: (...) -> (...);
approve: (...) -> (...);
allowance: (...) -> (...);
...

// drc20
drc20_name: () -> (text) query;
drc20_symbol: () -> (text) query;
drc20_decimals: () -> (nat8) query;
drc20_totalSupply: () -> (nat) query;
drc20_balanceOf: (...) -> (...) query;
drc20_transfer: (...) -> (...);
drc20_transferFrom: (...) -> (...);
drc20_approve: (...) -> (...);
drc20_allowance: (...) -> (...);
...

Standard List.

(Welcome to add new token standards!)

Fungible Token

Non-Fungible Token

1 Like

This sounds similar to:

I think the suggestion to use a variant still has a lot of merit.

1 Like

I backed off pushing the proposal during the ICDevs neuron stuff, but I’m glad to pick up the torch again. I think it makes sense as a protocol and we’ve even had some discussions with the Foundation about the ICP ledger so maybe we can rope that in so that we can all interoperate like one big happy family!

2 Likes

I hadn’t noticed that topic before, this is to address the same issue.

Using variant-type is not a good solution, because variants are considered different types after extending members and are not forward compatible.

It looks like it will become difficult to drive this at the ic system level.

So I’m thinking about a non-forcing convention that is non-intrusive to the original code and maintains forward compatibility.

We are updating the spec to make variant extension possible: https://github.com/dfinity/candid/pull/311

3 Likes

Example: