- Status: Accepted
- Date: 2026-08-25
- Deciders: Smart Contract Engineering Team, Security Maintainers
Decentralized crowdfunding contracts manage user funds, contributor pledges, platform fees, and milestone distributions on the Stellar blockchain. Over the lifecycle of Fund-My-Cause, contract logic inevitably requires bug fixes, gas optimizations, security hardening (such as reentrancy guards and circuit breakers), and storage layout evolutions.
However, smart contract upgrades introduce significant security and operational risks:
- Address Immutability: External consumers (the Next.js frontend, mobile wallet adapters, indexers, and registry contracts) store contract IDs. Changing contract IDs on every release would break bookmarks, deep links, indexer history, and active crowdfunding pledges.
- State & Fund Safety: Contributor pledges and campaign parameters stored in instance/persistent storage must remain intact and accessible across code versions without loss of funds.
- Decentralization & Governance: Upgrades must be restricted to authorized administrators or multi-sig controllers and be fully auditable on-chain.
We needed a defined, test-verified upgrade and migration strategy for contracts/crowdfund and contracts/registry.
We adopt Soroban native in-place WASM upgradeability (env.deployer().update_current_contract_wasm(...)) coupled with additive storage versioning and lazy/explicit state migration functions.
- In-Place Bytecode Replacement: The deployed contract exposes an
upgradeentry point gated by admin authorization:pub fn upgrade(env: Env, new_wasm_hash: soroban_sdk::BytesN<32>) { let admin: Address = env.storage().instance().get(&KEY_ADMIN).unwrap(); admin.require_auth(); env.deployer().update_current_contract_wasm(new_wasm_hash); }
- Storage Preservation: All instance and persistent storage keys remain untouched at the same contract address.
- Compile-Time & Runtime Versioning: Contracts export a compile-time
CONTRACT_VERSION: u32constant via aversion()view function, synchronized with Cargo semantic versioning.
- Additive Changes (Default): New features introduce new storage keys with default/fallback handling (e.g.,
unwrap_or_default()), requiring zero storage migration steps. - Breaking Data Restructuring: For struct field changes or enum migrations, a temporary admin-guarded
migratefunction is invoked immediately after bytecode deployment and removed in the subsequent release. - Continuous Backward Compatibility Testing: Storage layout stability and cross-version migrations are tested via
contracts/crowdfund/tests/upgrade_tests.rs.
| Option | Pros | Cons | Verdict |
|---|---|---|---|
1. Native Soroban in-place WASM update (update_current_contract_wasm) |
• Preserves contract address • Zero transfer of escrowed funds needed • Native runtime support with minimal gas overhead • Preserves indexer history |
• Requires disciplined storage key discipline • Admin key must be secured with multi-sig |
Accepted (Chosen) |
| 2. EVM-style Proxy Pattern (ERC-1967 / DELEGATECALL) | • Familiar to Ethereum developers | • Unnecessary complexity in Soroban • Extra call indirection and gas costs • Soroban host natively supports WASM replacement |
Rejected |
| 3. Immutable Non-Upgradeable Contracts | • Maximum trust minimization • Impossible for admin to change rules maliciously |
• Critical bugs cannot be patched • Requires migrating entire campaign balances to new contracts on every feature release |
Rejected |
| 4. Factory Deprecate & Redeploy (New Address per Release) | • Clean isolation between versions | • Breaks external URLs and registry discovery • High friction for ongoing active campaigns • Indexers must reconcile multiple contract addresses per campaign |
Rejected |
- Stable Contract Identifiers: Frontends, indexers, and registry contracts retain identical contract IDs across contract logic updates.
- Safe Escrow Management: Crowdfunding balances remain locked in the contract instance without requiring risky balance transfers between contracts.
- Test-Driven Upgrade Verification: All upgrade paths are covered by automated unit and migration tests in
upgrade_tests.rs. - Auditable On-Chain Upgrades: WASM hash updates emit standard Stellar ledger events for full transparency.
- Admin Key Security Requirement: The
KEY_ADMINkey becomes a high-value security target, requiring hardware security or multi-sig protection for production deployments. - Storage Key Immutability: Developers must ensure existing symbol keys (e.g.,
"GOAL","CREATOR","TOKEN") are never repurposed or renamed without an explicit migration path.