From 9f9b1bcc83999d1b4ea38b36f73895b742c80238 Mon Sep 17 00:00:00 2001 From: Steve Date: Fri, 17 Oct 2025 13:01:20 -0400 Subject: [PATCH 1/3] chore: added changes to index page, ownable, and fungible --- content/stellar-contracts/access/ownable.mdx | 46 ++++++++++++++++++- content/stellar-contracts/index.mdx | 2 - .../tokens/fungible/fungible.mdx | 21 +++++++++ 3 files changed, 66 insertions(+), 3 deletions(-) diff --git a/content/stellar-contracts/access/ownable.mdx b/content/stellar-contracts/access/ownable.mdx index d96f0332..255a43d8 100644 --- a/content/stellar-contracts/access/ownable.mdx +++ b/content/stellar-contracts/access/ownable.mdx @@ -25,7 +25,51 @@ Until the transfer is accepted, the original owner retains full control and can The Ownable module allows the owner to permanently renounce ownership of the contract. This is a one-way operation that cannot be undone. After ownership is renounced, all functions marked with `#[only_owner]` become permanently inaccessible. -This feature is useful for contracts that need to become fully decentralized after an initial setup phase. +This feature is useful for contracts that need to become fully decentralized after an initial setup phase, or to make a contract **immutable and non-upgradeable** by removing administrative control entirely. + +#### Example: Making a Contract Immutable + +A common use case is renouncing ownership after initial setup to ensure the contract becomes immutable and cannot be upgraded: + +```rust +use soroban_sdk::{contract, contractimpl, Address, Env}; +use stellar_access::ownable::{self as ownable, Ownable}; +use stellar_macros::only_owner; + +#[contract] +pub struct MyContract; + +#[contractimpl] +impl MyContract { + pub fn __constructor(e: &Env, initial_owner: Address) { + ownable::set_owner(e, &initial_owner); + } + + #[only_owner] + pub fn finalize_and_lock(e: &Env) { + // Perform any final configuration here + // ... + + // Renounce ownership to make the contract immutable + // After this call, no owner-restricted functions can ever be called again + ownable::renounce_ownership(e); + + // The contract is now permanently locked and non-upgradeable + } + + #[only_owner] + pub fn emergency_upgrade(e: &Env, new_wasm_hash: BytesN<32>) { + // This function becomes permanently inaccessible after renounce_ownership + e.deployer().update_current_contract_wasm(new_wasm_hash); + } +} +``` + +**Important Notes:** +- Once `renounce_ownership()` is called, there is no way to restore ownership +- All functions marked with `#[only_owner]` become permanently inaccessible +- This effectively makes the contract immutable and non-upgradeable +- You cannot renounce ownership while a transfer is in progress ### Procedural Macro diff --git a/content/stellar-contracts/index.mdx b/content/stellar-contracts/index.mdx index 3f98ed9a..bb0c5382 100644 --- a/content/stellar-contracts/index.mdx +++ b/content/stellar-contracts/index.mdx @@ -8,7 +8,6 @@ Explore our comprehensive suite of secure and scalable smart contract utilities * **[Fungible Tokens](/stellar-contracts/tokens/fungible/fungible)**: Digital assets representing a fixed or dynamic supply of identical units. * **[Non-Fungible Tokens (NFTs)](/stellar-contracts/tokens/non-fungible/non-fungible)**: Unique digital assets with verifiable ownership. -* **Multi-Tokens**: Hybrid tokens enabling both fungible and non-fungible token functionalities (work in progress). ## Access Control @@ -31,7 +30,6 @@ we use the following convention: * Fungible: `1XX` * Non-Fungible: `2XX` -* Multi-Token: `3XX` Any future tokens will continue from `4XX`, `5XX`, and so on. diff --git a/content/stellar-contracts/tokens/fungible/fungible.mdx b/content/stellar-contracts/tokens/fungible/fungible.mdx index c3d99493..c1f08f99 100644 --- a/content/stellar-contracts/tokens/fungible/fungible.mdx +++ b/content/stellar-contracts/tokens/fungible/fungible.mdx @@ -22,6 +22,25 @@ The module provides several implementation options to suit different use cases: These implementations share core functionality and a common interface, exposing identical contract functions as entry-points. However, the extensions provide specialized behavior by overriding certain functions to implement their specific requirements. +## SAC + +The Stellar Asset Contract (SAC) is a special built-in implementation of [CAP-46-6 Smart Contract Standardized Asset](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0046-06.md) and [SEP-41 Token Interface](https://developers.stellar.org/docs/tokens/token-interface). The SAC acts as a bridge between traditional Stellar assets and Soroban smart contracts. + +SAC is NOT a library or custom contract; it's a built-in protocol feature that automatically wraps existing Stellar assets (like USDC, XLM, or any issued asset) so they can be used in smart contracts. Think of it as the "smart contract version" of any Stellar asset. + +Key points to know: +- Every Stellar asset gets its own SAC instance with a deterministic contract address +- No bridging or wrapping tokens needed - it's the same asset, just accessible via smart contracts +- Anyone can deploy a SAC for any asset (the original issuer doesn't need to be involved) +- SAC implements the same SEP-41 interface as OpenZeppelin fungible tokens, ensuring compatibility +- When you transfer between Stellar accounts and contracts, the balances are stored differently but represent the same underlying asset + +When to use SAC vs OpenZeppelin tokens: +- Use SAC: When you want to interact with existing Stellar assets (USDC, XLM, etc.) in your smart contracts +- Use OpenZeppelin: When creating new custom tokens with specialized logic, access controls, or unique tokenomics + +For example, if you want to build a DeFi protocol that uses USDC, you'd deploy the SAC for USDC rather than creating a new token. Users can then interact with the same USDC they hold in their Stellar wallets directly through your smart contract. + ## Usage We’ll create a simple token for a game’s in-game currency. Players can earn tokens by completing tasks, @@ -135,3 +154,5 @@ To comply with the SEP-41 specification, a contract must implement both the `Fun The library handles the TTL (Time-To-Live) of only `temporary` and `persistent` storage entries declared by the library. The `instance` TTL management is left to the implementor due to flexibility. The library exposes default values for extending the TTL: `INSTANCE_TTL_THRESHOLD` and `INSTANCE_EXTEND_AMOUNT`. + +For a comprehensive understanding of Soroban's three storage types (`temporary`, `persistent`, and `instance`) and their archival behavior, see the [State Archival documentation](https://developers.stellar.org/docs/learn/fundamentals/contract-development/storage/state-archival#contract-data-type-descriptions). From 2946559ede228e57466c8c73d64383de5ee8c3d9 Mon Sep 17 00:00:00 2001 From: Steve Date: Fri, 17 Oct 2025 13:30:32 -0400 Subject: [PATCH 2/3] chore: removed returns --- content/stellar-contracts/tokens/fungible/fungible.mdx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/content/stellar-contracts/tokens/fungible/fungible.mdx b/content/stellar-contracts/tokens/fungible/fungible.mdx index c1f08f99..2dcba939 100644 --- a/content/stellar-contracts/tokens/fungible/fungible.mdx +++ b/content/stellar-contracts/tokens/fungible/fungible.mdx @@ -151,8 +151,6 @@ To comply with the SEP-41 specification, a contract must implement both the `Fun ## TTL Management -The library handles the TTL (Time-To-Live) of only `temporary` and `persistent` storage entries declared -by the library. The `instance` TTL management is left to the implementor due to flexibility. The library -exposes default values for extending the TTL: `INSTANCE_TTL_THRESHOLD` and `INSTANCE_EXTEND_AMOUNT`. +The library handles the TTL (Time-To-Live) of only `temporary` and `persistent` storage entries declared by the library. The `instance` TTL management is left to the implementor due to flexibility. The library exposes default values for extending the TTL: `INSTANCE_TTL_THRESHOLD` and `INSTANCE_EXTEND_AMOUNT`. For a comprehensive understanding of Soroban's three storage types (`temporary`, `persistent`, and `instance`) and their archival behavior, see the [State Archival documentation](https://developers.stellar.org/docs/learn/fundamentals/contract-development/storage/state-archival#contract-data-type-descriptions). From d00bac0b80641b7b6a514b670ebaa6a5966b670c Mon Sep 17 00:00:00 2001 From: brozorec <9572072+brozorec@users.noreply.github.com> Date: Tue, 21 Oct 2025 11:47:16 +0200 Subject: [PATCH 3/3] re-order SAC --- .../tokens/fungible/fungible.mdx | 40 +++++++++---------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/content/stellar-contracts/tokens/fungible/fungible.mdx b/content/stellar-contracts/tokens/fungible/fungible.mdx index 2dcba939..372a4991 100644 --- a/content/stellar-contracts/tokens/fungible/fungible.mdx +++ b/content/stellar-contracts/tokens/fungible/fungible.mdx @@ -22,25 +22,6 @@ The module provides several implementation options to suit different use cases: These implementations share core functionality and a common interface, exposing identical contract functions as entry-points. However, the extensions provide specialized behavior by overriding certain functions to implement their specific requirements. -## SAC - -The Stellar Asset Contract (SAC) is a special built-in implementation of [CAP-46-6 Smart Contract Standardized Asset](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0046-06.md) and [SEP-41 Token Interface](https://developers.stellar.org/docs/tokens/token-interface). The SAC acts as a bridge between traditional Stellar assets and Soroban smart contracts. - -SAC is NOT a library or custom contract; it's a built-in protocol feature that automatically wraps existing Stellar assets (like USDC, XLM, or any issued asset) so they can be used in smart contracts. Think of it as the "smart contract version" of any Stellar asset. - -Key points to know: -- Every Stellar asset gets its own SAC instance with a deterministic contract address -- No bridging or wrapping tokens needed - it's the same asset, just accessible via smart contracts -- Anyone can deploy a SAC for any asset (the original issuer doesn't need to be involved) -- SAC implements the same SEP-41 interface as OpenZeppelin fungible tokens, ensuring compatibility -- When you transfer between Stellar accounts and contracts, the balances are stored differently but represent the same underlying asset - -When to use SAC vs OpenZeppelin tokens: -- Use SAC: When you want to interact with existing Stellar assets (USDC, XLM, etc.) in your smart contracts -- Use OpenZeppelin: When creating new custom tokens with specialized logic, access controls, or unique tokenomics - -For example, if you want to build a DeFi protocol that uses USDC, you'd deploy the SAC for USDC rather than creating a new token. Users can then interact with the same USDC they hold in their Stellar wallets directly through your smart contract. - ## Usage We’ll create a simple token for a game’s in-game currency. Players can earn tokens by completing tasks, @@ -122,9 +103,26 @@ The `FungibleBlockList` trait extends the `FungibleToken` trait to provide a blo can be managed by an authorized account. This extension ensures that blocked accounts cannot transfer/receive tokens, or approve token transfers. -## Utility Modules +## Stellar Asset Contract (SAC) + +The Stellar Asset Contract (SAC) is a special built-in implementation of [CAP-46-6 Smart Contract Standardized Asset](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0046-06.md) and [SEP-41 Token Interface](https://developers.stellar.org/docs/tokens/token-interface). The SAC acts as a bridge between traditional Stellar assets and Soroban smart contracts. + +SAC automatically wraps existing Stellar assets (like USDC, XLM, or any issued asset) so they can be used in smart contracts. Think of it as the "smart contract version" of any Stellar asset. + +Key points to know: +- Every Stellar asset gets its own SAC instance with a deterministic contract address +- No bridging or wrapping tokens needed - it's the same asset, just accessible via smart contracts +- Anyone can deploy a SAC for any asset (the original issuer doesn't need to be involved) +- When you transfer between Stellar accounts and contracts, the balances are stored differently but represent the same underlying asset +- SAC implements the same SEP-41 interface as OpenZeppelin fungible tokens + +When to use SAC vs OpenZeppelin tokens: +- Use SAC: When you want to interact with existing Stellar assets (USDC, XLM, etc.) in your smart contracts +- Use OpenZeppelin: When creating new custom tokens with specialized logic, access controls, or unique tokenomics + +For example, if you want to build a DeFi protocol that uses USDC, you'd deploy the SAC for USDC rather than creating a new token. Users can then interact with the same USDC they hold in their Stellar wallets directly through your smart contract. -The package includes utility modules to help with common token implementation patterns: +Every SAC has an admin interface for privileged operations like minting or clawback. The OpenZeppelin fungible token module provides utilities that enable you to set a separate contract as the admin for these operations: ### - SAC Admin Generic [Source Code](https://github.com/OpenZeppelin/stellar-contracts/tree/main/packages/tokens/src/fungible/utils/sac_admin_generic)