| Crates.io | darklake-sdk-on-chain |
| lib.rs | darklake-sdk-on-chain |
| version | 0.5.0 |
| created_at | 2025-09-22 14:04:11.725979+00 |
| updated_at | 2025-10-25 10:50:53.055351+00 |
| description | Darklake DEX SDK - A standalone SDK for interacting directly with Darklake AMM pools |
| homepage | https://github.com/darklakefi/sdk-on-chain |
| repository | https://github.com/darklakefi/sdk-on-chain.git |
| max_upload_size | |
| id | 1850083 |
| size | 4,524,397 |
This project is part of a wider integration project composed by:
A standalone SDK for interacting with Darklake AMM pools on Solana. This SDK provides two main usage flows:
_tx): Return fully formatted transaction that can be signed and sent_ix): Return core instruction, allowing users to manage additional calls as needed⚠️ All public SDK methods are async - require
.awaitwhen called.
📚 Detailed Examples: For comprehensive examples and advanced usage patterns, see the SDK Examples Repository.
The functions are only necessary if _ix functions are used. As the SDK user is expected to call load_poo and updated_accounts before calling any _ix.
The SDK includes internal chain state tracking functions:
load_pool: Loads pool data for internal state trackingupdate_accounts: Updates internal state with latest chain dataget_order: Exception helper that bypasses internal cache and fetches the latest order state directly from the chain. This is used to help reduce on-chain calls when only the order is needed. Also exports Order struct.Add this to your Cargo.toml:
[dependencies]
darklake-sdk-on-chain = "0.1.7"
use darklake_sdk_on_chain::DarklakeSDK;
use solana_sdk::commitment_config::CommitmentLevel;
// Initialize the SDK
let mut sdk = DarklakeSDK::new(
"https://api.devnet.solana.com",
CommitmentLevel::Confirmed,
true, // is_devnet
None, // label (optional, up to 10 characters)
None, // ref_code (optional, up to 20 characters)
)?;
label: Optional string up to 10 characters for identifying your application (Supply None if not needed)ref_code: Optional string up to 20 characters for referral tracking (Supply None if not needed)The SDK uses Versioned Transactions by default, which is the preferred approach for better performance and reduced transaction size. All transaction functions (_tx) return VersionedTransaction objects.
For devnet usage, you can import the pre-configured address lookup table (DEVNET_LOOKUP/MAINNET_LOOKUP):
use darklake_sdk_on_chain::DEVNET_LOOKUP;
The Darklake DEX does not support direct SOL pairs - only WSOL (Wrapped SOL) pairs are supported.
The transaction functions (swap_tx) automatically handle SOL/WSOL conversion by:
The instruction functions (swap_ix, finalize_ix) do not automatically handle SOL/WSOL wrapping. When using these methods:
unwrap_wsol parameter in FinalizeParamsIx if necessary or add a WSOL token account closing._tx) - Fully Formatted TransactionsThese functions return complete transactions ready to be signed and sent:
// Swap tx
let (swap_tx, order_key, min_out, salt) = sdk
.swap_tx(&token_mint_x, &token_mint_y, 1_000, 1, &user_keypair.pubkey())
.await?;
let tx = VersionedTransaction::try_new(swap_tx.message, &[&user_keypair])?;
let res = rpc_client.send_and_confirm_transaction_with_spinner(&tx)?;
let finalize_tx: solana_sdk::transaction::VersionedTransaction = sdk
.finalize_tx(&order_key, unwrap_wsol, min_out, salt, None)
.await?;
let tx = VersionedTransaction::try_new(finalize_tx.message, &[&user_keypair])?;
_ix) - Core InstructionsThese functions return core instructions, allowing you to manage additional calls as needed:
sdk.load_pool(&token_mint_x, &token_mint_y).await?;
sdk.update_accounts().await?;
let salt = [1, 2, 3, 4, 5, 6, 7, 8];
let min_out = 1;
let swap_params = SwapParamsIx {
source_mint: token_mint_x,
destination_mint: token_mint_y,
token_transfer_authority: user_keypair.pubkey(),
amount_in: 1_000,
swap_mode: SwapMode::ExactIn,
min_out,
salt,
};
let swap_ix = sdk.swap_ix(&swap_params).await?;
let recent_blockhash = rpc_client
.get_latest_blockhash()
.context("Failed to get recent blockhash")?;
let address_lookup_table = get_address_lookup_table(&rpc_client, DEVNET_LOOKUP).await?;
let message_v0 = v0::Message::try_compile(
&user_keypair.pubkey(),
&[swap_ix],
&[address_lookup_table.clone()],
recent_blockhash,
)?;
let mut transaction = VersionedTransaction {
signatures: vec![],
message: VersionedMessage::V0(message_v0),
};
transaction.signatures = vec![user_keypair.sign_message(&transaction.message.serialize())];
let finalize_params = FinalizeParamsIx {
settle_signer: user_keypair.pubkey(),
order_owner: user_keypair.pubkey(),
unwrap_wsol: false, // Set to true if output is wrapped SOL
min_out, // Same min_out as swap
salt, // Same salt as swap
output: order.d_out, // Fetched from on chain order
commitment: order.c_min, // Fetched from on chain order
deadline: order.deadline, // Fetched from on chain order
current_slot: rpc_client.get_slot()?,
};
let compute_budget_ix: Instruction = ComputeBudgetInstruction::set_compute_unit_limit(500_000);
let finalize_ix = sdk.finalize_ix(&finalize_params).await?;
let recent_blockhash = rpc_client
.get_latest_blockhash()
.context("Failed to get recent blockhash")?;
let message_v0 = v0::Message::try_compile(
&user_keypair.pubkey(),
&[compute_budget_ix, finalize_ix],
&[address_lookup_table],
recent_blockhash,
)?;
let mut transaction = VersionedTransaction {
signatures: vec![],
message: VersionedMessage::V0(message_v0),
};
transaction.signatures = vec![user_keypair.sign_message(&transaction.message.serialize())];
DarklakeSDK::new(rpc_endpoint, commitment_level, is_devnet, label, ref_code)Creates a new Darklake SDK instance.
Parameters:
rpc_endpoint: &str - Solana RPC endpoint URLcommitment_level: CommitmentLevel - Commitment level for RPC callsis_devnet: bool - Whether using devnet. Currently only devnet/mainnet supported.label: Option<&str> - Optional application/user label (max 10 characters). For example Some("duck-ag").ref_code: Option<&str> - Optional referral code (max 20 characters)Returns: Result<DarklakeSDK>
Example:
let sdk = DarklakeSDK::new(
"https://api.devnet.solana.com",
CommitmentLevel::Confirmed,
true, // is_devnet
None, // label
None, // ref_code
)?;
_tx) - Fully Formatted Transactionsquote(&token_in, &token_out, amount_in) - Get a quote for a swap. The quote returns Darklake controlled fees in the fee_amount field and the fee_pct field (which do not include fees imposed by tokens themselves), but it does take them into account when calculating the output.swap_tx(&token_in, &token_out, amount_in, min_out, &token_owner) - Generate swap transaction, returns (VersionedTransaction, order_key, min_out, salt)finalize_tx(&order_key, unwrap_wsol, min_out, salt, settle_signer) - Generate finalize transaction using parameters from swap_tx_ix) - Core Instructionsswap_ix(&swap_params) - Generate swap instructionfinalize_ix(&finalize_params) - Generate finalize instructionload_pool(&token_x, &token_y) - Load pool data for internal state trackingupdate_accounts() - Update internal state with latest chain dataget_order(&user, commitment_level) - Get order data (bypasses internal cache, fetches latest state directly from chain)pub struct SwapParamsIx {
pub source_mint: Pubkey,
pub destination_mint: Pubkey,
pub token_transfer_authority: Pubkey,
pub amount_in: u64,
pub swap_mode: SwapMode,
pub min_out: u64,
pub salt: [u8; 8],
}
pub struct FinalizeParamsIx {
pub settle_signer: Pubkey,
pub order_owner: Pubkey,
pub unwrap_wsol: bool, // Set to true if output is WSOL and you want to unwrap it to SOL
pub min_out: u64,
pub salt: [u8; 8],
pub output: u64,
pub commitment: [u8; 32],
pub deadline: u64,
pub current_slot: u64,
}
The quote() function returns a Quote object with the following structure:
interface Quote {
inAmount: BN; // Amount that the exchange will use to trade, calculated by subtracting ALL fees from the user input. So it's NOT the user input value.
outAmount: BN; // The output amount from the exchange EXCLUDING any transfer fees imposed by the token itself (if it does so)
feeAmount: BN; // The total amount of fees deducted by the exchange NOT including any fees imposed by tokens
feeMint: PublicKey; // Pubkey address of a token in which the fees are charged
feePct: BN; // The current total fee rate of the trade in percentage. Max value 1000000 = 100%
}
SDK needs an rpc url which is used for on chain data fetching.
The SDK provides pre-configured address lookup tables for use with versioned transaction:
DEVNET_LOOKUP: Pre-configured address lookup table for devnet usageMAINNET_LOOKUP: Pre-configured address lookup table for mainnet usageuse darklake_sdk_on_chain::DEVNET_LOOKUP;
MIT License - see LICENSE file for details.
For issues and questions:
Note: Make sure you are using the same commitment level both for your own rpc and the sdk, unless you know what you are doing.
Note: This SDK is for interacting with the Darklake DEX on Solana. Always test thoroughly on devnet before using on mainnet.