> ## 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 HyperEVM

> Intent-based cross-network swaps from a HyperEVM perspective: one signed EVM transaction, solver-filled, settled across networks, with optional delivery into HyperCore.

SODAX swaps are intents, not bridges. Your user signs one transaction on HyperEVM that locks the input and declares what they want on the destination network. Solvers fill it; the SODAX relayer carries proof between HyperEVM, the hub (Sonic), and the destination. If nothing fills, the intent can be cancelled and funds recovered.

From your side it is one SDK call. From your user's side it is one wallet prompt, plus an approval the first time they swap an ERC-20 token.

## What this looks like on HyperEVM

* **Source**: the intent transaction is an ordinary EVM transaction on HyperEVM, signed by the user's wallet and paid for in HYPE. `ChainKeys.HYPEREVM_MAINNET` (`'hyper'`) identifies the network everywhere in the SDK.
* **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-HyperEVM asset list](/hyperevm/networks-and-assets) only bounds what users hold on HyperEVM itself, not what they can swap into.
* **Tokens**: HYPE uses the zero address; every other token is a HyperEVM ERC-20 contract. Only HyperEVM balances count: assets in HyperCore spot or perps have to be transferred to HyperEVM before they can be swapped.
* **Settlement**: output lands on the destination network at `dstAddress`. Swaps into HyperEVM settle as ordinary HYPE or ERC-20 balances at the recipient's HyperEVM address, unless you route USDC into HyperCore with the deposit hook below.

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

`swap()` does not approve the input token for you. HYPE is the native token and needs no approval. Every ERC-20 does: SODAX's asset manager pulls it through the token's ERC-20 interface, so check the allowance first and approve when it falls short.

```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()`.

## Quoting

The solver API quotes both directions:

```typescript theme={null}
const quoteResult = await sodax.swaps.getQuote({
  token_src: hype.address,            // token on HyperEVM
  token_dst: usdc.address,            // token on the destination network
  token_src_blockchain_id: ChainKeys.HYPEREVM_MAINNET,
  token_dst_blockchain_id: ChainKeys.ARBITRUM_MAINNET,
  amount: 10n * 10n ** BigInt(hype.decimals), // 10 HYPE
  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).

The user also pays HyperEVM's network fee for the intent transaction, in HYPE, like any other HyperEVM transaction.

## Executing

Prefer `swap()`. It creates the intent on HyperEVM, verifies it landed, submits it to the relay, waits for the packet on the hub, and notifies the solver. The [Quickstart](/hyperevm/quickstart#4-quote-and-swap) has the complete call. Track progress with `getStatus(request)`, and cancel unfilled intents with `cancelIntent`. Limit orders (intents without deadlines) work from HyperEVM too, via `createLimitOrder`.

Orchestrating manually with `createIntent` and `submitIntent` works the same as on any EVM network: HyperEVM intents need no relay extra data.

<h2 id="delivering-into-hypercore">
  Delivering into HyperCore
</h2>

A swap into HyperEVM normally pays the recipient's HyperEVM wallet. When your user wants to trade on Hyperliquid, the SDK can instead deposit the output into their HyperCore perps account in the same delivery, using the HyperCore deposit hook registered for HyperEVM.

Set `outputToken` to USDC on HyperEVM, `dstChainKey` to `ChainKeys.HYPEREVM_MAINNET`, and add `hook`. The source can be any SODAX network; this example swaps ETH on Arbitrum:

```typescript theme={null}
import { Sodax, ChainKeys, HookKind, type XToken } from '@sodax/sdk';

const sodax = new Sodax();

const bySymbol = (tokens: readonly XToken[], symbol: string) => {
  const token = tokens.find(t => t.symbol === symbol);
  if (!token) throw new Error(`${symbol} is not a supported swap token`);
  return token;
};

const eth = bySymbol(sodax.swaps.getSupportedSwapTokensByChainId(ChainKeys.ARBITRUM_MAINNET), 'ETH');
const usdcHyper = bySymbol(sodax.swaps.getSupportedSwapTokensByChainId(ChainKeys.HYPEREVM_MAINNET), 'USDC');

const inputAmount = 10n ** BigInt(eth.decimals) / 10n; // 0.1 ETH

const quoteResult = await sodax.swaps.getQuote({
  token_src: eth.address,
  token_dst: usdcHyper.address,
  token_src_blockchain_id: ChainKeys.ARBITRUM_MAINNET,
  token_dst_blockchain_id: ChainKeys.HYPEREVM_MAINNET,
  amount: inputAmount,
  quote_type: 'exact_input',
});
if (!quoteResult.ok) throw new Error('Quote failed');

const deadlineResult = await sodax.swaps.getSwapDeadline(300n);
if (!deadlineResult.ok) throw new Error('Deadline lookup failed');

const result = await sodax.swaps.swap({
  params: {
    inputToken: eth.address,
    outputToken: usdcHyper.address,             // HyperCore credits USDC only
    inputAmount,
    minOutputAmount: (quoteResult.value.quoted_amount * 99n) / 100n,
    deadline: deadlineResult.value,
    allowPartialFill: false,
    srcChainKey: ChainKeys.ARBITRUM_MAINNET,
    dstChainKey: ChainKeys.HYPEREVM_MAINNET,
    srcAddress: await arbitrumWalletProvider.getWalletAddress(),
    dstAddress: traderAddress,                  // the account credited on HyperCore
    solver: '0x0000000000000000000000000000000000000000',
    data: '0x',
    hook: { kind: HookKind.HYPERCORE_DEPOSIT }, // deposit into HyperCore instead of the wallet
  },
  walletProvider: arbitrumWalletProvider, // EvmWalletProvider for Arbitrum, the source network
});
```

With `hook` set, `dstAddress` keeps its plain meaning: the account being credited. The SDK looks up the hook's deployed address on HyperEVM, makes it the real delivery target, and encodes `dstAddress` into the payload the hook reads. A few rules:

* **USDC only.** The hook's registry entry accepts HyperEVM USDC as the delivered token. Check a token before you offer the option with `isHookSupportedToken(ChainKeys.HYPEREVM_MAINNET, HookKind.HYPERCORE_DEPOSIT, token.address)`.
* **Never the zero address.** The SDK rejects a zero `dstAddress` when a hook is set, because the delivery could not be recovered on arrival.
* **Quote as usual.** The quote is the same USDC-to-HyperEVM quote; the hook only changes where the output goes on arrival.

## 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.