> For the complete documentation index, see [llms.txt](https://docs.augustdigital.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.augustdigital.io/developers/typescript-sdk/code-examples/solana-actions.md).

# Solana Actions

Execute transactions on Solana vaults including deposits, withdrawals, and queries. All operations follow the same pattern as EVM vaults for consistency.

### Overview

Solana vault interactions use the same pattern as EVM:

1. Use `sdk.getVault()` to query vault data
2. Use `sdk.solana.vaultDeposit()` to deposit
3. Use `sdk.solana.vaultRedeem()` to withdraw

A vault with a **withdrawal queue** withdraws in two steps instead, like an EVM vault's request and claim: `sdk.solana.vaultRequestRedeem()`, then `sdk.solana.vaultRedeem()` with the request once its cooldown has run. See [Vaults with a Withdrawal Queue](#vaults-with-a-withdrawal-queue).

The SDK handles all Solana-specific complexities (PDAs, token accounts, etc.) automatically.

### Setup

#### Basic Initialization

Include Solana RPC endpoint when initializing the SDK:

```typescript
import AugustSDK from '@augustdigital/sdk';

const sdk = new AugustSDK({
  appName: 'your-app-name', // required
  providers: {
    -1: 'https://api.mainnet-beta.solana.com', // Solana Mainnet
  },
});

// Access Solana adapter
const solana = sdk.solana;
```

#### Custom RPC Endpoint

```typescript
const sdk = new AugustSDK({
  appName: 'your-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:

```typescript
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.

```typescript
sdk.solana.setWalletProvider(
  publicKey: PublicKey | string,
  signTransaction: (tx: Transaction) => Promise<Transaction>
): void
```

**Parameters:**

* `publicKey`: User's Solana public key
* `signTransaction`: Function to sign transactions (from wallet adapter)

**Example:**

```typescript
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.

```typescript
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

```typescript
// 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

```typescript
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

```typescript
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`.

```typescript
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` | `undefined`             | No       | Ignored and scheduled for removal. 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:

```typescript
// 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

```typescript
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:

1. Fetches the vault state and derives the PDAs
2. Creates the share token account when the depositor has none, in the same transaction
3. Converts a `number` amount to raw units with the deposit mint's decimals
4. Quotes the expected shares and applies the slippage floor
5. Signs through the registered wallet and confirms at the adapter's commitment level (`finalized` by 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.

This instant path is for vaults **without** a withdrawal queue. On a vault with one attached, a direct redeem is refused before signing, with an `AugustValidationError` pointing to [Request Withdrawal](#request-withdrawal); pass the request as `options.request` to [claim it](#claim-redemption) instead.

```typescript
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` | `undefined`            | No       | Ignored and scheduled for removal. 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

```typescript
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);
```

### Vaults with a Withdrawal Queue

A vault can have a withdrawal queue attached. While it does, shares cannot be redeemed directly. A holder withdraws in two steps:

1. **Request.** [`vaultRequestRedeem`](#request-withdrawal) moves the shares into escrow in a request account, which starts the queue's cooldown.
2. **Claim.** Once the cooldown has run, [`vaultRedeem`](#claim-redemption) with `options.request` redeems the escrowed shares and pays the request's recipient.

The claim prices the shares **when it settles**, not when the request was made, at the share price of that moment and net of the vault's withdrawal fee. It never pays less than the request's **floor**, set when the request is made: by default the net quote at that moment lowered by 50 bps, so a fee rise or AUM mark-down in between makes the claim fail rather than pay less, while yield earned in the meantime is still paid. Anyone the request permits may claim it: the holder, and anyone else unless the request names a finalizer, so a keeper can settle it for the holder. Until it is claimed, the holder can [cancel the request](#cancel-request) to get the shares back.

A queue may also set a **fulfillment window**: a request not claimed within it after its cooldown expires, and can then only be cancelled.

{% hint style="info" %}
The withdrawal queue program is deployed on **mainnet-beta** (since release v0.3.0), **devnet** and **localnet**. Whether a vault uses it is per vault: most vaults have no queue attached and keep the direct redeem path. Read the vault first and choose the path from its `withdrawalQueue`.
{% endhint %}

Check a vault before choosing the path:

```typescript
const vault = await sdk.getVault({ vault: 'VaultAddress...', chainId: -1 });

if (vault.withdrawalQueue?.enabled) {
  // Request, then claim.
  console.log(`Cooldown: ${vault.withdrawalQueue.cooldownSeconds}s`);
} else {
  // Instant redeem with vaultRedeem, as above.
}
```

`vault.withdrawalQueue` is absent for a vault that never had a queue. For one that did, it reports:

| Field                      | Description                                                                                                                                                                               |
| -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `address`                  | The queue account                                                                                                                                                                         |
| `enabled`                  | Whether the vault's redemptions go through this queue. `false` once the queue has been released, when the vault is back to instant redemption while any requests made before still settle |
| `cooldownSeconds`          | Wait between a new request and its claim                                                                                                                                                  |
| `fulfillmentWindowSeconds` | How long after the cooldown a new request stays claimable; `0` for no limit                                                                                                               |
| `pendingCount`             | Requests not yet claimed or cancelled, across all holders                                                                                                                                 |
| `pendingShares`            | Shares escrowed across those requests                                                                                                                                                     |

### Request Withdrawal

Put shares into a withdrawal request on a vault with a withdrawal queue.

```typescript
sdk.solana.vaultRequestRedeem({
  vault: PublicKey | string;
  wallet: PublicKey | string;
  amount: number | bigint;
  recipient?: PublicKey | string;
  finalizer?: PublicKey | string;
  requestId?: bigint;
  slippageBps?: number;
  minAssetsOut?: bigint;
}): Promise<ISolanaRequestRedeemResult>
```

#### Parameters

| Parameter      | Type                  | Required | Description                                                                                                                                                                                           |
| -------------- | --------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `vault`        | `PublicKey \| string` | Yes      | Vault state account                                                                                                                                                                                   |
| `wallet`       | `PublicKey \| string` | Yes      | The holder, who signs and pays the request account's rent (refunded when it is claimed or cancelled)                                                                                                  |
| `amount`       | `number \| bigint`    | Yes      | Shares to escrow: `bigint` is raw share units; `number` is a UI amount                                                                                                                                |
| `recipient`    | `PublicKey \| string` | No       | Wallet the claim pays. Defaults to the holder. Its deposit-token account is created in the same transaction when missing, at the holder's expense; multisig vaults and program addresses are accepted |
| `finalizer`    | `PublicKey \| string` | No       | The one key besides the holder allowed to claim. Defaults to anyone                                                                                                                                   |
| `requestId`    | `bigint`              | No       | The request's id, unique per holder while pending. Defaults to a random `u64`                                                                                                                         |
| `slippageBps`  | `number`              | No       | Tolerance below the quoted net payout for the request's floor, `0` to `10000`. Defaults to `50`. Ignored when `minAssetsOut` is given                                                                 |
| `minAssetsOut` | `bigint`              | No       | Explicit floor in raw deposit-mint units, net of the withdrawal fee. `0n` for no floor                                                                                                                |

#### Returns

`{ signature, request, requestId }`: the transaction signature, the new request account's address (pass it as `request` to claim or cancel), and its id as a decimal string.

#### Example

```typescript
const { request } = await sdk.solana.vaultRequestRedeem({
  vault: 'VaultAddress...',
  wallet: publicKey,
  amount: 50, // 50 shares, UI amount
});

console.log('Requested:', request);
```

#### Behavior

Before asking the wallet to sign, the SDK:

1. Reads the vault state and its queue, and refuses a vault without an attached queue
2. Converts a `number` amount to raw units with the share mint's decimals
3. Refuses the request if the holder's share account is frozen or holds too few shares, or if the recipient's token account is frozen (every claim would then fail)
4. Creates the recipient's deposit-token account when missing, in the same transaction
5. Quotes the net payout from the vault state and sets the floor from it, unless `minAssetsOut` is given. A vault with no share price (no assets, shares outstanding) cannot be quoted; pass `minAssetsOut: 0n` to request without a floor

### Check Requests

List a wallet's requests on a vault with `sdk.getVaultAvailableRedemptions()` or `sdk.getVaultPositions()`, as for EVM vaults. For Solana, `wallet` is the holder's base58 address.

```typescript
const { availableRedemptions, pendingRedemptions } =
  await sdk.getVaultAvailableRedemptions({
    vault: 'VaultAddress...',
    wallet: publicKey.toBase58(),
  });
```

| List                   | Status              | Meaning                                                 |
| ---------------------- | ------------------- | ------------------------------------------------------- |
| `pendingRedemptions`   | `READY_TO_CLAIM`    | Past its cooldown; can be claimed now                   |
| `availableRedemptions` | `AWAITING_COOLDOWN` | Still in its cooldown; `date` is when it can be claimed |
| `availableRedemptions` | `EXPIRED`           | Past its fulfillment window; can only be cancelled      |

Each entry's `id` is the request account's address, and what `request` expects. `amount` is the escrowed shares; `estimatedAssets` is what claiming would pay now, in deposit tokens and net of the withdrawal fee. It is an estimate, since the claim prices at settlement. `receiver` is the wallet the request pays.

### Claim Redemption

Claim a request once its cooldown has run: pass it to `vaultRedeem` as `options.request`.

```typescript
sdk.solana.vaultRedeem(
  vaultProgramId: PublicKey | string,
  idl: object,
  publicKey: PublicKey | string,
  redeemShares: number | bigint, // ignored when claiming; pass 0n
  sendTransaction: undefined,
  vaultAddress: undefined, // ignored when claiming: read from the request
  options: { request: PublicKey | string },
): Promise<string>
```

The request fixes the shares, the recipient and the vault, so `redeemShares` and `vaultAddress` are ignored. The floor was fixed when the request was made, so `slippageBps` and `minAssetsOut` must not be set alongside `request`. A claim that would pay less than that floor fails with `PayoutBelowFloor` and leaves the request pending.

#### Returns

Transaction signature as `string`.

#### Example

```typescript
const { pendingRedemptions } = await sdk.getVaultAvailableRedemptions({
  vault: 'VaultAddress...',
  wallet: publicKey.toBase58(),
});

for (const redemption of pendingRedemptions) {
  const signature = await sdk.solana.vaultRedeem(
    Solana.constants.programIds['mainnet-beta'].vault,
    Solana.constants.vaultIdl,
    publicKey,
    0n,
    undefined,
    undefined,
    { request: redemption.id },
  );
  console.log(`Claimed ~${redemption.estimatedAssets?.normalized}:`, signature);
}
```

#### Behavior

Before asking the wallet to sign, the SDK refuses a claim that could only fail: by a key the request does not permit, during the cooldown, past the fulfillment window, or to a payout account that is frozen. A payout account closed since the request is recreated in the same transaction when it is the holder's associated token account; any other closed payout account is refused, and the holder can cancel the request instead. The SDK also creates the vault's fee-recipient account when missing, in the same transaction. If the vault's liquid reserve cannot cover the payout, the claim fails with `NotEnoughLiquidity` and the request stays pending to be claimed later.

### Cancel Request

Cancel a pending request, returning its shares to the holder.

```typescript
sdk.solana.vaultCancelRedeemRequest({
  wallet: PublicKey | string;
  request: PublicKey | string;
}): Promise<string>
```

#### Parameters

| Parameter | Type                  | Required | Description                                                |
| --------- | --------------------- | -------- | ---------------------------------------------------------- |
| `wallet`  | `PublicKey \| string` | Yes      | The holder who made the request; no one else may cancel it |
| `request` | `PublicKey \| string` | Yes      | The request account's address                              |

#### Returns

Transaction signature as `string`. The shares return to the holder's share account (recreated if they closed it) and the request's rent is refunded.

#### Example

```typescript
await sdk.solana.vaultCancelRedeemRequest({
  wallet: publicKey,
  request: 'RequestAddress...',
});
```

A request can be cancelled at any time while it exists: during the cooldown, after it, past the fulfillment window, and while the vault is paused.

### Examples

#### Complete Deposit Flow

```typescript
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: 'your-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

```typescript
function SolanaVaultWithdraw() {
  const { publicKey, signTransaction } = useWallet();

  const sdk = new AugustSDK({
    appName: 'your-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. A vault with a withdrawal queue: request now, claim after the cooldown
      const vault = await sdk.getVault({ vault: vaultAddress, chainId: -1 });
      if (vault.withdrawalQueue?.enabled) {
        const { request } = await sdk.solana.vaultRequestRedeem({
          vault: vaultAddress,
          wallet: publicKey,
          amount: shares,
        });
        console.log('Requested; claim it after the cooldown:', request);
        return request;
      }

      // 4. Otherwise redeem instantly (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

```typescript
// 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:

```typescript
// 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

```typescript
import { Solana } from '@augustdigital/sdk';
```

**deriveShareMintPda()**

Derive the share mint PDA for a vault.

```typescript
const shareMintPda = Solana.utils.deriveShareMintPda('VaultProgramId...');

console.log('Share Mint PDA:', shareMintPda.toString());
```

**getToken()**

Get token metadata from mint address.

```typescript
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.

```typescript
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.

```typescript
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.

```typescript
const provider = Solana.utils.getReadOnlyProvider({
  network: 'mainnet-beta',
  connection: sdk.solana.connection,
});
```

#### getProgram()

Create an Anchor program instance.

```typescript
const program = Solana.utils.getProgram({
  network: 'mainnet-beta',
  provider: anchorProvider,
  idl: programIdl,
});
```

### Constants

```typescript
import { Solana } from '@augustdigital/sdk';
```

#### Vault IDL

```typescript
const vaultIdl = Solana.constants.vaultIdl;
```

#### Program IDs

```typescript
const programId = Solana.constants.programIds['mainnet-beta'].vault;
// Mapped only where the queue is deployed (devnet and localnet for now).
const queueProgramId = Solana.constants.programIds.devnet.withdrawalQueue;

// Per network; `undefined` where the programs are not deployed.
const devnet = Solana.constants.getDeployedProgramIds('devnet');

// Or from the adapter, for its own network; throws AugustValidationError
// where the program is not deployed (the queue, on mainnet-beta):
const queue = sdk.solana.getProgramId('withdrawalQueue');
```

#### Fallback Values

```typescript
const fallbackDecimals = Solana.constants.fallbackDecimals; // 8
const fallbackNetwork = Solana.constants.fallbackNetwork; // 'mainnet-beta'
```

### Error Handling

#### Connection Errors

```typescript
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

```typescript
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);
  }
}
```

#### Withdrawal Queue Errors

Checks the SDK can make itself are thrown as `AugustValidationError` before the wallet is asked to sign: a vault without a queue, a request still in its cooldown or past its window, a claim by a key the request does not permit, a cancel by anyone but the holder. When the transaction itself fails, the `AugustSDKError` message carries the program's reason and error code, followed by the next step where there is one:

| Program error             | What the message tells you to do                                              |
| ------------------------- | ----------------------------------------------------------------------------- |
| `WithdrawalQueueRequired` | Request with `vaultRequestRedeem`, then claim                                 |
| `CooldownNotElapsed`      | Claim once the eligibility time has passed                                    |
| `RequestExpired`          | Cancel the request to get the shares back                                     |
| `FinalizerNotAllowed`     | Only the holder or the named finalizer may claim                              |
| `PayoutBelowFloor`        | Claim once the price recovers, or cancel and request again with a lower floor |
| `StaleRequestSequence`    | The request changed since it was read; read it again                          |
| `NotEnoughLiquidity`      | The vault's reserve cannot cover the payout yet; the request stays pending    |
