Source: src/rwa_token.rs
The RWAToken contract is the core token implementation for all Real-World Assets. It implements a Stellar-compatible token with advanced features:
- Mint/Burn — Admin-controlled supply management
- Transfer with Compliance — Every transfer is validated against the
ComplianceRegistry - Lock/Unlock — Token locking for governance voting power
- Pause/Freeze — Admin emergency controls
- Token Info — Comprehensive on-chain metadata
┌──────────────┐
│ RWAToken │
└──────┬───────┘
│
┌────────────┼────────────┐
│ │ │
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────────────┐
│ Mint/ │ │ Transfer │ │ Lock/Unlock │
│ Burn │ │(+compliance)│ │ (voting power) │
└──────────┘ └────┬─────┘ └──────────────────┘
│
▼
┌──────────────────┐
│ ComplianceRegistry│
│ (KYC/Blacklist/ │
│ Transfer Limits) │
└──────────────────┘
| Variant | Code | Description |
|---|---|---|
AlreadyInitialized |
1 | Token already initialized |
NotInitialized |
2 | Token not yet initialized |
TokenInfoNotFound |
3 | Token info storage missing |
TransferPaused |
4 | Transfers are paused |
AssetFrozen |
5 | Asset is frozen |
KYCNotVerified |
6 | KYC required for operation |
TransferRestriction |
7 | Transfer exceeds restrictions |
InvalidAmount |
8 | Amount is zero or negative |
InsufficientBalance |
9 | Not enough unlocked tokens |
Unauthorized |
10 | Caller not authorized |
ComplianceCheckFailed |
11 | Compliance validation failed |
| Field | Type | Description |
|---|---|---|
name |
Symbol |
Token name |
symbol |
Symbol |
Ticker symbol |
total_supply |
i128 |
Current total supply |
decimals |
u32 |
Decimal places |
asset_type |
Symbol |
Asset class string |
is_paused |
bool |
Transfer pause status |
is_frozen |
bool |
Freeze status |
metadata |
Map<Symbol, String> |
Key-value metadata |
compliance_registry |
Address |
Compliance contract |
dividend_distributor |
Address |
Dividend contract |
version |
u32 |
Storage version |
| Field | Type | Description |
|---|---|---|
amount |
i128 |
Spendable (unlocked) balance |
locked_amount |
i128 |
Total locked tokens |
voting_power |
i128 |
Voting power derived from locks |
| Field | Type | Description |
|---|---|---|
amount |
i128 |
Locked amount |
unlock_time |
u64 |
Timestamp when lock expires |
initialize(env, auth, name, symbol, total_supply, decimals, asset_type, metadata, compliance_registry, dividend_distributor)
Initializes token state and mints total_supply to the admin (auth).
| Parameter | Type | Description |
|---|---|---|
env |
Env |
Soroban environment |
auth |
Address |
Admin address (signs + receives minted supply) |
name |
Symbol |
Token name |
symbol |
Symbol |
Ticker symbol |
total_supply |
i128 |
Initial supply (> 0) |
decimals |
u32 |
Decimal precision (max 18) |
asset_type |
Symbol |
Asset class identifier |
metadata |
Map<Symbol, String> |
Arbitrary metadata |
compliance_registry |
Address |
Compliance contract address |
dividend_distributor |
Address |
Dividend distributor contract |
Auth: auth.require_auth()
Returns: Nothing
Errors:
AlreadyInitialized— Already initializedInvalidAmount—total_supply <= 0ordecimals > 18
Events:
initializedwith topics(name, symbol, total_supply)
Example:
let token_id = env.register_contract(None, RWAToken);
let token = RWATokenClient::new(&env, &token_id);
token.initialize(
&admin,
&Symbol::new(&env, "ManhattanOffice"),
&Symbol::new(&env, "MNO"),
&1_000_000i128,
&6u32,
&Symbol::new(&env, "real_estate"),
&Map::new(&env),
&compliance_id,
÷nd_distributor_id,
);Storage migration for admin. Upgrades version through any defined migration steps.
| Parameter | Type | Description |
|---|---|---|
env |
Env |
Soroban environment |
auth |
Address |
Admin address |
Auth: Admin check
Returns: Nothing
Errors:
Unauthorized— Caller is not admin
Events:
migratedwith topics(old_version, new_version)
Mints additional supply to to. Increases both the recipient's balance and total_supply.
| Parameter | Type | Description |
|---|---|---|
env |
Env |
Soroban environment |
auth |
Address |
Admin address |
to |
Address |
Recipient address |
amount |
i128 |
Amount to mint (> 0) |
Auth: Admin authorization
Returns: Nothing
Errors:
InvalidAmount—amount <= 0TokenPaused— Transfers are paused
Events:
mintwith topics(to, amount)
Example:
let recipient = Address::generate(&env);
token.mint(&admin, &recipient, &10_000i128);Burns tokens from from. Decreases balance and total_supply.
| Parameter | Type | Description |
|---|---|---|
env |
Env |
Soroban environment |
from |
Address |
Address whose tokens to burn |
amount |
i128 |
Amount to burn (> 0) |
Returns: Nothing
Errors:
InvalidAmount—amount <= 0TokenPaused— Transfers are pausedInsufficientBalance— Unlocked balance too lowComplianceCheckFailed— Compliance check failed
Events:
burnwith topics(from, amount)
Example:
token.burn(&admin, &500i128);Transfers spendable (unlocked) tokens between addresses. Validates all compliance rules.
| Parameter | Type | Description |
|---|---|---|
env |
Env |
Soroban environment |
from |
Address |
Sender address |
to |
Address |
Recipient address |
amount |
i128 |
Amount to transfer (> 0) |
Auth: from.require_auth()
Checks:
- Version check — token must be initialized
- Pause/freeze check —
TransferPausedorAssetFrozenif active - Compliance check — KYC, blacklist, transfer limits
- Spendable balance — Only unlocked tokens can be transferred
Returns: Nothing
Errors:
TransferPaused— Token is paused or frozenComplianceCheckFailed— Compliance validation failedInsufficientBalance— Not enough unlocked tokens
Events:
transferwith topics(from, to, amount)
Example:
let recipient = Address::generate(&env);
token.transfer(&admin, &recipient, &500i128);Returns complete token metadata from storage.
| Parameter | Type | Description |
|---|---|---|
env |
Env |
Soroban environment |
Returns: TokenInfo
Errors:
NotInitialized— Token has not been initialized
Example:
let info = token.get_token_info();
assert_eq!(info.total_supply, 1_000_000);
assert_eq!(info.decimals, 6);Returns the on-chain balance for an address, including locked amount and voting power.
| Parameter | Type | Description |
|---|---|---|
env |
Env |
Soroban environment |
address |
Address |
Address to query |
Returns: Balance
Example:
let balance = token.get_balance(&admin);
// balance.amount — spendable tokens
// balance.locked_amount — locked tokens
// balance.voting_power — voting powerLocks tokens for lock_period seconds, reducing spendable balance and increasing voting power.
| Parameter | Type | Description |
|---|---|---|
env |
Env |
Soroban environment |
auth |
Address |
Must be the token owner |
owner |
Address |
Token owner address |
amount |
i128 |
Amount to lock (> 0) |
lock_period |
u64 |
Lock duration in seconds |
Auth: auth.require_auth() and auth == owner
Returns: Nothing
Errors:
InvalidAmount—amount <= 0InsufficientBalance— Not enough unlocked tokens
Events:
tokens_lockedwith topics(owner, amount, lock_period)
Example:
// Lock 100,000 tokens for 90 days
token.lock_tokens(&admin, &admin, &100_000i128, &(86400 * 90));Unlocks tokens, restoring spendable balance and reducing voting power.
| Parameter | Type | Description |
|---|---|---|
env |
Env |
Soroban environment |
auth |
Address |
Must be the token owner |
owner |
Address |
Token owner address |
amount |
i128 |
Amount to unlock (> 0) |
Auth: auth.require_auth() and auth == owner
Returns: Nothing
Errors:
InvalidAmount—amount <= 0InsufficientBalance— Locked balance too low
Events:
tokens_unlockedwith topics(owner, amount)
Pauses or resumes all transfers. Admin-only.
| Parameter | Type | Description |
|---|---|---|
env |
Env |
Soroban environment |
auth |
Address |
Admin address |
Auth: Admin check
Events: paused / unpaused
Freezes or unfreezes all transfers. Admin-only.
Events: frozen / unfrozen
| Event | Topics | Emitted By |
|---|---|---|
initialized |
name, symbol, total_supply |
initialize() |
migrated |
old_version, new_version |
migrate() |
mint |
to, amount |
mint() |
burn |
from, amount |
burn() |
transfer |
from, to, amount |
transfer() |
tokens_locked |
owner, amount, lock_period |
lock_tokens() |
tokens_unlocked |
owner, amount |
unlock_tokens() |
paused |
timestamp |
pause() |
unpaused |
timestamp |
unpause() |
frozen |
timestamp |
freeze() |
unfrozen |
timestamp |
unfreeze() |
RWAToken
│
├──transfer()──▶ ComplianceRegistry.check_compliance()
│ ComplianceRegistry.check_outbound_participant()
│
├──lock_tokens()──▶ Balance.voting_power update
│
└──mint/burn()──▶ Total Supply update