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:
-
Base implementation (
FungibleToken
withBase
contract type): Suitable for most standard token use cases. -
AllowList extension (
FungibleToken
withAllowList
contract type): For tokens that require an allowlist mechanism to control who can transfer tokens. -
BlockList extension (
FungibleToken
withBlockList
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.
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
.