Skip to main content
A TokenEntry defines one accepted deposit token within an ExponentStrategyVault. Each token entry specifies how the token is priced, where its escrow accounts live, and which yield protocol it is deployed into.

TokenEntry

pub struct TokenEntry {
    /// SPL mint of the accepted token
    pub mint: Pubkey,

    /// Price calculation method for this token's AUM contribution
    pub price_id: PriceId,

    /// Token account owned by the Squads smart account (squads_vault)
    /// Deposited tokens land here and are deployed from here
    pub token_squads_account: Pubkey,

    /// Policy seeds used for force-deallocate emergency flows
    pub force_deallocate_policy_ids: Vec<u64>,
}
The deserialized TypeScript TokenEntry type includes additional fields (tokenEscrow, currentLiquidity, mintFlag, interfaceType) that are derived at fetch time but are not stored directly in the Rust struct.

InterfaceType

The interface_type determines which yield protocol the token entry’s capital is deployed through.
InterfaceType is not stored on-chain in the TokenEntry struct. It is derived by the SDK’s fetcher during deserialization based on the token entry’s configuration.
pub enum InterfaceType {
    /// No specific protocol — managed generically
    Generic,
    /// Deployed into Kamino Lending reserves
    Kamino,
    /// Deployed into Marginfi lending
    Marginfi,
    /// Deployed into Jito Restaking
    JitoRestaking,
    /// Deployed into Perena yield
    Perena,
}

PriceId

The PriceId determines how the vault computes the base-unit value of this token for AUM calculations:
pub enum PriceId {
    /// Single price feed: token value = price[price_id]
    Simple { price_id: u64 },

    /// Product of multiple price feeds: value = price[0] × price[1] × ...
    /// Useful for LST pricing: LST/SOL rate × SOL/USD rate
    Multiply { price_ids: Vec<u64> },
}
Prices are read from the global ExponentPrices account (["exponent_prices"]).

Token Account Layout

Each token entry uses two token accounts:
AccountOwnerPurpose
token_squads_accountSquads smart account (squads_vault)Receives deposits; capital is deployed from here
token_escrowVault PDA (self_address)Holds tokens allocated for pending withdrawal fills
The escrow PDA is derived as:
seeds = ["token_entry_escrow", vault, mint]

TypeScript Interface

When constructing a vault via the SDK, token entries are specified as TokenEntryInput:
import { TokenEntryInput } from "@exponent-labs/exponent-sdk";
import { ExponentVaultsPDA } from "@exponent-labs/exponent-vaults-pda";
import { PublicKey } from "@solana/web3.js";

const tokenEntry: TokenEntryInput = {
  // The token mint (e.g., USDC)
  mint: new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"),

  // Price source: simple oracle reference
  priceId: { simple: { priceId: 1n, underlyingMint: new PublicKey("...") } },

  // Squads-controlled token account for this entry
  tokenSquadsAccount: squadsTokenAccount,

  // Vault PDA-controlled escrow for withdrawals
  tokenEscrow: new ExponentVaultsPDA().tokenEntryEscrow({ vault, mint })[0],

  // Target allocation in basis points (e.g., 5000 = 50%)
  shareBp: 5000,

  // Initial liquidity (set to 0 for new entries)
  currentLiquidity: 0n,

  // 0 = standard SPL token, 1 = Token-2022
  mintFlag: 0,

  // Protocol type for this entry (optional)
  interfaceType: { kamino: {} },

  // Policy IDs for emergency force-deallocate (optional, defaults to [])
  forceDeallocatePolicyIds: [],
};

Reading Token Entries

Fetch a vault’s token entries after loading:
import { ExponentVault } from "@exponent-labs/exponent-sdk";

const vault = await ExponentVault.load({ connection, address: vaultAddress });

for (const entry of vault.state.tokenEntries) {
  console.log("Mint:", entry.mint.toBase58());
  console.log("Interface:", entry.interfaceType);
  console.log("Liquidity:", entry.currentLiquidity.toString());
}