> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sodax.com/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> SODAX is mainnet-only (no testnet chains or RPC endpoints exist) with a hub-and-spoke architecture; Sonic is the hub. SODAX is non-custodial protocol/software: it routes and settles; independent solvers on the marketplace fill — never say 'our solver', 'the SODAX solver', that SODAX trades, takes custody, or fills orders. For frontend/React integrations, prefer @sodax/dapp-kit hooks over calling @sodax/sdk directly. SDK operations — the methods that build, submit or await a transaction, and the API/quote calls — return Result<T, E> ({ ok: true, value } or { ok: false, error }): check result.ok, never wrap them in try/catch or branch on error.message; discriminate on the narrow error.code union instead. Synchronous config getters (getPartnerFee, getSupportedSwapTokens, getVault, ...) return their value directly, not a Result.

# Swaps on Sonic

> Intent-based cross-network swaps from the SODAX hub: one signed EVM transaction on Sonic, registered directly with the intents contract, solver-filled, with no relay hop.

SODAX swaps are intents, not bridges. Your user signs one transaction that locks the input and declares what they want on the destination network. Solvers fill it, and if nothing fills, the intent can be cancelled and funds recovered.

On every other network, that transaction goes to a spoke contract and the SODAX relayer carries it to the hub. On Sonic, the user's transaction calls the SODAX intents contract on the hub directly. From your side it is the same SDK call as on any network. From your user's side it is one wallet prompt, plus an approval the first time they swap an ERC-20.

## What this looks like on Sonic

* **Source**: the intent transaction is an EVM transaction on Sonic that creates the intent on the hub intents contract. Native S is sent as the transaction value; ERC-20 inputs are pulled by the intents contract. `ChainKeys.SONIC_MAINNET` (`'sonic'`) identifies the network everywhere in the SDK.
* **No relay hop**: the source transaction is the hub transaction. `swap()` skips the relay step, and the same hash is what the solver and `getStatus` key on.
* **Reach**: any solver-compatible asset on any SODAX network is a valid destination, <span data-sodax-config="count" data-metric="swap-tokens">166</span> assets today. The [on-Sonic asset list](/sonic/networks-and-assets) only bounds what users hold on Sonic itself, not what they can swap into.
* **Tokens**: the Sonic list mixes Sonic-native tokens (S, wS, USDC, and others) with SODAX hub tokens, such as the `soda*` vault tokens and hub representations of assets from other networks. Read addresses and decimals from the SDK config; never hard-code them.
* **Settlement**: output lands on the destination network at `dstAddress`. A swap into Sonic pays out in the Sonic token at `dstAddress` on Sonic.

<h2 id="approvals">
  Approvals
</h2>

`swap()` does not approve the input token for you. Native S needs no approval. Every ERC-20 on Sonic does, and the spender is different from a spoke network: on a spoke the SDK approves that network's asset manager, while on Sonic it approves the SODAX **intents contract**, because the user creates the intent there directly. `isAllowanceValid` and `approve` select the spender from `srcChainKey`, so the code is the same as on any EVM network:

```typescript theme={null}
const allowance = await sodax.swaps.isAllowanceValid({ params, walletProvider });
if (!allowance.ok) throw allowance.error;

if (!allowance.value) {
  const approval = await sodax.swaps.approve({ params, walletProvider });
  if (!approval.ok) throw approval.error;
  // wait for the approval to be mined before calling swap()
}
```

`params` is the same intent params object you pass to `swap()`.

An allowance for swaps does not carry over to the money market. Supplying or repaying on Sonic approves a different spender, the user's hub wallet; see [Money Market on Sonic](/sonic/money-market#supply-on-sonic).

## Quoting

The solver API quotes both directions:

```typescript theme={null}
const quoteResult = await sodax.swaps.getQuote({
  token_src: s.address,               // token on Sonic
  token_dst: usdc.address,            // token on the destination network
  token_src_blockchain_id: ChainKeys.SONIC_MAINNET,
  token_dst_blockchain_id: ChainKeys.ARBITRUM_MAINNET,
  amount: 10n * 10n ** BigInt(s.decimals), // 10 S
  quote_type: 'exact_input',          // the only supported quote type
});
```

`getQuote` deducts any configured partner fee before quoting, so `quoted_amount` is the net output the user actually receives.

## Fees

Using SODAX is free to integrate. Two fees can apply to a trade:

* **Base fee**: a fixed 0.1% of the input, taken by the protocol. Not configurable; compute it ahead of time with `getSolverFee(inputAmount)`.
* **Your fee**: optional platform fee on top, set by you and paid to you. It is the only fee you control. Configure it at SDK setup and check it with `getPartnerFee(inputAmount)`. See [Monetize SDK](/developers/how-to/monetize_sdk).

Your fee receiver is a Sonic address, whichever network your users swap from. Fees accrue there as hub tokens, and you claim or convert them on Sonic through `sodax.partners.feeClaim`, covered in [Monetize SDK](/developers/how-to/monetize_sdk).

The user also pays Sonic's network fee for the intent transaction, in S.

## Executing

Prefer `swap()`. On Sonic it creates the intent on the hub, confirms it, and notifies the solver; the relay step it runs for spoke sources is skipped. The [Quickstart](/sonic/quickstart#4-quote-and-swap) has the complete call. Track progress with `getStatus({ intent_tx_hash })`, passing `intentDeliveryInfo.dstTxHash`. Limit orders (intents without deadlines) work from Sonic too, via `createLimitOrder`.

Cancelling is shorter on Sonic as well. `cancelIntent` sends one transaction on the hub and returns without waiting for a relay packet, so `srcChainTxHash` and `dstChainTxHash` are the same hash.

Orchestrating manually with `createIntent`: a Sonic intent needs no relay extra data and no relay submission. Pass the Sonic transaction hash straight to `postExecution` as the hub hash. [Migrate a manual swap to the backend submit-tx flow](/developers/how-to/migrate_swap_to_submit_tx) shows the hub-source branch next to the spoke one.

## Error handling

Operations return `Result<T>` instead of throwing. The core methods (`swap`, `createIntent`, `postExecution`) return a typed `SodaxError` union you can `switch` on by `error.code`.

***

Full reference, including raw mode, limit orders, cancellation, and the complete error-code table: [Swaps](/developers/packages/foundation/sdk/functional-modules/swaps).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.