1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
use fvm_actor_utils::receiver::RecipientData;
use fvm_ipld_encoding::tuple::{Deserialize_tuple, Serialize_tuple};
use fvm_ipld_encoding::RawBytes;
use fvm_shared::address::Address;
use fvm_shared::econ::TokenAmount;

/// A standard fungible token interface allowing for on-chain transactions that implements the
/// FRC-0046 standard. This represents the external interface exposed to other on-chain actors
///
/// Token authors must implement this trait and link the methods to standard dispatch numbers (as
/// defined by [FRC-0042](https://github.com/filecoin-project/FIPs/blob/master/FRCs/frc-0042.md)).
pub trait FRC46Token {
    type TokenError;
    /// Returns the name of the token
    ///
    /// Must not be empty
    fn name(&self) -> String;

    /// Returns the ticker symbol of the token
    ///
    /// Must not be empty. Should be a short uppercase string
    fn symbol(&self) -> String;

    /// Returns the smallest amount of tokens which is indivisible.
    ///
    /// All transfers, burns, and mints must be a whole multiple of the granularity. All balances
    /// must be a multiple of this granularity (but allowances need not be). Must be at least 1.
    /// Must never change.
    ///
    /// A granularity of 10^18 corresponds to whole units only, with no further decimal precision.
    fn granularity(&self) -> GranularityReturn;

    /// Returns the total amount of the token in existence
    ///
    /// Must be non-negative. The total supply must equal the balances of all addresses. The total
    /// supply should equal the sum of all minted tokens less the sum of all burnt tokens.
    fn total_supply(&mut self) -> TotalSupplyReturn;

    /// Returns the balance of an address
    ///
    /// Balance is always non-negative. Uninitialised addresses have an implicit zero balance.
    fn balance_of(&mut self, params: Address) -> Result<BalanceReturn, Self::TokenError>;

    /// Returns the allowance approved for an operator on a spender's balance
    ///
    /// The operator can burn or transfer the allowance amount out of the owner's address.
    fn allowance(
        &mut self,
        params: GetAllowanceParams,
    ) -> Result<AllowanceReturn, Self::TokenError>;

    /// Transfers tokens from the caller to another address
    ///
    /// Amount must be non-negative (but can be zero). Transferring to the caller's own address must
    /// be treated as a normal transfer. Must call the receiver hook on the receiver's address,
    /// failing and aborting the transfer if calling the hook fails or aborts.
    fn transfer(&mut self, params: TransferParams) -> Result<TransferReturn, Self::TokenError>;

    /// Transfers tokens from one address to another
    ///
    /// The caller must have previously approved to control at least the sent amount. If successful,
    /// the amount transferred is deducted from the caller's allowance.
    fn transfer_from(
        &mut self,
        params: TransferFromParams,
    ) -> Result<TransferFromReturn, Self::TokenError>;

    /// Atomically increases the approved allowance that a operator can transfer/burn from the
    /// caller's balance
    ///
    /// The increase must be non-negative. Returns the new total allowance approved for that
    /// owner-operator pair.
    fn increase_allowance(
        &mut self,
        params: IncreaseAllowanceParams,
    ) -> Result<IncreaseAllowanceReturn, Self::TokenError>;

    /// Atomically decreases the approved balance that a operator can transfer/burn from the caller's
    /// balance
    ///
    /// The decrease must be non-negative. Sets the allowance to zero if the decrease is greater
    /// than the currently approved allowance. Returns the new total allowance approved for that
    /// owner-operator pair.
    fn decrease_allowance(
        &mut self,
        params: DecreaseAllowanceParams,
    ) -> Result<DecreaseAllowanceReturn, Self::TokenError>;

    /// Sets the allowance a operator has on the owner's account to zero
    fn revoke_allowance(
        &mut self,
        params: RevokeAllowanceParams,
    ) -> Result<RevokeAllowanceReturn, Self::TokenError>;

    /// Burns tokens from the caller's balance, decreasing the total supply
    fn burn(&mut self, params: BurnParams) -> Result<BurnReturn, Self::TokenError>;

    /// Burns tokens from an address's balance
    ///
    /// The caller must have been previously approved to control at least the burnt amount.
    fn burn_from(&mut self, params: BurnFromParams) -> Result<BurnFromReturn, Self::TokenError>;
}

pub type GranularityReturn = u64;
pub type TotalSupplyReturn = TokenAmount;
pub type BalanceReturn = TokenAmount;
pub type AllowanceReturn = TokenAmount;
pub type IncreaseAllowanceReturn = TokenAmount;
pub type DecreaseAllowanceReturn = TokenAmount;
pub type RevokeAllowanceReturn = ();

/// Return value after a successful mint.
/// The mint method is not standardised, so this is merely a useful library-level type,
/// and recommendation for token implementations.
#[derive(Serialize_tuple, Deserialize_tuple, Clone, Debug)]
pub struct MintReturn {
    /// The new balance of the owner address
    pub balance: TokenAmount,
    /// The new total supply.
    pub supply: TokenAmount,
    /// (Optional) data returned from receiver hook
    pub recipient_data: RawBytes,
}

/// Intermediate data used by mint_return to construct the return data
#[derive(Clone, Debug)]
pub struct MintIntermediate {
    /// Recipient address to use for querying balance
    pub recipient: Address,
    /// (Optional) data returned from receiver hook
    pub recipient_data: RawBytes,
}

impl RecipientData for MintIntermediate {
    fn set_recipient_data(&mut self, data: RawBytes) {
        self.recipient_data = data;
    }
}

/// Instruction to transfer tokens to another address
#[derive(Serialize_tuple, Deserialize_tuple, Clone, Debug)]
pub struct TransferParams {
    pub to: Address,
    /// A non-negative amount to transfer
    pub amount: TokenAmount,
    /// Arbitrary data to pass on via the receiver hook
    pub operator_data: RawBytes,
}

/// Return value after a successful transfer
#[derive(Serialize_tuple, Deserialize_tuple, Clone, Debug)]
pub struct TransferReturn {
    /// The new balance of the `from` address
    pub from_balance: TokenAmount,
    /// The new balance of the `to` address
    pub to_balance: TokenAmount,
    /// (Optional) data returned from receiver hook
    pub recipient_data: RawBytes,
}

/// Intermediate data used by transfer_return to construct the return data
#[derive(Debug)]
pub struct TransferIntermediate {
    pub from: Address,
    pub to: Address,
    /// (Optional) data returned from receiver hook
    pub recipient_data: RawBytes,
}

impl RecipientData for TransferIntermediate {
    fn set_recipient_data(&mut self, data: RawBytes) {
        self.recipient_data = data;
    }
}

/// Instruction to transfer tokens between two addresses as an operator
#[derive(Serialize_tuple, Deserialize_tuple, Clone, Debug)]
pub struct TransferFromParams {
    pub from: Address,
    pub to: Address,
    /// A non-negative amount to transfer
    pub amount: TokenAmount,
    /// Arbitrary data to pass on via the receiver hook
    pub operator_data: RawBytes,
}

/// Return value after a successful delegated transfer
#[derive(Serialize_tuple, Deserialize_tuple, Clone, Debug)]
pub struct TransferFromReturn {
    /// The new balance of the `from` address
    pub from_balance: TokenAmount,
    /// The new balance of the `to` address
    pub to_balance: TokenAmount,
    /// The new remaining allowance between `owner` and `operator` (caller)
    pub allowance: TokenAmount,
    /// (Optional) data returned from receiver hook
    pub recipient_data: RawBytes,
}

/// Intermediate data used by transfer_from_return to construct the return data
#[derive(Clone, Debug)]
pub struct TransferFromIntermediate {
    pub operator: Address,
    pub from: Address,
    pub to: Address,
    /// (Optional) data returned from receiver hook
    pub recipient_data: RawBytes,
}

impl RecipientData for TransferFromIntermediate {
    fn set_recipient_data(&mut self, data: RawBytes) {
        self.recipient_data = data;
    }
}

/// Instruction to increase an allowance between two addresses
#[derive(Serialize_tuple, Deserialize_tuple, Clone, Debug)]
pub struct IncreaseAllowanceParams {
    pub operator: Address,
    /// A non-negative amount to increase the allowance by
    pub increase: TokenAmount,
}

/// Instruction to decrease an allowance between two addresses
#[derive(Serialize_tuple, Deserialize_tuple, Clone, Debug)]
pub struct DecreaseAllowanceParams {
    pub operator: Address,
    /// A non-negative amount to decrease the allowance by
    pub decrease: TokenAmount,
}

/// Instruction to revoke (set to 0) an allowance
#[derive(Serialize_tuple, Deserialize_tuple, Clone, Debug)]
pub struct RevokeAllowanceParams {
    pub operator: Address,
}

/// Params to get allowance between to addresses
#[derive(Serialize_tuple, Deserialize_tuple, Clone, Debug)]
pub struct GetAllowanceParams {
    pub owner: Address,
    pub operator: Address,
}

/// Instruction to burn an amount of tokens
#[derive(Serialize_tuple, Deserialize_tuple, Clone, Debug)]
pub struct BurnParams {
    /// A non-negative amount to burn
    pub amount: TokenAmount,
}

/// The updated value after burning
#[derive(Serialize_tuple, Deserialize_tuple, Clone, Debug)]
pub struct BurnReturn {
    /// New balance in the account after the successful burn
    pub balance: TokenAmount,
}

/// Instruction to burn an amount of tokens from another address
#[derive(Serialize_tuple, Deserialize_tuple, Clone, Debug)]
pub struct BurnFromParams {
    pub owner: Address,
    /// A non-negative amount to burn
    pub amount: TokenAmount,
}

/// The updated value after a delegated burn
#[derive(Serialize_tuple, Deserialize_tuple, Clone, Debug)]
pub struct BurnFromReturn {
    /// New balance in the account after the successful burn
    pub balance: TokenAmount,
    /// New remaining allowance between the owner and operator (caller)
    pub allowance: TokenAmount,
}