-
Notifications
You must be signed in to change notification settings - Fork 98
feat: proposed fungible token trait #5
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
Changes from 2 commits
556730d
cc6e3a4
53636c9
d69b1f6
f7f5c90
96998dd
bdcf8b2
6708391
462755b
557602c
7affd69
ff10071
19d0d53
7301efd
0429c32
836e95a
4dd02c8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,132 @@ | ||
| ## Preamble | ||
|
|
||
| - Sip Number: 010 | ||
hstove marked this conversation as resolved.
Outdated
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.
Outdated
Show resolved
Hide resolved
|
||
| - License: CC0-1.0 | ||
| - Sign-off: | ||
hstove marked this conversation as resolved.
Outdated
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.
Outdated
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.
Outdated
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.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ## Specification | ||
|
|
||
| The fungible token trait, `ft-trait`, has a few methods: | ||
|
|
||
| ### Transfer | ||
|
|
||
| `(transfer ((recipient principal) (amount uint)) (response bool uint))` | ||
|
||
|
|
||
| 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)`. | ||
|
|
||
| This method must be defined with `define-public`, as it alters state, and should be externally callable. | ||
|
|
||
| ### 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
|
||
|
|
||
| This method should be defined as read-only, i.e. `define-read-only`. | ||
jcnelson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| ### Symbol | ||
|
|
||
| `(symbol () (response (string-ascii 32) uint))` | ||
hstove marked this conversation as resolved.
Outdated
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.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| This method should be defined as read-only, i.e. `define-read-only`. | ||
|
|
||
| ### Decimals | ||
|
|
||
| `(decimals () (response uint uint))` | ||
hstove marked this conversation as resolved.
Outdated
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`. | ||
|
|
||
| This method should be defined as read-only, i.e. `define-read-only`. | ||
|
|
||
| ### Balance of | ||
|
|
||
| `(balance-of (principal) (response uint uint))` | ||
hstove marked this conversation as resolved.
Outdated
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
|
||
|
|
||
| This method should be defined as read-only, i.e. `define-read-only`. | ||
|
|
||
| ### 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`. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What to put if total-supply is unlimited?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you have an example of a token with unlimited liquid supply? There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||
|
|
||
| This method should be defined as read-only, i.e. `define-read-only`. | ||
|
|
||
| ## 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.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ## Credit | ||
|
||
|
|
||
| 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 wish 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. | ||
|
|
||
| ### 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.
Outdated
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.
Outdated
Show resolved
Hide resolved
|
||
Uh oh!
There was an error while loading. Please reload this page.