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
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
use soroban_token_sdk::metadata::TokenMetadata;
use stellar_axelar_gateway::executable::AxelarExecutableInterface;
use stellar_axelar_std::interfaces::{
OperatableInterface, OwnableInterface, PausableInterface, UpgradableInterface,
};
use stellar_axelar_std::types::Token;
use stellar_axelar_std::{contractclient, soroban_sdk, Address, Bytes, BytesN, Env, String};
use crate::error::ContractError;
use crate::types::TokenManagerType;
#[contractclient(name = "InterchainTokenServiceClient")]
pub trait InterchainTokenServiceInterface:
AxelarExecutableInterface
+ OwnableInterface
+ OperatableInterface
+ PausableInterface
+ UpgradableInterface
{
/// Returns the address of the Gas Service contract.
fn gas_service(env: &Env) -> Address;
/// Returns the name of the current chain.
fn chain_name(env: &Env) -> String;
/// Returns the name of the chain on which the ITS Hub is deployed.
fn its_hub_chain_name(env: &Env) -> String;
/// Returns the address of the ITS Hub.
fn its_hub_address(env: &Env) -> String;
/// Returns the address of the native token on the current chain.
fn native_token_address(env: &Env) -> Address;
/// Returns the WASM hash of the token contract used for deploying interchain tokens.
fn interchain_token_wasm_hash(env: &Env) -> BytesN<32>;
/// Returns the WASM hash of the token manager contract used for deploying token managers.
fn token_manager_wasm_hash(env: &Env) -> BytesN<32>;
/// Returns whether the specified chain is trusted for cross-chain messaging.
fn is_trusted_chain(env: &Env, chain: String) -> bool;
/// Sets the specified chain as trusted for cross-chain messaging.
/// # Authorization
/// - [`OperatableInterface::operator`] must authorize.
fn set_trusted_chain(env: &Env, chain: String) -> Result<(), ContractError>;
/// Removes the specified chain from trusted chains.
/// # Authorization
/// - [`OperatableInterface::operator`] must authorize.
fn remove_trusted_chain(env: &Env, chain: String) -> Result<(), ContractError>;
/// Computes the unique identifier for an interchain token.
///
/// The token ID is derived uniquely from the deployer's address and the provided salt.
///
/// # Parameters
/// - `deployer`: The address of the token deployer. In the case of tokens deployed by this contract, it will be Stellar's "dead" address.
/// - `salt`: A unique value used to generate the token ID.
///
/// # Returns
/// - A `BytesN<32>` value representing the token's unique ID.
fn interchain_token_id(env: &Env, deployer: Address, salt: BytesN<32>) -> BytesN<32>;
/// Computes a 32-byte token id for a canonical token.
///
/// The salt is derived uniquely from the chain name hash and token address.
///
/// # Parameters
/// - `token_address`: The address of the token for which the deployment salt is being generated.
///
/// # Returns
/// - A `BytesN<32>` value representing the computed deployment salt.
fn canonical_interchain_token_id(env: &Env, token_address: Address) -> BytesN<32>;
/// Computes a 32-byte token id for a linked token.
///
/// The salt is derived uniquely from the chain name hash and token address.
///
/// # Parameters
/// - `deployer`: The address of the token deployer.
/// - `salt`: A unique value used to generate the token ID.
fn linked_token_id(env: &Env, deployer: Address, salt: BytesN<32>) -> BytesN<32>;
/// Returns the predicted address of the native interchain token associated with the specified token ID.
///
/// # Arguments
/// - `token_id`: The token ID for the interchain token.
///
/// # Returns
/// - `Address`: The address of the interchain token.
fn interchain_token_address(env: &Env, token_id: BytesN<32>) -> Address;
/// Returns the predicted address of the token manager that will be deployed for the specified token ID.
///
/// # Arguments
/// - `token_id`: The token ID for the interchain token.
///
/// # Returns
/// - `Address`: The address of the token manager.
fn token_manager_address(env: &Env, token_id: BytesN<32>) -> Address;
/// Returns the address of the token associated with the specified token ID.
fn registered_token_address(env: &Env, token_id: BytesN<32>) -> Address;
/// Returns the address of the token manager associated with the specified token ID.
fn deployed_token_manager(env: &Env, token_id: BytesN<32>) -> Address;
/// Returns the type of the token manager associated with the specified token ID.
fn token_manager_type(env: &Env, token_id: BytesN<32>) -> TokenManagerType;
/// Returns the flow limit for the token associated with the specified token ID.
/// Returns `None` if no limit is set.
fn flow_limit(env: &Env, token_id: BytesN<32>) -> Option<i128>;
/// Returns the amount that has flowed out of the chain to other chains during the current epoch
/// for the token associated with the specified token ID.
fn flow_out_amount(env: &Env, token_id: BytesN<32>) -> i128;
/// Retrieves the amount that has flowed into the chain from other chains during the current epoch
/// for the token associated with the specified token ID.
fn flow_in_amount(env: &Env, token_id: BytesN<32>) -> i128;
/// Sets or updates the flow limit for a token.
///
/// Flow limit controls how many tokens can flow in/out during a single epoch.
/// Setting the limit to `None` disables flow limit checks for the token.
/// Setting the limit to 0 effectively freezes the token by preventing any flow.
///
/// # Arguments
/// - `token_id`: Unique identifier of the token.
/// - `flow_limit`: The new flow limit value. Must be positive if Some.
///
/// # Errors
/// - [`ContractError::InvalidFlowLimit`]: If the provided flow limit is not positive.
///
/// # Authorization
/// - [`OperatableInterface::operator`] must authorize.
fn set_flow_limit(
env: &Env,
token_id: BytesN<32>,
flow_limit: Option<i128>,
) -> Result<(), ContractError>;
/// Deploys a new interchain token on the current chain with specified metadata and optional
/// initial supply. If initial supply is provided, it is minted to the caller. The
/// caller can also specify an optional minter address for the interchain token.
///
/// # Arguments
/// - `caller`: Address of the caller initiating the deployment.
/// - `salt`: A 32-byte unique salt used for token deployment.
/// - `token_metadata`: Metadata for the new token (name, symbol, decimals).
/// - `initial_supply`: Initial amount to mint to caller, if greater than 0.
/// - `minter`: Optional address that will have a minter role for the deployed interchain token.
///
/// # Returns
/// - `Ok(BytesN<32>)`: Returns the token ID.
///
/// # Errors
/// - [`ContractError::InvalidMinter`]: If the minter address is invalid.
///
/// # Authorization
/// - The `deployer` must authorize.
fn deploy_interchain_token(
env: &Env,
deployer: Address,
salt: BytesN<32>,
token_metadata: TokenMetadata,
initial_supply: i128,
minter: Option<Address>,
) -> Result<BytesN<32>, ContractError>;
/// Initiates the deployment of an interchain token to a specified destination chain.
///
/// # Arguments
/// - `caller`: Address of the caller initiating the deployment.
/// - `salt`: A 32-byte unique salt used for token deployment.
/// - `destination_chain`: The name of the destination chain where the token will be deployed.
/// - `gas_token`: An optional gas token used to pay for the gas cost of the cross-chain call.
///
/// # Returns
/// - `Ok(BytesN<32>)`: Returns the token ID.
///
/// # Errors
/// - [`ContractError::InvalidTokenId`]: If the token ID does not exist in the persistent storage.
/// - Any error propagated from `pay_gas_and_call_contract`.
///
/// # Authorization
/// - The `caller` must authorize.
fn deploy_remote_interchain_token(
env: &Env,
caller: Address,
salt: BytesN<32>,
destination_chain: String,
gas_token: Option<Token>,
) -> Result<BytesN<32>, ContractError>;
/// Registers a canonical token as an interchain token.
///
/// # Arguments
/// - `token_address` - The address of the canonical token.
///
/// # Returns
/// - `Ok(BytesN<32>)`: Returns the token ID.
///
/// # Errors
/// - [`ContractError::TokenAlreadyRegistered`]: If the token ID is already registered.
fn register_canonical_token(
env: &Env,
token_address: Address,
) -> Result<BytesN<32>, ContractError>;
/// Deploys a remote canonical token on a specified destination chain.
///
/// Anyone can call this to deploy a trustless canonical representation of the token to any trusted destination chain.
/// If the token name is longer than 32 characters, the symbol will be used as the name.
/// Specifically, natively issued Stellar assets will be deployed with the symbol as the name.
///
/// # Arguments
/// * `token_address` - The address of the token to be deployed.
/// * `destination_chain` - The name of the destination chain where the token will be deployed.
/// * `spender` - The spender of the cross-chain gas.
/// * `gas_token` - An optional gas token used to pay for gas during the deployment.
///
/// # Returns
/// - `Ok(BytesN<32>)`: Returns the token ID.
///
/// # Errors
/// - [`ContractError::InvalidTokenId`]: If the token ID does not exist in the persistent storage.
/// - Any error propagated from `pay_gas_and_call_contract`.
///
/// # Authorization
/// - `spender` needs to authorize `pay_gas` call to the gas service.
fn deploy_remote_canonical_token(
env: &Env,
token_address: Address,
destination_chain: String,
spender: Address,
gas_token: Option<Token>,
) -> Result<BytesN<32>, ContractError>;
/// Registers token metadata with the ITS Hub.
///
/// This function validates the token's metadata and sends a message to the ITS Hub
/// to register the token's metadata (address and decimals). The token must be a valid
/// token contract that implements the required metadata interface.
///
/// # Arguments
/// - `token_address`: The address of the token whose metadata is being registered.
/// - `spender`: The address that will pay for the cross-chain gas.
/// - `gas_token`: An optional gas token used to pay for cross-chain message execution.
///
/// # Returns
/// - `Ok(())`: If the metadata was successfully registered.
///
/// # Errors
/// - [`ContractError::InvalidTokenAddress`]: If the token address is invalid or the token contract doesn't implement the required interface.
/// - [`ContractError::TokenInvocationError`]: If the token contract call fails.
/// - Any error propagated from `pay_gas_and_call_contract`.
///
/// # Authorization
/// - `spender` needs to authorize `pay_gas` call to the gas service.
fn register_token_metadata(
env: &Env,
token_address: Address,
spender: Address,
gas_token: Option<Token>,
) -> Result<(), ContractError>;
/// Registers a custom token as an interchain token.
///
/// This function is used to register custom tokens on this chain.
/// Then link token can be used to register those tokens to other chains.
///
/// # Arguments
/// - `deployer`: Address of the deployer initiating the registration.
/// - `salt`: A unique salt to deterministically derive the tokenId for the custom token.
/// - `token_address`: The address of the custom token contract to register.
/// - `token_manager_type`: The type of token manager to use for the token registration (e.g., LockUnlock).
///
/// # Returns
/// - `Ok(BytesN<32>)`: Returns the derived token ID for the registered custom token.
///
/// # Errors
/// - [`ContractError::TokenAlreadyRegistered`]: If the token ID is already registered.
/// - [`ContractError::InvalidTokenManagerType`]: If the provided token manager type is not allowed for custom tokens.
///
/// # Authorization
/// - The `deployer` must authorize.
fn register_custom_token(
env: &Env,
deployer: Address,
salt: BytesN<32>,
token_address: Address,
token_manager_type: TokenManagerType,
) -> Result<BytesN<32>, ContractError>;
/// Links a remote token on the destination chain to a local token corresponding to the token ID computed from the provided salt.
///
/// A local token must have been registered first using the `register_custom_token` function.
///
/// # Arguments
/// - `deployer`: Address of the deployer initiating the token linking. It will also pay the cross-chain gas.
/// - `salt`: The salt used to derive the token ID for the custom token registration. The same salt must be used when linking this token on other chains under the same token ID.
/// - `destination_chain`: The name of the destination chain. Cannot be the same as the current chain.
/// - `destination_token_address`: The token address of the token being linked on the destination chain.
/// - `token_manager_type`: The token manager type used for the token link. Cannot be `[TokenManagerType::NativeInterchainToken]`.
/// - `link_params`: Optional Additional parameters for the token link depending on the destination chain.
/// - `gas_token`: An optional gas token used to pay for cross-chain message execution.
///
/// # Returns
/// - `Ok(BytesN<32>)`: Returns the token ID corresponding to the linked token.
///
/// # Errors
/// - [`ContractError::InvalidTokenManagerType`]: If the provided token manager type is NativeInterchainToken.
/// - [`ContractError::InvalidDestinationChain`]: If the destination chain is the same as the current chain.
/// - Any error propagated from token metadata validation or `pay_gas_and_call_contract`.
///
/// # Authorization
/// - The `deployer` must authorize.
fn link_token(
env: &Env,
deployer: Address,
salt: BytesN<32>,
destination_chain: String,
destination_token_address: Bytes,
token_manager_type: TokenManagerType,
link_params: Option<Bytes>,
gas_token: Option<Token>,
) -> Result<BytesN<32>, ContractError>;
/// Initiates a cross-chain token transfer.
///
/// Takes tokens from the caller on the source chain and initiates a transfer
/// to the specified destination chain. The tokens will be transferred to the destination address
/// when the message is executed on the destination chain.
///
/// If `data` is provided, the `destination_address` will also be executed as a contract with the
/// `data` to allow arbitrary processing of the transferred tokens.
///
/// # Arguments
/// - `caller`: The address initiating the transfer.
/// - `token_id`: The unique identifier of the token being transferred.
/// - `destination_chain`: The chain to which tokens will be transferred.
/// - `destination_address`: The recipient address on the destination chain.
/// - `amount`: The amount of tokens to transfer. Must be greater than 0.
/// - `data`: Optional data to be handled by the destination address if it's a contract.
/// - `gas_token`: An optional gas token used to pay for cross-chain message execution.
///
/// # Errors
/// - [`ContractError::InvalidAmount`]: If amount is not greater than 0.
/// - [`ContractError::FlowLimitExceeded`]: If transfer would exceed flow limits.
/// - Any error propagated from `pay_gas_and_call_contract`.
///
/// # Authorization
/// - The `caller` must authorize.
fn interchain_transfer(
env: &Env,
caller: Address,
token_id: BytesN<32>,
destination_chain: String,
destination_address: Bytes,
amount: i128,
metadata: Option<Bytes>,
gas_token: Option<Token>,
) -> Result<(), ContractError>;
/// Transfers the admin role of a Stellar Classic Asset registered under the `token_id`
/// from the corresponding token manager to the `new_admin`.
///
/// # Arguments
/// - `token_id`: The unique identifier of the registered token.
/// - `new_admin`: The address that will become the new admin of the token.
///
/// # Authorization
/// - [`OwnableInterface::owner`] must authorize.
fn transfer_token_admin(
env: &Env,
token_id: BytesN<32>,
new_admin: Address,
) -> Result<(), ContractError>;
}