Solnet.JupiterPerps
C# SDK & Client for interacting with the Jupiter Perpetuals on-chain program on Solana.
Solnet.JupiterPerps is a .NET 8.0 library that enables developers, trading bots, quant systems, and backend services to read on-chain state and craft valid transactions for Jupiter's Perpetuals Program. It builds on top of the official Solnet stack (Solana.Rpc, Solana.Programs, Solana.Extensions, Solana.KeyStore).
The SDK exposes:
- Low-level instruction builders (via
PerpetualsProgram) for every supported on-chain instruction. - A typed async client (
PerpetualsClient) to fetch and deserialize program accounts (pools, custodies, positions, position requests, etc.). - PDA helpers in
PDALookupto derive program-derived addresses deterministically. - Strongly-typed parameters & account record classes under
Records/andTypes/namespaces.
- Discover and load program state: Perpetuals config, pools, custodies, positions, position requests.
- Create increase & decrease position market requests including SOL collateral wrapping.
- Build raw Solana
TransactionInstructionobjects for advanced / custom pipelines. - Liquidate or close positions (where permitted by program state and rules).
- Derive PDAs for custody, pool, and perpetuals accounts.
Solnet.JupiterPerps/
├─ JupiterPerpsProgram.cs // Static instruction builders (serialization + account metas)
├─ JupiterPerpsClient.cs // High-level async RPC client wrappers
├─ Utils.cs // PDA derivation helpers (PDALookup)
├─ Errors.cs // Enum mapping on-chain error codes → names
├─ Records/ // Account meta groupings for each instruction
└─ Types/ // Parameter + account layout types (Borsh-like serialization)
Each static method on PerpetualsProgram returns a fully populated TransactionInstruction:
var ix = PerpetualsProgram.IncreasePosition4(accounts, paramsObj);These builders:
- Set the correct discriminator / instruction tag (first 8 bytes).
- Serialize parameters into the byte buffer.
- Attach ordered account metas (read-only / writable / signer flags) as required by the on-chain program.
PerpetualsClient wraps RPC account fetch flows with discriminator-based filtering using getProgramAccounts and typed deserialization:
var rpc = ClientFactory.GetClient(Cluster.MainNet); // from Solnet
var perpClient = new PerpetualsClient(rpc);
var pools = await perpClient.GetPoolsAsync();Deterministic derivations to avoid manual seed handling:
PublicKey custody = PDALookup.FindCustodyPDA(tokenMint);
PublicKey pool = PDALookup.FindPoolPDA(ownerOrSeedKey);
PublicKey perpCfg = PDALookup.FindPerpetualsPDA(adminOrSeedKey);Add the project as a dependency (until published to NuGet):
- Clone the repository.
- Reference the
.csprojfrom your solution or add a project reference:<ItemGroup> <ProjectReference Include="..\Solnet.JupiterPerps\Solnet.JupiterPerps.csproj" /> </ItemGroup>
- Restore & build:
dotnet restore; dotnet build -c Release
Planned: Publish to NuGet as Solnet.JupiterPerps once APIs stabilize.
using Solnet.JupiterPerps;
using Solnet.Wallet;
using Solnet.Rpc;
using Solnet.Rpc.Types;
// 1. Initialize RPC + wallet
var rpc = ClientFactory.GetClient(Cluster.MainNet);
var trader = new Wallet.Wallet(new Mnemonic("<seed words>"));
var perpClient = new PerpetualsClient(rpc);
// 2. Build accounts + params (illustrative – adapt to real account keys)
var accounts = new CreateIncreasePositionMarketRequestAccounts
{
// Populate: user account, pool, custody, position request PDA, token accounts, oracle feeds, etc.
};
var parameters = new CreateIncreasePositionMarketRequestParams
{
// Populate: size, leverage, side, slippage tolerances, etc.
};
// 3. Fund with SOL collateral (lamports) and submit combined transaction
ulong collateralLamports = 1_000_000_000; // 1 SOL example
string rawResponse = await perpClient.SendCreateIncreasePositionAsync(trader.Account, collateralLamports, accounts, parameters);
Console.WriteLine(rawResponse);If you need to batch multiple Jupiter Perps instructions, you can manually chain builders:
var ix1 = PerpetualsProgram.CreateIncreasePositionMarketRequest(accts1, params1);
var ix2 = PerpetualsProgram.InstantCreateLimitOrder(accts2, limitParams);
var blockhash = (await rpc.GetLatestBlockHashAsync()).Result.Value.Blockhash;
var tx = new TransactionBuilder()
.SetRecentBlockHash(blockhash)
.SetFeePayer(traderPubKey)
.AddInstruction(ComputeBudgetProgram.SetComputeUnitLimit(120_000))
.AddInstruction(ix1)
.AddInstruction(ix2)
.Build(traderAccount);
var sig = await rpc.SendTransactionAsync(tx);On-chain custom errors are enumerated in PerpetualsErrorKind (see Errors.cs). A non-exhaustive subset:
| Code | Name | Meaning |
|---|---|---|
| 6000 | MathOverflow | Internal arithmetic overflow detected |
| 6022 | MaxLeverage | Requested leverage exceeds pool or custody limits |
| 6021 | MaxPriceSlippage | Slippage tolerance breached |
| 6019 | InsufficientTokenAmount | Not enough tokens provided for the action |
| 6063 | CannotLiquidate | Liquidation conditions not met |
When a transaction fails, decode the InstructionError → custom error code and map to the enum for user-friendly messaging.
- Always verify oracle freshness (stale price errors 6003 / 6046 appear if not).
- Wrap SOL correctly (the helper flow in
SendCreateIncreasePositionAsynccreates and syncs the associated wSOL ATA). - Monitor compute unit usage; complex position flows may require budget increases (
ComputeBudgetProgram). - Validate PDAs locally rather than trusting external input.
- Automatic position close helper (removing current manual requirement).
- Take Profit / Stop Loss management & update flows (TPSL convenience wrappers).
- Signed backend co-signature integration (Jupiter API) for close path optimizations.
- NuGet packaging & semantic versioning.
- Expanded high-level convenience methods (e.g., margin health checks, liquidation candidates scan).
- Optional caching layer for frequently polled accounts.
Pull requests welcome. Please ensure:
- Deterministic instruction ordering.
- No breaking changes to public method signatures without discussion.
- Clear commit messages referencing instruction / feature touched.
git clone https://github.com/Bifrost-Technologies/Solnet.JupiterPerps.git
cd Solnet.JupiterPerps/Solnet.JupiterPerps
dotnet buildRun a quick smoke test by attempting to fetch pools:
var rpc = ClientFactory.GetClient(Cluster.MainNet);
var client = new PerpetualsClient(rpc);
var pools = await client.GetPoolsAsync();
Console.WriteLine($"Pools fetched: {pools.ParsedResult?.Count}");This SDK is an independent, community-maintained integration layer. Use at your own risk. Always test with small amounts and review on-chain program updates.
MIT – see LICENSE.
Questions or feature requests? Open an issue or discussion on the repository.