Spark Vaults Smart Contracts Examples
These examples show common Spark Vaults flows in viem 2.51.0, ethers 6.16.0, and Solidity.
The examples use the mainnet spUSDC vault:
Vault: 0x28B3a8fb53B741A8Fd78c0fb9A6B2393d896a43d
Asset: 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
SavingsVaultIntents: 0x592B7DB9906E6f8924C4D74c2A0aB86CE44fDDDfSetup
viem
import { createPublicClient, createWalletClient, custom, http, parseAbi, parseUnits } from 'viem'
import { mainnet } from 'viem/chains'
const vault = '0x28B3a8fb53B741A8Fd78c0fb9A6B2393d896a43d'
const asset = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'
const intents = '0x592B7DB9906E6f8924C4D74c2A0aB86CE44fDDDf'
const erc20Abi = parseAbi([
'function approve(address spender, uint256 value) returns (bool)',
])
const vaultAbi = parseAbi([
'function balanceOf(address account) view returns (uint256 shares)',
'function assetsOf(address owner) view returns (uint256 assets)',
'function convertToAssets(uint256 shares) view returns (uint256 assets)',
'function deposit(uint256 assets, address receiver) returns (uint256 shares)',
'function withdraw(uint256 assets, address receiver, address owner) returns (uint256 shares)',
'function redeem(uint256 shares, address receiver, address owner) returns (uint256 assets)',
])
const intentsAbi = parseAbi([
'function request(address vault, uint256 shares, address recipient, uint256 deadline) returns (uint256 requestId)',
'function cancel(address vault) returns (uint256 requestId)',
'function withdrawRequests(address account, address vault) view returns (uint256 requestId, uint256 shares, address recipient, uint256 deadline)',
'function vaultConfig(address vault) view returns (bool whitelisted, uint256 minIntentAssets, uint256 maxIntentAssets)',
'function maxDeadlineDuration() view returns (uint256)',
])
const publicClient = createPublicClient({
chain: mainnet,
transport: http(),
})
const walletClient = createWalletClient({
chain: mainnet,
transport: custom(window.ethereum),
})
const [account] = await walletClient.getAddresses()Read Balance in Assets
viem
const assets = await publicClient.readContract({
address: vault,
abi: vaultAbi,
functionName: 'assetsOf',
args: [account],
})Deposit
viem
const depositAssets = parseUnits('1000', 6)
const approveDepositHash = await walletClient.writeContract({
address: asset,
abi: erc20Abi,
functionName: 'approve',
args: [vault, depositAssets],
})
await publicClient.waitForTransactionReceipt({ hash: approveDepositHash })
const depositHash = await walletClient.writeContract({
address: vault,
abi: vaultAbi,
functionName: 'deposit',
args: [depositAssets, account],
})
await publicClient.waitForTransactionReceipt({ hash: depositHash })Withdraw
viem
const withdrawHash = await walletClient.writeContract({
address: vault,
abi: vaultAbi,
functionName: 'withdraw',
args: [parseUnits('100', 6), account, account],
})
await publicClient.waitForTransactionReceipt({ hash: withdrawHash })Withdraw Everything
viem
const allShares = await publicClient.readContract({
address: vault,
abi: vaultAbi,
functionName: 'balanceOf',
args: [account],
})
const redeemHash = await walletClient.writeContract({
address: vault,
abi: vaultAbi,
functionName: 'redeem',
args: [allShares, account, account],
})
await publicClient.waitForTransactionReceipt({ hash: redeemHash })Submit Intent
viem
const intentShares = parseUnits('1000000', 6)
const requestedDeadline = BigInt(Math.floor(Date.now() / 1000) + 7 * 24 * 60 * 60)
const maxDeadlineDuration = await publicClient.readContract({
address: intents,
abi: intentsAbi,
functionName: 'maxDeadlineDuration',
})
const maxDeadline = BigInt(Math.floor(Date.now() / 1000)) + maxDeadlineDuration
const deadline = requestedDeadline > maxDeadline ? maxDeadline : requestedDeadline
const [whitelisted, minIntentAssets, maxIntentAssets] = await publicClient.readContract({
address: intents,
abi: intentsAbi,
functionName: 'vaultConfig',
args: [vault],
})
const intentAssets = await publicClient.readContract({
address: vault,
abi: vaultAbi,
functionName: 'convertToAssets',
args: [intentShares],
})
if (!whitelisted) throw new Error('Vault is not supported for intents')
if (intentAssets < minIntentAssets) throw new Error('Intent amount is below minimum')
if (intentAssets > maxIntentAssets) throw new Error('Intent amount is above maximum')
const approveIntentHash = await walletClient.writeContract({
address: vault,
abi: erc20Abi,
functionName: 'approve',
args: [intents, intentShares],
})
await publicClient.waitForTransactionReceipt({ hash: approveIntentHash })
const requestHash = await walletClient.writeContract({
address: intents,
abi: intentsAbi,
functionName: 'request',
args: [vault, intentShares, account, deadline],
})
await publicClient.waitForTransactionReceipt({ hash: requestHash })Read or Cancel Intent
viem
const pendingRequest = await publicClient.readContract({
address: intents,
abi: intentsAbi,
functionName: 'withdrawRequests',
args: [account, vault],
})
const cancelHash = await walletClient.writeContract({
address: intents,
abi: intentsAbi,
functionName: 'cancel',
args: [vault],
})
await publicClient.waitForTransactionReceipt({ hash: cancelHash })