Skip to Content
Program ReferenceCore Lending

Core Lending Instructions

Initialize

Discriminator: 0x00

Creates a new LendingPool PDA for the given SPL token mint with default interest rate parameters. Must be called by the protocol authority before any deposits or borrows.

Accounts

#NameFlagsDescription
0payersigner, writablePays for the PDA allocation
1authoritysignerBecomes the pool authority (can call admin instructions)
2poolwritableNew LendingPool PDA — seeds: ["pool", token_mint]
3token_mintreadonlySPL token this pool lends
4vaultreadonlyPre-created SPL token account owned by pool_authority PDA
5system_programreadonly

Instruction Data

OffsetSizeFieldDescription
01discriminator0x00
11pool_bumpBump for the pool PDA
21authority_bumpBump for the pool authority PDA
31vault_bumpBump for the vault (pass 0 if vault was created externally)

Example

import { initializeIx } from './lib/veil/instructions'; import { findPoolPda, findPoolAuthorityPda } from './lib/veil/pda'; const [pool, poolBump] = await findPoolPda(tokenMint); const [authority, authorityBump] = await findPoolAuthorityPda(pool); const ix = initializeIx( payer.publicKey, admin.publicKey, pool, tokenMint, vault, poolBump, authorityBump, 0, );

Deposit

Discriminator: 0x01

Deposit tokens into the pool. Mints deposit shares to the user’s UserPosition at the current supply_index. The UserPosition PDA is created on first deposit.

Accounts

#NameFlagsDescription
0usersigner, writableDepositor
1user_tokenwritableUser’s SPL token account (source)
2vaultwritablePool vault (destination)
3poolwritableLendingPool — interest is accrued before state is updated
4user_positionwritableUserPosition PDA — created if it doesn’t exist
5pool_authorityreadonlyPool authority PDA (vault owner)
6system_programreadonly
7token_programreadonly

Instruction Data

OffsetSizeFieldDescription
01discriminator0x01
18amountTokens to deposit (u64 LE)
91position_bumpBump for the UserPosition PDA

Share Calculation

shares_minted = amount × WAD / supply_index

Because supply_index only grows over time, later depositors receive fewer shares per token — correctly reflecting that earlier depositors have already earned interest.

Example

import { depositIx } from './lib/veil/instructions'; import { findUserPositionPda } from './lib/veil/pda'; const [userPosition, positionBump] = await findUserPositionPda(user, pool); const ix = depositIx( user, userTokenAccount, vault, pool, userPosition, poolAuthority, 1_000_000n, // amount in base units positionBump, );

Withdraw

Discriminator: 0x02

Burn deposit shares and transfer the underlying tokens back to the user.

Accounts

#NameFlagsDescription
0usersigner, writable
1user_tokenwritableDestination token account
2vaultwritablePool vault (source)
3poolwritable
4user_positionwritable
5pool_authorityreadonly
6token_programreadonly

Instruction Data

OffsetSizeFieldDescription
01discriminator0x02
18sharesDeposit shares to burn (u64 LE)

Token Amount

tokens_out = shares × supply_index / WAD

Errors

  • ExceedsDepositBalance — shares requested exceed user_position.deposit_shares
  • InsufficientLiquidity — pool doesn’t have enough free liquidity to cover the withdrawal

Borrow

Discriminator: 0x03

Borrow tokens against deposited collateral. Enforces the LTV cap and ensures the health factor remains ≥ 1.0 after the borrow.

Accounts

#NameFlagsDescription
0usersigner, writableBorrower
1user_tokenwritableDestination token account
2vaultwritablePool vault (source)
3poolwritable
4user_positionwritable
5pool_authorityreadonly
6token_programreadonly

Instruction Data

OffsetSizeFieldDescription
01discriminator0x03
18amountTokens to borrow (u64 LE)

Risk Checks (in order)

  1. pool.paused == 0 — pool must be active
  2. debt_after ≤ deposit_balance × LTV — LTV cap
  3. health_factor(deposit_balance, debt_after, liq_threshold) ≥ WAD — HF ≥ 1.0
  4. amount ≤ total_deposits - total_borrows - accumulated_fees — available liquidity

Health Factor Formula

HF = (deposit_balance × liquidation_threshold) / current_debt

If HF < WAD (i.e. < 1.0), the position is liquidatable.

Errors

  • PoolPaused — pool is paused
  • ExceedsCollateralFactor — borrow would exceed LTV cap
  • Undercollateralised — resulting HF < 1.0
  • InsufficientLiquidity — not enough free liquidity

Repay

Discriminator: 0x04

Repay outstanding debt. The repay amount is capped at the current total debt (principal + accrued interest).

Accounts

#NameFlagsDescription
0usersigner, writable
1user_tokenwritableSource token account
2vaultwritablePool vault (destination)
3poolwritable
4user_positionwritable
5token_programreadonly

Instruction Data

OffsetSizeFieldDescription
01discriminator0x04
18amountTokens to repay (u64 LE). Pass u64::MAX to repay all.

Errors

  • NoBorrow — user has no outstanding debt
  • ExceedsDebtBalance — amount exceeds total debt (capped automatically in practice)

Liquidate

Discriminator: 0x05

Repay part of an underwater position and seize collateral at a discount. Requires no instruction data beyond the discriminator.

Liquidation is only allowed when the target position’s health factor is below 1.0. Calling this on a healthy position returns PositionHealthy.

Accounts

#NameFlagsDescription
0liquidatorsigner, writable
1liquidator_tokenwritableSource token account (liquidator repays debt)
2borrower_tokenwritableBorrower’s collateral token account (receives seized)
3vaultwritablePool vault
4poolwritable
5borrower_positionwritableUnderwater UserPosition
6pool_authorityreadonly
7protocol_treasurywritableReceives the protocol fee portion of seized collateral
8token_programreadonly

Instruction Data

OffsetSizeFieldDescription
01discriminator0x05

Liquidation Mechanics

repay_amount = current_debt × close_factor (default: 50%) seized = repay_amount × (1 + liquidation_bonus) (default: +5%) protocol_fee = seized × protocol_liq_fee (default: 10% of seized) liquidator_gets = seized - protocol_fee

Default parameters:

  • Close factor: 50%
  • Liquidation bonus: 5%
  • Protocol liquidation fee: 10% of seized

Errors

  • PositionHealthy — HF ≥ 1.0
  • NoBorrow — position has no debt
Last updated on