Spark Vaults Smart Contracts Integration Guide
This guide shows how to integrate the Spark Vaults smart contracts for common user flows: reading balances, depositing, withdrawing, withdrawing everything, and requesting large withdrawals through Savings Vault Intents.
For a full contract reference, supported functions, roles, and events, see Spark Savings Vaults V2. For the intent contract reference, see Savings Vault Intents.
Supported Mainnet Vaults
| Vault | Protocol | Underlying asset | Vault address |
|---|---|---|---|
| spUSDC | Spark | USDC | 0x28B3a8fb53B741A8Fd78c0fb9A6B2393d896a43d |
| spUSDT | Spark | USDT | 0xe2e7a17dFf93280dec073C995595155283e3C372 |
| sUSDT | Sky | USDT | 0x74cb54e082411cfCAEADb00a0765625B10410DAa |
All Spark-related addresses are tracked in the Spark Address Registry.
Download the SparkVault ABI to interact with Spark Vaults.
Core Concepts
Spark Vaults are ERC-4626 vaults. A user deposits an underlying asset, such as USDC or USDT, and receives vault shares, such as spUSDC or spUSDT.
The user's share balance does not automatically increase. Instead, each share becomes redeemable for more underlying assets over time as the vault accrues yield. This means integrations usually show balances in underlying asset terms, not only in share terms.
For example, if a user holds spUSDC, the most useful display balance is their current USDC value:
asset balance = assetsOf(user)assets are denominated in the underlying token's decimals. For the mainnet USDC and USDT vaults above, that means 6-decimal units. shares are denominated in the vault token's decimals, which match the underlying asset for these vaults.
Vault Functions
Read Balance in Assets
balanceOf(address account) returns (uint256 shares)
assetsOf(address owner) returns (uint256 assets)Use assetsOf(owner) to show a user's current balance in underlying asset terms.
Deposit
deposit(uint256 assets, address receiver) returns (uint256 shares)
deposit(uint256 assets, address receiver, uint16 referral) returns (uint256 shares)
previewDeposit(uint256 assets) returns (uint256 shares)
maxDeposit(address receiver) returns (uint256 assets)The user approves the vault to spend the underlying asset, then calls deposit. The vault transfers the underlying asset from the caller and issues vault shares to receiver.
Use previewDeposit(assets) when quoting expected shares, and maxDeposit(receiver) when checking remaining deposit capacity.
The referral overload is optional. Integrators can use it when Spark has assigned them a referral code for attribution or campaigns — see Referral Codes for how to get one and what it enables. If you do not have a referral code, use the two-argument deposit(assets, receiver) function.
Withdraw
withdraw(uint256 assets, address receiver, address owner) returns (uint256 shares)
previewWithdraw(uint256 assets) returns (uint256 shares)
maxWithdraw(address owner) returns (uint256 assets)Use withdraw when the user wants a specific amount of underlying assets back. The vault burns enough shares from owner and sends assets underlying tokens to receiver.
Withdrawals depend on the vault's current idle liquidity. The vault can deploy assets through the Spark Liquidity Layer, so totalAssets() can be higher than the underlying token balance currently held by the vault.
If maxWithdraw(owner) is smaller than the amount the user wants to withdraw, the user has two options:
- Withdraw in smaller chunks. Spark's offchain infrastructure normally refills vault idle liquidity shortly after withdrawals.
- Use Savings Vault Intents for a single request that will be fulfilled after liquidity is prepared.
Withdraw Everything
balanceOf(address account) returns (uint256 shares)
maxRedeem(address owner) returns (uint256 shares)
redeem(uint256 shares, address receiver, address owner) returns (uint256 assets)Use redeem(balanceOf(owner), receiver, owner) when the user wants to withdraw their full vault position.
Before showing a one-click "withdraw all" action, compare balanceOf(owner) with maxRedeem(owner). If maxRedeem(owner) is lower than the user's full share balance, the vault does not currently have enough idle liquidity to withdraw everything immediately. In that case, the user can withdraw in chunks as liquidity is refilled, or submit a Savings Vault Intent.
Savings Vault Intents
Savings Vault Intents is a separate mainnet contract for large withdrawals:
SavingsVaultIntents: 0x592B7DB9906E6f8924C4D74c2A0aB86CE44fDDDfView the contract on Etherscan.
Download the SavingsVaultIntents ABI to interact with the intents contract.
Use intents when a user wants to withdraw more than the vault can immediately satisfy from its current idle balance. The user creates an onchain withdrawal request for a vault and a share amount. Spark's offchain infrastructure monitors these requests, prepares liquidity for the target vault, and fulfills the request automatically by calling the intent contract.
The intent contract does not custody the user's shares when the request is created. The user keeps their vault shares until fulfillment. To allow fulfillment, the user must approve the intent contract to spend the requested vault shares.
When a request is fulfilled, the intent contract calls redeem(shares, recipient, account) on the vault. The underlying assets are sent directly to recipient, and the request emits RequestFulfilled(account, vault, requestId).
Each user can have one active request per vault. Calling request again for the same (user, vault) replaces the previous request and returns a new requestId. A user can cancel their active request with cancel(vault), which emits RequestCancelled(account, vault, requestId).
If the deadline passes before fulfillment, the request is no longer fulfillable. The user's shares remain in their wallet because they were never escrowed. The user can cancel the expired request or submit a replacement request with a new deadline.
Intent Functions
request(address vault, uint256 shares, address recipient, uint256 deadline) returns (uint256 requestId)
cancel(address vault) returns (uint256 requestId)
withdrawRequests(address account, address vault) returns (uint256 requestId, uint256 shares, address recipient, uint256 deadline)
vaultConfig(address vault) returns (bool whitelisted, uint256 minIntentAssets, uint256 maxIntentAssets)
maxDeadlineDuration() returns (uint256 seconds)request creates or replaces the user's active request for a vault. recipient receives the underlying assets when the request is fulfilled. deadline is the latest timestamp at which the request can be fulfilled. The deadline cannot be more than maxDeadlineDuration() seconds in the future.
withdrawRequests(account, vault) returns the currently active request for an account and vault. Use it to show pending request status in an interface.
Only whitelisted vaults and request sizes within minIntentAssets and maxIntentAssets are supported. If the requested share amount converts to an asset amount below minIntentAssets or above maxIntentAssets, the transaction will be rejected.
Examples
See Spark Vaults Smart Contracts Examples for viem, ethers, and Solidity recipes.