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 andgetStatuskey on. - Reach: any solver-compatible asset on any SODAX network is a valid destination, 166 assets today. The on-Sonic asset list 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 atdstAddresson Sonic.
Approvals
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:
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.
Quoting
The solver API quotes both directions: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.
sodax.partners.feeClaim, covered in Monetize SDK.
The user also pays Sonic’s network fee for the intent transaction, in S.
Executing
Preferswap(). 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 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 shows the hub-source branch next to the spoke one.
Error handling
Operations returnResult<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.