-
Notifications
You must be signed in to change notification settings - Fork 308
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
SEP-41: Add a token contract interface proposal #1402
Merged
Merged
Changes from all commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
6507693
Add a token contract interface proposal
leighmcculloch d2b509d
add dependencies
leighmcculloch 227728b
Update cip-0001.md
leighmcculloch 537cbc4
remove abstract
leighmcculloch 6866a5e
Merge branch 'master' into token
leighmcculloch 72bc8a1
Update cip-0001.md
leighmcculloch 719f5b8
Make final
leighmcculloch e2db590
make SEP and add events setion
leighmcculloch 8539fb9
tob
leighmcculloch 551f8e7
Remove deps because it has none
leighmcculloch 6ee0080
title
leighmcculloch 0a5d5a6
Merge branch 'master' into token
leighmcculloch 748ecc3
Add Soroban prefix
leighmcculloch 78c137f
Update README.md
leighmcculloch 5349ffb
Update sep-0041.md
leighmcculloch ea496f0
typo
leighmcculloch 6fb11b2
live_until_ledger
leighmcculloch 47fe8e1
live_until_ledger
leighmcculloch File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,239 @@ | ||
## Preamble | ||
|
||
``` | ||
SEP: 0041 | ||
Title: Soroban Token Interface | ||
Authors: Jonathan Jove <@jonjove>, Siddharth Suresh <@sisuresh> | ||
Track: Standard | ||
Status: Draft | ||
Created: 2023-09-22 | ||
Version 0.1.0 | ||
Discussion: https://discord.com/channels/897514728459468821/1159937045322547250 | ||
``` | ||
|
||
## Simple Summary | ||
|
||
This proposal defines a standard contract interface for tokens. The interface is | ||
a subset of the Stellar Asset contract, and compatible with its descriptive and | ||
token interfaces defined in [CAP-46-6]. | ||
|
||
## Motivation | ||
|
||
A fungible asset is a fundamental concept on blockchains. Fungible assets can | ||
conceptually be divided into two pieces: standard functionality enabling push | ||
and pull transfers, and varying functionality around asset administration. Most | ||
blockchain ecosystems have very little innovation in the space of fungible | ||
assets, with developers often relying on open source implementations such as | ||
OpenZeppelin. | ||
|
||
[CAP-46-6] defines a Stellar Asset contract that implements a combination of | ||
that standard functionality, as well as functions to support behaviors that are | ||
specialized to Stellar assets. | ||
|
||
Tokens could implement the interface that the Stellar Asset contract defines, | ||
but it contains functions that support behaviors that are specialized to Stellar | ||
assets. | ||
|
||
An interface is needed that is less opinionated than the interface of the Stellar | ||
Asset contract. Tokens that implement this interface would support at least the | ||
standard functionality of tokens, without needing to support the specialized | ||
behaviors of Stellar Assets. | ||
|
||
An interface is needed that is a subset of the Stellar Asset contract, such that | ||
the Stellar Asset contract would implement the interface. Tokens that implement | ||
the interface and the Stellar Asset contract would be usable with contracts that | ||
support the standard interface, and would be largely indistinguishable. | ||
|
||
[CAP-46-6]: ../core/CAP-0046-06.md | ||
|
||
## Specification | ||
|
||
### Interface | ||
|
||
```rust | ||
pub trait TokenInterface { | ||
/// Returns the allowance for `spender` to transfer from `from`. | ||
/// | ||
/// # Arguments | ||
/// | ||
/// - `from` - The address holding the balance of tokens to be drawn from. | ||
/// - `spender` - The address spending the tokens held by `from`. | ||
fn allowance(env: Env, from: Address, spender: Address) -> i128; | ||
|
||
/// Set the allowance by `amount` for `spender` to transfer/burn from | ||
/// `from`. | ||
/// | ||
/// # Arguments | ||
/// | ||
/// - `from` - The address holding the balance of tokens to be drawn from. | ||
/// - `spender` - The address being authorized to spend the tokens held by | ||
/// `from`. | ||
/// - `amount` - The tokens to be made available to `spender`. | ||
/// - `live_until_ledger` - The ledger number where this allowance expires. | ||
/// Cannot be less than the current ledger number unless the amount is being | ||
/// set to 0. An expired entry (where live_until_ledger < the current | ||
/// ledger number) should be treated as a 0 amount allowance. | ||
/// | ||
/// # Events | ||
/// | ||
/// Emits an event with topics `["approve", from: Address, | ||
/// spender: Address], data = [amount: i128, live_until_ledger: u32]` | ||
/// | ||
/// Emits an event with: | ||
/// - topics - `["approve", from: Address, spender: Address]` | ||
/// - data - `[amount: i128, live_until_ledger: u32]` | ||
fn approve(env: Env, from: Address, spender: Address, amount: i128, live_until_ledger: u32); | ||
|
||
/// Returns the balance of `id`. | ||
/// | ||
/// # Arguments | ||
/// | ||
/// - `id` - The address for which a balance is being queried. If the | ||
/// address has no existing balance, returns 0. | ||
fn balance(env: Env, id: Address) -> i128; | ||
|
||
/// Returns the spendable balance of `id`. | ||
/// | ||
/// If the token implementation makes a portion of the balance unavailable | ||
/// for general use, this should return the portion that is available for | ||
/// withdrawal. | ||
/// | ||
/// Should always return a value that is less than or equal to the amount | ||
/// returned by `balance`. | ||
/// | ||
/// # Arguments | ||
/// | ||
/// - `id` - The address for which a spendable balance is being queried. | ||
fn spendable_balance(env: Env, id: Address) -> i128; | ||
|
||
/// Transfer `amount` from `from` to `to`. | ||
/// | ||
/// # Arguments | ||
/// | ||
/// - `from` - The address holding the balance of tokens which will be | ||
/// withdrawn from. | ||
/// - `to` - The address which will receive the transferred tokens. | ||
/// - `amount` - The amount of tokens to be transferred. | ||
/// | ||
/// # Events | ||
/// | ||
/// Emits an event with: | ||
/// - topics - `["transfer", from: Address, to: Address]` | ||
/// - data - `[amount: i128]` | ||
fn transfer(env: Env, from: Address, to: Address, amount: i128); | ||
|
||
/// Transfer `amount` from `from` to `to`, consuming the allowance of | ||
/// `spender`. Authorized by spender (`spender.require_auth()`). | ||
/// | ||
/// # Arguments | ||
/// | ||
/// - `spender` - The address authorizing the transfer, and having its | ||
/// allowance consumed during the transfer. | ||
/// - `from` - The address holding the balance of tokens which will be | ||
/// withdrawn from. | ||
/// - `to` - The address which will receive the transferred tokens. | ||
/// - `amount` - The amount of tokens to be transferred. | ||
/// | ||
/// # Events | ||
/// | ||
/// Emits an event with: | ||
/// - topics - `["transfer", from: Address, to: Address]` | ||
/// - data - `[amount: i128]` | ||
fn transfer_from(env: Env, spender: Address, from: Address, to: Address, amount: i128); | ||
|
||
/// Burn `amount` from `from`. | ||
/// | ||
/// # Arguments | ||
/// | ||
/// - `from` - The address holding the balance of tokens which will be | ||
/// burned from. | ||
/// - `amount` - The amount of tokens to be burned. | ||
/// | ||
/// # Events | ||
/// | ||
/// Emits an event with: | ||
/// - topics - `["burn", from: Address]` | ||
/// - data - `[amount: i128]` | ||
fn burn(env: Env, from: Address, amount: i128); | ||
|
||
/// Burn `amount` from `from`, consuming the allowance of `spender`. | ||
/// | ||
/// # Arguments | ||
/// | ||
/// - `spender` - The address authorizing the burn, and having its allowance | ||
/// consumed during the burn. | ||
/// - `from` - The address holding the balance of tokens which will be | ||
/// burned from. | ||
/// - `amount` - The amount of tokens to be burned. | ||
/// | ||
/// # Events | ||
/// | ||
/// Emits an event with: | ||
/// - topics - `["burn", from: Address]` | ||
/// - data - `[amount: i128]` | ||
fn burn_from(env: Env, spender: Address, from: Address, amount: i128); | ||
|
||
/// Returns the number of decimals used to represent amounts of this token. | ||
fn decimals(env: Env) -> u32; | ||
|
||
/// Returns the name for this token. | ||
fn name(env: Env) -> String; | ||
|
||
/// Returns the symbol for this token. | ||
fn symbol(env: Env) -> String; | ||
} | ||
``` | ||
|
||
### Events | ||
|
||
#### Approve Event | ||
|
||
The `approve` event is emitted when the allowance is set. | ||
|
||
The event has topics: | ||
- `Symbol` with value `"approve"` | ||
- `Address` the address holding the balance of tokens to be drawn | ||
from. | ||
- `Address` the address spending the tokens held by `from`. | ||
|
||
The event has data: | ||
- `i128` the amount allowed to be spent. | ||
- `u32` the expiration ledger. | ||
|
||
#### Transfer Event | ||
|
||
The `transfer` event is emitted when an amount is transferred from one address | ||
to another. | ||
|
||
The event has topics: | ||
- `Symbol` with value `"transfer"` | ||
- `Address` the address holding the balance of tokens that was drawn from. | ||
- `Address` the address that received the tokens. | ||
|
||
The event has data: | ||
- `i128` the amount transferred. | ||
|
||
#### Burn Event | ||
|
||
The `burn` event is emitted when an amount is burned from one address. | ||
|
||
The event has topics: | ||
- `Symbol` with value `"burn"` | ||
- `Address` the address holding the balance of tokens that was burned. | ||
|
||
The event has data: | ||
- `i128` the amount burned. | ||
|
||
|
||
## Changelog | ||
|
||
- `v0.1.0` - Initial draft based on [CAP-46-6]. | ||
|
||
## Implementations | ||
|
||
- The [Rust soroban-sdk] contains a copy of the interface verbatim, and a | ||
generated client for use in contracts. | ||
- The Soroban Env contains a native implementation of the interface that is a | ||
presentation layer on top of Stellar Assets. | ||
|
||
[Rust soroban-sdk]: https://github.com/stellar/rs-soroban-sdk |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this interface need a
spendable_balance
(I think this was discussed recently but don't remember what came out of that).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The discussion and resolution is here:
The resolution was we could go both ways so leave it. But, I've lost count how many times this has come up, and every time the opinion is "it doesn't belong."
I think we could remove it with little impact.
cc @tomerweller