SDK

Integrate Zorya

The TypeScript SDK builds the instructions. The open-source program decides price, health, and settlement. You never send an APR or a liquidation price on-chain.

Protocol on GitHub

Install

The program is public at github.com/zorya-finance/zorya. The TypeScript client lives in sdk/. Pair it with Anchor 0.31 and web3.js. Program id today: 8U8gwf1R6VNX6GwbzNwnXbrBnTnR4M98aGQBzoJVTm17.

Dependencies
npm install @coral-xyz/anchor @solana/web3.js @solana/spl-token
Import
import { BN, Program } from "@coral-xyz/anchor";
import {
  ZoryaClient,
  findPdas,
  SOL_USD_FEED_ID,
  PYTH_RECEIVER,
} from "../../sdk/src";

Create the client

Wrap your Anchor Program<Zorya>. The client derives every address from the program id.

const program = anchor.workspace.Zorya as Program<Zorya>;
const client = new ZoryaClient(program);

// Optional: same PDAs without a live program
const pdas = findPdas(program.programId);

Authority calls initializeConfig once per deployment. Markets are a pair, a calendar maturity (Unix seconds), and an LLTV. Default LLTV is 70% (7000 bps). Tick spacing defaults to 200 bps.

Open a market
const maturity = new BN(
  Math.floor(Date.parse("2026-12-31T00:00:00Z") / 1000),
);

const keys = await client.createMarket({
  authority: provider.publicKey,
  collateralMint, // wSOL
  loanMint,       // USDC
  maturity,
  minFillUnits: new BN(1_000_000),
  // omit oracleFeedId for a local mock market
  // oracleFeedId: SOL_USD_FEED_ID,
});

Lend

A lender posts a funded quote. USDC leaves the maker wallet and sits in the quote vault before anyone can fill. tick sets price P on-chain. units is face at maturity.

const { quote, quoteVault } = await client.createQuote({
  maker: lender.publicKey,
  market: keys.market,
  loanMint,
  makerLoan: lenderUsdcAta,
  seq: new BN(1),
  tick: 256,
  units: new BN(100_000_000),
  signers: [lender],
});

Borrow

Two instructions, usually in one transaction: deposit collateral, then fill. The program does not offer a mega-ix. Wrap native SOL to wSOL before deposit.

await client.depositCollateral({
  owner: borrower.publicKey,
  market: keys.market,
  collateralMint,
  ownerCollateral: borrowerWsolAta,
  collateralVault: keys.collateralVault,
  amount: new BN(10_000_000_000),
  signers: [borrower],
});

await client.fillQuote({
  taker: borrower.publicKey,
  market: keys.market,
  collateralMint,
  quote,
  quoteVault,
  takerLoan: borrowerUsdcAta,
  maker: lender.publicKey,
  makerLoan: lenderUsdcAta,
  mockPrice: keys.mockPrice,
  curve: keys.curve,
  maxUnits: new BN(100_000_000),
  signers: [borrower],
});

After fill, the maker holds Claims and the taker holds an Obligation. Face is the units taken. Cash received now is units * P, computed by the program.

Repay and redeem

Repay burns Obligation face with USDC. After the market date, redeem pays Claim holders from the loan vault. Age of the fill does not move the date.

await client.repay({
  owner: borrower.publicKey,
  market: keys.market,
  ownerLoan: borrowerUsdcAta,
  loanVault: keys.loanVault,
  units: new BN(40_000_000),
  signers: [borrower],
});

await client.redeem({
  owner: lender.publicKey,
  market: keys.market,
  ownerLoan: lenderUsdcAta,
  loanVault: keys.loanVault,
  units: new BN(100_000_000),
  signers: [lender],
});

Addresses

client.pdas (or findPdas) is the only way you should build these keys.

config
["config"]
market
collateral, loan, maturity, lltv
quote
market, maker, seq
claim
market, owner
obligation
market, owner
curve
collateral, loan

Oracle

A zero feed id creates a mock market for localnet. A live Pyth market uses SOL_USD_FEED_ID and PYTH_RECEIVER. On fill, withdraw, and liquidate, pass a verified PriceUpdateV2 as priceUpdate. Pull mode posts it in the same transaction; Devnet push mode reads an existing sponsored account. Both require a fresh price accepted by L1. Mock markets can omit it. The client then uses the mock-price account.

await client.fillQuote({
  ...fill,
  priceUpdate: verifiedPriceUpdateV2,
});

// repay, redeem, and cancel do not read the oracle

Rules

  • Display APR and liquidation price in your UI only. Never send them to the program.
  • Maturity is the market calendar date, not now + 90 days.
  • A quote is not live until the loan mint is in the quote vault.
  • Health is checked on fill. Deposit first if you need more cap.
  • Core fees are 0. Do not invent a fee field on the instruction.
  • No real capital. Localnet and fake mints only until a reviewed deploy.