@elmntl/jlpd-sdk
v0.1.6
Published
SDK for JLP.D (JLP Deconstructed) by Elemental
Readme
JLP.D SDK
SDK for interacting with the JLP.D (JLP Deconstructed) protocol on Solana.
Installation
# Using npm
npm install git+https://github.com/elementalfund/jlpd-sdk.git
# Using yarn
yarn add git+https://github.com/elementalfund/jlpd-sdk.gitOr add directly to package.json:
{
"dependencies": {
"jlpd-sdk": "git+https://github.com/elementalfund/jlpd-sdk.git"
}
}Peer Dependencies
| Package | Version |
|---|---|
| @coral-xyz/anchor | ^0.32.1 |
| @solana/web3.js | ^1.95.0 |
| @solana/spl-token | ^0.4.0 |
Quick Start
import { Connection } from "@solana/web3.js";
import { JlpdClient } from "jlpd-sdk";
// Connect to Solana mainnet
const connection = new Connection("https://api.mainnet-beta.solana.com");
const client = JlpdClient.mainnet(connection);Architecture
The SDK uses the Anchor IDL (@coral-xyz/anchor 0.32.1) for instruction serialization. All instruction builders call program.methods.<instruction>().accounts({}).instruction() under the hood, which ensures correct serialization from the on-chain IDL.
The JlpdClient exposes an Anchor Program instance for advanced use:
// Access the typed Anchor program directly
const program = client.program;
// Build instructions manually if needed
const ix = await program.methods
.deposit(new BN(1_000_000_000))
.accounts({ user: walletPublicKey, jlpVault: client.vaultPda, /* ... */ })
.instruction();You can also create a standalone program instance:
import { createProgram } from "jlpd-sdk";
import type { JlpDProgram } from "jlpd-sdk";
const program = createProgram(connection);Available Pools
| Pool | Description |
| ---------- | ----------- |
| "SOL" | Solana |
| "USDC" | USD Coin |
| "JupUSD" | Jupiter USD |
| "BTC" | Bitcoin |
| "ETH" | Ethereum |
User Operations
Deposit
Deposit tokens and receive vault shares (jvX tokens).
import { BN } from "@coral-xyz/anchor";
const pool = client.pool("SOL");
const tx = await pool.deposit({
user: walletPublicKey,
amount: new BN(1_000_000_000), // 1 SOL (9 decimals)
});
// Sign and send transaction with your wallet
const signature = await wallet.sendTransaction(tx, connection);Withdraw
Burn vault shares and receive tokens back.
const tx = await pool.withdraw({
user: walletPublicKey,
shares: new BN(500_000_000), // Amount of jvX shares to burn
});
const signature = await wallet.sendTransaction(tx, connection);Reading Data
Get Vault Info
const vault = await client.fetchVault();
console.log("Admin:", vault.admin.toBase58());
console.log("Manager:", vault.manager.toBase58());Get Pool (STV) Info
const stv = await client.fetchStv(MINTS.SOL);
console.log("Price per share:", stv.pps.toString());
console.log("Total fees accrued:", stv.accruedFeesJlx.toString());Get Exchange Rate
const rate = await client.fetchExchangeRate("SOL");
console.log("Exchange rate:", rate.rate); // e.g., 1.05 means 5% yield
console.log("Is fresh:", rate.isFresh);Calculate APY
Calculate annualized return based on PPS (price per share) growth over time.
// You need a starting PPS and timestamp (e.g., from when user deposited)
const startPps = new BN("1000000000"); // 1.0 (9 decimals)
const startTime = 1706140800; // Unix timestamp when PPS was recorded
// Calculate compound APY
const apy = await client.calculateApy("SOL", startPps, startTime);
console.log(`APY: ${(apy * 100).toFixed(2)}%`); // e.g., "APY: 12.50%"
// Or calculate simple APY (non-compounded)
const simpleApy = await client.calculateSimpleApy("SOL", startPps, startTime);
console.log(`Simple APY: ${(simpleApy * 100).toFixed(2)}%`);Note: Store the user's PPS and timestamp when they deposit to calculate their personal returns later.
Manager Operations
These operations require manager permissions.
Jupiter Earn (Deposit/Withdraw to Jupiter Lend)
const pool = client.pool("SOL");
// Deposit base tokens to Jupiter Lend
const depositTx = await pool.jupEarn({
manager: managerPublicKey,
direction: "Deposit",
amount: new BN(1_000_000_000),
});
// Withdraw from Jupiter Lend
const withdrawTx = await pool.jupEarn({
manager: managerPublicKey,
direction: "Withdraw",
amount: new BN(1_000_000_000),
});Move Tokens Between STV and Vault
const pool = client.pool("SOL");
// Move jlX tokens to vault (for JLP conversion)
const toVaultTx = await pool.moveJlx({
manager: managerPublicKey,
direction: "ToVault",
jlxAmount: new BN(1_000_000_000),
});
// Move jlX tokens back from vault to STV
const fromVaultTx = await pool.moveJlx({
manager: managerPublicKey,
direction: "FromVault",
jlxAmount: new BN(1_000_000_000),
});Claim Fees
const pool = client.pool("SOL");
const tx = await pool.claimFees({
manager: managerPublicKey,
});Settle Yield
Distributes JLP yield across all pools. Requires fetching the current JLP price.
import { fetchJlpRate, MINTS } from "jlpd-sdk";
// Fetch current JLP price from Jupiter
const jlpRate = await fetchJlpRate(MINTS.JLP.toBase58());
// Settle yield
const admin = client.admin();
const tx = await admin.settleYield({
manager: managerPublicKey,
jlpRate,
});Swap Operations
Swap jlX to/from JLP
const swap = client.swap();
// Get a quote first
const quote = await swap.quoteJlxJlp({
pool: "SOL",
direction: "JlxToJlp", // or "JlpToJlx"
amountIn: new BN(1_000_000_000),
slippageBps: 30, // 0.3% slippage
});
console.log("Expected output:", quote.outAmount.toString());
console.log("Price impact:", quote.priceImpactPct, "%");
// Execute the swap
const tx = await swap.swapJlxJlp({
manager: managerPublicKey,
pool: "SOL",
direction: "JlxToJlp",
amountIn: new BN(1_000_000_000),
expectedOut: quote.outAmount,
quote,
});Swap Between jlX Types
const swap = client.swap();
// Get a quote
const quote = await swap.quoteJlxJlx({
fromPool: "SOL",
toPool: "USDC",
amountIn: new BN(1_000_000_000),
slippageBps: 30,
});
// Execute the swap
const tx = await swap.swapJlxJlx({
manager: managerPublicKey,
fromPool: "SOL",
toPool: "USDC",
amountIn: new BN(1_000_000_000),
minOut: quote.minOutAmount,
quote,
});Token Decimals Reference
| Token | Decimals | Example |
| ------ | -------- | ----------------------- |
| SOL | 9 | 1 SOL = 1_000_000_000 |
| USDC | 6 | 1 USDC = 1_000_000 |
| JupUSD | 6 | 1 JupUSD = 1_000_000 |
| BTC | 8 | 1 BTC = 100_000_000 |
| ETH | 8 | 1 ETH = 100_000_000 |
Working with BN (Big Numbers)
Solana uses big integers for token amounts. Use the BN class:
import { BN } from "@coral-xyz/anchor";
// Create from number (small amounts only)
const small = new BN(1000);
// Create from string (recommended for large amounts)
const large = new BN("1000000000000");
// Arithmetic
const sum = a.add(b);
const diff = a.sub(b);
const product = a.mul(b);
const quotient = a.div(b);
// Comparison
a.gt(b); // greater than
a.lt(b); // less than
a.eq(b); // equal
a.isZero();
// Convert to display string
const displayAmount = amount.toString();Error Handling
import { JlpdClientError } from "jlpd-sdk";
try {
const tx = await pool.deposit({
user: walletPublicKey,
amount: new BN(0), // Invalid amount
});
} catch (error) {
if (error instanceof JlpdClientError) {
console.error("SDK Error:", error.message);
} else {
console.error("Unexpected error:", error);
}
}Low-Level Instruction Builders
For direct transaction construction (e.g., from a backend server), the SDK exports individual instruction builders. Each takes an Anchor Program instance as the first argument.
import {
createProgram,
createDepositInstruction,
createWithdrawInstruction,
createInitOrUpdateVaultInstruction,
createUpdateStvInstruction,
createJupEarnInstruction,
createMoveJlxInstruction,
createSwapJlxJlxInstruction,
createSwapJlxJlpInstruction,
createSettleYieldInstruction,
createClaimFeesInstruction,
} from "jlpd-sdk";
const program = createProgram(connection);
// Example: build a deposit instruction
const ix = await createDepositInstruction(
program,
new BN(1_000_000_000),
{
user: userPubkey,
jlpVault: vaultPda,
stv: stvPda,
baseMint: MINTS.SOL,
jlMint: jlSolMint,
jvMint: jvSolMint,
userBaseAta: userSolAta,
userJvxAta: userJvSolAta,
stvBaseAta: stvSolAta,
stvJlxAta: stvJlSolAta,
tokenProgram: TOKEN_PROGRAM_ID,
},
remainingAccounts, // optional exchange rate accounts
);Some accounts are auto-resolved by Anchor from the IDL (PDAs and known addresses) and should be omitted from .accounts():
| Instruction | Auto-resolved accounts |
|---|---|
| initOrUpdateJlpVault | jlpVault (PDA), systemProgram |
| initializeStv | stv (PDA), stvJlxAta (PDA), systemProgram, associatedTokenProgram, rent |
| jupEarnDepositWithdraw | tokenProgram |
Constants
import { MINTS, JLPD_PROGRAM_ID } from "jlpd-sdk";
// Token mints
MINTS.SOL; // Native SOL mint
MINTS.USDC; // USDC mint
MINTS.JLP; // JLP token mint
MINTS.WBTC; // Wrapped BTC mint
MINTS.WETH; // Wrapped ETH mint
// Program ID
JLPD_PROGRAM_ID; // Main program addressFull Example: Deposit Flow
import { Connection, PublicKey } from "@solana/web3.js";
import { BN } from "@coral-xyz/anchor";
import { JlpdClient } from "jlpd-sdk";
async function deposit(walletPublicKey: PublicKey, wallet: any) {
// 1. Create client
const connection = new Connection("https://api.mainnet-beta.solana.com");
const client = JlpdClient.mainnet(connection);
// 2. Get pool context
const pool = client.pool("SOL");
// 3. Check current exchange rate (optional)
const rate = await client.fetchExchangeRate("SOL");
console.log(`Current yield: ${((rate.rate - 1) * 100).toFixed(2)}%`);
// 4. Build deposit transaction
const tx = await pool.deposit({
user: walletPublicKey,
amount: new BN(1_000_000_000), // 1 SOL
});
// 5. Send transaction
const signature = await wallet.sendTransaction(tx, connection);
console.log("Transaction sent:", signature);
// 6. Confirm transaction
await connection.confirmTransaction(signature, "confirmed");
console.log("Deposit confirmed!");
}Support
For issues or questions, contact the Elemental team.
