adrena-sdk
v1.0.0-beta.15
Published
SDK for interacting with Adrena Protocol
Maintainers
Readme
TypeScript SDK for the Adrena Protocol — a Solana perpetuals DEX. Built on @solana/kit (Web3.js v2).
Links: Website · Docs · Discord · X
Table of Contents
- Installation
- Configuration
- Supported Assets
- Trading — Crypto Assets
- Trading — Synthetic Commodities
- Liquidity
- Staking
- Advanced: Building Instructions Manually
- Error Handling
Installation
# npm
npm install adrena-sdk-ts@beta
# yarn
yarn add adrena-sdk-ts@betaUpdating the IDL
The SDK depends on @adrena/abi (pinned to a specific commit) as the canonical source of truth for the on-chain program IDL. When the Adrena program is upgraded, update the pinned commit in package.json:
"@adrena/abi": "github:AdrenaFoundation/adrena-abi#<new-commit-sha>"Then regenerate the Codama-generated instruction builders:
yarn install
yarn codamaCommit both package.json, yarn.lock, and the updated codama-generated/ files together so the IDL version and generated code stay in sync.
Configuration
All SDK functions require a wallet (transaction signer) and an rpc client. The easiest way to create both is with createKitClient.
Option 1 — .env file (recommended)
Create a .env file in your project root:
PRIVATE_KEY_STR=<your-base58-private-key>
RPC_URL=https://your-rpc-url.com
WS_URL=wss://your-ws-url.com # optionalAdd
.envto your.gitignore. Never commit private keys.
Then in code:
import { createKitClient } from 'adrena-sdk-ts/clients';
const { wallet, rpc } = await createKitClient();Option 2 — Pass credentials directly
import { createKitClient } from 'adrena-sdk-ts/clients';
const { wallet, rpc } = await createKitClient({
privateKey: 'your-base58-private-key',
rpcUrl: 'https://your-rpc-url.com',
});Supported Assets
Adrena runs two separate on-chain pools. The SDK exposes both.
Main Pool — Crypto Assets
| Symbol | Role | Decimals | |---------|-----------------------------|----------| | JITOSOL | Principal / Collateral | 9 | | WBTC | Principal / Collateral | 8 | | BONK | Principal / Collateral | 5 | | USDC | Collateral / Liquidity | 6 |
PrincipalToken — the asset you are trading: "JITOSOL" | "WBTC" | "BONK"
CollateralToken — the asset you deposit as margin: "USDC" | "JITOSOL" | "WBTC" | "BONK"
For longs the collateral token must match the principal token (e.g. JITOSOL long requires JITOSOL collateral).
For shorts the collateral token must be"USDC".
Commodities Pool — Synthetic Assets
| Symbol | Name | Decimals | Oracle feed ID | |--------|------------|----------|----------------| | XAU | Gold | 6 | 2056 | | XAG | Silver | 6 | 2069 | | WTI | Crude Oil | 6 | 2035 |
CommodityToken — "XAU" | "XAG" | "WTI"
Commodity positions are always collateralised in USDC for both longs and shorts. There is no token swap — you deposit USDC and trade a price-feed-backed synthetic custody. Commodity positions belong to the commodities-pool and are settled in USDC on close.
Trading — Crypto Assets
Open a Long Position
import { openMarketLong } from 'adrena-sdk-ts/core';
import { createKitClient } from 'adrena-sdk-ts/clients';
import { checkTransactionConfirmed } from 'adrena-sdk-ts/helpers';
const { wallet, rpc } = await createKitClient();
const result = await openMarketLong({
wallet,
rpc,
principalToken: 'JITOSOL', // asset to trade
collateralToken: 'JITOSOL', // must match principal for longs
collateralAmount: 10, // human-readable units (10 JITOSOL)
leverage: 3, // 3× leverage
stopLossPrice: 130, // optional — trigger price in USD
takeProfitPrice: 180, // optional — trigger price in USD
});
console.log('tx:', result.txSignature);
console.log('position:', result.positionAddress);
const confirmed = await checkTransactionConfirmed(result.txSignature, rpc);Open a Short Position
import { openMarketShort } from 'adrena-sdk-ts/core';
import { createKitClient } from 'adrena-sdk-ts/clients';
const { wallet, rpc } = await createKitClient();
const result = await openMarketShort({
wallet,
rpc,
principalToken: 'JITOSOL', // asset to short
collateralToken: 'USDC', // must be USDC for shorts
collateralAmount: 50, // 50 USDC
leverage: 5,
stopLossPrice: 175, // optional — above entry price for shorts
takeProfitPrice: 120, // optional — below entry price for shorts
});Close a Long Position
import { closeLong } from 'adrena-sdk-ts/core';
import { createKitClient } from 'adrena-sdk-ts/clients';
const { wallet, rpc } = await createKitClient();
const result = await closeLong({
wallet,
rpc,
principalToken: 'JITOSOL',
// price: 155.0, // optional: override close price (defaults to current oracle price)
});Close a Short Position
import { closeShort } from 'adrena-sdk-ts/core';
import { createKitClient } from 'adrena-sdk-ts/clients';
const { wallet, rpc } = await createKitClient();
const result = await closeShort({
wallet,
rpc,
principalToken: 'JITOSOL',
collateralToken: 'USDC',
});Check Position Status
import { getPositionStatus } from 'adrena-sdk-ts/core';
import { createKitClient } from 'adrena-sdk-ts/clients';
import {
fetchPoolUtil,
loadCustodies,
getCustodyByMint,
findPositionAddress,
PRINCIPAL_ADDRESSES,
} from 'adrena-sdk-ts/helpers';
const { wallet, rpc } = await createKitClient();
const principalToken = 'JITOSOL';
const side = 'long'; // or 'short'
// Derive the on-chain position address
const pool = await fetchPoolUtil('main-pool', undefined, rpc);
const custodies = await loadCustodies(pool.data, rpc);
const principalCustody = getCustodyByMint(custodies, PRINCIPAL_ADDRESSES[principalToken].address);
const positionAddress = (await findPositionAddress(
pool.address,
wallet.address,
principalCustody!.address,
side,
))[0];
const status = await getPositionStatus({ wallet, rpc, principalToken, positionAddress });
// status contains: pnl, size, collateral, leverage, liquidationPrice, entryPrice, etc.
console.log(status);Limit Orders
import { addLimitOrder } from 'adrena-sdk-ts/core';
import { createKitClient } from 'adrena-sdk-ts/clients';
const { wallet, rpc } = await createKitClient();
const result = await addLimitOrder({
wallet,
rpc,
principalToken: 'JITOSOL',
collateralToken: 'JITOSOL', // matches principal for long; USDC for short
collateralAmount: 0.5,
leverage: 10,
side: 'long',
triggerPrice: 130, // order fills when oracle price reaches this level
limitPrice: null, // null = market price at fill; or set a max fill price
});Cancel Stop Loss / Take Profit
import { cancelSLTP } from 'adrena-sdk-ts/core';
import { createKitClient } from 'adrena-sdk-ts/clients';
const { wallet, rpc } = await createKitClient();
const result = await cancelSLTP(
wallet,
rpc,
'JITOSOL', // principalToken
'long', // side
true, // cancelStopLoss
true, // cancelTakeProfit
);Trading — Synthetic Commodities
Commodity trades go through the commodities-pool. The key differences from crypto trading are:
- Collateral is always USDC — for both longs and shorts, no token swap involved
collateralAmountis in USDC native units (multiply human amount by10^6)- Positions auto-detect open vs increase — the same function handles both
- Closing always pays out in USDC
Open a Commodity Long
import { openCommodityLong } from 'adrena-sdk-ts/core';
import { createKitClient } from 'adrena-sdk-ts/clients';
import { CommodityToken } from 'adrena-sdk-ts/helpers';
const { wallet, rpc } = await createKitClient();
// Go long on Gold with 100 USDC collateral at 5× leverage
const result = await openCommodityLong({
wallet,
rpc,
commodityToken: 'XAU' as CommodityToken,
collateralAmount: BigInt(100_000_000), // 100 USDC (6 decimals)
leverage: 5,
// price: 2_050, // optional — override oracle price in USD
});
console.log('tx:', result.txSignature);
console.log('position:', result.positionAddress);Other commodity tokens follow the same pattern:
// Silver long
await openCommodityLong({ wallet, rpc, commodityToken: 'XAG', collateralAmount: BigInt(50_000_000), leverage: 3 });
// Crude Oil long
await openCommodityLong({ wallet, rpc, commodityToken: 'WTI', collateralAmount: BigInt(200_000_000), leverage: 10 });Open a Commodity Short
import { openCommodityShort } from 'adrena-sdk-ts/core';
import { createKitClient } from 'adrena-sdk-ts/clients';
const { wallet, rpc } = await createKitClient();
// Short Gold with 100 USDC collateral at 5× leverage
const result = await openCommodityShort({
wallet,
rpc,
commodityToken: 'XAU',
collateralAmount: BigInt(100_000_000), // 100 USDC
leverage: 5,
});Close a Commodity Long
import { closeCommodityLong } from 'adrena-sdk-ts/core';
import { createKitClient } from 'adrena-sdk-ts/clients';
const { wallet, rpc } = await createKitClient();
const result = await closeCommodityLong({
wallet,
rpc,
commodityToken: 'XAU',
// price: 2_100, // optional override
});
// USDC is returned to the wallet on closeClose a Commodity Short
import { closeCommodityShort } from 'adrena-sdk-ts/core';
import { createKitClient } from 'adrena-sdk-ts/clients';
const { wallet, rpc } = await createKitClient();
const result = await closeCommodityShort({
wallet,
rpc,
commodityToken: 'XAU',
});Liquidity
Liquidity providers deposit collateral tokens into the ALP pool and receive ALP tokens representing their share. ALP earns trading fees.
Add Liquidity (ALP)
import { addLiquidity } from 'adrena-sdk-ts/core';
import { createKitClient } from 'adrena-sdk-ts/clients';
const { wallet, rpc } = await createKitClient();
const result = await addLiquidity({
wallet,
rpc,
collateralToken: 'USDC',
amountIn: BigInt(100_000_000), // 100 USDC in native units (6 decimals → 100 * 10^6)
minLpAmountOut: BigInt(0), // minimum ALP to receive; set >0 for slippage protection
});Remove Liquidity (ALP)
import { removeLiquidity } from 'adrena-sdk-ts/core';
import { createKitClient } from 'adrena-sdk-ts/clients';
const { wallet, rpc } = await createKitClient();
const result = await removeLiquidity({
wallet,
rpc,
collateralToken: 'USDC', // token to receive on exit
lpAmountIn: BigInt(50_000_000), // ALP tokens to burn (6 decimals)
minAmountOut: BigInt(0), // minimum collateral to receive
});Swap
Swap between any two supported collateral tokens through the ALP pool.
import { swap } from 'adrena-sdk-ts/core';
import { createKitClient } from 'adrena-sdk-ts/clients';
const { wallet, rpc } = await createKitClient();
const result = await swap({
wallet,
rpc,
fromToken: 'USDC',
toToken: 'JITOSOL',
amountIn: BigInt(50_000_000), // 50 USDC (6 decimals)
minAmountOut: BigInt(0), // set >0 for slippage protection
});Staking
ADX (governance token) and ALP (LP token) can both be staked to earn protocol fee distributions in USDC plus ADX emissions.
stakingType: 1 = ADX staking (default)stakingType: 2 = ALP staking
Liquid Staking (ADX or ALP)
Liquid stakes have no lock-up. You can unstake at any time.
import { addLiquidStake } from 'adrena-sdk-ts/core';
import { createKitClient } from 'adrena-sdk-ts/clients';
const { wallet, rpc } = await createKitClient();
// Stake 100 ADX (6 decimals)
await addLiquidStake({
wallet,
rpc,
stakingType: 1, // 1 = ADX, 2 = ALP
amount: BigInt(100_000_000), // 100 ADX in native units
});
// Remove liquid stake
import { removeLiquidStake } from 'adrena-sdk-ts/core';
await removeLiquidStake({
wallet,
rpc,
stakingType: 1,
amount: BigInt(100_000_000),
});Locked Staking
Lock your stake for a fixed duration to earn boosted rewards. Longer lock durations provide a higher multiplier.
import { addLockedStake } from 'adrena-sdk-ts/core';
import { createKitClient } from 'adrena-sdk-ts/clients';
const { wallet, rpc } = await createKitClient();
// Lock 500 ADX for 90 days
await addLockedStake({
wallet,
rpc,
stakingType: 1,
amount: BigInt(500_000_000), // 500 ADX
lockedDays: 90, // lock duration in days
});Common lock durations for ADX: 7, 30, 60, 90, 180, 360, 540, 720 days.
Remove Locked Stake
After your lock period ends you can withdraw the locked stake by its index in the UserStaking account.
import { removeLockedStake } from 'adrena-sdk-ts/core';
import { createKitClient } from 'adrena-sdk-ts/clients';
const { wallet, rpc } = await createKitClient();
await removeLockedStake({
wallet,
rpc,
stakingType: 1,
lockedStakeIndex: 0, // index of the lock in the UserStaking account (0-based)
});Claim Staking Rewards
Claims all pending USDC fee rewards and ADX emissions for the given staking type.
import { claimStakes } from 'adrena-sdk-ts/core';
import { createKitClient } from 'adrena-sdk-ts/clients';
const { wallet, rpc } = await createKitClient();
// Claim ADX staking rewards
await claimStakes({ wallet, rpc, stakingType: 1 });
// Claim ALP staking rewards
await claimStakes({ wallet, rpc, stakingType: 2 });Advanced: Building Instructions Manually
Every core function is a thin wrapper that calls an instructions builder and then sends the transaction via Jito. If you want to compose your own transactions or add instructions, use the builders directly:
import { getOpenLongIxs } from 'adrena-sdk-ts/instructions';
import { getAddLiquidityIxs } from 'adrena-sdk-ts/instructions';
import { sendTransactionWithJito } from 'adrena-sdk-ts/helpers';
import { createKitClient } from 'adrena-sdk-ts/clients';
import { ADRENA_LOOKUP_TABLE_ADDRESS } from 'adrena-sdk-ts/helpers';
const { wallet, rpc } = await createKitClient();
// Build instructions
const { ixns, positionAddress } = await getOpenLongIxs(
wallet,
'JITOSOL',
'JITOSOL',
10, // collateral amount (human-readable)
3, // leverage
rpc,
);
// Add your own instructions before/after, then send
const txSig = await sendTransactionWithJito(
ixns,
wallet,
rpc,
false, // simulate only
true, // use Jito bundle
[ADRENA_LOOKUP_TABLE_ADDRESS],
);All staking and liquidity instruction builders follow the same pattern — see src/instructions/ for the full set.
Error Handling
All core functions return { txSignature: string } on success. Use checkTransactionConfirmed to poll for on-chain confirmation:
import { checkTransactionConfirmed } from 'adrena-sdk-ts/helpers';
const result = await openMarketLong({ ... });
if (!result.txSignature) {
console.error('Transaction failed to send');
return;
}
const confirmed = await checkTransactionConfirmed(result.txSignature, rpc);
if (confirmed) {
console.log('Position opened:', result.positionAddress);
} else {
console.warn('Transaction did not confirm within timeout');
}Transactions are submitted via Jito bundles for MEV protection and faster landing. If the Jito tip endpoint is unreachable the SDK falls back to a standard RPC send.
