Payload Logo

back to news

Integrate with the SODAX SDK

The SODAX SDK gives you direct, simplified access to SODAX’s Unified Liquidity Layer — connecting liquidity across (a current) 12 chains and 6 tech stacks, with fast settlement and intent-based execution. To find out which ecosystems will be joining the SODAX SDK soon, you can browse our roadmap.

The SDK abstracts away cross-chain complexity, so you can integrate intent swaps, lending, and borrowing with a few lines of code, supporting both EVM and non-EVM networks. This guide walks you through a complete integration: from installation and configuration to enabling chains, executing swaps, and interacting with the money market. Build multichain DeFi without the headache.


Purpose for the core SDK:

  • To enable usage of all SODAX features in a seamless way.
  • To provide partners with a whole suite of functions required to complete specific user actions (e.g. swap).
  • To abstract away the complexity of cross-chain logic, assembling of the low level transactions and other data structures. Users and partners do not need to know anything about how cross-chain infrastructure works.
  • To provide configurations and constants as well as primitive type interfaces which enable dependency free (primitive types based only) interaction with our core SDK.



Step-by-step integration walkthrough

Process accurate as of Aug 7 2025: Code snippets are merely for illustration purposes, latest code may differ due to the active ongoing improvements.

1. Install @sodax/sdk NPM package

Currently SODAX SDK’s only support typescript and javascript environments.


Shell commands for installing the package using different package managers:

1// using npm
2npm install @sodax/sdk
3
4// using pnpm
5pnpm add @sodax/sdk
6
7// using yarn
8yarn add @sodax/sdk


2. Instantiate SODAX instance

All SODAX core features (swap, money market) are reachable through SODAX instances which must be constructed as a class. A SODAX instance can be created with or without configuration - in this case default mainnet configuration is used. Using SODAX features requires only a single instance, thus we suggest you treat it as a singleton.


If you are a protocol integrating SODAX as part of your suite, you can monetize it by configuring a partner fee.

See examples on how to instantiate a default or customized SODAX instance below:

1// Initialize Sodax using default Sonic mainnet configurations (no fees)
2const sodax = new Sodax();
3
4// Partner fee can be defined as a percentage or a definite token amount.
5// Fee is optional, you can leave it empty/undefined.
6const partnerFeePercentage = {
7  address: '0x...', // address to receive fee too
8  percentage: 100, // 100 = 1%, 10000 = 100%
9} satisfies PartnerFee;
10
11const partnerFeeAmount = {
12  address: '0x...', // address to receive fee too
13  amount: 1000n, // definite amount denominated in token decimal precision
14} satisfies PartnerFee;
15
16// Use default config but put fee on solver (intent swaps)
17const sodaxWithSolverFees = new Sodax({
18  solver: { partnerFee: partnerFeePercentage },
19});
20
21// Use default config with fee on money market (borrows)
22const sodaxWithMoneyMarketFees = new Sodax({
23  moneyMarket: { partnerFee: partnerFeePercentage },
24});
25
26// or use default config with fees on both solver and money market
27const sodaxWithFees = new Sodax({
28  solver: { partnerFee: partnerFeePercentage },
29  moneyMarket: { partnerFee: partnerFeePercentage },
30});

Full Customization:

1// example of custom solver config
2const customSolverConfig = {
3  intentsContract: '0x...',
4  solverApiEndpoint: 'https://...',
5  partnerFee: partnerFeePercentage, // or partnerFeeAmount
6} satisfies SolverConfigParams;
7
8// pre-defined default solver config per hub chain id (Sonic hub is the default)
9const solverConfig: SolverConfigParams = getSolverConfig(SONIC_MAINNET_CHAIN_ID);
10
11// example of custom money market config
12const customMoneyMarketConfig = {
13  lendingPool: '0x...',
14  uiPoolDataProvider: '0x...',
15  poolAddressesProvider: '0x...',
16  bnUSD: '0x...',
17  bnUSDVault: '0x...',
18} satisfies MoneyMarketConfig;
19
20// pre-defined default money market config per hub chain id (Sonic hub is the default)
21const moneyMarketConfig = getMoneyMarketConfig(SONIC_MAINNET_CHAIN_ID);
22
23// example of custom hub config
24const hubConfig = {
25  hubRpcUrl: 'https://rpc.soniclabs.com',
26  chainConfig: getHubChainConfig(SONIC_MAINNET_CHAIN_ID),
27} satisfies EvmHubProviderConfig;
28
29
30// Initialize Sodax using custom/default configurations
31const sodax = new Sodax({
32  solver: solverConfig,
33  moneyMarket: moneyMarketConfig,
34  hubProviderConfig: hubConfig,
35});


3. Enable chains and connectivity

SODAX provides support for EVM (Arbitrum, Avalanche, Base, BSC, ...) and many non-EVM chains (Sui, Solana, Injective, ...). You can refer to SDK docs to see the up to date list of chains supported per each SODAX feature.


In SODAX SDK we name every supported chain on which SODAX features can be invoked as a “spoke chain” .The core chain is named “hub chain” because it is a hub for all of the spokes. In our case the hub is the Sonic chain. Partners should only have to deal with the spoke chains (Sonic is also treated as one) since our SDK abstracts away the complexity of dealing with hub chain logic.


If you want to interact with a specific selection of chains, you need to:

  1. Pick out chains (by ID) you want to support from predefined constants found in here. Note that SODAX uses custom chain IDs which may not reflect the “native” chain ID.
  2. Create a Spoke Provider instance for each of the chains you want to support. A Spoke provider is a logical entity representing a connection to a specific chain and should be treated as a singleton instance.

Available spoke chain configuration constants and utils:

1import { 
2 SPOKE_CHAIN_IDS,      // array of currently supported spoke chain ids
3 supportedSpokeChains, // alias for SPOKE_CHAIN_IDS
4 isValidSpokeChainId   // util function to check if certain chain ID is valid
5} from '@sodax/sdk';

Example of creating an instance of EVM chain type Spoke Provider:

1// BSC spoke chain provider of EVM type
2const bscSpokeProvider: EvmSpokeProvider = new EvmSpokeProvider(
3  evmWalletProvider, // connected wallet constructed using Wallet SDK or implementation of IEvmWalletProvider interface
4  spokeChainConfig[BSC_MAINNET_CHAIN_ID], // connected chain config
5);

SODAX SDK enables you to choose whether to use our (Wallet SDK) or your custom implementation of wallet connectivity. Example implementation for each supported chain can be found inside wallet providers directory of the Wallet SDK.


4. Accessing SODAX features

At the time of writing this SODAX supports two main features: swap and money market.



Swap (Intents & Solver)

Swaps are enabled by intent and solver technology where the user initiates an intent and solver tries to solve it as efficiently as possible.


You should be able to retrieve all supported tokens per chain from our preconfigured constants.

All supported tokens per chain can be retrieved or verified as following:

1import { getSupportedSolverTokens, SpokeChainId, Token } from "@sodax/sdk"
2
3// using spoke chain id to retrieve supported tokens for solver (intent swaps)
4const supportedSolverTokens: readonly Token[] = getSupportedSolverTokens(spokeChainId);
5
6// check if token address for given spoke chain id is supported in solver
7const isSolverSupportedToken: boolean = isSolverSupportedToken(spokeChainId, token)


In order to create a successful swap you need to:

  1. Get a quote (kind of optional but advised in order to derive the minimal expected output amount and price). Request a Quote docs can be found here.
  2. Check allowance and approve the token spending if required
  3. Create a swap if you are satisfied with the given quote and allowance to transfer tokens is valid


Example quote request:

1const quoteRequest = {
2  token_src: '0x2170Ed0880ac9A755fd29B2688956BD959F933F8', // ETH token on BSC
3  token_dst: '0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f', // wBTC token on ARB
4  token_src_blockchain_id: BSC_MAINNET_CHAIN_ID,           // src spoke chain id
5  token_dst_blockchain_id: ARBITRUM_MAINNET_CHAIN_ID,      // dst spoke chain id
6  amount: 1000n,            // amount of src token to swap
7  quote_type: 'exact_input',// quote type: "exact_input" or "exact_output"
8} satisfies SolverIntentQuoteRequest;
9
10const result = await sodax.solver.getQuote(quoteRequest);

After you are satisfied with the quote you can create intent params as following:

1const createIntentParams = {
2  inputToken: '0x..',  // The address of the input token on spoke chain
3  outputToken: '0x..',  // The address of the output token on spoke chain
4  inputAmount: BigInt(1000000), // The amount of input tokens
5  minOutputAmount: BigInt(900000), // min amount you are expecting to receive
6  deadline: BigInt(0), // Optional timestamp after which intent expires (0 = no deadline)
7  allowPartialFill: false, // Whether the intent can be partially filled
8  srcChain: BSC_MAINNET_CHAIN_ID, // Chain ID where input tokens originate
9  dstChain: ARBITRUM_MAINNET_CHAIN_ID, // Chain ID where output tokens should be delivered
10  srcAddress: '0x..', // Source address (original address on spoke chain)
11  dstAddress: '0x..', // Destination address (original address on spoke chain)
12  solver: '0x0000000000000000000000000000000000000000', // Optional specific solver address (address(0) = any solver)
13  data: '0x', // Additional arbitrary data
14} satisfies CreateIntentParams;

Once you have intent params established you should first make sure that SODAX has an allowance to transfer the token amount you want to swap.


Example on how to check allowance and approve if needed:

1// First check if approval is needed
2const isApproved = await sodax.solver.isAllowanceValid(
3  createIntentParams,
4  bscSpokeProvider
5);
6
7if (!isApproved.ok) {
8  // Handle error
9  console.error('Failed to check allowance:', isApproved.error);
10} else if (!isApproved.value) {
11  // Approve Sodax to transfer your tokens
12  const approveResult = await sodax.solver.approve(
13    bscEthToken, // BSC ETH token address
14    createIntentParams.inputAmount, // Amount to approve
15    bscSpokeProvider
16  );
17
18  if (!approveResult.ok) {
19    // Handle error
20    console.error('Failed to approve tokens:', approveResult.error);
21  } else {
22    // wait for tx hash from approveResult.value to be mined before proceeding
23  }
24}

After allowance for SODAX to transfer your tokens is approved you can create swap as following:

1const swapResult = await sodax.solver.swap(
2    createIntentParams,
3    bscSpokeProvider,
4  );
5
6  if (!swapResult.ok) {
7    // handle error as described in Error Handling section
8  }
9
10  // txHash and created Intent data as Intent & FeeAmount type
11  const [txHash, intent] = swapResult.value;


Error handling for swaps are very important and so we have implemented relevant guards to handle errors as described in the Handling Swap Errors section of the docs.

If you require higher customization of individual execution steps (create intent, relay tx) you can find more docs here. We also provide the ability to estimate gas for each kind of money market related action. You can find docs on how to do that here.


After a swap intent is created you can:

  • Get intent status to check what state intent is currently in
  • Cancel swap intent

Get intent status:

1const result = await sodax.solver.getStatus({
2  intent_tx_hash: '0x...', // tx hash of create intent blockchain transaction
3} satisfies SolverIntentStatusRequest);

Cancel swap intent:

1const result = await sodax.solver.cancelIntent(
2  intent,
3  bscSpokeProvider,
4  hubProvider,
5  false, // true = get raw transaction, false = execute and return tx hash
6);
7
8if (result.ok) {
9  console.log('[cancelIntent] txHash', txResult.value);
10} else {
11  // handle error
12  console.error('[cancelIntent] error', txResult.error);
13}



Money market

The Money Market part of SDK provides abstractions to assist you with interacting with the cross-chain Money Market smart contracts.


You can retrieve all supported tokens per chain from our preconfigured constants.

All supported tokens per chain can be retrieved or verified as following:

1// using spoke chain id to retrieve supported tokens address
2const supportedMoneyMarketTokens: readonly Token[] = getSupportedMoneyMarketTokens(spokeChainId)
3
4// check if token address for given spoke chain id is supported
5const isMoneyMarketSupportedToken: boolean = isMoneyMarketSupportedToken(spokeChainId, token)


Our money market supports the following user actions:

  • Supply
  • Borrow
  • Repay
  • Withdraw


In order to successfully use those features you need to:

  1. Check allowance for the action and approve token transfer if needed
  2. Execute the action


Example flow of supply action execution:

  1. Create supply params:
1const supplyParams: MoneyMarketSupplyParams = {
2  token: '0x...', // Address of the token (spoke chain) to supply
3  amount: 1000n, // Amount to supply (in token decimals)
4  action: 'supply',
5};
  1. Check allowance of supply action:
1// Step 1: Check if allowance is sufficient
2const allowanceCheck = await sodax.moneyMarket.isAllowanceValid(supplyParams, spokeProvider);
3
4if (!allowanceCheck.ok) {
5 console.error('Allowance check failed:', allowanceCheck.error);
6 return;
7}
8
9// Step 2: Approve if allowance is insufficient
10if (!allowanceCheck.value) {
11 console.log('Insufficient allowance, approving...');
12
13 const approveResult = await sodax.moneyMarket.approve(supplyParams, spokeProvider);
14
15 if (!approveResult.ok) {
16 console.error('Approval failed:', approveResult.error);
17 return;
18 }
19
20 console.log('Approval successful:', approveResult.value);
21}
22
  1. Once allowance is valid you can execute supply action on the money market as following:
1// Step 3: Now you can proceed with supply
2const supplyResult = await sodax.moneyMarket.supply(supplyParams, spokeProvider);
3
4if (supplyResult.ok) {
5 const [spokeTxHash, hubTxHash] = supplyResult.value;
6 console.log('Supply successful:', { spokeTxHash, hubTxHash });
7} else {
8 console.error('Supply failed:', supplyResult.error);
9}
10

Flow for all other actions is very similar if not equal!



Need any help?

We provide the ability to estimate gas for each kind of money market related action, and extensive support for error handling of each action.
You can find gas estimation docs here.

You can find Error Handling docs here.

For any further issues or to reach out to our team during the integration process, you can provide your contact information through the form on our Gitbook, open an issue on our Github, or reach out directly to SODAX through Discord

Blog,  Software

SODAX SDKs (Core, Wallet, dApp Kit) allow partners to tap into fast, scalable DeFi with intent-based execution and deep cross-chain liquidity.

Technology

The SODAX SDK is fully integrated and ready for partners, with Solvers powering cross-chain intents-based execution through Protocol-Owned Liquidity.