For the complete documentation index, see llms.txt. This page is also available as Markdown.

Monetize SDK

Learn how to configure fees and monetize your Sodax SDK integration.

When using the SODAX SDK, you can monetize your integration by collecting fees from the transactions processed through your application. Fees are configured globally per feature when creating the Sodax instance, and the swap feature additionally accepts a per-action override: getQuote() takes an optional partnerFee argument, and swap() / createIntent() read extras.partnerFee. When omitted, the configured fee applies.

Defining Fee

import { PartnerFee } from '@sodax/sdk';

// Partner fee can be defined as a percentage or a definite token amount.
// Fee is optional, you can leave it empty/undefined.
const partnerFeePercentage = {
  address: '0x0000000000000000000000000000000000000000', // EVM (Sonic) address to receive fee
  percentage: 100, // 100 = 1%, 10000 = 100%
} satisfies PartnerFee;

const partnerFeeAmount = {
  address: '0x0000000000000000000000000000000000000000', // EVM (Sonic) address to receive fee
  amount: 1000n, // definite amount denominated in token decimal precision
} satisfies PartnerFee;

Global fee configuration

The recommended approach is to configure fees globally per feature when creating your SDK config using new Sodax({...configuration}). This ensures all requests use the same fee configuration automatically:

Per-request fee configuration

The swap feature supports a per-action fee override that beats the configured swaps.partnerFee (per-feature override, else global). When omitted, the configured fee applies. This is what lets a backend construct swap intents on behalf of partners whose fee differs per request.

Quote request

SwapService.getQuote() deducts the partner fee from the amount before forwarding to the solver, so quoted_amount reflects the net output. No fee field appears in the request payload. Pass an optional partnerFee second argument to match a per-action override used on createIntent / swap; omit it to use the configured swap fee.

Swap request

The fee is applied automatically by the service. No fee field appears on the wire. Pass extras.partnerFee to override the configured swaps.partnerFee for this single action — omit extras (or extras.partnerFee) to use the configured fee.

Partner Fee Claiming

Partners earn fees from every swap or bridge operation they facilitate. Those fees accrue as wrapped ERC-20 tokens on the Sonic hub chain. The sodax.partners service exposes the full lifecycle for retrieving and converting those balances.

Accessing the partner service

Step 1 — Query accrued balances

fetchAssetsBalances issues a multicall to the hub chain and returns only non-zero balances, keyed by the wrapped asset address on Sonic.

Step 2 — Configure auto-swap preferences

Before claiming, configure where swapped proceeds should be delivered. Preferences are stored on-chain and applied automatically to every future createIntentAutoSwap call.

setSwapPreference supports both signed execution (raw: false) and raw transaction building (raw: true). When raw: true, walletProvider must be omitted — the method returns the unsigned transaction object instead.

Step 3 — Approve the fee token

Before swapping, ensure the ProtocolIntents contract is approved to spend the fee token. Native tokens are pre-approved and always return true from isTokenApproved.

Step 4 — Claim fees (end-to-end swap)

swap is the high-level method that submits the auto-swap intent on-chain and notifies the solver to execute it in one call.

Use createIntentAutoSwap instead of swap when you need manual control over the solver notification step (e.g. to retry independently).

Step 5 — Same-token claims (no conversion) and recovery

The solver cannot fill a swap whose output token equals its input token. If a partner's configured output token is the same asset as the fee token they are claiming (e.g. claiming BTC fees while the auto-swap output is BTC), swap rejects it up front with VALIDATION_FAILED instead of creating an unfillable intent that would lock the funds.

To deliver such a fee as-is, skip the swap and move the wrapped fee token off Sonic with the bridge — to its native chain, or to a Sonic address for same-chain delivery:

Bridging from Sonic pulls the token via the partner's hub-wallet router, so it needs a bridge allowance first (sodax.bridge.isAllowanceValid / sodax.bridge.approve) — a different spender than the ProtocolIntents approval used by swap.

If a same-token claim was already submitted before this guard existed, the funds sit in an unfillable intent. Recover them with cancelIntent, which calls ProtocolIntents' own cancelIntent(fromToken, toToken) and refunds the locked amount to the partner. This is the only authorized cancel path: the intent's creator is the ProtocolIntents contract, so the generic SwapService.cancelIntent reverts Unauthorized().

Error handling

All partners.feeClaim methods return Promise<Result<T, SodaxError<PartnerErrorCode>>> from the unified vocabulary. Discriminate on error.code (closed reason-only union) and error.feature === 'partner'. The original lower-level failure is preserved on error.cause; operation/method partition is on error.context.action / error.context.method.

PartnerErrorCode is the narrow union 'VALIDATION_FAILED' | 'LOOKUP_FAILED' | 'APPROVE_FAILED' | 'EXECUTION_FAILED' | 'UNKNOWN'. Use isPartnerError(e) instead of instanceof SodaxError in dapp/app code (bundle-safe).

Raw transaction mode

Every write method on PartnerFeeClaimService supports raw: true to obtain the unsigned transaction instead of broadcasting it. When raw: true, the walletProvider field must be omitted — TypeScript enforces this at compile time.

Last updated