Skip to content
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

Integrate a Stellar asset contracts #754

Merged
merged 12 commits into from
Jul 24, 2024
94 changes: 94 additions & 0 deletions docs/build/guides/conventions/stellar-asset-contract.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
---
title: Integrate Stellar Assets Contracts
description: Test and use Stellar assets in a Soroban smart contract
---

From the contract perspective Stellar Asset Contract is not different from any other token that implements the Soroban [SEP-41 Token Interface]. The Rust SDK contains a pregenerated client for any contract that implements the token interface:
tupui marked this conversation as resolved.
Show resolved Hide resolved

```rust
use soroban_sdk::token;

struct MyContract;
tupui marked this conversation as resolved.
Show resolved Hide resolved

#[contractimpl]
impl MyContract {
fn token_fn(e: Env, id: Address) {
tupui marked this conversation as resolved.
Show resolved Hide resolved
// 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 operations part of the SEP-41 token interface
client.transfer(...);
}
}
```

The address parameter is not the address of the issuer of an asset, it corresponds to the deployed contract address for this asset.
tupui marked this conversation as resolved.
Show resolved Hide resolved

```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
tupui marked this conversation as resolved.
Show resolved Hide resolved

A client created by [`token::Client`] 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.
tupui marked this conversation as resolved.
Show resolved Hide resolved

```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(...);
```

:::

### 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 operations
let token = TokenClient::new(&e, &token_address);
// client for Stellar Asset Contract operations
ElliotFriend marked this conversation as resolved.
Show resolved Hide resolved
let token_sac = StellarAssetClient::new(&e, &token_address);

// 1e7 diff between minimal unit and unit itself
ElliotFriend marked this conversation as resolved.
Show resolved Hide resolved
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 `xfer` to and from the contract
tupui marked this conversation as resolved.
Show resolved Hide resolved
- [Atomic swap](../../smart-contracts/example-contracts/atomic-swap.mdx) uses `incr_allow` to transfer token on behalf of the user
ElliotFriend marked this conversation as resolved.
Show resolved Hide resolved

[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
11 changes: 0 additions & 11 deletions docs/build/guides/testing/mint-native-token.mdx

This file was deleted.

60 changes: 2 additions & 58 deletions docs/tokens/stellar-asset-contract.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,12 @@ Every Stellar asset on Stellar has reserved a contract address that the Stellar

It can be deployed using the [Stellar CLI] as shown [here](../build/guides/cli/deploy-stellar-asset-contract.mdx).

Or the [Stellar SDK] can be used as shown [here](../learn/encyclopedia/contract-development/contract-interactions/stellar-transaction.mdx#xdr-usage) by calling `InvokeHostFunctionOp` with `HOST_FUNCTION_TYPE_CREATE_CONTRACT` and `CONTRACT_ID_FROM_ASSET`. The resulting token will have a deterministic identifier, which will be the sha256 hash of `HashIDPreimage::ENVELOPE_TYPE_CONTRACT_ID_FROM_ASSET` xdr specified [here][contract_id].
Or the [Stellar CLI] can be used as shown [here](../learn/encyclopedia/contract-development/contract-interactions/stellar-transaction.mdx#xdr-usage) by calling `InvokeHostFunctionOp` with `HOST_FUNCTION_TYPE_CREATE_CONTRACT` and `CONTRACT_ID_FROM_ASSET`. The resulting token will have a deterministic identifier, which will be the sha256 hash of `HashIDPreimage::ENVELOPE_TYPE_CONTRACT_ID_FROM_ASSET` xdr specified [here][contract_id].

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
tupui marked this conversation as resolved.
Show resolved Hide resolved

## Interacting with classic Stellar assets

Expand Down Expand Up @@ -103,62 +103,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].
Expand Down
Loading