Skip to main content

sep_41_token/
lib.rs

1//! Interface for SEP-41 Token Standard
2//! https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0041.md
3
4#![no_std]
5
6#[cfg(any(test, feature = "testutils"))]
7pub mod testutils;
8
9use soroban_sdk::{contractclient, symbol_short, Address, Env, String};
10
11/// SEP-0041 Token Standard Trait
12#[contractclient(name = "TokenClient")]
13pub trait Token {
14    /// Returns the allowance for `spender` to transfer from `from`.
15    ///
16    /// # Arguments
17    ///
18    /// - `from` - The address holding the balance of tokens to be drawn from.
19    /// - `spender` - The address spending the tokens held by `from`.
20    fn allowance(env: Env, from: Address, spender: Address) -> i128;
21
22    /// Set the allowance by `amount` for `spender` to transfer/burn from
23    /// `from`. Overrides any existing allowance set between `spender` and `from`.
24    ///
25    /// # Arguments
26    ///
27    /// - `from` - The address holding the balance of tokens to be drawn from.
28    /// - `spender` - The address being authorized to spend the tokens held by
29    /// `from`.
30    /// - `amount` - The tokens to be made available to `spender`.
31    /// - `live_until_ledger` - The ledger number where this allowance expires.
32    /// Cannot be less than the current ledger number unless the amount is being
33    /// set to 0.  An expired entry (where live_until_ledger < the current
34    /// ledger number) should be treated as a 0 amount allowance.
35    ///
36    /// # Events
37    ///
38    /// Emits an event with topics `["approve", from: Address,
39    /// spender: Address], data = [amount: i128, live_until_ledger: u32]`
40    ///
41    /// Emits an event with:
42    /// - topics - `["approve", from: Address, spender: Address]`
43    /// - data - `[amount: i128, live_until_ledger: u32]`
44    fn approve(env: Env, from: Address, spender: Address, amount: i128, live_until_ledger: u32);
45
46    /// Returns the balance of `id`.
47    ///
48    /// # Arguments
49    ///
50    /// - `id` - The address for which a balance is being queried. If the
51    /// address has no existing balance, returns 0.
52    fn balance(env: Env, id: Address) -> i128;
53
54    /// Transfer `amount` from `from` to `to`.
55    ///
56    /// # Arguments
57    ///
58    /// - `from` - The address holding the balance of tokens which will be
59    /// withdrawn from.
60    /// - `to` - The address which will receive the transferred tokens.
61    /// - `amount` - The amount of tokens to be transferred.
62    ///
63    /// # Events
64    ///
65    /// Emits an event with:
66    /// - topics - `["transfer", from: Address, to: Address]`
67    /// - data - `[amount: i128]`
68    fn transfer(env: Env, from: Address, to: Address, amount: i128);
69
70    /// Transfer `amount` from `from` to `to`, consuming the allowance of
71    /// `spender`. Authorized by spender (`spender.require_auth()`).
72    ///
73    /// # Arguments
74    ///
75    /// - `spender` - The address authorizing the transfer, and having its
76    /// allowance consumed during the transfer.
77    /// - `from` - The address holding the balance of tokens which will be
78    /// withdrawn from.
79    /// - `to` - The address which will receive the transferred tokens.
80    /// - `amount` - The amount of tokens to be transferred.
81    ///
82    /// # Events
83    ///
84    /// Emits an event with:
85    /// - topics - `["transfer", from: Address, to: Address]`
86    /// - data - `[amount: i128]`
87    fn transfer_from(env: Env, spender: Address, from: Address, to: Address, amount: i128);
88
89    /// Burn `amount` from `from`.
90    ///
91    /// # Arguments
92    ///
93    /// - `from` - The address holding the balance of tokens which will be
94    /// burned from.
95    /// - `amount` - The amount of tokens to be burned.
96    ///
97    /// # Events
98    ///
99    /// Emits an event with:
100    /// - topics - `["burn", from: Address]`
101    /// - data - `[amount: i128]`
102    fn burn(env: Env, from: Address, amount: i128);
103
104    /// Burn `amount` from `from`, consuming the allowance of `spender`.
105    ///
106    /// # Arguments
107    ///
108    /// - `spender` - The address authorizing the burn, and having its allowance
109    /// consumed during the burn.
110    /// - `from` - The address holding the balance of tokens which will be
111    /// burned from.
112    /// - `amount` - The amount of tokens to be burned.
113    ///
114    /// # Events
115    ///
116    /// Emits an event with:
117    /// - topics - `["burn", from: Address]`
118    /// - data - `[amount: i128]`
119    fn burn_from(env: Env, spender: Address, from: Address, amount: i128);
120
121    /// Returns the number of decimals used to represent amounts of this token.
122    fn decimals(env: Env) -> u32;
123
124    /// Returns the name for this token.
125    fn name(env: Env) -> String;
126
127    /// Returns the symbol for this token.
128    fn symbol(env: Env) -> String;
129}
130
131/// Extension for functions implemented by the SEP-0041 compliant native Stellar Asset
132/// Contract: https://github.com/stellar/rs-soroban-env/blob/main/soroban-env-host/src/native_contract/token/contract.rs
133#[contractclient(name = "StellarAssetClient")]
134pub trait StellarAssetExtension {
135    /// Create `amount` of tokens and assigns them to `to`.
136    ///
137    /// Requires authorization by the admin.
138    ///
139    /// # Arguments
140    ///
141    /// - `to` - The address which will receive the created tokens.
142    /// - `amount` - The amount of tokens to be created.
143    fn mint(env: Env, to: Address, amount: i128);
144
145    /// Set the authorization status of an address to `authorize`.
146    ///
147    /// Requires authorization by the admin.
148    ///
149    /// # Arguments
150    ///
151    /// - `addr` - The address which will have their authorization modified.
152    /// - `authorize` - The authorization status to be set.
153    fn set_authorized(env: Env, addr: Address, authorize: bool);
154
155    /// Get the authorization status of an address.
156    ///
157    /// # Arguments
158    ///
159    /// - `addr` - The address which will have their authorization status queried.
160    fn authorized(env: Env, addr: Address) -> bool;
161
162    /// Clawback `amount` of tokens from `from`.
163    ///
164    /// Requires authorization by the admin.
165    ///
166    /// # Arguments
167    ///
168    /// - `from` - The address which will have their tokens clawed back.
169    /// - `amount` - The amount of tokens to be clawed back.
170    fn clawback(env: Env, from: Address, amount: i128);
171
172    /// Set the admin address to `new_admin`.
173    ///
174    /// Requires authorization by the admin.
175    ///
176    /// # Arguments
177    ///
178    /// - `new_admin` - The address which will be set as the new admin.
179    fn set_admin(env: Env, new_admin: Address);
180
181    /// Get the admin address.
182    fn admin(env: Env);
183}
184
185pub struct TokenEvents {}
186
187impl TokenEvents {
188    /// Emitted when an allowance is set
189    ///
190    /// - topics - `["approve", from: Address, spender: Address]`
191    /// - data - `[amount: i128, live_until_ledger: u32]`
192    pub fn approve(
193        env: &Env,
194        from: Address,
195        spender: Address,
196        amount: i128,
197        live_until_ledger: u32,
198    ) {
199        let topics = (symbol_short!("approve"), from, spender);
200        env.events().publish(topics, (amount, live_until_ledger));
201    }
202
203    /// Emitted when an amount is transferred from one address to another
204    ///
205    /// - topics - `["transfer", from: Address, to: Address]`
206    /// - data - `[amount: i128]`
207    pub fn transfer(env: &Env, from: Address, to: Address, amount: i128) {
208        let topics = (symbol_short!("transfer"), from, to);
209        env.events().publish(topics, amount);
210    }
211
212    /// Emitted when an amount of tokens is burnt from one address
213    ///
214    /// - topics - `["burn", from: Address]`
215    /// - data - `[amount: i128]`
216    pub fn burn(env: &Env, from: Address, amount: i128) {
217        let topics = (symbol_short!("burn"), from);
218        env.events().publish(topics, amount);
219    }
220
221    /// Emitted when an amount of tokens is created and assigned to an address
222    ///
223    /// - topics - `["mint", admin: Address, to: Address]`
224    /// - data - `[amount: i128]`
225    pub fn mint(env: &Env, admin: Address, to: Address, amount: i128) {
226        let topics = (symbol_short!("mint"), admin, to);
227        env.events().publish(topics, amount);
228    }
229}