Solana Actions
Query, deposit into, and redeem from Solana vaults with the Upshift SDK, plus low-level Anchor utilities and constants.
Overview
Solana vault interactions use the same pattern as EVM:
- Use
sdk.getVault()to query vault data - Use
sdk.solana.vaultDeposit()to deposit - Use
sdk.solana.vaultRedeem()to withdraw
The SDK handles all Solana-specific complexities (PDAs, token accounts, etc.) automatically.
Setup
Basic Initialization
Include Solana RPC endpoint when initializing the SDK:
import AugustSDK from '@augustdigital/sdk';
const sdk = new AugustSDK({
appName: '<APP_NAME>', // required
providers: {
-1: 'https://api.mainnet-beta.solana.com', // Solana Mainnet
},
});
// Access Solana adapter
const solana = sdk.solana;Custom RPC Endpoint
const sdk = new AugustSDK({
appName: '<APP_NAME>', // required
providers: {
-1: 'https://solana-mainnet.g.alchemy.com/v2/YOUR_KEY',
},
});For Write Operations
To execute transactions, you need to set a wallet provider:
import { useWallet } from '@solana/wallet-adapter-react';
// In your React component
const { publicKey, signTransaction } = useWallet();
// Set wallet for signing transactions
if (publicKey && signTransaction) {
sdk.solana.setWalletProvider(publicKey, signTransaction);
}Adapter API
Methods
setWalletProvider()
Set the wallet provider for write operations.
sdk.solana.setWalletProvider(
publicKey: PublicKey | string,
signTransaction: (tx: Transaction) => Promise<Transaction>
): voidParameters:
publicKey: User's Solana public keysignTransaction: Function to sign transactions (from wallet adapter)
Example:
import { useWallet } from '@solana/wallet-adapter-react';
function MyComponent() {
const { publicKey, signTransaction } = useWallet();
useEffect(() => {
if (publicKey && signTransaction) {
sdk.solana.setWalletProvider(publicKey, signTransaction);
}
}, [publicKey, signTransaction]);
}Get Vault Data
Query Solana vault information using the same sdk.getVault() method as EVM vaults.
sdk.getVault({
vault: string; // Solana program ID
chainId?: number; // -1 for mainnet
options?: {
solanaWallet?: string; // For user position data
};
}): Promise<IVault>Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
vault | string | Yes | Solana vault program ID |
options.solanaWallet | string | No | User's Solana public key for position data |
Example
// Get vault details
const vault = await sdk.getVault({
vault: 'VaultProgramId...',
chainId: -1, // Solana mainnet
});
console.log('Name:', vault.name);
console.log('Version:', vault.version); // "sol-0"
console.log('Total Assets:', vault.totalAssets.normalized);
console.log('APY:', vault.apy.apy);
console.log('Deposit Token:', vault.depositAssets[0].symbol);
// Get vault with user position
const vaultWithPosition = await sdk.getVault({
vault: 'VaultProgramId...',
chainId: -1,
options: {
solanaWallet: 'UserPublicKey...',
},
});
if (vaultWithPosition.position) {
console.log(
'Your balance:',
vaultWithPosition.position.walletBalance.normalized,
);
}Get All Solana Vaults
const solanaVaults = await sdk.getVaults({
chainIds: [-1], // Filter to Solana mainnet only
solanaWallet: 'UserPublicKey...', // Optional: include positions
});
solanaVaults.forEach((vault) => {
console.log(`${vault.name}: ${vault.totalAssets.normalized} TVL`);
});Get User Positions
const positions = await sdk.getVaultPositions({
solanaWallet: 'UserPublicKey...',
chainId: -1,
});
positions.forEach((position) => {
console.log(`Vault: ${position.vault}`);
console.log(`Balance: ${position.walletBalance.normalized}`);
});Vault Deposit
Deposit tokens into a Solana vault. The SDK derives the vault PDAs, creates the depositor's share token account when it is missing, and sends the program's deposit_checked instruction through the wallet registered with setWalletProvider.
sdk.solana.vaultDeposit(
vaultProgramId: PublicKey | string,
idl: object,
publicKey: PublicKey | string,
depositAmount: number | bigint,
sendTransaction?: undefined,
vaultAddress?: PublicKey | string,
options?: ISolanaDepositOptions,
): Promise<string>Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
vaultProgramId | PublicKey | string | Yes | Vault program ID — Solana.constants.programIds['mainnet-beta'].vault on mainnet |
idl | object | Yes | Program IDL — pass Solana.constants.vaultIdl |
publicKey | PublicKey | string | Yes | Depositor's wallet public key |
depositAmount | number | bigint | Yes | bigint is raw on-chain units; number is a UI amount converted with the deposit mint's decimals |
sendTransaction | deprecated callback | No | Accepted and ignored — share-account creation is prepended to the deposit instruction, so there is no second transaction to send. Removed in the next major. Pass undefined rather than dropping the argument, or vaultAddress shifts into this slot |
vaultAddress | PublicKey | string | No | Vault state account. Omit only for legacy single-vault programs, which derive it from the program ID |
options | ISolanaDepositOptions | No | Slippage protection, see below |
Slippage protection
Deposits send the program's deposit_checked instruction. The SDK quotes the shares the deposit should mint from the vault's current state and passes that quote, lowered by a tolerance, as min_shares_out; the program reverts with SlippageExceeded if the share price moves past it before execution. Control it with the trailing options argument:
// Default: 50 bps (0.5%) below the quote.
await sdk.solana.vaultDeposit(programId, idl, wallet, amount, undefined, vaultAddress);
// Tighter or looser tolerance, in basis points.
await sdk.solana.vaultDeposit(programId, idl, wallet, amount, undefined, vaultAddress, {
slippageBps: 10,
});
// Your own floor in raw share units (skips the quote and its snapshot read).
// `0n` restores the unguarded behaviour of the plain `deposit` instruction.
await sdk.solana.vaultDeposit(programId, idl, wallet, amount, undefined, vaultAddress, {
minSharesOut: 995_000n,
});Returns
Transaction signature as string.
Example
import { Solana } from '@augustdigital/sdk';
import { useWallet } from '@solana/wallet-adapter-react';
const { publicKey, signTransaction } = useWallet();
if (publicKey && signTransaction) {
sdk.solana.setWalletProvider(publicKey, signTransaction);
}
const signature = await sdk.solana.vaultDeposit(
Solana.constants.programIds['mainnet-beta'].vault,
Solana.constants.vaultIdl,
publicKey,
100, // 100 tokens, UI amount
undefined,
'VaultAddress...',
);
console.log('Deposit successful:', signature);Behavior
The SDK automatically:
- Fetches the vault state and derives the PDAs
- Creates the share token account when the depositor has none, in the same transaction
- Converts a
numberamount to raw units with the deposit mint's decimals - Quotes the expected shares and applies the slippage floor
- Signs through the registered wallet and confirms at the adapter's commitment level (
finalizedby default)
Vault Withdraw
Redeem shares from a Solana vault. The program's redeem_checked instruction burns the shares and transfers the payout in the same transaction.
sdk.solana.vaultRedeem(
vaultProgramId: PublicKey | string,
idl: object,
publicKey: PublicKey | string,
redeemShares: number | bigint,
sendTransaction?: undefined,
vaultAddress?: PublicKey | string,
options?: ISolanaRedeemOptions,
): Promise<string>Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
vaultProgramId | PublicKey | string | Yes | Vault program ID — Solana.constants.programIds['mainnet-beta'].vault on mainnet |
idl | object | Yes | Program IDL — pass Solana.constants.vaultIdl |
publicKey | PublicKey | string | Yes | Share holder's wallet public key |
redeemShares | number | bigint | Yes | bigint is raw share units; number is a UI amount |
sendTransaction | deprecated callback | No | Accepted and ignored — payout- and fee-recipient-account creation is prepended to the redeem instruction, so there is no second transaction to send. Removed in the next major. Pass undefined rather than dropping the argument, or vaultAddress shifts into this slot |
vaultAddress | PublicKey | string | No | Vault state account. Omit only for legacy single-vault programs |
options | ISolanaRedeemOptions | No | Slippage protection, see below |
Slippage protection
Redemptions send redeem_checked. The floor is on what the wallet receives, net of the withdrawal fee, quoted from the vault state the SDK already reads; the default tolerance is 50 bps. Pass slippageBps or an explicit minAssetsOut (raw deposit-mint units) in the trailing options argument, exactly as for deposits. A SlippageExceeded revert is reported with a message saying the price moved past your tolerance and to retry or raise it.
Returns
Transaction signature as string.
Example
const positions = await sdk.getVaultPositions({
solanaWallet: publicKey.toString(),
chainId: -1,
});
if (positions[0].walletBalance.raw === '0') {
throw new Error('No balance to redeem');
}
const signature = await sdk.solana.vaultRedeem(
Solana.constants.programIds['mainnet-beta'].vault,
Solana.constants.vaultIdl,
publicKey,
50, // redeem 50 shares, UI amount
undefined,
'VaultAddress...',
);
console.log('Redemption complete:', signature);Examples
Complete Deposit Flow
import AugustSDK, { Solana } from '@augustdigital/sdk';
import { useWallet } from '@solana/wallet-adapter-react';
function SolanaVaultDeposit() {
const { publicKey, signTransaction } = useWallet();
const [loading, setLoading] = useState(false);
const sdk = new AugustSDK({
appName: '<APP_NAME>', // required
providers: {
-1: 'https://api.mainnet-beta.solana.com',
},
});
const deposit = async (vaultAddress: string, amount: number) => {
if (!publicKey || !signTransaction) {
throw new Error('Wallet not connected');
}
setLoading(true);
try {
// 1. Set wallet provider
sdk.solana.setWalletProvider(publicKey, signTransaction);
// 2. Get vault details
const vault = await sdk.getVault({
vault: vaultAddress,
chainId: -1,
});
console.log(`Depositing to ${vault.name}`);
// 3. Execute deposit (SDK handles everything)
const signature = await sdk.solana.vaultDeposit(
Solana.constants.programIds['mainnet-beta'].vault,
Solana.constants.vaultIdl,
publicKey,
amount,
undefined,
vaultAddress,
);
console.log('Deposit successful:', signature);
return signature;
} catch (error) {
console.error('Deposit failed:', error);
throw error;
} finally {
setLoading(false);
}
};
return (
<button
onClick={() => deposit('VaultAddress...', 100)}
disabled={loading || !publicKey}
>
{loading ? 'Depositing...' : 'Deposit 100 Tokens'}
</button>
);
}Complete Withdrawal Flow
function SolanaVaultWithdraw() {
const { publicKey, signTransaction } = useWallet();
const sdk = new AugustSDK({
appName: '<APP_NAME>', // required
providers: {
-1: 'https://api.mainnet-beta.solana.com',
},
});
const withdraw = async (vaultAddress: string) => {
if (!publicKey || !signTransaction) {
throw new Error('Wallet not connected');
}
try {
// 1. Set wallet provider
sdk.solana.setWalletProvider(publicKey, signTransaction);
// 2. Check user's position
const position = await sdk.getVaultPositions({
solanaWallet: publicKey.toString(),
chainId: -1,
});
if (!position[0] || position[0].walletBalance.raw === '0') {
throw new Error('No balance to withdraw');
}
const shares = BigInt(position[0].walletBalance.raw);
console.log(`Redeeming ${position[0].walletBalance.normalized} shares`);
// 3. Execute redemption (all shares, in raw units)
const signature = await sdk.solana.vaultRedeem(
Solana.constants.programIds['mainnet-beta'].vault,
Solana.constants.vaultIdl,
publicKey,
shares,
undefined,
vaultAddress,
);
console.log('Withdrawal successful:', signature);
return signature;
} catch (error) {
console.error('Withdrawal failed:', error);
throw error;
}
};
return (
<button onClick={() => withdraw('VaultAddress...')}>
Withdraw All
</button>
);
}Query Vault Before Depositing
// 1. Get vault info
const vault = await sdk.getVault({
vault: 'VaultAddress...',
chainId: -1,
});
// 2. Check if deposits are enabled
if (vault.isDepositPaused) {
throw new Error('Vault deposits are paused');
}
// 3. Show user the vault details
console.log(`Vault: ${vault.name}`);
console.log(`APY: ${vault.apy.apy}%`);
console.log(`TVL: ${vault.totalAssets.normalized}`);
console.log(`Deposit token: ${vault.depositAssets[0].symbol}`);
// 4. Deposit
await sdk.solana.vaultDeposit(
Solana.constants.programIds['mainnet-beta'].vault,
Solana.constants.vaultIdl,
publicKey,
100,
undefined,
vault.address,
);Advanced Operations
For advanced use cases, the Solana adapter exposes low-level methods and utilities.
Direct Program Access
Access Solana connection and provider for custom operations:
// Get connection
const connection = sdk.solana.connection;
const balance = await connection.getBalance(publicKey);
// Get Anchor provider
const provider = sdk.solana.provider;
// Get program instance
const program = sdk.solana.getProgram(Solana.constants.vaultIdl);
// Query vault account directly
const vaultState = await program.account.vault.fetch(vaultPda);Utility Functions
import { Solana } from '@augustdigital/sdk';deriveShareMintPda()
Derive the share mint PDA for a vault.
const shareMintPda = Solana.utils.deriveShareMintPda('VaultProgramId...');
console.log('Share Mint PDA:', shareMintPda.toString());getToken()
Get token metadata from mint address.
const token = await Solana.utils.getToken({
mintAddress: 'MintPublicKey...',
endpoint: 'https://api.mainnet-beta.solana.com',
connection: sdk.solana.connection,
});
console.log('Symbol:', token.symbol);
console.log('Decimals:', token.decimals);
console.log('Supply:', token.supply);getVaultStateReadOnly()
Get vault state without a wallet provider.
const vaultState = await Solana.utils.getVaultStateReadOnly({
vaultProgramId: 'VaultProgramId...',
idl: vaultIdl,
endpoint: 'https://api.mainnet-beta.solana.com',
connection: sdk.solana.connection,
});getProvider()
Create an Anchor provider with wallet.
import { PublicKey } from '@solana/web3.js';
const provider = Solana.utils.getProvider({
network: 'mainnet-beta',
connection: sdk.solana.connection,
publicKey: new PublicKey('UserPublicKey...'),
signTransaction: signTransactionFunction,
});getReadOnlyProvider()
Create a read-only Anchor provider.
const provider = Solana.utils.getReadOnlyProvider({
network: 'mainnet-beta',
connection: sdk.solana.connection,
});getProgram()
Create an Anchor program instance.
const program = Solana.utils.getProgram({
network: 'mainnet-beta',
provider: anchorProvider,
idl: programIdl,
});Constants
import { Solana } from '@augustdigital/sdk';Vault IDL
const vaultIdl = Solana.constants.vaultIdl;Program IDs
const programId = Solana.constants.programIds['mainnet-beta'].vault;
// Per network; `undefined` where the program is not deployed.
const devnet = Solana.constants.getDeployedProgramIds('devnet');Fallback Values
const fallbackDecimals = Solana.constants.fallbackDecimals; // 8
const fallbackNetwork = Solana.constants.fallbackNetwork; // 'mainnet-beta'Error Handling
Connection Errors
try {
const vaultState = await sdk.solana.getVaultState('VaultId...', vaultIdl);
} catch (error) {
if (error.message.includes('404')) {
console.error('Vault program not found');
} else if (error.message.includes('Network request failed')) {
console.error('RPC connection failed');
} else {
console.error('Unknown error:', error);
}
}Transaction Errors
try {
await sdk.solana.vaultDeposit(
Solana.constants.programIds['mainnet-beta'].vault,
Solana.constants.vaultIdl,
publicKey,
1_000_000_000n,
undefined,
'VaultAddress...',
);
} catch (error) {
if (error.message.includes('User rejected')) {
console.error('Transaction cancelled by user');
} else if (error.message.includes('insufficient funds')) {
console.error('Not enough SOL for transaction');
} else {
console.error('Transaction failed:', error);
}
}