SRC-20: Fungible token standard

Summary

SRC-20 is a standard for fungible tokens built in Sway.

Abstract

SRC-20 defines a common interface for Sway smart contracts that issue fungible tokens. Given that the Fuel VM supports native assets, this standard will be primarily concerned with asset metadata (name, symbol, supply, decimals), as well as other optional functions (mint, burn).

Note: while most SRCs will be numbered sequentially, the number SRC-20 was chosen to align with the EVM’s famous “ERC-20 standard”, as well other similar standards like BSC’s BEP-20 or CosmWasm’s CW-20.

Motivation

A standardized token format will allow for smart contracts to interact with any arbitrary fungible token. This SRC provides all the standard features that developers have learned to expect from the ERC-20 standard.

Specification

Methods

total_supply

fn name() -> u64

Returns the total supply of tokens that have been minted.

decimals

fn decimals() -> u8

Returns the number of decimals the token uses - e.g. 8, means to divide the token amount by 100000000 to get its user representation.

Note: is it worth considering ERC777’s granularity, which is more powerful?

name

Note: Requires dynamic-length strings, which are not yet implemented

fn name() -> String

Returns the symbol of the token, such as “ETH”.

symbol

Note: Requires dynamic-length strings, which are not yet implemented

fn symbol() -> String

Returns the name of the token, such as “Ether”.

mint (optional)

fn mint(recipient: Identity, amount: u64)

Mints amount tokens and transfers them to the recipient address. This function may contain arbitrary conditions for minting, and revert if those conditions are not met.

Emits a Mint event.

burn (optional)

fn burn()

Burns all tokens sent to the contract in this function invocation.

Emits a Burn event.

Events

Mint

struct Mint {
    recipient: b256,
    amount: u64,
}

Burn

struct Burn {
    sender: b256,
    amount: u64,
}

Reference Implementation

contract;

abi Token {
    #[storage(read)]
    fn total_supply() -> u64;
    fn decimals() -> u8;
    fn name() -> String;
    fn symbol() -> String;
    fn mint(recipient: Identity, amount: u64);
    fn burn();
}

struct Mint {
    recipient: b256,
    amount: u64,
}

struct Burn {
    sender: b256,
    amount: u64,
}

storage {
    total_supply: u64 = 0,
}

impl Token for Contract {
    #[storage(read)]
    fn total_supply() -> u64 {
        storage.total_supply
    }

    fn decimals() -> u8 {
        9
    }

    fn name() -> String {
        // TODO
    }

    fn symbol() -> String {
        // TODO
    }


    fn mint(recipient: Identity, amount: u64) {
        storage.total_supply += amount;
        mint_to_address(storage.mint_amount, recipient);
        log(Mint);
    }

    fn burn() {
        burn(msg_amount());
        log(Burn);
    }
}

Security Considerations

This standard does not introduce any security concerns, as it does not call external contracts, nor does it define any mutations of the contract state.

46 Likes

First of all, it’s great to see some effort toward creating standards by the community!

I will look over this more closely, but one thing that jumped out at me was that fn mint takes an Identity type for the recipient param (as it should), so it should therefore use std::token::mint_to which also takes an Identity.

Also, we do have a public repo set up for just this type of thing here:

13 Likes

Some quick updates:

Thanks @furnic for the tip regarding mint_to. I’ll update the post to include that once it’s possible to edit posts ([Meta] Ability to edit posts).

Also, @fuel had a good post about the ability to store strings in Sway:

@fuel’s current token implementation (https://github.com/sway-gang/fuel-token-standard/blob/master/src/main.sw) currently uses fixed-length character arrays for the name & symbol elements. This is probably the best way to implement these strings today, however I believe the final token standard should use dynamic-length strings (which aren’t available yet).

6 Likes

i think this should be fn totoal_supply() -> u64?

1 Like

so difficult information

1 Like

the mint function has to be a permissioned function, please consider adding onlyOwner or onlyDAO similar logic into the consideration.

Besides, I feel the modern day token contracts all have hardcoded inflation, such as Uniswap governance, where project team are only allow less than 2% of the token inflation.

@david Sorry for the delay on this, but it looks like letting users edit posts is NOT on the agenda atm. So, I suggest posting an updated abi based on feedback and we can continue to discuss from there :slightly_smiling_face:

I’m Alex from SWAY GANG , we’re building swaylend.com (Compound rewritten into Sway)

I would like to discuss a fungible token standard on fuel.

Teams building defi projects on Fuel use their own temporary token standards.

Let’s join forces and build a universal and efficient token standard.

As I see it, we now have two options:

  1. Rewrite the ERC-20-like fuel standard

  2. Implement a token standard based on the native token

We have already implemented option 2 in swaylend.com

It has methods for getting decimals, name, symbol etc

1 Like

Thanks for sharing the “Fuel Token Standard”, I just had a quick look over it now.
What is the purpose of set_mint_amount ? It was not clear to me what it does without docs.
I think in general, a token standard should be as minimal as practical. So any admin functions for example could be part of a separate TokenAdmin abi . A fungible token contract would implement the basic Token abi, and could optionally implement the TokenAdmin abi if that functionality is needed, without forcing all users of the standard to implement unneeded functions. So we can compose functionality by combining the set of abis we need for a given use case.
Exposing a transfer function in the abi is key, so nice to see your transfer_coins function. It should probably take an Identity instead of an Address if you want to be able to transfer to contracts as well.
Just a few of my own thought based on an initial readthrough, but nice work!

1 Like

Most of the methods associated with administering tokens are only needed for the testnet period. As soon as the testnet comes, they are all gone. Also I brought up this topic to agree on a standard with all of you, so please let’s first decide which approach we will choose and then develop a standard. I am so far ready to participate 100%.

1 Like

So after some discussion last week about this with some fuel contributors, we were leaning towards something like the following as far as the abi goes, which is pretty much what @david originally proposed:

abi Token {
    #[storage(read)]
    fn total_supply() -> U256;
    fn decimals() -> u8;
    fn name() -> str[64];
    fn symbol() -> str[32];
}

Any other functions would be part of some optional add-on abis, i.e: mint, burn, etc… and these would also need to be specified in a standard way.

A return type of U256 for total_supply would support tokens with either very large supplies or high precision needs(18 decimals for example), but most tokens could probably be fine 9 decimals precision and storing the total supply as a u64 (and just casting to a U256 when returning).

name and symbol are tricky as the support for dynamic strings in Sway is not implemented yet. I think using static sized strings for these and just padding the strings with spaces to the required size is fine, for example: const SYMBOL: str[32] = "MYTKN ";.
It’s a little hacky but gets the job done for now and the frontend can easily trim the whitespace.

Speak up if you have any thoughts, questions or concerns with this approach, as nothing is written in stone yet :slight_smile:

Also, as much as the dev in me appreciates the SRC prefix, I wonder if we should consider using FRC for Fuel, as there will likely be other languages targeting the Fuel VM meaning the standard should to be higher level than just Sway. :thinking:

cc @david @fuel

1 Like

@furnic @david
Let’s have a call and discuss this,
Also, I want to suggest setup a telegram/discord chat about token standard because its too big response time here

1 Like

For everyone interested, I’ve copied the main points over from this topic to a github issue in the Fuel labs RFCs repo to try to finalize a standard: Create a standard abi for fungible tokens. · Issue #13 · FuelLabs/rfcs · GitHub
I feel like we’re close, but need a bit more discussion of fine details.

cc @fuel @david

Just a reminder: please comment here if you want to have more input on a fungible token standard!

cc @david @fuel

sorry ser, missed this message
Will do right now :saluting_face:

Hey @fuel, we’ve moved standards to the sway-standards repo.

The new place for SRC-20 discussions is here: