Soroban SDK: v23 · Rust toolchain: stable +
wasm32-unknown-unknowntarget
Source:apps/onchain/contracts/· Operations & Deployment Playbook:document/CONTRACT_DEPLOYMENT_ROLLBACK_PLAYBOOK.md
This document provides a complete technical reference for every public function (WASM entrypoint), emitted event, error code, and storage layout across all Soroban smart contracts in the LumenPulse workspace. For operational deployment steps, canonical manifest management, and emergency rollback procedures, see the Contract Deployment & Rollback Playbook.
- Version Introspection
- LumenToken
- CrowdfundVault
- ContributorRegistry
- VestingWallet
- UpgradableContract
Crate: version-interface · Trait: VersionedContract · Generated client: VersionedClient
Source: contracts/version-interface/src/lib.rs
Issue #1046 introduced a standardized, on-chain version introspection interface so clients and operators can query a deployed contract's semantic version directly — instead of relying only on off-chain deployment manifests.
pub struct ContractVersion {
pub major: u32,
pub minor: u32,
pub patch: u32,
}This is a stable SemVer-style triple:
| Field | Bumped when |
|---|---|
major |
The storage layout or interface changes in a way that is not backward compatible — clients/operators must treat this as a different contract surface. |
minor |
A backward-compatible addition (new entrypoint, new optional behavior). |
patch |
A backward-compatible fix with no interface or storage change. |
ContractVersion also derives Ord/PartialOrd for straightforward comparison, and exposes:
pub fn is_compatible_with(&self, other: &ContractVersion) -> boolTwo versions are compatible when they share the same major (for a pre-1.0 0.x line, minor is treated as breaking too, since that line carries no stability guarantee). This is the method backend config validation and release tooling should use to decide whether a newly deployed contract is safe to talk to, rather than comparing fields by hand.
pub trait VersionedContract {
fn contract_version(env: Env) -> ContractVersion;
}Any contract that implements this trait exposes a contract_version entrypoint with this exact signature — implementers declare impl VersionedContract for ..., so a signature change is a compile-time break across the whole workspace, and the crate's conformance suite exercises every implementer end to end through the trait-generated VersionedClient.
| Contract | contract_version() |
|---|---|
LumenToken |
1.0.0 |
CrowdfundVaultContract |
1.0.0 |
ContributorRegistryContract |
1.0.0 |
VestingWalletContract |
1.0.0 |
UpgradableContract |
1.0.0 (also keeps the pre-existing version() -> u32 entrypoint for backward compatibility — prefer contract_version for new integrations) |
Example (Soroban CLI):
soroban contract invoke \
--id <CONTRACT_ID> \
--fn contract_versionCrate: lumen_token · Contract struct: LumenToken
Source: contracts/lumen_token/src/
A standard Soroban token following the SEP-41 token interface with admin-controlled minting, account freezing, and WASM upgrade capabilities.
pub fn initialize(e: Env, admin: Address, decimal: u32, name: String, symbol: String)One-time initialization. Sets the admin, decimal precision, token name, and symbol. Panics if already initialized.
| Parameter | Type | Description |
|---|---|---|
admin |
Address |
The initial administrator address |
decimal |
u32 |
Number of decimal places (e.g., 7) |
name |
String |
Human-readable token name |
symbol |
String |
Token ticker symbol |
Returns: ()
Auth: None (one-time setup guard).
pub fn mint(e: Env, to: Address, amount: i128)Mint new tokens to an address. Admin-only.
| Parameter | Type | Description |
|---|---|---|
to |
Address |
Recipient of minted tokens |
amount |
i128 |
Number of tokens to mint |
Returns: ()
Auth: Requires admin authorization.
pub fn set_admin(e: Env, new_admin: Address)Transfer the admin role. Emits AdminChangedEvent.
| Parameter | Type | Description |
|---|---|---|
new_admin |
Address |
The new administrator address |
Returns: ()
Auth: Requires current admin authorization.
pub fn freeze(e: Env, id: Address)Freeze an account, preventing it from sending, approving, or burning tokens.
| Parameter | Type | Description |
|---|---|---|
id |
Address |
Account to freeze |
Returns: ()
Auth: Requires admin authorization.
pub fn unfreeze(e: Env, id: Address)Unfreeze a previously frozen account.
| Parameter | Type | Description |
|---|---|---|
id |
Address |
Account to unfreeze |
Returns: ()
Auth: Requires admin authorization.
pub fn allowance(e: Env, from: Address, spender: Address) -> i128Query the remaining allowance a spender has from from.
Returns: i128 — the current allowance amount.
pub fn approve(e: Env, from: Address, spender: Address, amount: i128, expiration_ledger: u32)Set an allowance for spender to spend amount of from's tokens until expiration_ledger.
| Parameter | Type | Description |
|---|---|---|
from |
Address |
Token owner |
spender |
Address |
Authorized spender |
amount |
i128 |
Maximum spend amount |
expiration_ledger |
u32 |
Ledger sequence after which the allowance expires |
Returns: ()
Auth: Requires from authorization. Panics if from is frozen.
pub fn balance(e: Env, id: Address) -> i128Query the token balance of id.
Returns: i128 — the token balance.
pub fn transfer(e: Env, from: Address, to: Address, amount: i128)Transfer tokens between accounts.
| Parameter | Type | Description |
|---|---|---|
from |
Address |
Sender |
to |
Address |
Recipient |
amount |
i128 |
Amount to transfer |
Returns: ()
Auth: Requires from authorization.
pub fn transfer_from(e: Env, spender: Address, from: Address, to: Address, amount: i128)Transfer tokens on behalf of another account using a previously approved allowance.
| Parameter | Type | Description |
|---|---|---|
spender |
Address |
The authorized spender |
from |
Address |
Token owner |
to |
Address |
Recipient |
amount |
i128 |
Amount to transfer |
Returns: ()
Auth: Requires spender authorization. Panics if spender is frozen or allowance is insufficient/expired.
pub fn burn(e: Env, from: Address, amount: i128)Burn tokens from the caller's own balance. Emits BurnEvent.
| Parameter | Type | Description |
|---|---|---|
from |
Address |
Token holder |
amount |
i128 |
Amount to burn |
Returns: ()
Auth: Requires from authorization. Panics if from is frozen.
pub fn burn_from(e: Env, spender: Address, from: Address, amount: i128)Burn tokens from another account using an approved allowance. Emits BurnEvent.
| Parameter | Type | Description |
|---|---|---|
spender |
Address |
The authorized spender |
from |
Address |
Token holder |
amount |
i128 |
Amount to burn |
Returns: ()
Auth: Requires spender authorization. Panics if spender is frozen or allowance is insufficient/expired.
pub fn decimals(e: Env) -> u32Returns: u32 — the token's decimal precision.
pub fn name(e: Env) -> StringReturns: String — the token name.
pub fn symbol(e: Env) -> StringReturns: String — the token symbol.
pub fn upgrade(e: Env, caller: Address, new_wasm_hash: BytesN<32>)Upgrade the contract WASM. Emits UpgradedEvent.
| Parameter | Type | Description |
|---|---|---|
caller |
Address |
Must match stored admin |
new_wasm_hash |
BytesN<32> |
Hash of the new WASM binary |
Returns: ()
Auth: Requires admin authorization. Panics if caller != admin.
pub fn contract_version(env: Env) -> ContractVersionImplements VersionedContract (issue #1046).
Returns: ContractVersion { major: 1, minor: 0, patch: 0 }
| Event | Topics | Data | Emitted By |
|---|---|---|---|
UpgradedEvent |
admin: Address |
new_wasm_hash: BytesN<32> |
upgrade |
AdminChangedEvent |
old_admin: Address |
new_admin: Address |
set_admin |
BurnEvent |
from: Address |
amount: i128 |
burn, burn_from |
| Key | Tier | Type | Description |
|---|---|---|---|
DataKey::Admin |
Instance | Address |
Contract administrator |
DataKey::Decimals |
Instance | u32 |
Token decimal precision |
DataKey::Name |
Instance | String |
Token name |
DataKey::Symbol |
Instance | String |
Token symbol |
DataKey::Balance(Address) |
Persistent | i128 |
Token balance per account |
DataKey::State(Address) |
Persistent | bool |
true = account is frozen |
DataKey::Allowance(AllowanceDataKey) |
Temporary | AllowanceValue |
Spending allowance |
TSUPPLY (Symbol) |
Instance | i128 |
Total token supply counter |
Custom Types:
struct AllowanceDataKey { from: Address, spender: Address }
struct AllowanceValue { amount: i128, expiration_ledger: u32 }Crate: crowdfund_vault · Contract struct: CrowdfundVaultContract
Source: contracts/crowdfund_vault/src/
A full-featured crowdfunding platform with milestone-gated withdrawals, quadratic funding matching pool, contributor reputation, and emergency pause functionality.
pub fn propose_emergency_migration(
env: Env,
admin: Address,
project_id: u64,
recipient: Address,
amount: i128,
reason: Symbol,
) -> Result<(), CrowdfundError>Register an emergency migration plan for a paused round with stranded funds. The contract must be paused before calling this — which prevents any new deposits from racing the migration window.
| Parameter | Type | Description |
|---|---|---|
admin |
Address |
Must match the stored contract admin |
project_id |
u64 |
The project with stranded funds |
recipient |
Address |
Destination address for migrated tokens (must not be the contract itself) |
amount |
i128 |
Amount to migrate; must be > 0 and ≤ current project balance |
reason |
Symbol |
Short human-readable reason stored on-chain for auditors |
Returns: Ok(())
Auth: Requires admin authorization.
Requires: Contract must be paused (ContractPaused).
Emits: EmrgMigrProposedEvent
Errors: EmergencyMigrationRequiresPause, Unauthorized, ProjectNotFound, InvalidAmount, MigrationAmountExceedsBalance, InvalidMigrationRecipient, MigrationPlanAlreadyExists
pub fn veto_emergency_migration(env: Env, admin: Address, project_id: u64) -> Result<(), CrowdfundError>Permanently block a pending emergency migration plan. Once vetoed the plan status becomes Vetoed and can never be executed. A new plan may be proposed after a veto.
Auth: Admin only.
Emits: EmrgMigrVetoedEvent
Errors: Unauthorized, MigrationPlanNotFound, MigrationAlreadyExecuted
pub fn execute_emergency_migration(env: Env, admin: Address, project_id: u64) -> Result<i128, CrowdfundError>Execute a pending (non-vetoed) migration plan. Transfers exactly plan.amount tokens to plan.recipient, transitions the project to CANCELED (opening the contributor refund window), and decrements the TVL counter.
Returns: Ok(amount) — the number of tokens transferred.
Auth: Admin only. Contract must still be paused at execution time.
Emits: EmrgMigrExecutedEvent, ProjectCanceledEvent
Errors: EmergencyMigrationRequiresPause, Unauthorized, MigrationPlanNotFound, MigrationAlreadyExecuted, MigrationPlanVetoed, ProjectNotFound, MigrationAmountExceedsBalance
pub fn get_emergency_migration_plan(env: Env, project_id: u64) -> Result<EmergencyMigrationPlan, CrowdfundError>Read the current migration plan for a project (read-only, no state mutations).
Returns: Ok(EmergencyMigrationPlan)
Errors: MigrationPlanNotFound, ProjectNotFound
pub fn initialize(env: Env, admin: Address) -> Result<(), CrowdfundError>One-time initialization. Sets admin, pause state to false, and project ID counter to 0.
| Parameter | Type | Description |
|---|---|---|
admin |
Address |
The contract administrator |
Returns: Ok(()) or Err(AlreadyInitialized)
Auth: Requires admin authorization.
Emits: InitializedEvent
pub fn pause(env: Env, admin: Address) -> Result<bool, CrowdfundError>Emergency pause. Prevents create_project, deposit, approve_milestone, and withdraw.
Returns: Ok(true) on success.
Auth: Admin only.
Emits: ContractPauseEvent
pub fn unpause(env: Env, admin: Address) -> Result<bool, CrowdfundError>Unpause the contract after an emergency pause.
Returns: Ok(true) on success.
Auth: Admin only.
Emits: ContractUnpauseEvent
pub fn upgrade(env: Env, caller: Address, new_wasm_hash: BytesN<32>) -> Result<(), CrowdfundError>Upgrade the contract WASM hash.
Auth: Admin only.
Emits: UpgradedEvent
pub fn set_admin(env: Env, current_admin: Address, new_admin: Address) -> Result<(), CrowdfundError>Transfer the admin role.
Auth: Requires current admin.
Emits: AdminChangedEvent
pub fn create_project(
env: Env, owner: Address, name: Symbol,
target_amount: i128, token_address: Address,
) -> Result<u64, CrowdfundError>Create a new crowdfunding project. Auto-assigns an incrementing project ID.
| Parameter | Type | Description |
|---|---|---|
owner |
Address |
Project owner who can withdraw funds |
name |
Symbol |
Short project name |
target_amount |
i128 |
Fundraising goal |
token_address |
Address |
The token for contributions |
Returns: Ok(project_id) — the assigned u64 project ID.
Auth: Requires owner authorization. Fails if paused or target_amount <= 0.
Emits: ProjectCreatedEvent
pub fn cancel_project(env: Env, caller: Address, project_id: u64) -> Result<(), CrowdfundError>Cancel an active project. Only the project owner or admin may call this.
Auth: Owner or admin.
Emits: ProjectCanceledEvent
pub fn refund_contributors(env: Env, project_id: u64, caller: Address) -> Result<(), CrowdfundError>Refund all contributors of a canceled project. Iterates through all contributors and transfers their deposited tokens back.
Auth: Requires caller authorization. Project must be in CANCELED status.
Emits: ContributionRefundedEvent (one per contributor refunded)
pub fn deposit(env: Env, user: Address, project_id: u64, amount: i128) -> Result<(), CrowdfundError>Deposit tokens into a project. Tracks individual contributions for quadratic funding. Auto-registers new contributors.
| Parameter | Type | Description |
|---|---|---|
user |
Address |
The contributor |
project_id |
u64 |
Target project |
amount |
i128 |
Contribution amount (must be > 0) |
Auth: Requires user authorization. Fails if paused, project inactive, or amount <= 0.
Emits: DepositEvent
pub fn approve_milestone(env: Env, admin: Address, project_id: u64) -> Result<(), CrowdfundError>Approve a project milestone, unlocking withdrawals for the project owner.
Auth: Admin only. Fails if paused.
Emits: MilestoneApprovedEvent
pub fn withdraw(env: Env, project_id: u64, amount: i128) -> Result<(), CrowdfundError>Withdraw funds from a project. Requires prior milestone approval.
| Parameter | Type | Description |
|---|---|---|
project_id |
u64 |
Target project |
amount |
i128 |
Amount to withdraw (must be > 0) |
Auth: Requires project owner authorization. Fails if milestone not approved, paused, or insufficient balance.
Emits: WithdrawEvent
pub fn fund_matching_pool(env: Env, admin: Address, token_address: Address, amount: i128) -> Result<(), CrowdfundError>Add tokens to the quadratic funding matching pool.
Auth: Admin only.
pub fn calculate_match(env: Env, project_id: u64) -> Result<i128, CrowdfundError>Calculate matching funds for a project using the quadratic funding formula: (Σ √contribution_i)². Uses fixed-point arithmetic with a 1e9 scaling factor for precision.
Returns: Ok(match_amount) — the calculated matching amount.
pub fn distribute_match(env: Env, project_id: u64) -> Result<i128, CrowdfundError>Distribute calculated matching funds from the matching pool to the project balance. Distributes the minimum of the calculated match and the available pool balance.
Returns: Ok(actual_match) — the amount actually distributed.
pub fn register_contributor(env: Env, contributor: Address) -> Result<(), CrowdfundError>Register as a contributor. Initializes reputation to 0.
Auth: Requires contributor authorization.
Emits: ContributorRegisteredEvent
pub fn update_reputation(env: Env, admin: Address, contributor: Address, change: i128) -> Result<(), CrowdfundError>Adjust a contributor's reputation score.
Auth: Admin only.
Emits: ReputationUpdatedEvent
| Function | Signature | Returns |
|---|---|---|
get_admin |
(env) -> Result<Address, CrowdfundError> |
Admin address |
get_project |
(env, project_id: u64) -> Result<ProjectData, CrowdfundError> |
Full project data |
get_balance |
(env, project_id: u64) -> Result<i128, CrowdfundError> |
Project vault balance |
get_contribution |
(env, project_id: u64, contributor: Address) -> Result<i128, CrowdfundError> |
Individual contribution |
get_contributor_count |
(env, project_id: u64) -> Result<u32, CrowdfundError> |
Number of unique contributors |
get_total_contributions |
(env, project_id: u64) -> Result<i128, CrowdfundError> |
Total deposited amount |
get_contributor_contribution |
(env, project_id: u64, contributor: Address) -> Result<i128, CrowdfundError> |
Alias for get_contribution |
get_reputation |
(env, contributor: Address) -> Result<i128, CrowdfundError> |
Contributor reputation score |
get_matching_pool_balance |
(env, token_address: Address) -> Result<i128, CrowdfundError> |
Matching pool balance |
is_milestone_approved |
(env, project_id: u64) -> Result<bool, CrowdfundError> |
Milestone approval status |
get_project_status |
(env, project_id: u64) -> Result<Symbol, CrowdfundError> |
"ACTIVE" or "CANCELED" |
require_not_paused |
(env) -> bool |
Current pause state |
contract_version |
(env) -> ContractVersion |
Implements VersionedContract (issue #1046); returns { major: 1, minor: 0, patch: 0 } |
pub fn get_project_storage_summary(env: Env, project_id: u64) -> Result<ProjectStorageSummary, CrowdfundError>Contract: crowdfund_vault Type: Read-only query (no storage writes, no rent cost added)
Returns a ProjectStorageSummary for the given project_id containing:
- project_id: the queried project
- project_exists: false if the project was never created
- contributor_count: number of contributors to this project (hot key signal)
- refund_receipt_count: number of refund receipts for this project
- total_projects: total projects ever created (growth indicator)
When to use:
- Testnet operators checking rent pressure on large projects
- Identifying which project_ids have the most contributor entries
- Monitoring overall protocol growth via total_projects
Example (Soroban CLI):
soroban contract invoke \
--id <CONTRACT_ID> \
--fn get_project_storage_summary \
-- --project_id 1| Event | Topics | Data | Emitted By |
|---|---|---|---|
InitializedEvent |
— | admin: Address |
initialize |
ProjectCreatedEvent |
owner: Address, token_address: Address |
project_id: u64 |
create_project |
DepositEvent |
user: Address, project_id: u64 |
amount: i128 |
deposit |
MilestoneApprovedEvent |
admin: Address |
project_id: u64 |
approve_milestone |
WithdrawEvent |
owner: Address, project_id: u64 |
amount: i128 |
withdraw |
ContributorRegisteredEvent |
— | contributor: Address |
register_contributor |
ReputationUpdatedEvent |
contributor: Address |
old_reputation: i128, new_reputation: i128 |
update_reputation |
ContractPauseEvent |
admin: Address |
paused: bool, timestamp: u64 |
pause |
ContractUnpauseEvent |
admin: Address |
paused: bool, timestamp: u64 |
unpause |
UpgradedEvent |
admin: Address |
new_wasm_hash: BytesN<32> |
upgrade |
AdminChangedEvent |
old_admin: Address |
new_admin: Address |
set_admin |
ProjectCanceledEvent |
— | project_id: u64, caller: Address |
cancel_project |
ContributionRefundedEvent |
— | project_id: u64, contributor: Address, amount: i128 |
refund_contributors |
EmrgMigrProposedEvent |
proposed_by: Address, project_id: u64 |
amount: i128 |
propose_emergency_migration |
EmrgMigrExecutedEvent |
executed_by: Address, project_id: u64 |
amount: i128 |
execute_emergency_migration |
EmrgMigrVetoedEvent |
vetoed_by: Address, project_id: u64 |
vetoed_at: u64 |
veto_emergency_migration |
pub enum CrowdfundError {
NotInitialized = 1,
AlreadyInitialized = 2,
Unauthorized = 3,
ProjectNotFound = 4,
MilestoneNotApproved = 5,
InsufficientBalance = 6,
ProjectNotActive = 7,
InvalidAmount = 8,
AlreadyRegistered = 9,
ContributorNotFound = 10,
ContractPaused = 11,
ProjectAlreadyCanceled = 12,
ProjectNotCancellable = 13,
RefundFailed = 14,
ContractNotPaused = 15,
// ── Emergency migration (issue #1047) ──────────────────────────────
EmergencyMigrationRequiresPause = 33, // contract must be paused
MigrationPlanAlreadyExists = 34, // pending plan already registered
MigrationPlanNotFound = 35, // no plan exists for this project
MigrationAlreadyExecuted = 36, // plan already executed or veto already final
InvalidMigrationRecipient = 37, // recipient is the contract itself
MigrationAmountExceedsBalance = 38, // amount > project vault balance
MigrationPlanVetoed = 39, // plan was vetoed; cannot execute
}| Key | Tier | Type | Description |
|---|---|---|---|
Admin |
Instance | Address |
Contract administrator |
Paused |
Instance | bool |
Emergency pause flag |
NextProjectId |
Instance | u64 |
Auto-incrementing project ID counter |
Project(u64) |
Persistent | ProjectData |
Full project record |
ProjectBalance(u64, Address) |
Persistent | i128 |
Vault balance per project × token |
ProjectStatus(u64) |
Persistent | Symbol |
"ACTIVE" or "CANCELED" |
MilestoneApproved(u64) |
Persistent | bool |
Whether milestone is approved |
Contribution(u64, Address) |
Persistent | i128 |
Individual contribution amount |
ContributorCount(u64) |
Persistent | u32 |
Count of unique contributors |
Contributor(u64, u32) |
Persistent | Address |
Contributor address by index |
MatchingPool(Address) |
Persistent | i128 |
Matching pool balance per token |
RegisteredContributor(Address) |
Persistent | bool |
Whether address is registered |
Reputation(Address) |
Persistent | i128 |
Contributor reputation score |
EmergencyMigrationPlan(u64) |
Persistent | EmergencyMigrationPlan |
Migration plan per project (issue #1047) |
Custom Types:
pub struct ProjectData {
pub id: u64,
pub owner: Address,
pub name: Symbol,
pub target_amount: i128,
pub token_address: Address,
pub total_deposited: i128,
pub total_withdrawn: i128,
pub is_active: bool,
}Crate: contributor_registry · Contract struct: ContributorRegistryContract
Source: contracts/contributor_registry/src/
An on-chain registry that maps Stellar addresses to GitHub handles, tracks reputation scores, and ensures unique GitHub handle ownership.
pub fn initialize(env: Env, admin: Address) -> Result<(), ContributorError>One-time initialization. Sets the admin.
Auth: Requires admin authorization.
pub fn register_contributor(env: Env, address: Address, github_handle: String) -> Result<(), ContributorError>Register a new contributor with their GitHub handle. Initializes reputation_score to 0 and records the registration timestamp.
| Parameter | Type | Description |
|---|---|---|
address |
Address |
The contributor's Stellar address |
github_handle |
String |
GitHub username (must be non-empty and unique) |
Auth: Requires address authorization.
Errors: ContributorAlreadyExists, InvalidGitHubHandle, GitHubHandleTaken
pub fn update_contributor(env: Env, address: Address, github_handle: String) -> Result<(), ContributorError>Update an existing contributor's GitHub handle. Automatically re-indexes the GitHub → Address mapping.
Auth: Requires address authorization.
Errors: ContributorNotFound, InvalidGitHubHandle, GitHubHandleTaken
pub fn update_reputation(env: Env, admin: Address, contributor_address: Address, delta: i64) -> Result<(), ContributorError>Adjust a contributor's reputation score. Positive delta adds points; negative delta subtracts (floors at 0).
| Parameter | Type | Description |
|---|---|---|
admin |
Address |
Must match stored admin |
contributor_address |
Address |
The contributor to update |
delta |
i64 |
Reputation change (positive or negative) |
Auth: Admin only.
Errors: ContributorNotFound, ReputationOverflow
pub fn upgrade(env: Env, caller: Address, new_wasm_hash: BytesN<32>) -> Result<(), ContributorError>Upgrade the contract WASM. Admin only.
Emits: UpgradedEvent
pub fn set_admin(env: Env, current_admin: Address, new_admin: Address) -> Result<(), ContributorError>Transfer the admin role.
Emits: AdminChangedEvent
| Function | Signature | Returns |
|---|---|---|
get_admin |
(env) -> Result<Address, ContributorError> |
Admin address |
get_contributor |
(env, address: Address) -> Result<ContributorData, ContributorError> |
Full contributor profile |
get_contributor_by_github |
(env, github_handle: String) -> Result<ContributorData, ContributorError> |
Lookup by GitHub handle |
get_reputation |
(env, contributor: Address) -> Result<u64, ContributorError> |
Reputation score |
contract_version |
(env) -> ContractVersion |
Implements VersionedContract (issue #1046); returns { major: 1, minor: 0, patch: 0 } |
| Event | Topics | Data | Emitted By |
|---|---|---|---|
UpgradedEvent |
admin: Address |
new_wasm_hash: BytesN<32> |
upgrade |
AdminChangedEvent |
old_admin: Address |
new_admin: Address |
set_admin |
pub enum ContributorError {
NotInitialized = 1,
AlreadyInitialized = 2,
Unauthorized = 3,
ContributorNotFound = 4,
ContributorAlreadyExists = 5,
InvalidGitHubHandle = 6,
ReputationOverflow = 7,
GitHubHandleTaken = 8,
}| Key | Tier | Type | Description |
|---|---|---|---|
Admin |
Instance | Address |
Contract administrator |
Contributor(Address) |
Persistent | ContributorData |
Contributor profile |
GitHubIndex(String) |
Persistent | Address |
Reverse index: GitHub handle → Address |
Custom Types:
pub struct ContributorData {
pub address: Address,
pub github_handle: String,
pub reputation_score: u64,
pub registered_timestamp: u64,
}Crate: vesting-wallet · Contract struct: VestingWalletContract
Source: contracts/vesting-wallet/src/
A linear token vesting contract. Admins create vesting schedules that unlock tokens proportionally over time. Beneficiaries can claim vested tokens at any point.
pub fn initialize(env: Env, admin: Address, token: Address) -> Result<(), VestingError>One-time initialization. Sets admin and the token address used for all vesting schedules.
| Parameter | Type | Description |
|---|---|---|
admin |
Address |
The contract administrator |
token |
Address |
The token contract address for vested tokens |
Auth: Requires admin authorization.
pub fn create_vesting(
env: Env, admin: Address, beneficiary: Address,
amount: i128, start_time: u64, duration: u64,
) -> Result<(), VestingError>Create a linear vesting schedule. Transfers amount tokens from admin to the contract. If a vesting already exists for the beneficiary, remaining unvested tokens are returned to admin before creating the new schedule.
| Parameter | Type | Description |
|---|---|---|
admin |
Address |
Must match stored admin |
beneficiary |
Address |
Recipient of vested tokens |
amount |
i128 |
Total tokens to vest (must be > 0) |
start_time |
u64 |
Unix timestamp when vesting begins (must be ≥ current time) |
duration |
u64 |
Vesting period in seconds (must be > 0) |
Auth: Admin only.
Emits: VestingCreatedEvent
pub fn claim(env: Env, beneficiary: Address) -> Result<i128, VestingError>Claim available vested tokens. Calculates the linearly vested amount based on elapsed time and transfers unclaimed tokens.
Vesting formula:
- Before
start_time: claimable =0 - After
start_time + duration: claimable =total_amount - claimed_amount - During vesting: claimable =
(total_amount × time_elapsed / duration) - claimed_amount
Returns: Ok(claimed_amount) — the amount of tokens transferred.
Auth: Requires beneficiary authorization.
Emits: TokensClaimedEvent
| Function | Signature | Returns |
|---|---|---|
get_admin |
(env) -> Result<Address, VestingError> |
Admin address |
get_token |
(env) -> Result<Address, VestingError> |
Token contract address |
get_vesting |
(env, beneficiary: Address) -> Result<VestingData, VestingError> |
Full vesting schedule data |
get_claimable |
(env, beneficiary: Address) -> Result<i128, VestingError> |
Currently claimable amount (view) |
get_available_amount |
(env, beneficiary: Address) -> Result<i128, VestingError> |
Alias for get_claimable |
contract_version |
(env) -> ContractVersion |
Implements VersionedContract (issue #1046); returns { major: 1, minor: 0, patch: 0 } |
pub fn upgrade(env: Env, caller: Address, new_wasm_hash: BytesN<32>) -> Result<(), VestingError>Upgrade the contract WASM. Admin only.
Emits: UpgradedEvent
pub fn set_admin(env: Env, current_admin: Address, new_admin: Address) -> Result<(), VestingError>Transfer the admin role.
Emits: AdminChangedEvent
| Event | Topics | Data | Emitted By |
|---|---|---|---|
VestingCreatedEvent |
beneficiary: Address |
amount: i128, start_time: u64, duration: u64 |
create_vesting |
TokensClaimedEvent |
beneficiary: Address |
amount_claimed: i128, remaining: i128 |
claim |
UpgradedEvent |
admin: Address |
new_wasm_hash: BytesN<32> |
upgrade |
AdminChangedEvent |
old_admin: Address |
new_admin: Address |
set_admin |
pub enum VestingError {
NotInitialized = 1,
AlreadyInitialized = 2,
Unauthorized = 3,
VestingNotFound = 4,
InvalidAmount = 5,
InvalidDuration = 6,
InvalidStartTime = 7,
NothingToClaim = 8,
InsufficientBalance = 9,
}| Key | Tier | Type | Description |
|---|---|---|---|
Admin |
Instance | Address |
Contract administrator |
Token |
Instance | Address |
Token contract used for vesting |
Vesting(Address) |
Persistent | VestingData |
Vesting schedule per beneficiary |
Custom Types:
pub struct VestingData {
pub beneficiary: Address,
pub total_amount: i128,
pub start_time: u64,
pub duration: u64,
pub claimed_amount: i128,
}Crate: upgradable-contract · Contract struct: UpgradableContract
Source: contracts/upgradable-contract/src/
A minimal reference contract demonstrating the WASM upgrade pattern on Soroban with admin governance, state preservation across upgrades (counter), and admin rotation.
pub fn init(env: Env, admin: Address)One-time initialization. Sets the admin. Panics if already initialized.
Auth: Requires admin authorization.
pub fn upgrade(env: Env, caller: Address, new_wasm_hash: BytesN<32>)Upgrade the contract WASM. Panics if caller != admin.
Auth: Admin only.
Emits: UpgradedEvent
pub fn set_admin(env: Env, current_admin: Address, new_admin: Address)Transfer the admin role. Panics if current_admin doesn't match stored admin.
Auth: Requires current_admin authorization.
Emits: AdminChangedEvent
pub fn get_admin(env: Env) -> AddressReturns: Address — the current admin. Panics if not initialized.
pub fn increment(env: Env) -> u32Increment the on-chain counter and return the new value. Demonstrates state preservation across upgrades.
Returns: u32 — the updated counter value.
pub fn get_count(env: Env) -> u32Returns: u32 — the current counter value (defaults to 0).
pub fn version() -> u32Legacy single-integer version identifier, kept for backward compatibility with existing callers. Prefer contract_version (below) for new integrations.
Returns: u32 — the contract version identifier (currently 1).
pub fn contract_version(env: Env) -> ContractVersionImplements VersionedContract (issue #1046).
Returns: ContractVersion { major: 1, minor: 0, patch: 0 }
| Event | Topics | Data | Emitted By |
|---|---|---|---|
UpgradedEvent |
admin: Address |
new_wasm_hash: BytesN<32> |
upgrade |
AdminChangedEvent |
old_admin: Address |
new_admin: Address |
set_admin |
| Key | Tier | Type | Description |
|---|---|---|---|
Admin |
Instance | Address |
Contract administrator / upgrader |
Counter |
Instance | u32 |
Incrementing counter (persists across upgrades) |
All contracts share these common design patterns:
| Pattern | Description |
|---|---|
| One-time init guard | initialize checks for existing Admin key before writing state |
| Admin auth | Functions that modify critical state call require_auth() on the admin address |
| WASM upgradability | upgrade + UpgradedEvent pattern using env.deployer().update_current_contract_wasm() |
| Admin rotation | set_admin + AdminChangedEvent for governance handoffs |
| Result-based errors | Vault, Registry, and Vesting use Result<T, ContractError> enums; Token and Upgradable use panics |
| Tier | Lifetime | Usage |
|---|---|---|
| Instance | Contract lifetime (shared TTL) | Admin, config, counters — contract-global singletons |
| Persistent | Survives archival (extendable TTL) | Balances, project data, vesting schedules — user-specific data |
| Temporary | Auto-expires after TTL | Token allowances — ephemeral approvals |