Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create a standard abi for fungible tokens. #13

Closed
nfurfaro opened this issue Jun 19, 2022 · 7 comments
Closed

Create a standard abi for fungible tokens. #13

nfurfaro opened this issue Jun 19, 2022 · 7 comments
Labels
enhancement New feature or request help wanted Extra attention is needed

Comments

@nfurfaro
Copy link

The use of native assets on Fuel introduces some differences in the way tokens are managed.
This means that some of the functionality required for ERC-20 compliance is not really relevant when working with fungible tokens on Fuel. For example, there's no need to call a token contract's transfer method in order to transfer tokens, so it doesn't make sense to include a transfer function in an abi spec for a native fungible token.
Likewise, the whole concept of approvals needs to be reconsidered(or removed completely).

@nfurfaro nfurfaro added enhancement New feature or request help wanted Extra attention is needed labels Jun 19, 2022
@nfurfaro
Copy link
Author

nfurfaro commented Mar 10, 2023

This has been discussed for a while already, so I will attempt to capture some of the main discussion points into this issue.

On the forum, we have this topic: https://forum.fuel.network/t/src-20-fungible-token-standard/186, so please read through the thread for the full discussion from the forum.

the first post was this one:
david
Dec '22
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 1 or CosmWasm’s CW-20 1.
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.

@nfurfaro
Copy link
Author

fuel
23d

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

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

After a few comments about the SRC-20 proposal, we had this contribution:

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:

Rewrite the ERC-20-like fuel standard

Implement a token standard based on the native token

We have already implemented option 2 in swaylend.com 1

It has methods for getting decimals, name, symbol etc

@nfurfaro
Copy link
Author

nfurfaro commented Mar 10, 2023

Just recently, posted the following to the discussion:

furnic
4d

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

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. 🤔

@tkporter
Copy link

tkporter commented Apr 18, 2023

Hi, has the ABI you shared been committed to?

I'm in the process of implementing tokens in Sway, would love to give my input

  1. The lack of approve / transfer / transferFrom implies that the native token accounting offered by the FuelVM should be used (which makes sense). But because this accounting is done entirely in u64s, this feels a bit in conflict with the total supply being a U256, and with the idea that there may be tokens with very high decimals. The FuelVM already basically prevents higher decimals like 18 decimals, (len(str(2**64)) = 20, so balances for an 18 token decimal don't really work without hitting the bounds of the 64 bits), so it feels a little unnatural to consider this as a reason to have a U256 total supply.
    I've never really considered having a # of bytes for balances and a higher one for total supply, but it just feels a bit strange. I suppose there's no strict downside other than quality of life / it being a little confusing

  2. Re: static sized strings -- has Bytes (or String) been considered? Fuels-rs fully supports it now, but afaik fuels-ts doesn't yet, which is maybe a good reason to steer clear.
    Another idea instead of having trailing whitespace is to recommend trailing null bytes instead

@chlenc
Copy link

chlenc commented May 19, 2023

@nfurfaro @tkporter

configurable {
    DECIMALS: u8 = 9,
    NAME: b256 = str[32],
    SYMBOL: b256 = str[8],
    OWNER = Address::from(ZERO_B256),
    MINT_AMOUNT: 64 = 0, 
}

storage {
    minted: StorageMap<Address, bool> = StorageMap {},
    admins: StorageMap<Address, bool> = StorageMap {}, // for testnet only
}

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

    fn mint_amount() -> u64; // everyone can mint mint_amount only one time
    fn is_minted(address: Address) -> bool;

    fn is_admin(address: Address) -> bool; // only admins can call fn _...

    fn _transfer(coins: u64, address: Address); //transfer coins from contract address

    #[storage(read, write)]
    fn mint();
    fn _delete_admin(address: Address);
    fn _add_admin(address: Address);
    fn _burn_coins(burn_amount: u64);
    fn _mint(amount: u64, recipient: Address);
   
}

@dmihal
Copy link

dmihal commented May 19, 2023

Hey @chlenc, and anyone else reading this:

Discussion of this standard has moved to the FuelLabs/sway-standards repo

The new SRC-20 token standard discussion is here:

FuelLabs/sway-standards#1

@Voxelot
Copy link
Member

Voxelot commented Sep 13, 2023

Closing since this specification has moved to sway-standards.

@Voxelot Voxelot closed this as completed Sep 13, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

5 participants