This document describes how the Callora Vault is deployed, how its state is stored, and how to migrate to a new contract if needed. Soroban contract upgradeability is limited: you cannot replace the code of an existing contract instance in place. Migration is done by deploying a new contract and moving state and traffic to it.
- One contract WASM: The vault is built as a single Soroban contract (
callora-vault). Build with:cd contracts/vault && cargo build --target wasm32-unknown-unknown --release
- One instance per vault: Each vault is a separate contract instance created by deploying the same WASM and calling
init(owner, initial_balance, min_deposit)once. The instance ID is the “vault address” used by the backend and frontend. - No in-place upgrades: There is no built-in mechanism to change the code of an existing instance. To change behavior, you deploy a new contract (new WASM or new instance) and migrate.
The vault uses instance storage with a single key:
| Key | Type | Description |
|---|---|---|
meta |
VaultMeta |
Owner, balance, and min_deposit |
VaultMeta layout is documented in contracts/vault/STORAGE.md. Any migration must read this layout so existing state can be exported and re-imported.
When you need to move to a new vault (e.g. new code or new instance):
-
Export state from the old vault
- Read
get_meta()from the current contract instance (owner, balance, min_deposit). - Optionally export event history or audit data for your records (from indexer/archives).
- Read
-
Deploy the new contract
- Build and deploy the new WASM (or deploy a new instance of the same WASM).
- Call
init(owner, Some(current_balance), Some(min_deposit))with the exported owner and, if desired, the same balance and min_deposit. - If you are not moving balance on-chain automatically, you may init with
initial_balance: Some(0)and treat the old vault as “drained” and the new one as the new ledger.
-
Move balance (if applicable)
- If the old vault holds real assets (e.g. USDC), you must transfer them off the old vault (e.g. via owner
withdrawor integration-specific flows) and then fund the new vault (e.g. deposit or token transfer). The current vault contract does not hold token balances; it tracks an internal balance. When token integration is added, migration would include withdrawing from the old vault and depositing into the new one.
- If the old vault holds real assets (e.g. USDC), you must transfer them off the old vault (e.g. via owner
-
Redirect users and backend
- Point the backend (and any frontend) to the new contract instance ID for that vault.
- Retire or deprecate the old instance (no further calls).
- Storage compatibility: New contract versions that add or change fields in
VaultMeta(or add new keys) are not backward compatible with existing instance data. Migration must either:- Deploy a new instance and init with the desired state (recommended), or
- Use a migration contract/tool that reads the old layout and writes the new one (advanced).
- Interface compatibility: Keep
init,deposit,deduct,balance,withdraw, andwithdraw_tosemantics stable for the same instance ID, or treat a new instance as a new vault and migrate as above.
- Deploy: One WASM, one
initper vault instance. - Storage: Single
metakey; see STORAGE.md for layout. - Upgrade: No in-place code upgrade; deploy a new contract/instance, export state, re-init and move balance as needed, then redirect traffic to the new instance.