Fungible Token

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 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:

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

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

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

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

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

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.

- 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.

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.