Overview
Kamino Earn vaults accept token deposits and automatically allocate them across lending markets. Depositors receive shares representing their portion of the vault, and yield accrues without any manual compounding. This guide walks through integrating Kamino vaults into a Next.js app with Dynamic embedded wallets. For the final code, see the GitHub repository.How it works
When a user deposits tokens, the Kamino SDK builds a set of instructions that create a share account and mint vault shares proportional to the deposit. Yield accrues as the vault allocates capital to borrowers. When withdrawing, shares are burned and the user receives back the underlying tokens plus earned interest. The SDK returns instruction groups that must each be sent as a separate transaction, confirmed in order:- Deposit:
depositIxs→stakeInFarmIfNeededIxs→stakeInFlcFarmIfNeededIxs - Withdraw:
unstakeFromFarmIfNeededIxs→withdrawIxs→postWithdrawIxs
| Approach | How it works | Requires |
|---|---|---|
| SVM Gas Sponsorship | Dynamic sponsors the SOL fee; user signs without holding SOL | SVM Gas Sponsorship enabled in the dashboard |
| Standard (no sponsorship) | User pays SOL fees from their wallet; all txs signed in one MPC round | SOL balance in the embedded wallet |
Setup
Project setup
Follow the React Quickstart using the Custom setup path with Solana. Scaffold a Next.js app withcreate-next-app.
In the Dynamic dashboard, enable Solana under Chains & Networks, enable Embedded wallets under Wallets, and add your app’s origin under Security → Allowed Origins.
Install dependencies
Environment variables
.env.local
NEXT_PUBLIC_SOLANA_RPC_URL if you prefer a specific endpoint.
Initialize Dynamic
Createsrc/lib/dynamic.ts:
src/lib/dynamic.ts
Set up wallet context
Createsrc/lib/providers.tsx. DynamicProvider owns reactive auth state; InnerProviders reads it via useUser() and useWalletAccounts() from @dynamic-labs-sdk/react-hooks:
src/lib/providers.tsx
Fetching vault data
Createsrc/lib/kamino.ts to load vaults and metrics from the Kamino REST API:
src/lib/kamino.ts
Deposit and withdraw
Createsrc/lib/useVaultOperations.ts. The shared prepareTransaction helper builds one unsigned VersionedTransaction per instruction group. The signing strategy differs between the two approaches.
Transaction preparation (shared)
Both approaches use the sameprepareTransaction helper:
With SVM Gas Sponsorship (gasless)
Enable SVM Gas Sponsorship in the Dynamic dashboard under Settings → Embedded Wallets. This is available exclusively for V3 MPC embedded wallets.
signAndSendSponsoredTransaction handles signing, fee-payer replacement, and broadcasting in one call. Transactions are sent one at a time since each is independently sponsored.
src/lib/useVaultOperations.ts
Without gas sponsorship
When SVM Gas Sponsorship is not enabled, users pay Solana transaction fees from their wallet SOL balance. All transactions are built in parallel and signed in a single MPC round withsignAllTransactions, then sent and confirmed sequentially. This minimizes round-trips to the MPC network.
src/lib/useVaultOperations.ts
Wiring it together
The main page loads vaults withuseQuery and disables SSR on the VaultsInterface component to avoid WASM errors:
src/app/page.tsx
VaultsInterface, vaults are paginated (6 per page) and metrics are fetched only for the current page. After an action completes, all transactions are already confirmed on-chain. Positions are refetched immediately and vault metrics are invalidated. Multiple retries at increasing intervals handle Kamino’s API indexing lag (can be up to ~15s):
handleDeposit and handleWithdraw return Promise<boolean> so VaultCard can clear its input field only on success:
Run the app
http://localhost:3000 to your allowed origins in the Dynamic dashboard under Developer Settings → CORS Origins.
If you’re using SVM Gas Sponsorship, also enable it in Settings → Embedded Wallets → SVM Gas Sponsorship.