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

feat: proposed fungible token trait #5

Merged
merged 17 commits into from
Sep 7, 2021
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 120 additions & 0 deletions sips/sip-010/sip-010-fungible-token-standard.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
## Preamble
hstove marked this conversation as resolved.
Show resolved Hide resolved

- Sip Number: 010
hstove marked this conversation as resolved.
Show resolved Hide resolved
- Title: Standard Trait Definition for Non-Fungibe Tokens
- Author: Hank Stoever (hstove@gmail.com)
- Consideration: Technical
- Type: Standard
- Status: Draft
- Created: 2021-01-25
hstove marked this conversation as resolved.
Show resolved Hide resolved
- License: CC0-1.0
- Sign-off:
hstove marked this conversation as resolved.
Show resolved Hide resolved

## Abstract

Fungible tokens are digital assets that can be sent, received, combined, and divided. Most forms of currency and cryptocurrencies are fungible tokens. They have become a building block of almost all blockchains. This SIP aims to provide a flexible and easy to implement standard that can be used by developers on the Stacks blockchain when creating their own tokens.
hstove marked this conversation as resolved.
Show resolved Hide resolved

## License and Copyright

This SIP is made available under the terms of the Creative Commons CC0 1.0 Universal license, available at https://creativecommons.org/publicdomain/zero/1.0/
This SIP’s copyright is held by the Stacks Open Internet Foundation.

## Introduction

Perhaps the oldest, and most well known, standard for fungible tokens is Ethereum's [ERC20](https://ethereum.org/en/developers/docs/standards/tokens/erc-20/) standard. It has become one of the strongest building blocks for the Ethereum ecosystem. When all fungible tokens follow the same standard, any wallet or application developer can interact with it without having to create custom logic for handling each individual token.
hstove marked this conversation as resolved.
Show resolved Hide resolved

Fungible tokens have become so popular that the Clarity smart contracting language has support for basic fungible token operations built-in. In fact, as you might see in this proposal's reference implementation, very little code is required to implement a fungible token. The important part of this standard is defining a Clarity trait that all fungible tokens can implement. Even though Clarity has fungible token operations built-in, it is important for each contract to define the same methods so that their contracts are easy to integrate.
hstove marked this conversation as resolved.
Show resolved Hide resolved

## Specification

The fungible token trait, `ft-trait`, has a few methods:

### Transfer

`(transfer ((recipient principal) (amount uint)) (response bool uint))`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The signature should have a sender because the sender can be the tx-sender or the contract-caller.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The order in the native function is amount sender recipient. To make it easier for clarity developers, I suggest to use that ordering of the native function.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had not needed to set a sender, but I suppose this is a valid point

Copy link
Contributor Author

@hstove hstove Jan 26, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Friedger, I will change this based on that suggestion. I am actually not sure how authorization works in ft-transfer - is there any? The docs don't mention it as an error code, so likely not. We should add a note about authorization, and add it as boilerplate in the example repo. I'll also add tests around authorization.

Error codes will be fleshed out, as well.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There isn't any built-in authorization in ft-transfer? (or nft-transfer? for that matter). The contract that declares the token is solely responsible for ensuring that the caller is permitted to use the given sender argument. Note that this is different from stx-transfer?, which does require that the sender argument is equal to the calling context's tx-sender.


Transfer the fungible token from the sender of this transaction to the recipient. The `amount` is an unsigned integer. It is recommended that implementing contracts use the built-in `ft-transfer` Clarity method. If the sender does not have enough tokens to complete the transaction, the transaction should abort and return an `(err uint)`.

### Name

`(name () (response (string-ascii 32) uint))`

Return a human-readable name for the contract, such as "CoolPoints", etc.
hstove marked this conversation as resolved.
Show resolved Hide resolved

### Symbol

`(symbol () (response (string-ascii 32) uint))`
hstove marked this conversation as resolved.
Show resolved Hide resolved

Return a symbol that allows for a shorter representation of your token. This is sometimes referred to as a "ticker". Examples: "STX", "COOL", etc. Typically, your token could be referred to as $SYMBOL when referencing it in writing.
hstove marked this conversation as resolved.
Show resolved Hide resolved

### Decimals

`(decimals () (response uint uint))`
hstove marked this conversation as resolved.
Show resolved Hide resolved

The number of decimal places in your token. All fungible token balances must be represented as integers, but providing the number of decimals provides for an abstraction of your token that humans are more familiar dealing with. For example, the US Dollar has 2 decimals, if the base unit is "cents", as is typically done in accounting. Stacks has 6 decimals, Bitcoin has 8 decimals, and so on.

As another example, if your token has 4 decimals, and the `balance-of` a particular user returns `100345000`, wallets and exchanges would likely represent that value as `10034.5`.

### Balance of

`(balance-of (principal) (response uint uint))`
hstove marked this conversation as resolved.
Show resolved Hide resolved

Return the balance of a particular principal (also known as "address" or "account"). Implementations should typically use the built-in Clarity method `ft-get-balance`.
jcnelson marked this conversation as resolved.
Show resolved Hide resolved

### Total supply

`(total-supply () (response uint uint))`

Return the total supply of this token. Implementations should typically use the built-in Clarity method `ft-get-supply`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What to put if total-supply is unlimited?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have an example of a token with unlimited liquid supply?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the supply may be unlimited, but this is meant to be the current supply if you sum all the addresses that contain the token. So always a specific value the token should keep track of


## Trait implementation

An implementation of the proposed trait is provided below.

```clarity
(define-trait ft-trait
(
;; Transfer from the caller to a new principal
(transfer (principal uint) (response bool uint))

;; the human readable name of the token
(name () (response (string-ascii 32) uint))

;; the ticker symbol, or empty if none
jcnelson marked this conversation as resolved.
Show resolved Hide resolved
(symbol () (response (string-ascii 32) uint))

;; the number of decimals used, e.g. 6 would mean 1_000_000 represents 1 token
(decimals () (response uint uint))

;; the balance of the passed principal
(balance-of (principal) (response uint uint))

;; the current total supply (which does not need to be a constant)
(total-supply () (response uint uint))
)
)
hstove marked this conversation as resolved.
Show resolved Hide resolved
```

## Example implementation

I have provided a simple implementation along with a Javascript client and tests. https://github.com/hstove/stacks-fungible-token
hstove marked this conversation as resolved.
Show resolved Hide resolved

## Credit
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you consider adding @psq as a co-author of this SIP?

Also, this paragraph would belong in the Related Work section, since it's describing a similar system.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course I would be more than happy to add @psq! Per SIP-000, I need to add an email address - do you have one you're willing to share, Pascal?


Credit for the work behind this proposal belongs to [@psq](https://github.com/psq), who wrote almost all of this code originally for use in his projects (such as [Flexr](https://github.com/psq/flexr)). I am simply re-packaging his existing code in a format that can be shared in this proposal.

## Implementing in wallets and other applications

Developers who with to interact with a fungible token contract should first be provided, or keep track of, various different fungible token implementations. When validating a fungible token contract, they should fetch the interface and/or source code for that contract. If the contract implements the trait, then the wallet can use this standard's contract interface for making transfers and getting balances.
hstove marked this conversation as resolved.
Show resolved Hide resolved

### Use of post conditions

In addition to fantastic built-in methods for fungible token contracts, the Stacks blockchain includes an innovation known as Post Conditions. By defining post conditions, users can create transactions that include pre-defined guarantees about what might happen in that contract.
hstove marked this conversation as resolved.
Show resolved Hide resolved

One such post condition could be "I will transfer exactly 100 of X token", where "X token" is referenced as a specific contract's fungible token. When wallets and applications implement the `transfer` method, they should _always_ use post conditions to specify that the user will transfer exactly the amount of tokens that they specify in the `amount` argument of the `transfer` function. Only in very specific circumstances should such a post condition not be included.

jcnelson marked this conversation as resolved.
Show resolved Hide resolved
## Related work

- [@psq's trait and implementation](https://github.com/psq/flexr/blob/master/contracts/src20-trait.clar)
- [@friedger's fungible token implementation](https://github.com/friedger/clarity-smart-contracts/blob/master/contracts/tokens/fungible-token.clar)
- [Ethereum ERC20 standard](https://ethereum.org/en/developers/docs/standards/tokens/erc-20/)
hstove marked this conversation as resolved.
Show resolved Hide resolved