diff --git a/docs/build/guides/conventions/stellar-asset-contract.mdx b/docs/build/guides/conventions/stellar-asset-contract.mdx new file mode 100644 index 000000000..821a9ca89 --- /dev/null +++ b/docs/build/guides/conventions/stellar-asset-contract.mdx @@ -0,0 +1,105 @@ +--- +title: Integrate Stellar Assets Contracts +description: Test and use Stellar assets in a Soroban smart contract +--- + +When interacting with assets in a smart contract, the Stellar Asset Contract is not different from any other token that implements the Stellar [SEP-41 Token Interface]. + +## Contract Code + +The Rust SDK contains a pre-generated client for any contract that implements the token interface: + +```rust +use soroban_sdk::{contract, contractimpl} +use soroban_sdk::token; + +#[contract] +pub struct MyContract; + +#[contractimpl] +impl MyContract { + pub fn token_fn(e: Env, id: Address) { + // Create a client instance for the provided token identifier. If the id + // value corresponds to an SAC contract, then SAC implementation is used. + let client = token::TokenClient::new(&env, &id); + // Call token functions part of the Stellar SEP-41 token interface + client.transfer(...); + } +} +``` + +The `asset` parameter is not the address of the issuer of an asset, it corresponds to the deployed contract address for this asset. + +```bash +stellar contract id asset \ + --source G... \ + --network testnet \ + --asset [asset:issuer] +``` + +E.g. for USDC, it would be `--asset USDC:G...` For the native asset, XLM, `--asset native`. See the [deploy SAC] guide for more details. + +[deploy SAC]: ../cli/deploy-stellar-asset-contract.mdx + +:::info[Clients] + +A client created by [`token::TokenClient`] implements the functions defined by any contract that implements the [SEP-41 Token Interface]. But with [CAP-46-6 smart contract standardized asset], the Stellar Asset Contract exposes additional functions such as `mint`. To access the additional functions, another client needs to be used: [`token::StellarAssetClient`]. This client only implements the functions from CAP-46-6, which are not part of the SEP-41 interface. + +```rust +let client = token::StellarAssetClient::new(&env, &id); +// Call token functions which are not part of the SEP-41 token interface +// but part of the CAP-46-6 Smart Contract Standardized Asset +client.mint(...); +``` + +::: + +## Testing + +Soroban Rust SDK provides an easy way to instantiate a Stellar Asset Contract tokens using `register_stellar_asset_contract`. This function can be seen as the deployment of a generic token. In the following example, we are following the best practices outlined in the [Issuing and Distribution Accounts section](../../../tokens/control-asset-access.mdx#issuing-and-distribution-accounts): + +```rust +#![cfg(test)] + +use soroban_sdk::testutils::Address as _; +use soroban_sdk::{token, Address, Env}; +use token::TokenClient; +use token::StellarAssetClient; + +#[test] +fn test() { + let e = Env::default(); + e.mock_all_auths(); + + let issuer = Address::random(); + let distributer = Address::random(); + + let token_address = e.register_stellar_asset_contract(issuer.clone()); + + // client for SEP-41 functions + let token = TokenClient::new(&e, &token_address); + // client for Stellar Asset Contract functions + let token_sac = StellarAssetClient::new(&e, &token_address); + + // note that you need to account for the difference between the minimal + // unit and the unit itself when working with amounts. + // E.g. to mint 1 TOKEN, we need to use 1*1e7 in the mint function. + let genesis_amount: i128 = 1_000_000_000 * 10_000_000; + + token_sac.mint(&issuer, &distributer, &genesis_amount); + + assert_eq!(token.balance(&distributor), genesis_amount); +} +``` + +## Examples + +See the full examples that utilize the token contract in various ways for more details: + +- [Timelock](../../smart-contracts/example-contracts/timelock.mdx) and [single offer](../../smart-contracts/example-contracts/single-offer-sale.mdx) move token via `transfer` to and from the contract +- [Atomic swap](../../smart-contracts/example-contracts/atomic-swap.mdx) uses `transfer` to transfer token on behalf of the user + +[sep-41 token interface]: ../../../tokens/token-interface.mdx +[cap-46-6 smart contract standardized asset]: https://github.com/stellar/stellar-protocol/blob/master/core/cap-0046-06.md +[`token::tokenclient`]: https://docs.rs/soroban-sdk/latest/soroban_sdk/token/struct.TokenClient.html +[`token::stellarassetclient`]: https://docs.rs/soroban-sdk/latest/soroban_sdk/token/struct.StellarAssetClient.html diff --git a/docs/build/guides/testing/mint-native-token.mdx b/docs/build/guides/testing/mint-native-token.mdx deleted file mode 100644 index fd404a0bb..000000000 --- a/docs/build/guides/testing/mint-native-token.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: Mint native XLM in a contract test -hide_table_of_contents: true -draft: true ---- - -It can often be necessary to test whether your contract's interactions surrounding tokens work as intended. Often, the token you test again can be created from arbitrary details. However, there are occassions where testing against a specific token can be advantageous. Here is a test function that makes use of the Stellar Asset Contract for the native XLM token. - -```rust -env.token.native_asset_contract(); // or some such... -``` diff --git a/docs/build/smart-contracts/example-contracts/atomic-swap.mdx b/docs/build/smart-contracts/example-contracts/atomic-swap.mdx index e50bf474a..db5b87f21 100644 --- a/docs/build/smart-contracts/example-contracts/atomic-swap.mdx +++ b/docs/build/smart-contracts/example-contracts/atomic-swap.mdx @@ -180,7 +180,7 @@ fn move_token( } ``` -The swap itself is implemented via two token moves: from `a` to `b` and from `b` to `a`. The token move is implemented via allowance: the users don't need to know each other in order to perform the swap, and instead they authorize the swap contract to spend the necessary amount of token on their behalf via `incr_allow`. Soroban auth framework makes sure that the `incr_allow` signatures would have the proper context, and they won't be usable outside the `swap` contract invocation. +The swap itself is implemented via two token moves: from `a` to `b` and from `b` to `a`. The token move is implemented via allowance: the users don't need to know each other in order to perform the swap, and instead they authorize the swap contract to spend the necessary amount of token on their behalf via `transfer`. Soroban auth framework makes sure that the `transfer` signatures would have the proper context, and they won't be usable outside the `swap` contract invocation. ### Tests diff --git a/docs/tokens/stellar-asset-contract.mdx b/docs/tokens/stellar-asset-contract.mdx index c43a8686e..068f47379 100644 --- a/docs/tokens/stellar-asset-contract.mdx +++ b/docs/tokens/stellar-asset-contract.mdx @@ -57,7 +57,8 @@ Or the [Stellar SDK] can be used as shown [here](../learn/encyclopedia/contract- Anyone can deploy the instances of Stellar Asset Contract. Note, that the initialization of the Stellar Asset Contracts happens automatically during the deployment. Asset Issuer will have the administrative permissions after the contract has been deployed. [contract_id]: https://github.com/stellar/stellar-xdr/blob/dc23adf60e095a6ce626b2b09128e58a5eae0cd0/Stellar-transaction.x#L661 -[stellar-cli]: ../tools/developer-tools/README.mdx#cli +[stellar cli]: ../tools/developer-tools/README.mdx#cli +[stellar sdk]: ../tools/sdks/library.mdx ## Interacting with classic Stellar assets @@ -103,62 +104,6 @@ Unprivileged mutators require authorization from the `Address` that spends or al Priviliged mutators require authorization from a specific privileged identity, known as the "administrator". For example, only the administrator can `mint` more of the token. Similarly, only the administrator can appoint a new administrator. -## Using Stellar Asset Contract with other contracts - -From the contract perspective Stellar Asset Contract is not different from any other token that implements the Soroban token interface. The Rust SDK contains a pregenerated client for any contract that implements the token interface: - -```rust -use soroban_sdk::token; - -struct MyContract; - -#[contractimpl] -impl MyContract { - fn token_fn(e: Env, id: Address) { - // Create a client instance for the provided token identifier. If the id - // value corresponds to an SAC contract, then SAC implementation is used. - let client = token::Client::new(&env, &id); - // Call token operations part of the SEP-41 token interface - client.transfer(...); - } -} -``` - -:::info Clients - -A client created by [`token::Client`] implements the functions defined by any contract that implements the [SEP-41 Token Interface]. But the Stellar Asset Contract exposes additional functions such as `mint`. To access the additional functions, another client needs to be used: [`token::StellarAssetClient`]. This client only implements the functions which are not part of the SEP-41. - -```rust -let client = token::StellarAssetClient::new(&env, &id); -// Call token operations which are not part of the SEP-41 token interface -// but part of the CAP-46-6 Smart Contract Standardized Asset -client.mint(...); -``` - -::: - -### Examples - -See the full examples that utilize the token contract in various ways for more details: - -- [Timelock](../build/smart-contracts/example-contracts/timelock.mdx) and [single offer](../build/smart-contracts/example-contracts/single-offer-sale.mdx) move token via `xfer` to and from the contract -- [Atomic swap](../build/smart-contracts/example-contracts/atomic-swap.mdx) uses `incr_allow` to transfer token on behalf of the user - -Notice, that these examples don't do anything to support SAC specifically. - -### Testing - -Soroban Rust SDK provides an easy way to instantiate a Stellar Asset Contract tokens using `register_stellar_asset_contract`. For example: - -```rust -let admin = Address::random(); -let user = Address::random(); -let token = StellarAssetClient::new(e, &e.register_stellar_asset_contract(admin.clone())); -token.mint(&admin, &user, &1000); -``` - -See the tests in the [examples](#examples) above for the full test implementation. - ## Contract Interface This interface can be found in the [SDK]. It extends the common [SEP-41 Token Interface]. @@ -167,6 +112,3 @@ This interface can be found in the [SDK]. It extends the common [SEP-41 Token In [sdk]: https://docs.rs/soroban-sdk/latest/soroban_sdk/token/index.html [cap-46-6 smart contract standardized asset]: https://github.com/stellar/stellar-protocol/blob/master/core/cap-0046-06.md [sep-41 token interface]: ./token-interface.mdx -[`soroban_sdk::token`]: https://docs.rs/soroban-sdk/latest/soroban_sdk/token/ -[`token::tokenclient`]: https://docs.rs/soroban-sdk/latest/soroban_sdk/token/struct.TokenClient.html -[`token::stellarassetclient`]: https://docs.rs/soroban-sdk/latest/soroban_sdk/token/struct.StellarAssetClient.html