C# Client Wrapper for Jupiter Aggregator v6 Swap API (Solana)
Solnet.JupiterSwap is a lightweight, strongly-typed C# wrapper around Jupiter's v6 Swap Aggregator API. It streamlines:
- Fetching optimal swap routes (quotes)
 - Building unsigned swap transactions (legacy by default)
 - Token metadata retrieval (strict vs full list)
 - Simple interop with existing 
Solnetwallet, RPC and program utilities 
Status: Legacy (non-versioned) transaction flow is implemented and tested. Versioned (v0) transactions require additional work (see Roadmap).
- Quote retrieval with configurable slippage & routing constraints
 - Swap transaction generation (unsigned) with support for:
- Shared accounts toggle
 - Auto wrap/unwrap SOL
 - Legacy transaction selection
 
 - Token list hydration (strict / all)
 - High-level strongly typed models: 
SwapQuoteAg,SwapRequest,SwapResponse,TokenData - Simple extension entry point via 
JupiterDexAg : IDexAggregator 
Package not yet published to NuGet (if you need this, open an issue). For now:
- Clone the repository
 - Add the 
Solnet.JupiterSwapproject to your solution - Reference it from your application project
 
Prerequisites:
- .NET 8 SDK
 - A Solana RPC endpoint (HTTPS) with sufficient rate limits
 - A funded keypair for signing & paying network fees
 
Below is a minimal end‑to‑end example performing a USDC -> SOL style swap (adjust mints + amount as needed).
using Solnet.JupiterSwap;
using Solnet.JupiterSwap.Models;
using Solnet.JupiterSwap.Types;
using Solnet.Rpc;
using Solnet.Rpc.Models;
using Solnet.Programs;
using Solnet.Wallet;
using System.Numerics;
// 1. RPC + wallet
IRpcClient rpc = ClientFactory.GetClient("https://your-rpc-endpoint");
Account trader = Account.FromSecretKey("<BASE58_SECRET_KEY>");
// 2. Aggregator client (optionally pass PublicKey)
var jupiter = new JupiterDexAg(trader.PublicKey);
// 3. Define mints (USDC -> SOL example; replace if needed)
PublicKey inputMint = new("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"); // USDC
PublicKey outputMint = new("So11111111111111111111111111111111111111112");   // SOL (wrapped)
// 4. Amounts are in base units (lamports)
// USDC has 6 decimals -> 1.5 USDC = 1_500_000
BigInteger amountIn = new BigInteger(1_500_000);
// 5. Get quote (ExactIn with 0.50% slippage)
SwapQuoteAg quote = await jupiter.GetSwapQuote(
		inputMint,
		outputMint,
		amountIn,
		swapMode: SwapMode.ExactIn,
		slippageBps: 50 // 50 bps = 0.50%
);
// 6. Build unsigned legacy transaction
Transaction unsignedSwap = await jupiter.Swap(
		quote,
		userPublicKey: trader.PublicKey,
		useSharedAccounts: false,
		wrapAndUnwrapSol: true,
		asLegacy: true
);
// 7. (OPTIONAL) Rebuild message & sign (pattern defensive vs direct Build)
Message? compiled = Message.Deserialize(unsignedSwap.CompileMessage());
Transaction finalTx = Transaction.Populate(compiled);
byte[] signed = finalTx.Build(trader);
// 8. Send
var sendResult = await rpc.SendTransactionAsync(signed);
Console.WriteLine(sendResult.RawRpcResponse);- SOL: 1 SOL = 1_000_000_000 lamports (9 decimals)
 - USDC: 1 USDC = 1_000_000 (6 decimals)
 
Constructor overloads:
JupiterDexAg(string endpoint = "https://quote-api.jup.ag/v6")JupiterDexAg(PublicKey account, string endpoint = ...)
Primary methods (via IDexAggregator):
| Method | Purpose | 
|---|---|
GetSwapQuote(...) | 
Retrieve best route & amounts | 
Swap(...) | 
Construct unsigned swap transaction | 
GetTokens(tokenListType) | 
Fetch token metadata list | 
GetTokenBySymbol(symbol) | 
Lookup token by symbol | 
GetTokenByMint(mint) | 
Lookup token by mint | 
inputMint/outputMint(PublicKey)amount(BigInteger) – Interpretation depends onswapMode:ExactIn: amount is input token quantityExactOut: amount is desired output token quantity
swapMode:ExactIn | ExactOutslippageBps: optional (basis points)excludeDexes: e.g.["Saber","Aldrin"]onlyDirectRoutes: restrict to single hopplatformFeeBps: optional fee charged (output token for ExactIn, input for ExactOut)maxAccounts: rough upper bound for account planning
quoteResponse: requiredSwapQuoteAgfrom previous stepuserPublicKey: wallet authority (falls back to constructor account)destinationTokenAccount: optional explicit output ATAwrapAndUnwrapSol: auto create/close temporary WSOL ATAuseSharedAccounts: use aggregator shared program accountsasLegacy: request legacy transaction (default true in this wrapper)
Not yet exposed here: dynamic compute unit tuning, token ledger, referral fee account injection (see
SwapRequestmodel fields). They can be added with minor extension work (see Contributing).
Key fields:
InAmount,OutAmount(string raw) + parsedInputAmount,OutputAmountInputMint,OutputMintSlippageBpsRoutePlan(list of route legs with AMM metadata)PriceImpactPct,ContextSlot,TimeTaken
Per-hop AMM route data: amounts, fee mint, label + AMM key.
Contains flags for advanced behaviors (ledger, referral, compute unit strategies, blockhash expiry tuning).
Returns base64 serialized transaction (SwapTransaction) ready for deserialization & signing.
Includes Name, Mint, Symbol, Decimals, LogoURI, optional Coingecko ID, flags: Whitelisted, PoolToken.
GetTokens(TokenListType.Strict) fetches the curated list.
TokenListType.All returns a superset including more experimental or newly added assets.
Caching: First call caches token list in-memory for the lifetime of the JupiterDexAg instance.
Network / API failures throw HttpRequestException with status code context.
Potential sources:
- Invalid mint addresses
 - Route not found (upstream returns non-success)
 - RPC later rejects swap (slippage exceeded, blockhash expired, account constraints)
 
Recommended patterns:
try
{
		var quote = await jupiter.GetSwapQuote(inputMint, outputMint, amountIn, slippageBps: 30);
}
catch (HttpRequestException ex)
{
		// log + classify (ex.StatusCode isn't directly on exception pre .NET 5, inspect Message)
}Jupiter v6 can return versioned (v0) transactions. Current wrapper forces legacy by sending asLegacyTransaction=true both on quote and swap. To add versioned support:
- Expose a public 
asLegacyboolean onGetSwapQuote(currently hardcoded to true) - When 
false, passasLegacyTransaction=falseto both endpoints - Deserialize returned transaction and sign using Solnet's versioned transaction pathway
 - Adjust docs + tests
 
- Versioned transaction support
 -  Referral fee account wiring (
feeAccount+platformFeeBpssynergy) - Dynamic compute unit limit & pricing controls
 - Optional token ledger workflow
 - Test suite (integration harness against a local validator or devnet)
 - NuGet package publishing & semantic versioning
 
PRs welcome. Please:
- Open an issue describing the change
 - Keep changes focused (one feature / fix per PR)
 - Include summary in the PR description
 
Suggested future improvements: typed errors, resilience policies (retry/backoff), structured logging hooks, metrics instrumentation, cancellation token support.
- Always validate mints & amounts before relaying user intent
 - Consider quoting and immediately executing to reduce route drift
 - Monitor slippage tolerance values — 500 bps (5%) is usually too high for stable pairs
 
Distributed under the MIT License. See LICENSE for details.
Use at your own risk. On-chain interactions involve financial risk; verify outputs and test on devnet when possible.
Open an issue for bugs, feature requests, or questions. If this project helps you ship, consider a star.
Happy building on Solana with Jupiter + C# 🚀