In the fast-evolving decentralized finance (DeFi) landscape, managing treasury reserves safely and transparently is a core requirement for any Web3 organization. Whether you are running a Decentralized Autonomous Organization (DAO), managing venture funding, or distributing developer bounties, you need two things: rock-solid security on-chain and clear observability off-chain.
In this article, we’ll walk through how we built Stellar Vault Ops—a production-grade Web3 vault operations dashboard built on Stellar Mainnet using Soroban smart contracts, Freighter wallet integration, and a real-time React dashboard. We will explore the contract design patterns, inter-contract calls, and how we solved common transaction UX challenges.
1. The Architectural Blueprint
A secure treasury architecture should avoid monolithic smart contracts. Instead, we follow a modular design, separating asset logic from business workflows:
- The Token Contract: A standard asset contract managing balances, minting, and transfers.
- The Vault Contract: A specialized treasury manager that holds reserves and coordinates transfers by performing inter-contract calls to the Token Contract.
- The Web Console: An operator console that lets admins deposit, distribute, and track transaction states (simulating, signing, submitting, and confirmed) in real-time.
+--------------------------------+
| Operator / Admin |
+--------------------------------+
|
v (1. Triggers Action)
+--------------------------------+
| React Web Console |
+--------------------------------+
|
v (2. Request Auth & Sign)
+--------------------------------+
| Freighter Wallet |
+--------------------------------+
|
v (3. Submit Signed Tx)
+--------------------------------+
| Stellar Mainnet RPC |
+--------------------------------+
|
v (4. Invoke)
+--------------------------------+
| Vault Contract |
+--------------------------------+
|
v (5. Inter-Contract Call: Transfer)
+--------------------------------+
| Token Contract |
+--------------------------------+
|
v (6. Mutate Balances)
+--------------------------------+
| Stellar Ledger |
+--------------------------------+
2. On-Chain Logic: Soroban Smart Contracts in Rust
Stellar’s smart contract platform, Soroban, provides a highly performant and secure environment using WebAssembly (WASM). Let’s dive into how our contracts are designed.
A. The Token Contract (TokenContract)
The Token Contract tracks state variables in instance storage and exposes standard ERC-20 style endpoints:
#[contractimpl]
impl TokenContract {
pub fn initialize(e: Env, admin: Address, name: String, symbol: String, decimals: u32) -> Result<(), TokenError> {
if e.storage().instance().has(&DataKey::Admin) {
return Err(TokenError::AlreadyInitialized);
}
admin.require_auth();
e.storage().instance().set(&DataKey::Admin, &admin);
e.storage().instance().set(&DataKey::Name, &name);
e.storage().instance().set(&DataKey::Symbol, &symbol);
e.storage().instance().set(&DataKey::Decimals, &decimals);
e.storage().instance().set(&DataKey::TotalSupply, &0_i128);
Ok(())
}
pub fn transfer(e: Env, from: Address, to: Address, amount: i128) -> Result<(), TokenError> {
if amount <= 0 { return Err(TokenError::InvalidAmount); }
from.require_auth();
let from_balance = read_balance(&e, &from);
if from_balance < amount { return Err(TokenError::InsufficientBalance); }
let to_balance = read_balance(&e, &to);
write_balance(&e, &from, from_balance - amount);
write_balance(&e, &to, to_balance + amount);
Ok(())
}
}
Security Feature: The from.require_auth() assertion guarantees that nobody can move tokens out of a wallet without a cryptographic signature from that wallet.
B. The Vault Contract & Inter-Contract Calls
The Vault Contract is responsible for tracking aggregate deposits and distributions. Rather than holding and ledgering balances itself, it holds the token reserves and calls the Token Contract to perform actual transfers.
Here is how the Vault handles a deposit operation:
pub fn deposit(e: Env, from: Address, amount: i128) -> Result<(), VaultError> {
if amount <= 0 { return Err(VaultError::InvalidAmount); }
read_admin(&e)?;
from.require_auth();
let token_contract = read_token_contract(&e)?;
let vault_address = e.current_contract_address();
// Inter-contract call: transfers tokens from user to this vault
e.invoke_contract::<()>(
&token_contract,
&soroban_sdk::symbol_short!("transfer"),
soroban_sdk::Vec::from_array(
&e,
[
from.clone().into_val(&e),
vault_address.into_val(&e),
amount.into_val(&e),
],
),
);
// Update aggregate metrics
let next_total_deposited = total_deposited(&e) + amount;
e.storage().instance().set(&DataKey::TotalDeposited, &next_total_deposited);
// Publish event
e.events().publish(
(soroban_sdk::symbol_short!("deposit"), from.clone()),
DepositEvent { from, amount },
);
Ok(())
}
By leveraging e.invoke_contract(...), the Vault contract keeps a single, secure gateway to execute transfers. The Vault itself does not need to duplicate transfer safety checks, as the Token Contract enforces them during execution.
3. Resolving Web3 UX Challenges: Frontend Observability
Web3 applications frequently suffer from poor feedback loops. Users click a button, sign a transaction, and are left staring at a static loader, wondering if their transaction went through, failed, or timed out.
To solve this in the Stellar Vault Ops console, we built a stateful transaction tracker using React hooks and the Stellar SDK:
-
Pre-Flight Simulation: Before asking the user to sign, we run
server.simulateTransaction(tx). This tests the execution off-chain. If the vault has insufficient funds, we throw a friendly message immediately, preventing wasted gas and user frustration. -
Freighter Wallet Integration: We integrate Freighter to securely request signatures. We set a strict
SIGN_TIMEOUT_MS(45 seconds) to catch users rejecting or ignoring the popups and return control to the UI. -
Optimized Polling & Finality Tracking: Stellar ledgers close every 5-6 seconds. Polling too aggressively can strain RPC nodes, while polling too slowly hurts UX. We built a decaying polling mechanism:
- Poll every 1 second initially.
- If not indexed after 3 attempts, scale to 2 seconds.
- Handle transient RPC union-switch parsing exceptions safely, treating them as pending rather than crashing the interface.
4. Security Audit Insights
Prior to launching on Stellar Mainnet, we conducted a security audit of our Rust code. Here are some of the design trade-offs and findings:
-
Relayer-Friendly Distributions (Design Choice): In the Vault's
distributemethod, we check that the contract is initialized, but do not calladmin.require_auth(). This allows automated relayer accounts or cron jobs to trigger payouts. If strict control is needed for a corporate treasury, this should be hardened to check permissions. -
Instance Storage Expiry: Soroban introduces storage fees and storage expiration. For production scale, switching to
persistentdata keys for balances and setting up automatic renewal is critical to prevent user funds from freezing if instance rent expires.
5. Mainnet Launch & Adoption
We officially deployed the Stellar Vault Ops smart contracts on the Stellar Mainnet:
-
Token Contract:
CBH5G42NMW7LARIUBBCUUWLA6WJ2Q373QFPQ3YCGRB72JUAVRBIRDEJP -
Vault Contract:
CC24WFEK4J2XFZL6VSNKTBTCZSQSBOGTCGJ7BFNA4QTG3RY3BHKPMBPL
To validate the deployment, we onboarded 100 active Web3 users who tested deposit, distribution, and monitoring actions on Mainnet. 70% of participants expressed high intent to reuse the dashboard for treasury management, liking the clean dark-mode visuals and the real-time transaction timeline.
Conclusion & Next Steps
Building on Stellar with Soroban offers a robust and highly secure developer experience. The strict separation of concerns, strong typing in Rust, and built-in signature authentication make it an ideal blockchain for treasury and DeFi operations.
In the next iteration of Stellar Vault Ops, we plan to implement:
- Multi-signature authentication for distribution operations.
- Real-time Slack/Discord webhooks for treasury movement tracking.
- Ledger and WalletConnect support.
Check out the full open-source code and onboarding telemetry on our GitHub Repository.
Top comments (0)