Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 45 additions & 1 deletion content/stellar-contracts/access/ownable.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 0 additions & 2 deletions content/stellar-contracts/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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.

Expand Down
27 changes: 22 additions & 5 deletions content/stellar-contracts/tokens/fungible/fungible.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -103,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 package includes utility modules to help with common token implementation patterns:
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.

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)
Expand All @@ -132,6 +149,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).