Skip to main content
This guide covers Cross-Program Invocation (CPI) integration for the Earn protocol’s deposit and withdraw functions. Use this when your on-chain program needs to call Jupiter Lend Earn directly. For TypeScript SDK integration (off-chain), see Deposit and Withdraw.

Program Addresses

ProgramMainnetDevnet
Lendingjup3YeL8QhtSx1e253b2FDvsMNC87fDrgQZivbrndc97tjE28izRUjzmxC1QNXnNwcc4N82CNYCexf3k8mw67s3
LiquidityjupeiUmn818Jg1ekPURTpr4mFo29p46vygyykFJ3wZC5uDkCoM96pwGYhAUucvCzLfm5UcjVRuxz6gH81RnRBmL

Deposit CPI

Discriminator

fn get_deposit_discriminator() -> Vec<u8> {
    // discriminator = sha256("global:deposit")[0..8]
    vec![242, 35, 198, 137, 82, 225, 242, 182]
}

Deposit CPI Struct

pub struct DepositParams<'info> {
    // User accounts
    pub signer: AccountInfo<'info>,
    pub depositor_token_account: AccountInfo<'info>,
    pub recipient_token_account: AccountInfo<'info>,

    pub mint: AccountInfo<'info>,

    // Protocol accounts
    pub lending_admin: AccountInfo<'info>,
    pub lending: AccountInfo<'info>,
    pub f_token_mint: AccountInfo<'info>,

    // Liquidity protocol accounts
    pub supply_token_reserves_liquidity: AccountInfo<'info>,
    pub lending_supply_position_on_liquidity: AccountInfo<'info>,
    pub rate_model: AccountInfo<'info>,
    pub vault: AccountInfo<'info>,
    pub liquidity: AccountInfo<'info>,
    pub liquidity_program: AccountInfo<'info>,

    // Rewards and programs
    pub rewards_rate_model: AccountInfo<'info>,
    pub token_program: AccountInfo<'info>,
    pub associated_token_program: AccountInfo<'info>,
    pub system_program: AccountInfo<'info>,

    // Target lending program
    pub lending_program: UncheckedAccount<'info>,
}

Deposit Implementation

impl<'info> DepositParams<'info> {
    pub fn deposit(&self, amount: u64) -> Result<()> {
        let mut instruction_data = get_deposit_discriminator();
        instruction_data.extend_from_slice(&amount.to_le_bytes());

        let account_metas = vec![
            AccountMeta::new(*self.signer.key, true),
            AccountMeta::new(*self.depositor_token_account.key, false),
            AccountMeta::new(*self.recipient_token_account.key, false),
            AccountMeta::new_readonly(*self.mint.key, false),
            AccountMeta::new_readonly(*self.lending_admin.key, false),
            AccountMeta::new(*self.lending.key, false),
            AccountMeta::new(*self.f_token_mint.key, false),
            AccountMeta::new(*self.supply_token_reserves_liquidity.key, false),
            AccountMeta::new(*self.lending_supply_position_on_liquidity.key, false),
            AccountMeta::new_readonly(*self.rate_model.key, false),
            AccountMeta::new(*self.vault.key, false),
            AccountMeta::new(*self.liquidity.key, false),
            AccountMeta::new(*self.liquidity_program.key, false),
            AccountMeta::new_readonly(*self.rewards_rate_model.key, false),
            AccountMeta::new_readonly(*self.token_program.key, false),
            AccountMeta::new_readonly(*self.associated_token_program.key, false),
            AccountMeta::new_readonly(*self.system_program.key, false),
        ];

        let instruction = Instruction {
            program_id: *self.lending_program.key,
            accounts: account_metas,
            data: instruction_data,
        };

        invoke(&instruction, &[
            self.signer.clone(), self.depositor_token_account.clone(),
            self.recipient_token_account.clone(), self.mint.clone(),
            self.lending_admin.clone(), self.lending.clone(),
            self.f_token_mint.clone(), self.supply_token_reserves_liquidity.clone(),
            self.lending_supply_position_on_liquidity.clone(), self.rate_model.clone(),
            self.vault.clone(), self.liquidity.clone(),
            self.liquidity_program.clone(), self.rewards_rate_model.clone(),
            self.token_program.clone(), self.associated_token_program.clone(),
            self.system_program.clone(),
        ]).map_err(|_| ErrorCodes::CpiToLendingProgramFailed.into())
    }
}

Deposit Account Explanations

AccountPurposeMutability
signerUser performing depositMutable, signer
depositor_token_accountUser’s underlying token account (source)Mutable
recipient_token_accountUser’s jlToken account (destination)Mutable
mintUnderlying token mintImmutable
lending_adminProtocol configuration PDAImmutable
lendingPool-specific configuration PDAMutable
f_token_mintjlToken mint accountMutable
supply_token_reserves_liquidityLiquidity protocol token reservesMutable
lending_supply_position_on_liquidityProtocol’s position in liquidity poolMutable
rate_modelInterest rate calculation modelImmutable
vaultProtocol vault holding deposited tokensMutable
liquidityMain liquidity protocol PDAMutable
liquidity_programLiquidity protocol program IDMutable
rewards_rate_modelRewards calculation model PDAImmutable

Withdraw CPI

Discriminator

fn get_withdraw_discriminator() -> Vec<u8> {
    // discriminator = sha256("global:withdraw")[0..8]
    vec![183, 18, 70, 156, 148, 109, 161, 34]
}

Withdraw CPI Struct

pub struct WithdrawParams<'info> {
    // User accounts
    pub signer: AccountInfo<'info>,
    pub owner_token_account: AccountInfo<'info>,
    pub recipient_token_account: AccountInfo<'info>,

    // Protocol accounts
    pub lending_admin: AccountInfo<'info>,
    pub lending: AccountInfo<'info>,
    pub mint: AccountInfo<'info>,
    pub f_token_mint: AccountInfo<'info>,

    // Liquidity protocol accounts
    pub supply_token_reserves_liquidity: AccountInfo<'info>,
    pub lending_supply_position_on_liquidity: AccountInfo<'info>,
    pub rate_model: AccountInfo<'info>,
    pub vault: AccountInfo<'info>,
    pub claim_account: AccountInfo<'info>,
    pub liquidity: AccountInfo<'info>,
    pub liquidity_program: AccountInfo<'info>,

    // Rewards and programs
    pub rewards_rate_model: AccountInfo<'info>,
    pub token_program: AccountInfo<'info>,
    pub associated_token_program: AccountInfo<'info>,
    pub system_program: AccountInfo<'info>,

    // Target lending program
    pub lending_program: UncheckedAccount<'info>,
}

Withdraw Account Explanations

AccountPurposeMutability
signerUser performing withdrawalMutable, signer
owner_token_accountUser’s jlToken account (source, burned)Mutable
recipient_token_accountUser’s underlying token account (destination)Mutable
lending_adminProtocol configuration PDAImmutable
lendingPool-specific configuration PDAMutable
mintUnderlying token mintImmutable
f_token_mintjlToken mint account (burned from supply)Mutable
supply_token_reserves_liquidityLiquidity protocol token reservesMutable
lending_supply_position_on_liquidityProtocol’s position in liquidity poolMutable
rate_modelInterest rate calculation modelImmutable
vaultProtocol vault (source of withdrawn tokens)Mutable
claim_accountHandles withdrawal claim processingMutable
liquidityMain liquidity protocol PDAMutable
liquidity_programLiquidity protocol program IDMutable
rewards_rate_modelRewards calculation model PDAImmutable

Context Helpers (TypeScript)

For frontend/client code that needs to resolve CPI accounts, the SDK provides context helpers that return all required account addresses:
import { getDepositContext, getWithdrawContext } from "@jup-ag/lend/earn";

// Get all accounts needed for a deposit CPI
const depositContext = await getDepositContext({
  asset: usdcMint,
  signer: userPublicKey,
});

// Get all accounts needed for a withdraw CPI
const withdrawContext = await getWithdrawContext({
  asset: usdcMint,
  signer: userPublicKey,
});

// Pass these accounts to your Anchor program
await program.methods
  .yourDepositMethod(amount)
  .accounts({
    signer: depositContext.signer,
    depositorTokenAccount: depositContext.depositorTokenAccount,
    recipientTokenAccount: depositContext.recipientTokenAccount,
    lendingAdmin: depositContext.lendingAdmin,
    lending: depositContext.lending,
    fTokenMint: depositContext.fTokenMint,
    // ... all other accounts from context
    lendingProgram: new PublicKey("jup3YeL8QhtSx1e253b2FDvsMNC87fDrgQZivbrndc9"),
  })
  .rpc();

Key Notes

Account Derivation

Most accounts follow standard PDA derivation patterns:
  • Lending PDA: [LENDING_SEED, mint.key(), f_token_mint.key()]
  • jlToken Mint: [F_TOKEN_MINT_SEED, mint.key()]
  • Lending Admin: [LENDING_ADMIN_SEED]

Special Considerations

  • Amount = u64::MAX: Deposits/withdraws the entire balance
  • Account Creation: ATA accounts are created automatically when needed (init_if_needed)
  • Claim Account: Only present in withdraw operations for processing withdrawal claims

Error Codes

ErrorDescription
FTokenMinAmountOutSlippage protection triggered
FTokenMaxAmountMaximum amount exceeded
FTokenOnlyAuthUnauthorised operation
FTokenOnlyRebalancerRebalancer-only operation
CpiToLendingProgramFailedCPI call failed

Return Values

  • deposit() returns shares minted
  • withdraw() returns shares burned