From fdb306305990734214638a53a7a928483d9705f6 Mon Sep 17 00:00:00 2001 From: Ozgun Ozerk Date: Tue, 21 Oct 2025 16:19:39 +0300 Subject: [PATCH 1/2] there is no need to keep prev verions as of yet --- .../stellar-contracts/0.2.0/get-started.mdx | 7 - content/stellar-contracts/0.2.0/index.mdx | 37 ---- .../0.2.0/tokens/fungible.mdx | 71 ------- .../0.2.0/tokens/nft-consecutive.mdx | 58 ----- .../0.2.0/tokens/nft-enumerable.mdx | 66 ------ .../0.2.0/tokens/non-fungible.mdx | 91 -------- .../0.2.0/utils/pausable.mdx | 33 --- .../0.2.0/utils/upgradeable.mdx | 185 ---------------- .../stellar-contracts/0.3.0/get-started.mdx | 7 - .../0.3.0/helpers/default-impl-macro.mdx | 95 --------- content/stellar-contracts/0.3.0/index.mdx | 51 ----- .../0.3.0/tokens/fungible/fungible.mdx | 144 ------------- .../tokens/fungible/sac-admin-generic.mdx | 197 ----------------- .../tokens/fungible/sac-admin-wrapper.mdx | 122 ----------- .../tokens/non-fungible/nft-consecutive.mdx | 58 ----- .../tokens/non-fungible/nft-enumerable.mdx | 66 ------ .../tokens/non-fungible/non-fungible.mdx | 108 ---------- .../0.3.0/utils/access/access-control.mdx | 110 ---------- .../0.3.0/utils/access/ownable.mdx | 99 --------- .../stellar-contracts/0.3.0/utils/crypto.mdx | 201 ------------------ .../0.3.0/utils/pausable.mdx | 33 --- .../0.3.0/utils/upgradeable.mdx | 185 ---------------- 22 files changed, 2024 deletions(-) delete mode 100644 content/stellar-contracts/0.2.0/get-started.mdx delete mode 100644 content/stellar-contracts/0.2.0/index.mdx delete mode 100644 content/stellar-contracts/0.2.0/tokens/fungible.mdx delete mode 100644 content/stellar-contracts/0.2.0/tokens/nft-consecutive.mdx delete mode 100644 content/stellar-contracts/0.2.0/tokens/nft-enumerable.mdx delete mode 100644 content/stellar-contracts/0.2.0/tokens/non-fungible.mdx delete mode 100644 content/stellar-contracts/0.2.0/utils/pausable.mdx delete mode 100644 content/stellar-contracts/0.2.0/utils/upgradeable.mdx delete mode 100644 content/stellar-contracts/0.3.0/get-started.mdx delete mode 100644 content/stellar-contracts/0.3.0/helpers/default-impl-macro.mdx delete mode 100644 content/stellar-contracts/0.3.0/index.mdx delete mode 100644 content/stellar-contracts/0.3.0/tokens/fungible/fungible.mdx delete mode 100644 content/stellar-contracts/0.3.0/tokens/fungible/sac-admin-generic.mdx delete mode 100644 content/stellar-contracts/0.3.0/tokens/fungible/sac-admin-wrapper.mdx delete mode 100644 content/stellar-contracts/0.3.0/tokens/non-fungible/nft-consecutive.mdx delete mode 100644 content/stellar-contracts/0.3.0/tokens/non-fungible/nft-enumerable.mdx delete mode 100644 content/stellar-contracts/0.3.0/tokens/non-fungible/non-fungible.mdx delete mode 100644 content/stellar-contracts/0.3.0/utils/access/access-control.mdx delete mode 100644 content/stellar-contracts/0.3.0/utils/access/ownable.mdx delete mode 100644 content/stellar-contracts/0.3.0/utils/crypto.mdx delete mode 100644 content/stellar-contracts/0.3.0/utils/pausable.mdx delete mode 100644 content/stellar-contracts/0.3.0/utils/upgradeable.mdx diff --git a/content/stellar-contracts/0.2.0/get-started.mdx b/content/stellar-contracts/0.2.0/get-started.mdx deleted file mode 100644 index 3b337982..00000000 --- a/content/stellar-contracts/0.2.0/get-started.mdx +++ /dev/null @@ -1,7 +0,0 @@ ---- -title: Get Started ---- - -Not sure where to start? Use the interactive generator below to bootstrap your contract and find about the components offered in OpenZeppelin Smart Contracts Suite for Stellar. You can also access the code generator from [here](https://wizard.openzeppelin.com/stellar). - - diff --git a/content/stellar-contracts/0.2.0/index.mdx b/content/stellar-contracts/0.2.0/index.mdx deleted file mode 100644 index 2dce7967..00000000 --- a/content/stellar-contracts/0.2.0/index.mdx +++ /dev/null @@ -1,37 +0,0 @@ ---- -title: Stellar Smart Contracts Suite ---- - -A comprehensive collection of secure, scalable smart contracts and utilities for the Stellar network, -supporting Fungible, Non-Fungible, and Multi-Token standards. - -## Tokens -Explore our implementations for token standards on Stellar Soroban: - -* ***[Fungible Tokens](/stellar-contracts/0.2.0/tokens/fungible)***: Digital assets representing a fixed or dynamic supply of identical units. -* ***[Non-Fungible Tokens](/stellar-contracts/0.2.0/tokens/non-fungible)***: Unique digital assets with verifiable ownership. -* ***Multi-Token***: Hybrid tokens enabling both fungible and non-fungible token functionalities (work in progress). - -## Utilities -Discover our utility contracts for Stellar Soroban, applicable to all token standards mentioned above: - -* ***[Pausable](/stellar-contracts/utils/pausable)*** -* ***[Upgrades and Migrations](/stellar-contracts/0.2.0/utils/upgradeable)*** - -## Error Codes -In Stellar Soroban, each error variant is assigned an integer. To prevent duplication of error codes, -we use the following convention: - -* Utilities: `1XX` - * Pausable: `10X` - * Upgradeable: `11X` - * any future utilities will continue from `12X`, `13X`, and so on. -* Fungible: `2XX` -* Non-Fungible: `3XX` -* Multi-Token: `4XX` - -## Audits -You can find our audit reports [here](https://github.com/OpenZeppelin/stellar-contracts/tree/main/audits). - -## Get Started -Get started [here](/stellar-contracts/0.2.0/get-started). diff --git a/content/stellar-contracts/0.2.0/tokens/fungible.mdx b/content/stellar-contracts/0.2.0/tokens/fungible.mdx deleted file mode 100644 index c29f26d5..00000000 --- a/content/stellar-contracts/0.2.0/tokens/fungible.mdx +++ /dev/null @@ -1,71 +0,0 @@ ---- -title: Fungible Token Standard ---- - -[Source Code](https://github.com/OpenZeppelin/stellar-contracts/tree/main/packages/tokens/fungible) - -## Purpose - -The Fungible Token Standard is a contract template designed to facilitate the creation and management of fungible tokens on the Stellar network. -It provides a flexible and secure framework for defining and managing token standards, enabling developers to create and manage tokens with ease. - -## Extensions - -We provide the below extensions to enhance the capabilities of the Fungible Token Standard. - -### - Mintable -[Source Code](https://github.com/OpenZeppelin/stellar-contracts/tree/main/packages/tokens/fungible/src/extensions/mintable) - -#### Summary -The `FungibleMintable` trait extends the `FungibleToken` trait to provide the capability to mint tokens. - -#### Events -* `mint_event` : broadcasted to the network when the `mint()` function is invoked. - -### - Capped -[Source Code](https://github.com/OpenZeppelin/stellar-contracts/tree/main/packages/tokens/fungible/src/extensions/capped) - -#### Summary -The `Capped` trait extends the `FungibleToken` trait to provide the capability to set a maximum supply for the token. - -Note that the `Capped` trait is designed to be used in conjunction with the `Mintable` trait. - -#### Events -There are no custom events associated with the `Capped` trait. - -### - Burnable -[Source Code](https://github.com/OpenZeppelin/stellar-contracts/tree/main/packages/tokens/fungible/src/extensions/burnable) - -#### Summary -The `FungibleBurnable` trait extends the `FungibleToken` trait to provide the -capability to burn tokens. - -To fully comply with the SEP-41 specification one have to implement the -this `FungibleBurnable` trait along with the `[FungibleToken]` trait. -SEP-41 mandates support for token burning to be considered compliant. - -Excluding the `burn` functionality from the `[FungibleToken]` trait -is a deliberate design choice to accommodate flexibility and customization -for various smart contract use cases. - -#### Events -* `burn_event`: broadcasted to the network when the `burn()` or `burn_from()` function is invoked. - -### - Metadata -[Source Code](https://github.com/OpenZeppelin/stellar-contracts/tree/main/packages/tokens/fungible/src/extensions/metadata) - -#### Summary -Provides `setter` and `getter` methods for `symbol`, `name`, and `decimal` metadata information for your token. - -#### Events -There are no custom events associated with the `Metadata` trait. - -## Misc - -To comply with the SEP-41 specification, a contract must implement both the `FungibleToken` and `FungibleBurnable` -traits. These traits together provide all the necessary methods to conform to `soroban_sdk::token::TokenInterface`, -offering another way to meet the SEP-41 requirements. - -For contracts that implement both `FungibleToken` and `FungibleBurnable`, -and also need to implement `TokenInterface`, we provide the `impl_token_interface!` macro. -This macro automatically generates the required boilerplate, simplifying the implementation process. diff --git a/content/stellar-contracts/0.2.0/tokens/nft-consecutive.mdx b/content/stellar-contracts/0.2.0/tokens/nft-consecutive.mdx deleted file mode 100644 index 50f8d360..00000000 --- a/content/stellar-contracts/0.2.0/tokens/nft-consecutive.mdx +++ /dev/null @@ -1,58 +0,0 @@ ---- -title: Non-Fungible Consecutive ---- - -[Source Code](https://github.com/OpenZeppelin/stellar-contracts/tree/main/packages/tokens/non-fungible/src/extensions/consecutive) - -Consecutive extension for [Non-Fungible Token](/stellar-contracts/0.2.0/tokens/non-fungible) is useful -for efficiently minting multiple tokens in a single transaction. This can significantly -reduce costs and improve performance when creating a large number of tokens at once. - -## Usage - -We’ll continue with the [example](/stellar-contracts/0.2.0/tokens/non-fungible#usage) from **Non-Fungible Token** -and modify the contract so that now batches of tokens can be minted with each call -to `award_items`. Please note any account can call `award_items` and we might want to -implement access control to restrict who can mint. - -```rust -use soroban_sdk::{contract, contractimpl, Address, Env, String}; -use stellar_default_impl_macro::default_impl; -use stellar_non_fungible::{ - consecutive::{Consecutive, NonFungibleConsecutive}, - Base, ContractOverrides, NonFungibleToken, -}; - -#[contract] -pub struct GameItem; - -#[contractimpl] -impl GameItem { - pub fn __constructor(e: &Env) { - Base::set_metadata( - e, - String::from_str(e, "www.mygame.com"), - String::from_str(e, "My Game Items Collection"), - String::from_str(e, "MGMC"), - ); - } - - pub fn award_items(e: &Env, to: Address, amount: u32) -> u32 { - // access control might be needed - Consecutive::batch_mint(e, &to, amount) - } - - pub fn burn(e: &Env, from: Address, token_id: u32) { - Consecutive::burn(e, &from, token_id); - } -} - -#[default_impl] -#[contractimpl] -impl NonFungibleToken for GameItem { - type ContractType = Consecutive; -} - -// no entry-point functions required, marker impl -impl NonFungibleConsecutive for GameItem {} -``` diff --git a/content/stellar-contracts/0.2.0/tokens/nft-enumerable.mdx b/content/stellar-contracts/0.2.0/tokens/nft-enumerable.mdx deleted file mode 100644 index d574af99..00000000 --- a/content/stellar-contracts/0.2.0/tokens/nft-enumerable.mdx +++ /dev/null @@ -1,66 +0,0 @@ ---- -title: Non-Fungible Enumerable ---- - -[Source Code](https://github.com/OpenZeppelin/stellar-contracts/tree/main/packages/tokens/non-fungible/src/extensions/enumerable) - -Enumerable extension for [Non-Fungible Token](/stellar-contracts/0.2.0/tokens/non-fungible) allows for enumeration -of all the token IDs in the contract as well as all the token IDs owned by each account. This is -useful for applications that need to list or iterate over tokens, such as marketplaces or wallets. - -## Usage - -We’ll build on the [example](/stellar-contracts/0.2.0/tokens/non-fungible#usage) from **Non-Fungible Token** -and modify the contract so that all tokens an address own can be listed. Please note any account -can call `award_item` and we might want to implement access control to restrict who can mint. - -```rust -use soroban_sdk::{contract, contractimpl, Address, Env, String}; -use stellar_default_impl_macro::default_impl; -use stellar_non_fungible::{ - enumerable::{Enumerable, NonFungibleEnumerable}, - Base, ContractOverrides, NonFungibleToken, -}; - -#[contract] -pub struct GameItem; - -#[contractimpl] -impl GameItem { - pub fn __constructor(e: &Env) { - Base::set_metadata( - e, - String::from_str(e, "www.mygame.com"), - String::from_str(e, "My Game Items Collection"), - String::from_str(e, "MGMC"), - ); - } - - pub fn award_item(e: &Env, to: Address) -> u32 { - // access control might be needed - Enumerable::sequential_mint(e, &to) - } - - pub fn burn(e: &Env, from: Address, token_id: u32) { - Enumerable::sequential_burn(e, &from, token_id); - } -} - -#[default_impl] -#[contractimpl] -impl NonFungibleToken for GameItem { - type ContractType = Enumerable; -} - -#[default_impl] -#[contractimpl] -impl NonFungibleEnumerable for GameItem {} -``` - -The extension exposes additionally the following entry-point functions, automatically implemented by `#[default_impl]`: - -```rust -fn total_supply(e: &Env) -> u32; -fn get_owner_token_id(e: &Env, owner: Address, index: u32) -> u32; -fn get_token_id(e: &Env, index: u32) -> u32; -``` diff --git a/content/stellar-contracts/0.2.0/tokens/non-fungible.mdx b/content/stellar-contracts/0.2.0/tokens/non-fungible.mdx deleted file mode 100644 index 3f6ec187..00000000 --- a/content/stellar-contracts/0.2.0/tokens/non-fungible.mdx +++ /dev/null @@ -1,91 +0,0 @@ ---- -title: Non-Fungible Token ---- - -[Source Code](https://github.com/OpenZeppelin/stellar-contracts/tree/main/packages/tokens/non-fungible) - -In the world of digital assets, not all tokens are alike. This becomes important in situations -like **real estate**, **voting rights**, or **collectibles**, where some items are valued more than -others due to their usefulness, rarity, etc. -On Stellar, you can create non-fungible tokens (NFTs), where each token is unique and -represents something distinct, with ownership tracked through Soroban smart contracts. - -## Overview - -The [non-fungible](https://github.com/OpenZeppelin/stellar-contracts/tree/main/packages/tokens/non-fungible) module -provides three different NFT variants that differ in how certain features like ownership tracking, -token creation and destruction are handled: - -1. **Default base implementations** (`NonFungibleToken` and `NonFungibleBurnable`), suitable for most use cases. -2. **Consecutive extension** (`NonFungibleConsecutive`) that fits needs where batch minting is envisioned, -the implementation is optimized for creation of large amounts of tokens. -3. **Enumerable extension** (`NonFungibleEnumerable`), for cases where on-chain enumerability is required, -enabling a smart contract to list all the NFTs an address owns. - -These three variants share core functionality and a common interface, exposing identical contract functions as -entry-points. However, composing custom flows must be handled with extra caution. That is required because of the -incompatible nature between the business logic of the different NFT variants or the need to wrap the base -functionality with additional logic. - -## Usage - -We’ll use an NFT to track game items, each having their own unique attributes. Whenever one is to be -awarded to a player, it will be minted and sent to them. Players are free to keep or burn their token or -trade it with other people as they see fit. Please note any account can call `award_item` and we might -want to implement access control to restrict who can mint. - -Here’s what a contract for tokenized items might look like: - -```rust -use soroban_sdk::{contract, contractimpl, Address, Env, String}; -use stellar_default_impl_macro::default_impl; -use stellar_non_fungible::{ - burnable::NonFungibleBurnable, - Base, ContractOverrides, NonFungibleToken, -}; - -#[contract] -pub struct GameItem; - -#[contractimpl] -impl GameItem { - pub fn __constructor(e: &Env) { - Base::set_metadata( - e, - String::from_str(e, "www.mygame.com"), - String::from_str(e, "My Game Items Collection"), - String::from_str(e, "MGMC"), - ); - } - - pub fn award_item(e: &Env, to: Address) -> u32 { - // access control might be needed - Base::sequential_mint(e, &to) - } -} - -#[default_impl] -#[contractimpl] -impl NonFungibleToken for GameItem { - type ContractType = Base; -} - -#[default_impl] -#[contractimpl] -impl NonFungibleBurnable for GameItem {} -``` - -## Base and Extensions - -The default base variant is split into two parts: - -1. **Non-Fungible Token**: The base logic for NFT transfers, approvals, minting and metadata handling. -2. **Non-Fungible Burnable**: Optional Extension with the base logic for token destruction by token holders. - -Separating the burn functionality from `NonFungibleToken` aims to accommodate flexibility and -customization for various use cases. - -The following optional extensions are also provided: - -* [Non-Fungible Consecutive](/stellar-contracts/0.2.0/tokens/nft-consecutive): Extension for optimized minting of batches of tokens. -* [Non-Fungible Enumerable](/stellar-contracts/0.2.0/tokens/nft-enumerable): Extension that allows enumerating the tokens on-chain. diff --git a/content/stellar-contracts/0.2.0/utils/pausable.mdx b/content/stellar-contracts/0.2.0/utils/pausable.mdx deleted file mode 100644 index 9b35dbc2..00000000 --- a/content/stellar-contracts/0.2.0/utils/pausable.mdx +++ /dev/null @@ -1,33 +0,0 @@ ---- -title: Pausable ---- - -[Source Code](https://github.com/OpenZeppelin/stellar-contracts/tree/main/packages/contract-utils/pausable) - -## Purpose - -Allows contracts to be paused and unpaused by authorized accounts. - -This utility contract can be used with any token standard (fungible, non-fungible, multi-token). - -## Design - -To make it easier to spot when inspecting the code, we turned this simple functionality into a macro that can annotate your smart contract functions. - -An example: -```rust -#[when_paused] -pub fn emergency_reset(e: &Env) { - e.storage().instance().set(&DataKey::Counter, &0); -} -``` - -Which will expand into the below code: - -```rust -pub fn emergency_reset(e: &Env) { - when_paused(e); - - e.storage().instance().set(&DataKey::Counter, &0); -} -``` diff --git a/content/stellar-contracts/0.2.0/utils/upgradeable.mdx b/content/stellar-contracts/0.2.0/utils/upgradeable.mdx deleted file mode 100644 index 18fc1595..00000000 --- a/content/stellar-contracts/0.2.0/utils/upgradeable.mdx +++ /dev/null @@ -1,185 +0,0 @@ ---- -title: Upgrades and Migrations ---- - -[Source code](https://github.com/OpenZeppelin/stellar-contracts/tree/main/packages/contract-utils/upgradeable) - -Soroban contracts are mutable by default. Mutability in the context of Stellar Soroban refers to the ability of a smart -contract to modify its WASM bytecode, thereby altering its function interface, execution logic, or metadata. - -Soroban provides a built-in, protocol-level defined mechanism for contract upgrades, allowing contracts to upgrade -themselves if they are explicitly designed to do so. One of the advantages of it is the flexibility it offers to -contract developers who can choose to make the contract immutable by simply not provisioning upgradability mechanics. On -the other hand, providing upgradability on a protocol level significantly reduces the risk surface, compared to other -smart contract platforms, which lack native support for upgradability. - -While Soroban’s built-in upgradability eliminates many of the challenges, related to managing smart contract upgrades -and migrations, certain caveats must still be considered. - -## Overview - -The [upgradeable](https://github.com/OpenZeppelin/stellar-contracts/tree/main/packages/contract-utils/upgradeable) module -provides a lightweight upgradeability framework with additional support for structured and safe migrations. - -It consists of two main components: - -1. ***[`Upgradeable`](/stellar-contracts/utils/upgradeable#upgrade-only)*** for cases where only the WASM binary needs to be updated. -2. ***[`UpgradeableMigratable`](/stellar-contracts/utils/upgradeable#upgrade-and-migrate)*** for more advanced scenarios where, in addition to the WASM binary, specific storage entries -must be modified (migrated) during the upgrade process. - -The recommended way to use this module is through the `\#[derive(Upgradeable)]` and `#[derive(UpgradeableMigratable)]` -macros. - -They handle the implementation of the necessary functions, allowing developers to focus solely on managing authorizations -and access control. These derive macros also leverage the crate version from the contract’s `Cargo.toml` and set it as -the binary version in the WASM metadata, aligning with the guidelines outlined in -[SEP-49](https://github.com/stellar/stellar-protocol/blob/master/ecosystem%2Fsep-0049.md). - - - -While the framework structures the upgrade flow, it does NOT perform deeper checks and verifications such as: - -* Ensuring that the new contract does not include a constructor, as it will not be invoked. -* Verifying that the new contract includes an upgradability mechanism, preventing an unintended loss of further - upgradability capacity. -* Checking for storage consistency, ensuring that the new contract does not inadvertently introduce storage mismatches. - - -## Usage - -### Upgrade Only -#### `Upgradeable` - -When only the WASM binary needs to be upgraded and no additional migration logic is required, developers should implement -the `UpgradeableInternal` trait. This trait is where authorization and custom access control logic are defined, -specifying who can perform the upgrade. This minimal implementation keeps the focus solely on controlling upgrade -permissions. - -```rust -use soroban_sdk::{ - contract, contracterror, contractimpl, panic_with_error, symbol_short, Address, Env, -}; -use stellar_upgradeable::UpgradeableInternal; -use stellar_upgradeable_macros::Upgradeable; - -#[contracterror] -#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] -#[repr(u32)] -pub enum ExampleContractError { - Unauthorized = 1, -} - -#[derive(Upgradeable)] -#[contract] -pub struct ExampleContract; - -#[contractimpl] -impl ExampleContract { - pub fn __constructor(e: &Env, admin: Address) { - e.storage().instance().set(&symbol_short!("OWNER"), &admin); - } -} - -impl UpgradeableInternal for ExampleContract { - fn _require_auth(e: &Env, operator: &Address) { - operator.require_auth(); - // `operator` is the invoker of the upgrade function and can be used - // to perform a role-based access control if implemented - let owner: Address = e.storage().instance().get(&symbol_short!("OWNER")).unwrap(); - if *operator != owner { - panic_with_error!(e, ExampleContractError::Unauthorized) - } - } -} -``` - -### Upgrade and Migrate -#### `UpgradeableMigratable` - -When both the WASM binary and specific storage entries need to be modified as part of the upgrade process, the -`UpgradeableMigratableInternal` trait should be implemented. In addition to defining access control and migration -logic, the developer must specify an associated type that represents the data required for the migration. - -The `#[derive(UpgradeableMigratable)]` macro manages the sequencing of operations, ensuring that the migration can -only be invoked after a successful upgrade, preventing potential state inconsistencies and storage corruption. - -```rust -use soroban_sdk::{ - contract, contracterror, contracttype, panic_with_error, symbol_short, Address, Env, -}; -use stellar_upgradeable::UpgradeableMigratableInternal; -use stellar_upgradeable_macros::UpgradeableMigratable; - -#[contracterror] -#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] -#[repr(u32)] -pub enum ExampleContractError { - Unauthorized = 1, -} - -#[contracttype] -pub struct Data { - pub num1: u32, - pub num2: u32, -} - -#[derive(UpgradeableMigratable)] -#[contract] -pub struct ExampleContract; - -impl UpgradeableMigratableInternal for ExampleContract { - type MigrationData = Data; - - fn _require_auth(e: &Env, operator: &Address) { - operator.require_auth(); - let owner: Address = e.storage().instance().get(&symbol_short!("OWNER")).unwrap(); - if *operator != owner { - panic_with_error!(e, ExampleContractError::Unauthorized) - } - } - - fn _migrate(e: &Env, data: &Self::MigrationData) { - e.storage().instance().set(&symbol_short!("DATA_KEY"), data); - } -} -``` - - -If a rollback is required, the contract can be upgraded to a newer version where the rollback-specific logic -is defined and performed as a migration. - - -#### Atomic upgrade and migration - -When performing an upgrade, the new implementation only becomes effective after the current invocation completes. -This means that if migration logic is included in the new implementation, it cannot be executed within the same -call. To address this, an auxiliary contract called `Upgrader` can be used to wrap both invocations, enabling an -atomic upgrade-and-migrate process. This approach ensures that the migration logic is executed immediately after the -upgrade without requiring a separate transaction. - -```rust -use soroban_sdk::{contract, contractimpl, symbol_short, Address, BytesN, Env, Val}; -use stellar_upgradeable::UpgradeableClient; - -#[contract] -pub struct Upgrader; - -#[contractimpl] -impl Upgrader { - pub fn upgrade_and_migrate( - env: Env, - contract_address: Address, - operator: Address, - wasm_hash: BytesN<32>, - migration_data: soroban_sdk::Vec, - ) { - operator.require_auth(); - let contract_client = UpgradeableClient::new(&env, &contract_address); - - contract_client.upgrade(&wasm_hash, &operator); - // The types of the arguments to the migrate function are unknown to this - // contract, so we need to call it with invoke_contract. - env.invoke_contract::<()>(&contract_address, &symbol_short!("migrate"), migration_data); - } -} -``` diff --git a/content/stellar-contracts/0.3.0/get-started.mdx b/content/stellar-contracts/0.3.0/get-started.mdx deleted file mode 100644 index d8b43894..00000000 --- a/content/stellar-contracts/0.3.0/get-started.mdx +++ /dev/null @@ -1,7 +0,0 @@ ---- -title: Get Started ---- - -Not sure where to start? Use the interactive generator below to bootstrap your contract and find about the components offered in OpenZeppelin Smart Contracts Suite for Stellar. You can also access the code generator from [here](https://wizard.openzeppelin.com/stellar). - - diff --git a/content/stellar-contracts/0.3.0/helpers/default-impl-macro.mdx b/content/stellar-contracts/0.3.0/helpers/default-impl-macro.mdx deleted file mode 100644 index 687bfb7e..00000000 --- a/content/stellar-contracts/0.3.0/helpers/default-impl-macro.mdx +++ /dev/null @@ -1,95 +0,0 @@ ---- -title: Default Implementation Macro ---- - -[Source Code](https://github.com/OpenZeppelin/stellar-contracts/tree/main/packages/contract-utils/default-impl-macro) - -## Overview - -The `#[default_impl]` macro is a utility that simplifies the implementation of OpenZeppelin Stellar -contract traits by automatically generating default implementations for trait methods. This allows developers -to focus only on overriding the methods they need to customize, while the macro handles the rest. - -## Background - -When using Soroban’s `#[contractimpl]` macro, all methods (including default implementations) must be explicitly -included in the implementation block for them to be accessible to the generated client. This is due to how -Rust macros work - they cannot access default implementations of trait methods that are not in the scope of the macro. - -The `#[default_impl]` macro solves this problem by automatically generating the missing default implementations -for OpenZeppelin Stellar traits. - -## Supported Traits - -The `#[default_impl]` macro supports the following OpenZeppelin Stellar traits: - -* `FungibleToken` -* `FungibleBurnable` -* `NonFungibleToken` -* `NonFungibleBurnable` -* `NonFungibleEnumerable` -* `AccessControl` -* `Ownable` - -The `#[default_impl]` macro intentionally does not support the following traits: - -* `FungibleAllowlist` -* `FungibleBlocklist` -* `NonFungibleRoyalties` - -This limitation is by design: authorization configurations require specific implementation tailored to -each project’s security requirements. By requiring manual implementation of these traits, we ensure -developers carefully consider and explicitly define their authorization logic rather than relying on generic defaults. - -## Usage - -To use the `[default_impl]` macro, place it above the `[contractimpl]` macro when implementing one of the supported traits: - -```rust -#[default_impl] // IMPORTANT: place this above `#[contractimpl]` -#[contractimpl] -impl NonFungibleToken for MyContract { - type ContractType = Base; - - // Only override the methods you need to customize - // All other methods will be automatically implemented with their default behavior -} -``` - -## How It Works - -The `#[default_impl]` macro: - -1. Identifies which trait is being implemented -2. Determines which methods are explicitly defined by the user -3. Uses the user defined methods to overwrite the default implementations -4. Fills the rest of the methods (not defined by the user) with default implementations -5. Adds any necessary imports for the trait - -This process ensures that all trait methods are available to the client generated by `#[contractimpl]`, while allowing developers to only write the code they need to customize. - -## Examples - -### Fungible Token Example - -```rust -use soroban_sdk::{contract, contractimpl, Address, Env}; -use stellar_fungible::FungibleToken; -use stellar_default_impl::default_impl; - -#[contract] -pub struct MyToken; - -#[default_impl] -#[contractimpl] -impl FungibleToken for MyToken { - type ContractType = Base; - - // Only override methods that need custom behavior - fn transfer(e: &Env, from: Address, to: Address, amount: i128) { - // custom transfer logic here - } - - // All other FungibleToken methods will be automatically implemented -} -``` diff --git a/content/stellar-contracts/0.3.0/index.mdx b/content/stellar-contracts/0.3.0/index.mdx deleted file mode 100644 index 3a6e88d6..00000000 --- a/content/stellar-contracts/0.3.0/index.mdx +++ /dev/null @@ -1,51 +0,0 @@ ---- -title: Stellar Smart Contracts Suite ---- - -A comprehensive collection of secure, scalable smart contracts and utilities for the Stellar network, -supporting Fungible, Non-Fungible, and Multi-Token standards. - -## Tokens -Explore our implementations for token standards on Stellar Soroban: - -* ***[Fungible Tokens](/stellar-contracts/tokens/fungible/fungible)***: Digital assets representing a fixed or dynamic supply of identical units. -* ***[Non-Fungible Tokens](/stellar-contracts/tokens/non-fungible/non-fungible)***: Unique digital assets with verifiable ownership. -* ***Multi-Token***: Hybrid tokens enabling both fungible and non-fungible token functionalities (work in progress). - -## Utilities -Discover our utility contracts for Stellar Soroban, applicable to all token standards mentioned above: - -* ***[Pausable](/stellar-contracts/0.3.0/utils/pausable)*** -* ***[Upgrades and Migrations](/stellar-contracts/0.3.0/utils/upgradeable)*** - -## Error Codes -In Stellar Soroban, each error variant is assigned an integer. To prevent duplication of error codes, -we use the following convention: - -* Fungible: `1XX` -* Non-Fungible: `2XX` -* Multi-Token: `3XX` - -Any future tokens will continue from `4XX`, `5XX`, and so on. - -* Utilities: `1XXX` - * Pausable: `10XX` - * Upgradeable: `11XX` - * Access: `12XX` - * Role Transfer (internal common module for 2-step role transfer): `120X` - * Access Control: `121X` - * Ownable: `122X` - * Merkle Distributor: `13XX` - -Any future utilities will continue from `14XX`, `15XX`, and so on. - -## Important Notes -As a deliberate design choice, this library manages the TTL for temporary and persistent storage items. -To provide flexibility to the owner of the contract, this library deliberately does not manage the TTL for instance storage items. -It is the responsibility of the developer to manage the TTL for instance storage items. - -## Audits -You can find our audit reports [here](https://github.com/OpenZeppelin/stellar-contracts/tree/main/audits). - -## Get Started -Get started [here](/stellar-contracts/0.3.0/get-started). diff --git a/content/stellar-contracts/0.3.0/tokens/fungible/fungible.mdx b/content/stellar-contracts/0.3.0/tokens/fungible/fungible.mdx deleted file mode 100644 index fe2e76f5..00000000 --- a/content/stellar-contracts/0.3.0/tokens/fungible/fungible.mdx +++ /dev/null @@ -1,144 +0,0 @@ ---- -title: Fungible Token ---- - -[Source Code](https://github.com/OpenZeppelin/stellar-contracts/tree/main/packages/tokens/fungible) - -Fungible tokens represent assets where each unit is identical and interchangeable, such as currencies, -commodities, or utility tokens. On Stellar, you can create fungible tokens where each token has the -same value and properties, with balances and ownership tracked through Soroban smart contracts. - -## Overview - -The [fungible](https://github.com/OpenZeppelin/stellar-contracts/tree/main/packages/tokens/fungible) -module provides three different Fungible Token variants that differ in how certain features like -token transfers and approvals are handled: - -The module provides several implementation options to suit different use cases: - -1. **Base implementation** (`FungibleToken` with `Base` contract type): Suitable for most standard token use cases. -2. **AllowList extension** (`FungibleToken` with `AllowList` contract type): For tokens that require an allowlist mechanism to control who can transfer tokens. -3. **BlockList extension** (`FungibleToken` with `BlockList` contract type): For tokens that need to block specific addresses from transferring tokens. - -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. - -## Usage - -We’ll create a simple token for a game’s in-game currency. Players can earn tokens by completing tasks, -and they can spend tokens on in-game items. The contract owner can mint new tokens as needed, -and players can transfer tokens between accounts. - -Here’s what a basic fungible token contract might look like: - -```rust -use soroban_sdk::{contract, contractimpl, Address, Env, String}; -use stellar_default_impl_macro::default_impl; -use stellar_fungible::{burnable::FungibleBurnable, Base, ContractOverrides, FungibleToken}; -use stellar_ownable::{self as ownable, Ownable}; -use stellar_ownable_macro::only_owner; - -#[contract] -pub struct GameCurrency; - -#[contractimpl] -impl GameCurrency { - pub fn __constructor(e: &Env, initial_owner: Address) { - // Set token metadata - Base::set_metadata( - e, - 8, // 8 decimals - String::from_str(e, "Game Currency"), - String::from_str(e, "GCUR"), - ); - - // Set the contract owner - ownable::set_owner(e, &initial_owner); - } - - #[only_owner] - pub fn mint_tokens(e: &Env, to: Address, amount: i128) { - // Mint tokens to the recipient - Base::mint(e, &to, amount); - } -} - -#[default_impl] -#[contractimpl] -impl FungibleToken for GameCurrency { - type ContractType = Base; -} - -#[default_impl] -#[contractimpl] -impl FungibleBurnable for GameCurrency {} -``` - -## Extensions - -The following optional extensions are provided: - -### - Burnable -[Source Code](https://github.com/OpenZeppelin/stellar-contracts/tree/main/packages/tokens/fungible/src/extensions/burnable) - -The `FungibleBurnable` trait extends the `FungibleToken` trait to provide the capability to burn tokens. -To fully comply with the SEP-41 specification, a contract must implement both the `FungibleToken` -and `FungibleBurnable` traits. - -### - Capped -[Source Code](https://github.com/OpenZeppelin/stellar-contracts/tree/main/packages/tokens/fungible/src/extensions/capped) - -Unlike other extensions, the capped extension does not expose a separate trait. Instead, -it offers helper functions designed to assist in implementing the mint function, enforcing a supply cap. - -### - AllowList -[Source Code](https://github.com/OpenZeppelin/stellar-contracts/tree/main/packages/tokens/fungible/src/extensions/allowlist) - -The `FungibleAllowList` trait extends the `FungibleToken` trait to provide an allowlist mechanism that -can be managed by an authorized account. This extension ensures that only allowed accounts can -transfer/receive tokens or approve token transfers. - -### - BlockList -[Source Code](https://github.com/OpenZeppelin/stellar-contracts/tree/main/packages/tokens/fungible/src/extensions/blocklist) - -The `FungibleBlockList` trait extends the `FungibleToken` trait to provide a blocklist mechanism that -can be managed by an authorized account. This extension ensures that blocked accounts cannot transfer/receive -tokens, or approve token transfers. - -### TokenInterface Macro - -For contracts that implement both `FungibleToken` and `FungibleBurnable` and also need to implement -`soroban_sdk::token::TokenInterface`, we provide the `impl_token_interface!` macro. This macro automatically -generates the required boilerplate, simplifying the implementation process. - -## Utility Modules - -The package includes utility modules to help with common token implementation patterns: - -### - SAC Admin Generic -[Source Code](https://github.com/OpenZeppelin/stellar-contracts/tree/main/packages/tokens/fungible/src/utils/sac_admin_generic) - -Provides generic admin functionality similar to the Stellar Asset Contract (SAC). This approach leverages the `__check_auth` function to handle authentication and authorization logic while maintaining a unified interface. - -For detailed documentation, see [SAC Admin Generic](/stellar-contracts/0.3.0/tokens/fungible/sac-admin-generic). - -### - SAC Admin Wrapper -[Source Code](https://github.com/OpenZeppelin/stellar-contracts/tree/main/packages/tokens/fungible/src/utils/sac_admin_wrapper) - -Provides a wrapper around the SAC admin functionality for easier integration. This approach defines specific entry points for each admin function and forwards calls to the corresponding SAC functions. - -For detailed documentation, see [SAC Admin Wrapper](/stellar-contracts/0.3.0/tokens/fungible/sac-admin-wrapper). - -## Compatibility and Compliance - -The module is designed to ensure full compatibility with SEP-0041. It also closely mirrors the Ethereum ERC-20 -standard, facilitating cross-ecosystem familiarity and ease of use. - -To comply with the SEP-41 specification, a contract must implement both the `FungibleToken` and -`FungibleBurnable` traits. These traits together provide all the necessary methods to conform to -`soroban_sdk::token::TokenInterface`. - -## 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`. diff --git a/content/stellar-contracts/0.3.0/tokens/fungible/sac-admin-generic.mdx b/content/stellar-contracts/0.3.0/tokens/fungible/sac-admin-generic.mdx deleted file mode 100644 index cf9afd3b..00000000 --- a/content/stellar-contracts/0.3.0/tokens/fungible/sac-admin-generic.mdx +++ /dev/null @@ -1,197 +0,0 @@ ---- -title: SAC Admin Generic ---- - -[Source Code](https://github.com/OpenZeppelin/stellar-contracts/tree/main/packages/tokens/fungible/src/utils/sac_admin_generic) - -## Overview - -The Stellar Asset Contract (SAC) Admin Generic module provides a way to implement custom administrative -functionality for Stellar Asset Contracts (SACs) using the generic approach. This approach leverages the -`__check_auth` function to handle authentication and authorization logic while maintaining a unified -interface for both user-facing and admin functions. - -## Key Concepts - -When a classic Stellar asset is ported to Soroban, it is represented by a SAC - a smart contract that provides -both user-facing and administrative functions for asset management. SACs expose standard functions for handling -fungible tokens, such as `transfer`, `approve`, `burn`, etc. Additionally, they include administrative functions -(`mint`, `clawback`, `set_admin`, `set_authorized`) that are initially restricted to the issuer (a G-account). - -The `set_admin` function enables transferring administrative control to a custom contract, allowing for more -complex authorization logic. This flexibility opens up possibilities for implementing custom rules, such as -role-based access control, two-step admin transfers, mint rate limits, and upgradeability. - -## Generic Approach - -The Generic approach to SAC Admin implementation: - -* Leverages the `__check_auth` function to handle authentication and authorization logic -* Maintains a unified interface for both user-facing and admin functions -* Allows for injecting any custom authorization logic -* Requires a more sophisticated authorization mechanism - -### Example Implementation - -Here’s a simplified example of a SAC Admin Generic contract: - -```rust -#[contracterror] -#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] -#[repr(u32)] -pub enum SACAdminGenericError { - Unauthorized = 1, - InvalidContext = 2, - MintingLimitExceeded = 3, -} - -#[contracttype] -#[derive(Clone)] -pub struct Signature { - pub public_key: BytesN<32>, - pub signature: BytesN<64>, -} - -#[contracttype] -pub enum SacDataKey { - Chief, - Operator(BytesN<32>), // -> true/false - MintingLimit(BytesN<32>), // -> (max_limit, curr) -} - -#[contract] -pub struct SacAdminExampleContract; - -#[contractimpl] -impl SacAdminExampleContract { - pub fn __constructor(e: Env, sac: Address, chief: BytesN<32>, operator: BytesN<32>) { - set_sac_address(&e, &sac); - e.storage().instance().set(&SacDataKey::Chief, &chief); - e.storage().instance().set(&SacDataKey::Operator(operator.clone()), &true); - e.storage() - .instance() - .set(&SacDataKey::MintingLimit(operator), &(1_000_000_000i128, 0i128)); - } - - pub fn get_sac_address(e: &Env) -> Address { - get_sac_address(e) - } -} -``` - -### Custom Authorization Logic - -The key feature of the Generic approach is the ability to implement custom authorization logic in the `__check_auth` -function: - -```rust -use soroban_sdk::{ - auth::{Context, CustomAccountInterface}, - contract, contracterror, contractimpl, contracttype, - crypto::Hash, - Address, BytesN, Env, IntoVal, Val, Vec, -}; - -#[contractimpl] -impl CustomAccountInterface for SacAdminExampleContract { - type Error = SACAdminGenericError; - type Signature = Signature; - - fn __check_auth( - e: Env, - payload: Hash<32>, - signature: Self::Signature, - auth_context: Vec, - ) -> Result<(), SACAdminGenericError> { - // authenticate - e.crypto().ed25519_verify( - &signature.public_key, - &payload.clone().into(), - &signature.signature, - ); - let caller = signature.public_key.clone(); - - // extract from context and check required permissions for every function - for ctx in auth_context.iter() { - let context = match ctx { - Context::Contract(c) => c, - _ => return Err(SACAdminGenericError::InvalidContext), - }; - - match extract_sac_contract_context(&e, &context) { - SacFn::Mint(amount) => { - // ensure caller has required permissions - ensure_caller_operator(&e, &SacDataKey::Operator(caller.clone()))?; - // ensure operator has minting limit - ensure_minting_limit(&e, &caller, amount)?; - } - SacFn::Clawback(_amount) => { - // ensure caller has required permissions - ensure_caller_operator(&e, &SacDataKey::Operator(caller.clone()))?; - } - SacFn::SetAuthorized(_) => { - // ensure caller has required permissions - ensure_caller_operator(&e, &SacDataKey::Operator(caller.clone()))?; - } - SacFn::SetAdmin => { - // ensure caller has required permissions - ensure_caller_chief(&e, &caller, &SacDataKey::Chief)?; - } - SacFn::Unknown => { - // ensure only chief can call other functions - ensure_caller_chief(&e, &caller, &SacDataKey::Chief)? - } - } - } - - Ok(()) - } -} - -// Helper functions -fn ensure_caller_chief>( - e: &Env, - caller: &BytesN<32>, - key: &K, -) -> Result<(), SACAdminGenericError> { - let operator: BytesN<32> = e.storage().instance().get(key).expect("chief or operator not set"); - if *caller != operator { - return Err(SACAdminGenericError::Unauthorized); - } - Ok(()) -} - -fn ensure_caller_operator>( - e: &Env, - key: &K, -) -> Result<(), SACAdminGenericError> { - match e.storage().instance().get::<_, bool>(key) { - Some(is_op) if is_op => Ok(()), - _ => Err(SACAdminGenericError::Unauthorized), - } -} -``` - -## Benefits and Trade-offs - -### Benefits - -* Maintains a unified interface for both user-facing and admin functions -* Allows for complex authorization logic -* Provides flexibility in implementing custom rules - -### Trade-offs - -* Requires a more sophisticated authorization mechanism -* More complex to implement compared to the wrapper approach -* Requires understanding of the Soroban authorization system - -## Full Example - -A complete example implementation can be found in the -[sac-admin-generic example](https://github.com/OpenZeppelin/stellar-contracts/tree/main/examples/sac-admin-generic). - -## See Also - -* [SAC Admin Wrapper](/stellar-contracts/0.3.0/tokens/fungible/sac-admin-wrapper) -* [Fungible Token](/stellar-contracts/0.3.0/tokens/fungible/fungible) diff --git a/content/stellar-contracts/0.3.0/tokens/fungible/sac-admin-wrapper.mdx b/content/stellar-contracts/0.3.0/tokens/fungible/sac-admin-wrapper.mdx deleted file mode 100644 index 2ac9f9f0..00000000 --- a/content/stellar-contracts/0.3.0/tokens/fungible/sac-admin-wrapper.mdx +++ /dev/null @@ -1,122 +0,0 @@ ---- -title: SAC Admin Wrapper ---- - -[Source Code](https://github.com/OpenZeppelin/stellar-contracts/tree/main/packages/tokens/fungible/src/utils/sac_admin_wrapper) - -## Overview - -The Stellar Asset Contract (SAC) Admin Wrapper module provides a way to implement custom administrative functionality for Stellar Asset Contracts (SACs) using the wrapper approach. This approach defines specific entry points for each admin function and forwards calls to the corresponding SAC functions, providing a straightforward and modular design. - -## Key Concepts - -When a classic Stellar asset is ported to Soroban, it is represented by a SAC - a smart contract that provides both user-facing and administrative functions for asset management. SACs expose standard functions for handling fungible tokens, such as `transfer`, `approve`, `burn`, etc. Additionally, they include administrative functions (`mint`, `clawback`, `set_admin`, `set_authorized`) that are initially restricted to the issuer (a G-account). - -The `set_admin` function enables transferring administrative control to a custom contract, allowing for more complex authorization logic. This flexibility opens up possibilities for implementing custom rules, such as role-based access control, two-step admin transfers, mint rate limits, and upgradeability. - -## Wrapper Approach - -The Wrapper approach to SAC Admin implementation: - -* Acts as a middleware, defining specific entry points for each admin function -* Forwards calls to the corresponding SAC functions -* Applies custom logic before forwarding the call -* Provides a straightforward and modular design -* Separates user-facing and admin interfaces - -### SACAdminWrapper Trait - -The `SACAdminWrapper` trait defines the interface for the wrapper approach: - -```rust -pub trait SACAdminWrapper { - fn set_admin(e: Env, new_admin: Address, operator: Address); - fn set_authorized(e: Env, id: Address, authorize: bool, operator: Address); - fn mint(e: Env, to: Address, amount: i128, operator: Address); - fn clawback(e: Env, from: Address, amount: i128, operator: Address); -} -``` - -### Example Implementation - -Here’s a simplified example of a SAC Admin Wrapper contract using the OpenZeppelin access control library: - -```rust -#[contract] -pub struct ExampleContract; - -#[contractimpl] -impl ExampleContract { - pub fn __constructor( - e: &Env, - default_admin: Address, - manager1: Address, - manager2: Address, - sac: Address, - ) { - access_control::set_admin(e, &default_admin); - - // create a role "manager" and grant it to `manager1` - access_control::grant_role_no_auth(e, &default_admin, &manager1, &symbol_short!("manager")); - - // grant it to `manager2` - access_control::grant_role_no_auth(e, &default_admin, &manager2, &symbol_short!("manager")); - - fungible::sac_admin_wrapper::set_sac_address(e, &sac); - } -} - -#[contractimpl] -impl SACAdminWrapper for ExampleContract { - #[only_admin] - fn set_admin(e: Env, new_admin: Address, _operator: Address) { - fungible::sac_admin_wrapper::set_admin(&e, &new_admin); - } - - #[has_role(operator, "manager")] - fn set_authorized(e: Env, id: Address, authorize: bool, operator: Address) { - fungible::sac_admin_wrapper::set_authorized(&e, &id, authorize); - } - - #[has_role(operator, "manager")] - fn mint(e: Env, to: Address, amount: i128, operator: Address) { - fungible::sac_admin_wrapper::mint(&e, &to, amount); - } - - #[has_role(operator, "manager")] - fn clawback(e: Env, from: Address, amount: i128, operator: Address) { - fungible::sac_admin_wrapper::clawback(&e, &from, amount); - } -} -``` - -### Integration with Access Control - -The wrapper approach works particularly well with the OpenZeppelin access control library, allowing for role-based access control to be applied to each admin function: - -* `#[only_admin]`: Restricts the function to be called only by the admin -* `#[has_role(operator, "manager")]`: Restricts the function to be called only by addresses with the "manager" role - -## Benefits and Trade-offs - -### Benefits - -* Simpler to implement compared to the generic approach -* More flexible in terms of function-specific authorization -* Works well with role-based access control -* Clear separation of concerns - -### Trade-offs - -* Requires additional entry points for each admin function -* Splits user-facing and admin interfaces -* May require more code for complex authorization scenarios - -## Full Example - -A complete example implementation can be found in the [sac-admin-wrapper example](https://github.com/OpenZeppelin/stellar-contracts/tree/main/examples/sac-admin-wrapper). - -## See Also - -* [SAC Admin Generic](/stellar-contracts/0.3.0/tokens/fungible/sac-admin-generic) -* [Fungible Token](/stellar-contracts/0.3.0/tokens/fungible/fungible) diff --git a/content/stellar-contracts/0.3.0/tokens/non-fungible/nft-consecutive.mdx b/content/stellar-contracts/0.3.0/tokens/non-fungible/nft-consecutive.mdx deleted file mode 100644 index 3d4e2458..00000000 --- a/content/stellar-contracts/0.3.0/tokens/non-fungible/nft-consecutive.mdx +++ /dev/null @@ -1,58 +0,0 @@ ---- -title: Non-Fungible Consecutive ---- - -[Source Code](https://github.com/OpenZeppelin/stellar-contracts/tree/main/packages/tokens/non-fungible/src/extensions/consecutive) - -Consecutive extension for [Non-Fungible Token](/stellar-contracts/0.3.0/tokens/non-fungible/non-fungible) is useful -for efficiently minting multiple tokens in a single transaction. This can significantly -reduce costs and improve performance when creating a large number of tokens at once. - -## Usage - -We’ll continue with the [example](/stellar-contracts/0.3.0/tokens/non-fungible/non-fungible#usage) from **Non-Fungible Token** -and modify the contract so that now batches of tokens can be minted with each call -to `award_items`. Please note any account can call `award_items` and we might want to -implement access control to restrict who can mint. - -```rust -use soroban_sdk::{contract, contractimpl, Address, Env, String}; -use stellar_default_impl_macro::default_impl; -use stellar_non_fungible::{ - consecutive::{Consecutive, NonFungibleConsecutive}, - Base, ContractOverrides, NonFungibleToken, -}; - -#[contract] -pub struct GameItem; - -#[contractimpl] -impl GameItem { - pub fn __constructor(e: &Env) { - Base::set_metadata( - e, - String::from_str(e, "www.mygame.com"), - String::from_str(e, "My Game Items Collection"), - String::from_str(e, "MGMC"), - ); - } - - pub fn award_items(e: &Env, to: Address, amount: u32) -> u32 { - // access control might be needed - Consecutive::batch_mint(e, &to, amount) - } - - pub fn burn(e: &Env, from: Address, token_id: u32) { - Consecutive::burn(e, &from, token_id); - } -} - -#[default_impl] -#[contractimpl] -impl NonFungibleToken for GameItem { - type ContractType = Consecutive; -} - -// no entry-point functions required, marker impl -impl NonFungibleConsecutive for GameItem {} -``` diff --git a/content/stellar-contracts/0.3.0/tokens/non-fungible/nft-enumerable.mdx b/content/stellar-contracts/0.3.0/tokens/non-fungible/nft-enumerable.mdx deleted file mode 100644 index 09a12e13..00000000 --- a/content/stellar-contracts/0.3.0/tokens/non-fungible/nft-enumerable.mdx +++ /dev/null @@ -1,66 +0,0 @@ ---- -title: Non-Fungible Enumerable ---- - -[Source Code](https://github.com/OpenZeppelin/stellar-contracts/tree/main/packages/tokens/non-fungible/src/extensions/enumerable) - -Enumerable extension for [Non-Fungible Token](/stellar-contracts/0.3.0/tokens/non-fungible/non-fungible) allows for enumeration -of all the token IDs in the contract as well as all the token IDs owned by each account. This is -useful for applications that need to list or iterate over tokens, such as marketplaces or wallets. - -## Usage - -We’ll build on the [example](/stellar-contracts/0.3.0/tokens/non-fungible/non-fungible#usage) from **Non-Fungible Token** -and modify the contract so that all tokens an address own can be listed. Please note any account -can call `award_item` and we might want to implement access control to restrict who can mint. - -```rust -use soroban_sdk::{contract, contractimpl, Address, Env, String}; -use stellar_default_impl_macro::default_impl; -use stellar_non_fungible::{ - enumerable::{Enumerable, NonFungibleEnumerable}, - Base, ContractOverrides, NonFungibleToken, -}; - -#[contract] -pub struct GameItem; - -#[contractimpl] -impl GameItem { - pub fn __constructor(e: &Env) { - Base::set_metadata( - e, - String::from_str(e, "www.mygame.com"), - String::from_str(e, "My Game Items Collection"), - String::from_str(e, "MGMC"), - ); - } - - pub fn award_item(e: &Env, to: Address) -> u32 { - // access control might be needed - Enumerable::sequential_mint(e, &to) - } - - pub fn burn(e: &Env, from: Address, token_id: u32) { - Enumerable::sequential_burn(e, &from, token_id); - } -} - -#[default_impl] -#[contractimpl] -impl NonFungibleToken for GameItem { - type ContractType = Enumerable; -} - -#[default_impl] -#[contractimpl] -impl NonFungibleEnumerable for GameItem {} -``` - -The extension exposes additionally the following entry-point functions, automatically implemented by `#[default_impl]`: - -```rust -fn total_supply(e: &Env) -> u32; -fn get_owner_token_id(e: &Env, owner: Address, index: u32) -> u32; -fn get_token_id(e: &Env, index: u32) -> u32; -``` diff --git a/content/stellar-contracts/0.3.0/tokens/non-fungible/non-fungible.mdx b/content/stellar-contracts/0.3.0/tokens/non-fungible/non-fungible.mdx deleted file mode 100644 index c2dd619b..00000000 --- a/content/stellar-contracts/0.3.0/tokens/non-fungible/non-fungible.mdx +++ /dev/null @@ -1,108 +0,0 @@ ---- -title: Non-Fungible Token ---- - -[Source Code](https://github.com/OpenZeppelin/stellar-contracts/tree/main/packages/tokens/non-fungible) - -In the world of digital assets, not all tokens are alike. This becomes important in situations -like **real estate**, **voting rights**, or **collectibles**, where some items are valued more than -others due to their usefulness, rarity, etc. -On Stellar, you can create non-fungible tokens (NFTs), where each token is unique and -represents something distinct, with ownership tracked through Soroban smart contracts. - -## Overview - -The [non-fungible](https://github.com/OpenZeppelin/stellar-contracts/tree/main/packages/tokens/non-fungible) module -provides three different NFT variants that differ in how certain features like ownership tracking, -token creation and destruction are handled: - -1. **Base**: Contract variant that implements the base logic for the NonFungibleToken interface. Suitable for most use cases. -2. **Consecutive**: Contract variant for optimized minting of batches of tokens. Builds on top of the base variant, and overrides the necessary functions from the `Base` variant. -3. **Enumerable**: Contract variant that allows enumerating the tokens on-chain. Builds on top of the base variant, and overrides the necessary functions from the `Base` variant. - -These three variants share core functionality and a common interface, exposing identical contract functions as -entry-points. However, composing custom flows must be handled with extra caution. That is required because of the -incompatible nature between the business logic of the different NFT variants or the need to wrap the base -functionality with additional logic. - -## Usage - -We’ll use an NFT to track game items, each having their own unique attributes. Whenever one is to be -awarded to a player, it will be minted and sent to them. Players are free to keep or burn their token or -trade it with other people as they see fit. Please note any account can call `award_item` and we might -want to implement access control to restrict who can mint. - -Here’s what a contract for tokenized items might look like: - -```rust -use soroban_sdk::{contract, contractimpl, Address, Env, String}; -use stellar_default_impl_macro::default_impl; -use stellar_non_fungible::{ - burnable::NonFungibleBurnable, - Base, ContractOverrides, NonFungibleToken, -}; - -#[contract] -pub struct GameItem; - -#[contractimpl] -impl GameItem { - pub fn __constructor(e: &Env) { - Base::set_metadata( - e, - String::from_str(e, "www.mygame.com"), - String::from_str(e, "My Game Items Collection"), - String::from_str(e, "MGMC"), - ); - } - - pub fn award_item(e: &Env, to: Address) -> u32 { - // access control might be needed - Base::sequential_mint(e, &to) - } -} - -#[default_impl] -#[contractimpl] -impl NonFungibleToken for GameItem { - type ContractType = Base; -} - -#[default_impl] -#[contractimpl] -impl NonFungibleBurnable for GameItem {} -``` - -## Extensions - -The following optional extensions are provided to enhance capabilities: - -### - Burnable -[Source Code](https://github.com/OpenZeppelin/stellar-contracts/tree/main/packages/tokens/non-fungible/src/extensions/burnable) - -The `NonFungibleBurnable` trait extends the `NonFungibleToken` trait to provide the capability to burn tokens. - -### - Consecutive -[Source Code](https://github.com/OpenZeppelin/stellar-contracts/tree/main/packages/tokens/non-fungible/src/extensions/consecutive) - -The `NonFungibleConsecutive` extension is optimized for batch minting of tokens with consecutive IDs. This approach drastically reduces storage writes during minting by storing ownership only at boundaries and inferring ownership for other tokens. See [Non-Fungible Consecutive](/stellar-contracts/0.3.0/tokens/non-fungible/nft-consecutive) for detailed documentation. - -This extension is build around the contract variant `Consecutive`. Here is an example usage: - -* [Non-Fungible Consecutive](/stellar-contracts/0.3.0/tokens/non-fungible/nft-consecutive) - -### - Enumerable -[Source Code](https://github.com/OpenZeppelin/stellar-contracts/tree/main/packages/tokens/non-fungible/src/extensions/enumerable) - -The `NonFungibleEnumerable` extension enables on-chain enumeration of tokens owned by an address. See [Non-Fungible Enumerable](/stellar-contracts/0.3.0/tokens/non-fungible/nft-enumerable) for detailed documentation. - -This extension is build around the contract variant `Enumerable`. Here is an example usage: - -* [Non-Fungible Enumerable](/stellar-contracts/0.3.0/tokens/non-fungible/nft-enumerable) - -### - Royalties -[Source Code](https://github.com/OpenZeppelin/stellar-contracts/tree/main/packages/tokens/non-fungible/src/extensions/royalties) - -The `NonFungibleRoyalties` trait extends the `NonFungibleToken` trait to provide royalty information for tokens, similar to ERC-2981 standard. This allows marketplaces to query royalty information and pay appropriate fees to creators. - -Note: The royalties extension allows both collection-wide default royalties and per-token royalty settings. diff --git a/content/stellar-contracts/0.3.0/utils/access/access-control.mdx b/content/stellar-contracts/0.3.0/utils/access/access-control.mdx deleted file mode 100644 index eaba8bef..00000000 --- a/content/stellar-contracts/0.3.0/utils/access/access-control.mdx +++ /dev/null @@ -1,110 +0,0 @@ ---- -title: Access Control ---- - -[Source Code](https://github.com/OpenZeppelin/stellar-contracts/tree/main/packages/access/access-control) - -## Overview - -The Access Control module provides a comprehensive role-based access control system for Soroban contracts. It enables developers to manage permissions through a hierarchical role system, with a renounceable single overarching admin and customizable role assignments. - -## Key Concepts - -### Admin Management - -The system features a single top-level admin with privileges to call any function in the `AccessControl` trait. This admin must be set during contract initialization for the module to function properly. This overarching admin can renounce themselves for decentralization purposes. - -Admin transfers are implemented as a two-step process to prevent accidental or malicious takeovers: - -1. The current admin **initiates** the transfer by specifying the new admin and an expiration time (`live_until_ledger`). -2. The designated new admin must **explicitly accept** the transfer to complete it. - -Until the transfer is accepted, the original admin retains full control and can override or cancel the transfer by initiating a new one or using a `live_until_ledger` of `0`. - -### Role Hierarchy - -The module supports a hierarchical role system where each role can have an "admin role" assigned to it. For example: - -* Create roles `minter` and `minter_admin` -* Assign `minter_admin` as the admin role for the `minter` role -* Accounts with the `minter_admin` role can grant/revoke the `minter` role to other accounts - -This allows for creating complex organizational structures with chains of command and delegated authority. - -### Role Enumeration - -The system tracks account-role pairs in storage with additional enumeration logic: - -* When a role is granted to an account, the pair is stored and added to enumeration storage -* When a role is revoked, the pair is removed from storage and enumeration -* If all accounts are removed from a role, the helper storage items become empty or 0 - -Roles exist only through their relationships with accounts, so a role with zero accounts is indistinguishable from a role that never existed. - -## Usage Example - -Here's a simple example of using the Access Control module: - -```rust -use soroban_sdk::contract, contractimpl, symbol_short, Address, Env; -use stellar_access_control::self as access_control, AccessControl; -use stellar_access_control_macros::has_role, only_admin; - -#[contract] -pub struct MyContract; - -#[contractimpl] -impl MyContract - pub fn __constructor(e: &Env, admin: Address) - // Set the contract admin - access_control::set_admin(e, &admin); - - // Create a "minter" role with admin as its admin - access_control::set_role_admin_no_auth(e, &symbol_short!("minter"), &symbol_short!("admin")); - - #[only_admin] - pub fn admin_restricted_function(e: &Env) -> Vec - vec![&e, String::from_str(e, "seems sus")] - - - // we want `require_auth()` provided by the macro, since there is no - // `require_auth()` in `Base::mint`. - #[only_role(caller, "minter")] - pub fn mint(e: &Env, caller: Address, to: Address, token_id: u32) - Base::mint(e, &to, token_id) - - - // allows either minter or burner role, does not enforce `require_auth` in the macro - #[has_any_role(caller, ["minter", "burner"])] - pub fn multi_role_action(e: &Env, caller: Address) -> String - caller.require_auth(); - String::from_str(e, "multi_role_action_success") - - - // allows either minter or burner role AND enforces `require_auth` in the macro - #[only_any_role(caller, ["minter", "burner"])] - pub fn multi_role_auth_action(e: &Env, caller: Address) -> String - String::from_str(e, "multi_role_auth_action_success") - - -``` - -## Benefits and Trade-offs - -### Benefits - -* Flexible role-based permission system -* Hierarchical role management -* Secure admin transfer process -* Admin is renounceable -* Easy integration with procedural macros - -### Trade-offs - -* More complex than single-owner models like Ownable - -## See Also - -* [Ownable](/stellar-contracts/0.3.0/utils/access/ownable) -* [Fungible Token](/stellar-contracts/0.3.0/tokens/fungible/fungible) -* [Non-Fungible Token](/stellar-contracts/0.3.0/tokens/non-fungible/non-fungible) diff --git a/content/stellar-contracts/0.3.0/utils/access/ownable.mdx b/content/stellar-contracts/0.3.0/utils/access/ownable.mdx deleted file mode 100644 index 6a653cd9..00000000 --- a/content/stellar-contracts/0.3.0/utils/access/ownable.mdx +++ /dev/null @@ -1,99 +0,0 @@ ---- -title: Ownable ---- - -[Source Code](https://github.com/OpenZeppelin/stellar-contracts/tree/main/packages/access/ownable) - -## Overview - -The Ownable module provides a simple access control mechanism where a contract has a single account (owner) that can be granted exclusive access to specific functions. This pattern is useful for contracts that need a straightforward authorization system with a single privileged account. - -## Key Concepts - -### Ownership Management - -The system designates a single owner with exclusive access to functions marked with the `#[only_owner]` macro. The initial owner must be ideally set during contract initialization for the module to function properly. - -Like the Access Control module, ownership transfers are implemented as a two-step process to prevent accidental or malicious takeovers: - -1. The current owner **initiates** the transfer by specifying the new owner and an expiration time (`live_until_ledger`). -2. The designated new owner must **explicitly accept** the transfer to complete it. - -Until the transfer is accepted, the original owner retains full control and can override or cancel the transfer by initiating a new one or using a `live_until_ledger` of `0`. - -### Ownership Renunciation - -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. - -### Procedural Macro - -The module includes a procedural macro to simplify owner authorization checks: - -#### @only_owner - -Ensures the caller is the owner before executing the function: - -```rust -#[only_owner] -pub fn restricted_function(e: &Env, other_param: u32) { - // Function body - only accessible to owner -} -``` - -This expands to code that retrieves the owner from storage and requires authorization before executing the function body. - -## Usage Example - -Here’s a simple example of using the Ownable module: - -```rust -use soroban_sdk::{contract, contractimpl, Address, Env}; -use stellar_ownable::{self as ownable, Ownable}; -use stellar_ownable_macro::only_owner; - -#[contract] -pub struct MyContract; - -#[contractimpl] -impl MyContract { - pub fn __constructor(e: &Env, initial_owner: Address) { - // Set the contract owner - ownable::set_owner(e, &initial_owner); - } - - #[only_owner] - pub fn update_config(e: &Env, new_value: u32) { - // Only the owner can call this function - // Implementation... - } - - // This function is accessible to anyone - pub fn get_config(e: &Env) -> u32 { - // Implementation... - 42 - } -} -``` - -## Benefits and Trade-offs - -### Benefits - -* Simple and straightforward ownership model -* Secure two-step ownership transfer process -* Option to permanently renounce ownership -* Easy integration with procedural macro -* Event emission for important actions - -### Trade-offs - -* Limited to a single privileged account (compared to role-based systems) -* Once ownership is renounced, privileged functions become permanently inaccessible - -## See Also - -* [Access Control](/stellar-contracts/0.3.0/utils/access/access-control) -* [Fungible Token](/stellar-contracts/0.3.0/tokens/fungible/fungible) -* [Non-Fungible Token](/stellar-contracts/0.3.0/tokens/non-fungible/non-fungible) diff --git a/content/stellar-contracts/0.3.0/utils/crypto.mdx b/content/stellar-contracts/0.3.0/utils/crypto.mdx deleted file mode 100644 index f75954fc..00000000 --- a/content/stellar-contracts/0.3.0/utils/crypto.mdx +++ /dev/null @@ -1,201 +0,0 @@ ---- -title: Cryptography Utilities ---- - -[Crypto Source Code](https://github.com/OpenZeppelin/stellar-contracts/tree/main/packages/contract-utils/crypto) | -[Merkle Distributor Source Code](https://github.com/OpenZeppelin/stellar-contracts/tree/main/packages/contract-utils/merkle-distributor) - -## Overview - -The Cryptography Utilities provide a set of cryptographic tools for Soroban smart contracts, -including hash functions, Merkle tree verification, and Merkle-based distribution systems. -These utilities enable secure data verification and efficient token distribution mechanisms. -The Cryptography Utilities consist of two main packages: - -* Crypto: A set of cryptographic primitives and utilities for Soroban contracts. -* Merkle Distributor: A system for distributing tokens or other assets using Merkle proofs for verification. - -## Crypto Package - -The crypto package provides fundamental cryptographic primitives and utilities for Soroban contracts, -with a focus on hashing and Merkle tree operations. - -### Key Components - -#### Hashers - -Provides a generic `Hasher` trait and implementations for common hash functions: - -* `Sha256`: Implementation of the SHA-256 hash function -* `Keccak256`: Implementation of the Keccak-256 hash function (used in Ethereum) - -Each hasher follows the same interface: - -```rust -pub trait Hasher { - type Output; - - fn new(e: &Env) -> Self; - fn update(&mut self, input: Bytes); - fn finalize(self) -> Self::Output; -} -``` - -#### Hashable - -The `Hashable` trait allows types to be hashed with any `Hasher` implementation: - -```rust -pub trait Hashable { - fn hash(&self, hasher: &mut H); -} -``` - -Built-in implementations are provided for `BytesN<32>` and `Bytes`. - -#### Utility Functions - -* `hash_pair`: Hashes two values together -* `commutative_hash_pair`: Hashes two values in a deterministic order (important for Merkle trees) - -#### Merkle Tree Verification - -The `Verifier` struct provides functionality to verify Merkle proofs: - -```rust -impl Verifier -where - H: Hasher, -{ - pub fn verify(e: &Env, proof: Vec, root: Bytes32, leaf: Bytes32) -> bool { - // Implementation verifies that the leaf is part of the tree defined by root - } -} -``` - -### Usage Examples - -#### Hashing Data - -```rust -use soroban_sdk::{Bytes, Env}; -use stellar_crypto::keccak::Keccak256; -use stellar_crypto::hasher::Hasher; - -// Hash some data with Keccak256 -let e = Env::default(); -let data = Bytes::from_slice(&e, "Hello, world!".as_bytes()); - -let mut hasher = Keccak256::new(&e); -hasher.update(data); -let hash = hasher.finalize(); -``` - -#### Verifying a Merkle Proof - -```rust -use soroban_sdk::{BytesN, Env, Vec}; -use stellar_crypto::keccak::Keccak256; -use stellar_crypto::merkle::Verifier; - -// Verify that a leaf is part of a Merkle tree -let e = Env::default(); -let root = /* merkle root as BytesN<32> */; -let leaf = /* leaf to verify as BytesN<32> */; -let proof = /* proof as Vec> */; - -let is_valid = Verifier::::verify(&e, proof, root, leaf); -``` - -## Merkle Distributor - -The Merkle Distributor package builds on the crypto package to provide a system for distributing tokens or -other assets using Merkle proofs for verification. - -### Key Concepts - -#### IndexableNode - -The `IndexableNode` trait defines the structure for nodes in the Merkle tree: - -```rust -pub trait IndexableNode { - fn index(&self) -> u32; -} -``` - -Each node must include a unique index that identifies its position in the Merkle tree. - -#### MerkleDistributor - -The `MerkleDistributor` struct provides functionality for: - -* Setting a Merkle root -* Checking if an index has been claimed -* Verifying proofs and marking indices as claimed - -### Usage Example - -```rust -use soroban_sdk::{contract, contractimpl, contracttype, Address, BytesN, Env, Vec}; -use stellar_crypto::keccak::Keccak256; -use stellar_merkle_distributor::{IndexableNode, MerkleDistributor}; - -// Define a leaf node structure -#[contracttype] -struct LeafData { - pub index: u32, - pub address: Address, - pub amount: i128, -} - -// Implement IndexableNode for the leaf structure -impl IndexableNode for LeafData { - fn index(&self) -> u32 { - self.index - } -} - -#[contract] -pub struct TokenDistributor; - -#[contractimpl] -impl TokenDistributor { - // Initialize the distributor with a Merkle root - pub fn initialize(e: &Env, root: BytesN<32>) { - MerkleDistributor::::set_root(e, root); - } - - // Claim tokens by providing a proof - pub fn claim(e: &Env, leaf: LeafData, proof: Vec>) { - // Verify the proof and mark as claimed - MerkleDistributor::::verify_and_set_claimed(e, leaf.clone(), proof); - - // Transfer tokens or perform other actions based on leaf data - // ... - } - - // Check if an index has been claimed - pub fn is_claimed(e: &Env, index: u32) -> bool { - MerkleDistributor::::is_claimed(e, index) - } -} -``` - -## Use Cases - -### Token Airdrops - -Efficiently distribute tokens to a large number of recipients without requiring individual transactions for each recipient. - -### NFT Distributions - -Distribute NFTs to a whitelist of addresses, with each address potentially receiving different NFTs. - -### Off-chain Allowlists - -Maintain a list of eligible addresses off-chain and allow them to claim tokens or other assets on-chain. - -### Snapshot-based Voting - -Create a snapshot of token holders at a specific block and allow them to vote based on their holdings. diff --git a/content/stellar-contracts/0.3.0/utils/pausable.mdx b/content/stellar-contracts/0.3.0/utils/pausable.mdx deleted file mode 100644 index 9b35dbc2..00000000 --- a/content/stellar-contracts/0.3.0/utils/pausable.mdx +++ /dev/null @@ -1,33 +0,0 @@ ---- -title: Pausable ---- - -[Source Code](https://github.com/OpenZeppelin/stellar-contracts/tree/main/packages/contract-utils/pausable) - -## Purpose - -Allows contracts to be paused and unpaused by authorized accounts. - -This utility contract can be used with any token standard (fungible, non-fungible, multi-token). - -## Design - -To make it easier to spot when inspecting the code, we turned this simple functionality into a macro that can annotate your smart contract functions. - -An example: -```rust -#[when_paused] -pub fn emergency_reset(e: &Env) { - e.storage().instance().set(&DataKey::Counter, &0); -} -``` - -Which will expand into the below code: - -```rust -pub fn emergency_reset(e: &Env) { - when_paused(e); - - e.storage().instance().set(&DataKey::Counter, &0); -} -``` diff --git a/content/stellar-contracts/0.3.0/utils/upgradeable.mdx b/content/stellar-contracts/0.3.0/utils/upgradeable.mdx deleted file mode 100644 index b2be6630..00000000 --- a/content/stellar-contracts/0.3.0/utils/upgradeable.mdx +++ /dev/null @@ -1,185 +0,0 @@ ---- -title: Upgrades and Migrations ---- - -[Source code](https://github.com/OpenZeppelin/stellar-contracts/tree/main/packages/contract-utils/upgradeable) - -Soroban contracts are mutable by default. Mutability in the context of Stellar Soroban refers to the ability of a smart -contract to modify its WASM bytecode, thereby altering its function interface, execution logic, or metadata. - -Soroban provides a built-in, protocol-level defined mechanism for contract upgrades, allowing contracts to upgrade -themselves if they are explicitly designed to do so. One of the advantages of it is the flexibility it offers to -contract developers who can choose to make the contract immutable by simply not provisioning upgradability mechanics. On -the other hand, providing upgradability on a protocol level significantly reduces the risk surface, compared to other -smart contract platforms, which lack native support for upgradability. - -While Soroban’s built-in upgradability eliminates many of the challenges, related to managing smart contract upgrades -and migrations, certain caveats must still be considered. - -## Overview - -The [upgradeable](https://github.com/OpenZeppelin/stellar-contracts/tree/main/packages/contract-utils/upgradeable) module -provides a lightweight upgradeability framework with additional support for structured and safe migrations. - -It consists of two main components: - -1. ***[`Upgradeable`](/stellar-contracts/0.3.0/utils/upgradeable#upgrade-only)*** for cases where only the WASM binary needs to be updated. -2. ***[`UpgradeableMigratable`](/stellar-contracts/0.3.0/utils/upgradeable#upgrade-and-migrate)*** for more advanced scenarios where, in addition to the WASM binary, specific storage entries -must be modified (migrated) during the upgrade process. - -The recommended way to use this module is through the `\#[derive(Upgradeable)]` and `#[derive(UpgradeableMigratable)]` -macros. - -They handle the implementation of the necessary functions, allowing developers to focus solely on managing authorizations -and access control. These derive macros also leverage the crate version from the contract’s `Cargo.toml` and set it as -the binary version in the WASM metadata, aligning with the guidelines outlined in -[SEP-49](https://github.com/stellar/stellar-protocol/blob/master/ecosystem%2Fsep-0049.md). - - - -While the framework structures the upgrade flow, it does NOT perform deeper checks and verifications such as: - -* Ensuring that the new contract does not include a constructor, as it will not be invoked. -* Verifying that the new contract includes an upgradability mechanism, preventing an unintended loss of further - upgradability capacity. -* Checking for storage consistency, ensuring that the new contract does not inadvertently introduce storage mismatches. - - -## Usage - -### Upgrade Only -#### `Upgradeable` - -When only the WASM binary needs to be upgraded and no additional migration logic is required, developers should implement -the `UpgradeableInternal` trait. This trait is where authorization and custom access control logic are defined, -specifying who can perform the upgrade. This minimal implementation keeps the focus solely on controlling upgrade -permissions. - -```rust -use soroban_sdk::{ - contract, contracterror, contractimpl, panic_with_error, symbol_short, Address, Env, -}; -use stellar_upgradeable::UpgradeableInternal; -use stellar_upgradeable_macros::Upgradeable; - -#[contracterror] -#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] -#[repr(u32)] -pub enum ExampleContractError { - Unauthorized = 1, -} - -#[derive(Upgradeable)] -#[contract] -pub struct ExampleContract; - -#[contractimpl] -impl ExampleContract { - pub fn __constructor(e: &Env, admin: Address) { - e.storage().instance().set(&symbol_short!("OWNER"), &admin); - } -} - -impl UpgradeableInternal for ExampleContract { - fn _require_auth(e: &Env, operator: &Address) { - operator.require_auth(); - // `operator` is the invoker of the upgrade function and can be used - // to perform a role-based access control if implemented - let owner: Address = e.storage().instance().get(&symbol_short!("OWNER")).unwrap(); - if *operator != owner { - panic_with_error!(e, ExampleContractError::Unauthorized) - } - } -} -``` - -### Upgrade and Migrate -#### `UpgradeableMigratable` - -When both the WASM binary and specific storage entries need to be modified as part of the upgrade process, the -`UpgradeableMigratableInternal` trait should be implemented. In addition to defining access control and migration -logic, the developer must specify an associated type that represents the data required for the migration. - -The `#[derive(UpgradeableMigratable)]` macro manages the sequencing of operations, ensuring that the migration can -only be invoked after a successful upgrade, preventing potential state inconsistencies and storage corruption. - -```rust -use soroban_sdk::{ - contract, contracterror, contracttype, panic_with_error, symbol_short, Address, Env, -}; -use stellar_upgradeable::UpgradeableMigratableInternal; -use stellar_upgradeable_macros::UpgradeableMigratable; - -#[contracterror] -#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] -#[repr(u32)] -pub enum ExampleContractError { - Unauthorized = 1, -} - -#[contracttype] -pub struct Data { - pub num1: u32, - pub num2: u32, -} - -#[derive(UpgradeableMigratable)] -#[contract] -pub struct ExampleContract; - -impl UpgradeableMigratableInternal for ExampleContract { - type MigrationData = Data; - - fn _require_auth(e: &Env, operator: &Address) { - operator.require_auth(); - let owner: Address = e.storage().instance().get(&symbol_short!("OWNER")).unwrap(); - if *operator != owner { - panic_with_error!(e, ExampleContractError::Unauthorized) - } - } - - fn _migrate(e: &Env, data: &Self::MigrationData) { - e.storage().instance().set(&symbol_short!("DATA_KEY"), data); - } -} -``` - - -If a rollback is required, the contract can be upgraded to a newer version where the rollback-specific logic -is defined and performed as a migration. - - -#### Atomic upgrade and migration - -When performing an upgrade, the new implementation only becomes effective after the current invocation completes. -This means that if migration logic is included in the new implementation, it cannot be executed within the same -call. To address this, an auxiliary contract called `Upgrader` can be used to wrap both invocations, enabling an -atomic upgrade-and-migrate process. This approach ensures that the migration logic is executed immediately after the -upgrade without requiring a separate transaction. - -```rust -use soroban_sdk::{contract, contractimpl, symbol_short, Address, BytesN, Env, Val}; -use stellar_upgradeable::UpgradeableClient; - -#[contract] -pub struct Upgrader; - -#[contractimpl] -impl Upgrader { - pub fn upgrade_and_migrate( - env: Env, - contract_address: Address, - operator: Address, - wasm_hash: BytesN<32>, - migration_data: soroban_sdk::Vec, - ) { - operator.require_auth(); - let contract_client = UpgradeableClient::new(&env, &contract_address); - - contract_client.upgrade(&wasm_hash, &operator); - // The types of the arguments to the migrate function are unknown to this - // contract, so we need to call it with invoke_contract. - env.invoke_contract::<()>(&contract_address, &symbol_short!("migrate"), migration_data); - } -} -``` From 496256b06fcb81818b160a0e67bfd02846b74ec2 Mon Sep 17 00:00:00 2001 From: Ozgun Ozerk Date: Fri, 24 Oct 2025 14:46:26 +0300 Subject: [PATCH 2/2] redirects --- netlify.toml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/netlify.toml b/netlify.toml index f3a45c23..3a4c87db 100644 --- a/netlify.toml +++ b/netlify.toml @@ -61,6 +61,16 @@ from = "/stellar-contracts/0.4.0/*" to = "/stellar-contracts/:splat" status = 301 +[[redirects]] +from = "/stellar-contracts/0.3.0/*" +to = "/stellar-contracts/:splat" +status = 301 + +[[redirects]] +from = "/stellar-contracts/0.2.0/*" +to = "/stellar-contracts/:splat" +status = 301 + [[redirects]] from = "/stellar-contracts/0.1.0/*" to = "/stellar-contracts/:splat"