Stellar Vaults
Native Soroban Upshift vaults on Stellar built on OpenZeppelin's stellar-tokens library with ERC-4626 share pricing.
Upshift Stellar Vaults bring the same institutional-grade vault infrastructure to the Stellar ecosystem. Built as a native Soroban smart contract on top of OpenZeppelin's stellar-tokens library, Stellar vaults offer fast, non-custodial yield generation transparently on-chain, with actively managed strategies.
| Property | Value |
|---|---|
| Contract | AugustVault (upgradeable Soroban contract) |
| Framework | Soroban + OpenZeppelin stellar-tokens (ERC-4626 pattern) |
| Deposit Asset | Any SEP-41 token (native SAC or custom contract) |
| Share Token | Fungible share token issued by the vault contract itself |
| Redemptions | Instant, no lock-ups (bounded by the vault's local balance) |
Vault Architecture
Each Upshift Stellar vault is a deployment of the AugustVault Soroban contract. The constructor binds the vault to a single underlying token, sets the share token's name and symbol, and fixes a virtual decimals offset (used for inflation-attack protection).
The contract follows the ERC-4626 Tokenized Vault Standard. Share-pricing logic is reimplemented on top of OpenZeppelin's primitives so that NAV reflects not only the tokens physically held by the vault but also capital that has been deployed off-vault: total_assets, convert_to_shares, convert_to_assets, all four preview_* functions, and max_deposit / max_mint / max_withdraw / max_redeem.
On deployment the contract initializes:
- Vault instance storage holding the asset address, share-token metadata, decimals offset, admin, operator, paused flag, deployed-assets aggregate, AUM limits, and the subaccount whitelist
- The share token issued by the vault itself (the same contract that custodies the underlying asset is also the share issuer)
- An on-chain TTL bump on every state-changing entrypoint so the instance never expires under normal traffic; a permissionless
extend_ttl()is provided as a fallback for quiet periods
Deposit Flow
- User calls
deposit(assets, receiver, from, operator)with their underlying tokens - The operator (the address authorizing the deposit) is
require_auth'd and the vault verifies it is not paused - The vault converts the asset amount to shares against current NAV using ERC-4626 math with the configured decimals offset:
shares_minted = assets * (total_supply + 10^offset) / (total_assets + 1)- The underlying tokens are pulled from
frominto the vault's contract balance, share tokens are minted toreceiver, and the contract's instance TTL is extended - A standard ERC-4626
Depositevent is emitted
mint(shares, receiver, from, operator) is the symmetric entrypoint: callers specify exact shares to mint and the vault computes the assets required (rounding up).
Redemption Flow
- User calls
redeem(shares, receiver, owner, operator)orwithdraw(assets, receiver, owner, operator) - The operator is authorized and the vault verifies it is not paused
- The vault computes the asset payout against current NAV:
assets_out = shares * (total_assets + 1) / (total_supply + 10^offset)- The redemption is capped at the vault's local token balance —
max_withdrawandmax_redeemare the minimum of the user's entitlement and the assets physically present in the vault. If the user's pro-rata share exceeds what's currently liquid, they must wait for the operator to return capital - Share tokens are burned from
ownerand the underlying is transferred toreceiver
A standard ERC-4626 Withdraw event is emitted.
Vault Share Price Mechanics
The share token price is fully derivable on-chain:
share_price = total_assets / total_supply
total_assets = local_balance
+ Σ IStrategy::get_balance() over all Strategy subaccounts
+ deployed_assetslocal_balance— the vault contract's own balance of the underlying token. Fully verifiable on-chain via a directtoken.balance(vault)readΣ get_balance()— each Strategy subaccount self-reports its full position (idle + deployed) on every NAV query. A strategy that traps, returns a non-i128, or returns a negative value causes the vault to halt the calculation with aStrategyUnreachable(orNegativeStrategyBalance) error rather than silently zero out — under-reporting NAV would let a buggy strategy crash the share pricedeployed_assets— the aggregate of capital attributed to Wallet subaccounts (the value the operator has moved off-vault to addresses whose balances the vault cannot trustlessly read). The invariantΣ WalletNetDeployed == deployed_assetsis maintained by every routine path;get_wallet_deployed_assets()exposes the Σ side for monitoringtotal_supply— the share token's supply, readable directly from the vault contract
Any Soroban contract can compute the share price by calling total_assets() and total_supply() on the vault. No external oracle is required.
The vault uses ERC-4626's virtual-shares-and-virtual-assets formula with a configurable decimals offset (minimum 3, maximum 10, default 6).
The Upshift Stellar contracts are open source at the upshift-protocol/stellar-upshift-vault-contracts repository on GitHub.