---
name: sodax
description: >-
  Entry point for building on SODAX, the cross-chain DeFi hub on Sonic —
  intent-based swaps, money-market lend/borrow, direct bridging, SODA/xSODA
  staking, DEX, leverage-yield, and ICX/bnUSD/BALN migration via `@sodax/sdk`,
  `@sodax/dapp-kit`, `@sodax/wallet-sdk-core`, and `@sodax/wallet-sdk-react`.
  Routes the task to the right granular `sodax-*` skill and supplies chain keys,
  the `Result<T, SodaxError>` model, and the gotchas that cause silent failures.
  Start here for any SODAX task — including single-chain SODAX actions such as
  supplying to the money market on one chain — whenever the task mentions SODAX,
  Sonic spokes, solvers or intents, xSODA, bnUSD, or moves value across EVM,
  Solana, Sui, Stellar, Bitcoin, Injective, NEAR, ICON, Stacks, HyperEVM,
  Hedera, or Kaia from one wallet. Do not load for chain work that does not
  involve SODAX.
license: MIT
compatibility: >-
  Requires Node 22.12+ (the `@sodax/sdk` engines floor) and any JS package
  manager (npm/pnpm/yarn/bun). Fetches current examples from docs.sodax.com when
  network access is available; behaviour degrades gracefully with cached shape
  only.
metadata:
  version: '2.1.0'
  author: sodax
---

# SODAX (umbrella)

Self-contained entry point for AI coding agents building on SODAX. Routes tasks to the right granular `sodax-*` skill and supplies chain keys, the `Result<T, SodaxError>` model, and the gotchas that cause silent failures. This umbrella gives you the shape; the docs (`docs.sodax.com`) and granular skills are the source of truth for runnable code.

## Read before writing any code

Six hard-failure gotchas. Every SODAX integration hits at least one of these.

1. **`await sodax.config.initialize()` is mandatory** before any config-driven lookup. Otherwise `findSupportedTokenBySymbol` returns `undefined`.
2. **`raw` discriminates the payload.** `{ raw: false, walletProvider }` for signing, `{ raw: true }` for unsigned. Passing `walletProvider` with `raw: true` fails to compile; forgetting `raw: false` on a signed call rejects `walletProvider`.
3. **`deadline` is Unix seconds, not milliseconds.** Use `BigInt(Math.floor(Date.now() / 1000) + 300)`.
4. **`sodax.moneyMarket.data` is a sub-namespace.** Use `sodax.moneyMarket.data.getReservesHumanized()`, not `sodax.moneyMarket.getReservesHumanized()`.
5. **Reserve-data pipeline order matters.** `getReservesHumanized` → `buildReserveDataWithPrice` → `formatReservesUSD` → `buildUserSummaryRequest` → `formatUserSummary`. Skipping the intermediate builds throws.
6. **`Result<T, E>` is checked on `result.ok`, not caught.** Never `try/catch` a Result-returning service call. Never branch on `error.message`. Discriminate on the narrow `error.code` union. Not every method is Result-wrapped: synchronous getters return their value directly (`sodax.config.getChains()`, `sodax.config.findSupportedTokenBySymbol(...)`, `sodax.leverageYield.getVault(name)`), and `sodax.hubProvider.getUserHubWalletAddress(...)` is async but resolves to a plain `Address`. Mind the name collisions: `sodax.swaps.getPartnerFee(bigint)` is synchronous and returns `bigint`, while `sodax.api.swaps.getPartnerFee(query)` is async and Result-wrapped.

**Key handling:** read private keys from environment variables only. Never hardcode, never log, never send to an external API.

## Canonical agent references

- **AI Integration Guide** — [docs.sodax.com/ai-integration-guide.md](https://docs.sodax.com/ai-integration-guide.md) — canonical entry for agents. Explains the `@sodax/skills` bundle (one mode-gated broad skill per `@sodax/*` package, four packages in all, each bundling two knowledge subtrees: `integration/knowledge/` for new v2 code and `migration-v1-to-v2/knowledge/` for v1→v2 porting, plus the `sodax-build` front-door skill when the package isn't chosen yet).
- **Documentation index (LLM-friendly)** — [docs.sodax.com/llms.txt](https://docs.sodax.com/llms.txt) — full page list. Fetch first when discovering topics.
- **API & SDK stack overview** — [docs.sodax.com/home/sdk-stack.md](https://docs.sodax.com/home/sdk-stack.md) — routes to the HTTP API or the open-source SDK. Both hit the same execution layer.
- **`@sodax/skills` package (GitHub source)** — [github.com/icon-project/sodax-sdks/tree/main/packages/skills](https://github.com/icon-project/sodax-sdks/tree/main/packages/skills)

## Identity

SODAX is a cross-chain DeFi hub, mainnet-only (no testnet chains or RPC endpoints). Sonic is the hub; 21 spoke chains connect to it. From one wallet on any supported chain a user can swap, lend, borrow, bridge, stake SODA, or migrate ICON-era assets to a new spoke.

**Non-custodial by design.** SODAX is protocol and software: it routes and settles. Independent solvers on an open marketplace fill intents. Never write "our solver", "the SODAX solver", "SODAX trades", "SODAX takes custody", or "SODAX fills orders" — those are inaccurate.

The SDK is intent-based: the user signs on a spoke, the SDK relays to Sonic, a solver or hub contract fulfills, and settlement lands on the destination chain. Feature-service methods return `Result<T, SodaxError>`; see Result and error handling for the direct-return helpers and `balnSwapService` exceptions that do not. For React frontends, prefer `@sodax/dapp-kit` hooks over calling `@sodax/sdk` directly.

## Install

Two integration surfaces (both hit the same execution layer — see the [API & SDK stack overview](https://docs.sodax.com/home/sdk-stack.md)):

### HTTP API — any language

Partner REST endpoints. Overview: [docs.sodax.com/developers/http-api.md](https://docs.sodax.com/developers/http-api.md). Pick this if you're not on TypeScript or you want a thin wire integration. Route directly to the sub-endpoint that matches the task:

| Sub-API | Endpoint prefix | Docs |
|---|---|---|
| Swaps (quote / build-intent / submit-tx / status) | `/v1/swaps/*` | [docs.sodax.com/developers/http-api/swaps.md](https://docs.sodax.com/developers/http-api/swaps.md) |
| Leverage yield vaults over HTTP | `/v1/leverage-yield/*` | [docs.sodax.com/developers/http-api/leverage.md](https://docs.sodax.com/developers/http-api/leverage.md) |
| Oracle candles + solver oracle prices | — | [docs.sodax.com/developers/http-api/oracle.md](https://docs.sodax.com/developers/http-api/oracle.md) |
| Protocol stats (networks / partners / volume / supply) | — | [docs.sodax.com/developers/http-api/stats.md](https://docs.sodax.com/developers/http-api/stats.md) |
| Stellar account sponsoring | `/v1/sponsorships/*` (API key required) | [docs.sodax.com/developers/how-to/stellar-sponsoring-getting-started.md](https://docs.sodax.com/developers/how-to/stellar-sponsoring-getting-started.md) |

Shared conventions (BigInts as decimal strings, error shape at the edge, caching): see the HTTP API root page.

API keys and partner fees: [docs.sodax.com/developers/how-to/api-keys.md](https://docs.sodax.com/developers/how-to/api-keys.md) · [docs.sodax.com/developers/how-to/monetize_sdk.md](https://docs.sodax.com/developers/how-to/monetize_sdk.md).

### Open-source SDK — TypeScript

Overview: [docs.sodax.com/developers/packages.md](https://docs.sodax.com/developers/packages.md). Three layers across four packages:

| Layer | Package | Docs |
|---|---|---|
| Foundation (core services + types) | `@sodax/sdk` | [docs.sodax.com/developers/packages/foundation/sdk/index.md](https://docs.sodax.com/developers/packages/foundation/sdk/index.md) |
| Connection — wallet providers (Node / non-React) | `@sodax/wallet-sdk-core` | [docs.sodax.com/developers/packages/connection/wallet-sdk-core.md](https://docs.sodax.com/developers/packages/connection/wallet-sdk-core.md) |
| Connection — React adapter (context, state) | `@sodax/wallet-sdk-react` | [docs.sodax.com/developers/packages/connection/wallet-sdk-react.md](https://docs.sodax.com/developers/packages/connection/wallet-sdk-react.md) |
| Experience — React hooks over the SDK | `@sodax/dapp-kit` | [docs.sodax.com/developers/packages/experience/dapp-kit.md](https://docs.sodax.com/developers/packages/experience/dapp-kit.md) |

Install with your JS package manager (npm / pnpm / yarn / bun):

- Core: `@sodax/sdk`
- React dapps: also `@sodax/dapp-kit` + `@sodax/wallet-sdk-react`
- Backend / Node signing without a browser wallet: also `@sodax/wallet-sdk-core`

Roles:

- `@sodax/sdk` core services (`sodax.swaps`, `sodax.moneyMarket`, `sodax.bridge`, `sodax.staking`, `sodax.dex`, `sodax.leverageYield`, `sodax.migration`, `sodax.partners`, `sodax.recovery`, `sodax.sponsoring`, `sodax.config`, `sodax.api`). Re-exports every `@sodax/types` symbol; do not install `@sodax/types` separately.
- `@sodax/dapp-kit` React hooks wrapping the SDK (`useSwap`, `useSupply`, `useBridge`, etc.).
- `@sodax/wallet-sdk-core` chain-specific `I*WalletProvider` implementations for Node / backend / non-React.
- `@sodax/wallet-sdk-react` React wallet connect layer (`useWalletProvider`, wallet-modal, WalletConnect).

## Route by intent

Pick the row that matches the user's task. Load the named granular skill for depth; this umbrella covers the fast path.

| Intent | Where to go next |
|---|---|
| Not sure what to build | `sodax-build` (guided interview, produces brief) |
| Backend, script, indexer, bot, non-React swap / bridge / lend / stake | `sodax-sdk` (broad) or `sodax-sdk/<feature>` if the feature is fixed |
| One SDK feature only (swap, money-market, bridge, staking, dex, leverage-yield, migration, partner, recovery, sponsoring, backend-api, swaps-api, leverage-yield-api, bridge-api) | `sodax-sdk/<feature>` |
| React dapp with hooks | `sodax-wallet-sdk-react` then `sodax-dapp-kit` (or the feature-specific `sodax-dapp-kit/<feature>`) |
| React dapp calling SDK directly (no dapp-kit) | `sodax-wallet-sdk-react` then `sodax-sdk` |
| Backend needs one chain's wallet | `sodax-wallet-sdk-core/<chain>` then `sodax-sdk/<feature>` |
| React wallet concern only (connect button, modal, chain switch, sign message, WalletConnect) | `sodax-wallet-sdk-react/<concern>` |
| Porting an existing v1 dapp | `sodax-wallet-sdk-react` (migration) then `sodax-dapp-kit` (migration) then `sodax-sdk` (migration) |
| Porting an existing v1 backend | `sodax-sdk` (migration) then `sodax-wallet-sdk-core` (migration; usually a no-op) |

If both migration and new features are in play, do migration first. Otherwise stale v1 patterns leak into new code.

## Bootstrap once

The SDK is constructed once and reused. Minimal form (`new Sodax()`) uses packaged defaults for hub + spoke RPCs with no failover. **Production form (recommended) passes `{ hub: { rpcUrls: [...] }, chains: { [ChainKeys.X]: { rpcUrls: [...] } } }`** for multi-endpoint failover. Same rotation shape for the hub (Sonic) and every spoke chain you touch. Call `await sodax.config.initialize()` before any config-driven lookup — it loads fresh config, is idempotent, and falls back to packaged defaults.

**Canonical example (kept current with the SDK):**
- Docs — [Bootstrap + SDK surface](https://docs.sodax.com/developers/packages/foundation/sdk.md)
- Granular skill — [`sodax-sdk/SKILL.md`](https://raw.githubusercontent.com/icon-project/sodax-sdks/main/packages/skills/skills/sodax-sdk/SKILL.md)

**Config-driven token lookup:** use `sodax.config.findSupportedTokenBySymbol(chainKey, symbol)`. Do not hand-construct `XToken`. Sanity-check chain keys with `sodax.config.isValidSpokeChainKey(...)`.

Every feature service is wired after construction: `sodax.swaps`, `sodax.moneyMarket`, `sodax.bridge`, `sodax.staking`, `sodax.dex`, `sodax.leverageYield`, `sodax.migration`, `sodax.partners`, `sodax.recovery`, `sodax.sponsoring`, `sodax.config`, `sodax.api`, `sodax.hubProvider`, `sodax.spoke`.

Version-gated behaviour lives in **Version notes** at the bottom of this skill.

## Wallet providers

Methods that sign take a `walletProvider` matching the source chain family. The `srcChainKey` on the payload narrows its type at compile time. Read methods (`sodax.config.*`, `sodax.bridge.getBridgeableAmount`, `sodax.staking.getStakingConfig`, quotes) and `raw: true` flows need no provider.

Node / backend (private-key, via `@sodax/wallet-sdk-core`) — one `I*WalletProvider` class per chain family. Constructor field conventions vary per chain (EVM: `privateKey` + `chainId` + `rpcUrl`; Solana: 64-byte `privateKey` + `endpoint`; Sui: `mnemonics` only; Bitcoin / Stellar: uppercase `type: 'PRIVATE_KEY'` + network; ICON / NEAR / Stacks: `privateKey` + `rpcUrl`/`endpoint` + optional `accountId`; Injective: nested `secret: { privateKey | mnemonics }`).

Browser / React — construct with a supplied client/adapter instead of a private key (EVM: viem wallet+public clients; Solana: adapter context with `publicKey` + `signTransaction`; Sui: wallet-standard client). In a React dapp, prefer the umbrella hook `useWalletProvider({ xChainId })` from `@sodax/wallet-sdk-react`.

**Canonical examples (per chain, kept current):**
- Docs — [Solana wallets](https://docs.sodax.com/solana/wallets.md) (pattern generalizes to every chain family)
- Granular skills — [`sodax-wallet-sdk-core/SKILL.md`](https://raw.githubusercontent.com/icon-project/sodax-sdks/main/packages/skills/skills/sodax-wallet-sdk-core/SKILL.md) with per-chain subskills: [evm](https://raw.githubusercontent.com/icon-project/sodax-sdks/main/packages/skills/skills/sodax-wallet-sdk-core/evm/SKILL.md) · [solana](https://raw.githubusercontent.com/icon-project/sodax-sdks/main/packages/skills/skills/sodax-wallet-sdk-core/solana/SKILL.md) · [sui](https://raw.githubusercontent.com/icon-project/sodax-sdks/main/packages/skills/skills/sodax-wallet-sdk-core/sui/SKILL.md) · [bitcoin](https://raw.githubusercontent.com/icon-project/sodax-sdks/main/packages/skills/skills/sodax-wallet-sdk-core/bitcoin/SKILL.md) · [stellar](https://raw.githubusercontent.com/icon-project/sodax-sdks/main/packages/skills/skills/sodax-wallet-sdk-core/stellar/SKILL.md) · [icon](https://raw.githubusercontent.com/icon-project/sodax-sdks/main/packages/skills/skills/sodax-wallet-sdk-core/icon/SKILL.md) · [injective](https://raw.githubusercontent.com/icon-project/sodax-sdks/main/packages/skills/skills/sodax-wallet-sdk-core/injective/SKILL.md) · [near](https://raw.githubusercontent.com/icon-project/sodax-sdks/main/packages/skills/skills/sodax-wallet-sdk-core/near/SKILL.md) · [stacks](https://raw.githubusercontent.com/icon-project/sodax-sdks/main/packages/skills/skills/sodax-wallet-sdk-core/stacks/SKILL.md)
- React — [`sodax-wallet-sdk-react/SKILL.md`](https://raw.githubusercontent.com/icon-project/sodax-sdks/main/packages/skills/skills/sodax-wallet-sdk-react/SKILL.md)

## Common flows

Every signed call takes the discriminator `{ raw: false, walletProvider }`. For unsigned-tx (Gnosis Safe, HW wallet, custom relay) use `{ raw: true }`; passing `walletProvider` alongside `raw: true` is a compile error.

### 1. Cross-chain swap (spoke to spoke)

Optional read-only preview via `sodax.swaps.getQuote(...)` — returns `{ ok, value: { quoted_amount, ... } }`. Then `sodax.swaps.swap({ params, raw: false, walletProvider })` with `params: CreateIntentParams` — needs `srcChainKey`, `dstChainKey`, `srcAddress`, `dstAddress`, `inputToken` (address, not `XToken` object), `outputToken` (address), `inputAmount`, `minOutputAmount` (from `quote.value.quoted_amount` × slippage), `deadline` (**Unix seconds, not ms**), `allowPartialFill`, `solver` (zero address = auto), `data` (`'0x'` unless custom). On success returns `{ solverExecutionResponse, intent, intentDeliveryInfo }`.

- Docs — [Swaps (Solver)](https://docs.sodax.com/developers/packages/foundation/sdk/functional-modules/swaps.md)
- Granular skill — [`sodax-sdk/swap/SKILL.md`](https://raw.githubusercontent.com/icon-project/sodax-sdks/main/packages/skills/skills/sodax-sdk/swap/SKILL.md)

### 2. Money market supply (single chain, or cross-chain via the same params shape)

`sodax.moneyMarket.supply({ params: { srcChainKey, srcAddress, token, amount, action: 'supply' }, raw: false, walletProvider })`. Returns `{ srcChainTxHash, dstChainTxHash }`. Solana, Sui, Stellar, Bitcoin, ICON, Injective, NEAR, Stacks do NOT need allowance/approve. On EVM sources, gate with `isAllowanceValid` and call `approve` first.

- Docs — [Lend / Borrow (Money Market)](https://docs.sodax.com/developers/packages/foundation/sdk/functional-modules/money_market.md)
- Granular skill — [`sodax-sdk/money-market/SKILL.md`](https://raw.githubusercontent.com/icon-project/sodax-sdks/main/packages/skills/skills/sodax-sdk/money-market/SKILL.md)

### 3. Money market borrow to another chain

Same as supply, but `action: 'borrow'` plus `dstChainKey` + `dstAddress` for cross-chain delivery. Omit `dstChainKey`/`dstAddress` for a same-chain borrow.

- Docs — [Lend / Borrow (Money Market)](https://docs.sodax.com/developers/packages/foundation/sdk/functional-modules/money_market.md)
- Granular skill — [`sodax-sdk/money-market/SKILL.md`](https://raw.githubusercontent.com/icon-project/sodax-sdks/main/packages/skills/skills/sodax-sdk/money-market/SKILL.md)

### 4. Money market reserves + user position (formatted USD summary)

Four-step pipeline living on the `sodax.moneyMarket.data` sub-namespace (**not** on `sodax.moneyMarket` directly). Order matters: `getReservesHumanized` + `getUserReservesHumanized(userHubAddress)` → `buildReserveDataWithPrice(reserves)` → `formatReservesUSD(request)` → `buildUserSummaryRequest(reserves, formattedReserves, userReserves)` → `formatUserSummary(request)`. Output includes `totalCollateralUSD`, `totalBorrowsUSD`, `netWorthUSD`, `healthFactor`, `availableBorrowsUSD`. Get the user hub address via `sodax.hubProvider.getUserHubWalletAddress(userAddress, srcChainKey)` — it resolves to the address itself, not a `Result`. aToken balances: `sodax.moneyMarket.data.getATokensBalances(aTokens, userHubAddress) → Map<Address, bigint>`. Aave RAY (27-decimal) precision is preserved; use formatted responses for display, raw for on-chain math.

- Docs — [Lend / Borrow (Money Market)](https://docs.sodax.com/developers/packages/foundation/sdk/functional-modules/money_market.md)
- Granular skill — [`sodax-sdk/money-market/SKILL.md`](https://raw.githubusercontent.com/icon-project/sodax-sdks/main/packages/skills/skills/sodax-sdk/money-market/SKILL.md)

### 5. SODA staking (stake, unstake, claim)

`sodax.staking.stake({ params: { srcChainKey, srcAddress, amount, minReceive (xSODA slippage floor), action: 'stake' }, raw: false, walletProvider })`. `unstake` uses `action: 'unstake'` with the xSODA amount. `claim` (after unstaking period) needs a `requestId` (source it from `getUnstakingInfoWithPenalty` or the staking data API). Read the penalty curve before UI with `sodax.staking.getUnstakingInfoWithPenalty(user, chainKey)`. `getStakeRatio(amount) → [xSodaAmount, previewDepositAmount]`. `instantUnstake` skips the waiting period at a slippage cost via `StakingRouter`.

- Docs — [Staking (SODA asset)](https://docs.sodax.com/developers/packages/foundation/sdk/functional-modules/staking.md)
- Granular skill — [`sodax-sdk/staking/SKILL.md`](https://raw.githubusercontent.com/icon-project/sodax-sdks/main/packages/skills/skills/sodax-sdk/staking/SKILL.md)

### 6. Direct bridge (asset transfer between two spokes)

`sodax.bridge.bridge({ params: { srcChainKey, srcAddress, srcToken, amount, dstChainKey, dstToken, recipient }, raw: false, walletProvider })`. **Preflight gates:** `sodax.bridge.isBridgeable({ from, to })` (must be true — tokens sharing a hub vault bridge to each other; different-vault tokens do not, use swap instead) and `sodax.bridge.getBridgeableAmount(from, to)` for the current limit. Vaults are the bridgeability unit.

- Docs — [Bridge](https://docs.sodax.com/developers/packages/foundation/sdk/functional-modules/bridge.md)
- Granular skill — [`sodax-sdk/bridge/SKILL.md`](https://raw.githubusercontent.com/icon-project/sodax-sdks/main/packages/skills/skills/sodax-sdk/bridge/SKILL.md)

### 7. Migration: bnUSD (legacy ICON to new EVM bnUSD)

`sodax.migration.migratebnUSD({ params: { srcChainKey, srcAddress, srcbnUSD, dstChainKey, dstbnUSD, amount, dstAddress }, raw: false, walletProvider })`. ICX and BALN migrations use their own param types (`IcxMigrateParams`, `BalnMigrateParams`) and are not generic over `K`. `sodax.migration.balnSwapService.*` lock-management methods (`stake`, `unstake`, `claim`, `cancelUnstake`, `getDetailedUserLocks`) **still throw** rather than return `Result<T>` (tech debt) — wrap in `try / catch`.

- Docs — [Migration](https://docs.sodax.com/developers/packages/foundation/sdk/functional-modules/migration.md)
- Granular skill — [`sodax-sdk/migration/SKILL.md`](https://raw.githubusercontent.com/icon-project/sodax-sdks/main/packages/skills/skills/sodax-sdk/migration/SKILL.md)

### 8. Partner fees

`PartnerService` exposes operations on `sodax.partners.feeClaim`. Hub chain key (`'sonic'`) is required. Flow: (1) `isTokenApproved({ srcChainKey: 'sonic', srcAddress: partnerAddress, token })`; (2) `approveToken(...)` if not; (3) `setSwapPreference(...)` to set the auto-swap target asset for collected fees; (4) per-action override at swap time via `extras: { partnerFee: { address, percentage } }` on `sodax.swaps.swap`. Same-token claims (output equals fee token) are rejected up front with `VALIDATION_FAILED` — bridge the wrapped hub asset off Sonic instead via `sodax.bridge.bridge(...)`.

- Granular skill — [`sodax-sdk/partner/SKILL.md`](https://raw.githubusercontent.com/icon-project/sodax-sdks/main/packages/skills/skills/sodax-sdk/partner/SKILL.md)

## ChainKey reference

The canonical spoke chain keys (`import { ChainKeys } from '@sodax/sdk';`). Keep this table inline — string values are unguessable and hallucinated constantly.

| ChainKey | String |
|---|---|
| `SONIC_MAINNET` (hub) | `'sonic'` |
| `ETHEREUM_MAINNET` | `'ethereum'` |
| `ARBITRUM_MAINNET` | `'0xa4b1.arbitrum'` |
| `BASE_MAINNET` | `'0x2105.base'` |
| `BSC_MAINNET` | `'0x38.bsc'` |
| `OPTIMISM_MAINNET` | `'0xa.optimism'` |
| `POLYGON_MAINNET` | `'0x89.polygon'` |
| `AVALANCHE_MAINNET` | `'0xa86a.avax'` |
| `HYPEREVM_MAINNET` | `'hyper'` |
| `LIGHTLINK_MAINNET` | `'lightlink'` |
| `REDBELLY_MAINNET` | `'redbelly'` |
| `KAIA_MAINNET` | `'0x2019.kaia'` |
| `HEDERA_MAINNET` | `'hedera'` |
| `ROBINHOOD_MAINNET` | `'robinhood'` |
| `INJECTIVE_MAINNET` | `'injective-1'` |
| `ICON_MAINNET` | `'0x1.icon'` |
| `SUI_MAINNET` | `'sui'` |
| `SOLANA_MAINNET` | `'solana'` |
| `STELLAR_MAINNET` | `'stellar'` |
| `NEAR_MAINNET` | `'near'` |
| `BITCOIN_MAINNET` | `'bitcoin'` |
| `STACKS_MAINNET` | `'stacks'` |

`ChainTypeArr`: `'ICON' | 'EVM' | 'INJECTIVE' | 'SUI' | 'STELLAR' | 'SOLANA' | 'STACKS' | 'NEAR' | 'BITCOIN'`.

## Result and error handling

Feature-service methods (swaps, money market, bridge, staking, dex, leverage-yield, migration except `balnSwapService`) return `Promise<Result<T, SodaxError>>`. Branch on `result.ok` before touching `result.value` (success) or `result.error` (failure); nothing throws across those service boundaries. That contract does **not** extend to direct-return helpers — `sodax.hubProvider.getUserHubWalletAddress` resolves to the hub address itself and the synchronous `sodax.config.*` getters return their value, so do not read `.ok` / `.value` on either — nor to `sodax.migration.balnSwapService`, which still throws. Use `isSodaxError(e)` (not bare `instanceof`) across bundle boundaries.

**`SodaxErrorCode` (full set):** `USER_REJECTED | VALIDATION_FAILED | INTENT_CREATION_FAILED | EXECUTION_FAILED | TX_VERIFICATION_FAILED | TX_SUBMIT_FAILED | RELAY_TIMEOUT | RELAY_FAILED | APPROVE_FAILED | ALLOWANCE_CHECK_FAILED | GAS_ESTIMATION_FAILED | LOOKUP_FAILED | EXTERNAL_API_ERROR | UNKNOWN`.

**Feature tags (`SodaxFeature`, on `e.feature`):** `swap | moneyMarket | bridge | staking | migration | dex | partner | recovery | backend | sponsoring | leverageYield`.

**Context fields:** carry the discriminator you actually need in a handler — `action` (`'supply'`, `'stake'`, `'migrateBaln'`, ...), `phase` (`validate | intentCreation | verify | submit | relay | destinationExecution | execution | postExecution | approve | allowanceCheck | gasEstimation | lookup`), `srcChainKey`, `dstChainKey`, `relayCode` (`SUBMIT_TX_FAILED | RELAY_TIMEOUT | RELAY_POLLING_FAILED | UNKNOWN`), `api` (`solver | backend | swaps | sponsoring`), `method`, `field`, `reason`. **Solver read-side errors** (`sodax.swaps.getQuote`) return a different shape (`SolverErrorResponse`) — read `error.detail.code` / `error.detail.message`.

**Canonical error-handling example (switch-per-code pattern):**
- Granular skill — [`sodax-sdk/SKILL.md`](https://raw.githubusercontent.com/icon-project/sodax-sdks/main/packages/skills/skills/sodax-sdk/SKILL.md) (Result / error section)

## Gotchas

Full list (the top six are promoted to **Read before writing any code** above).

- **`await sodax.config.initialize()` is mandatory before any config-driven lookup.**
- **`srcChainKey` narrows `walletProvider` at compile time.** Passing a Solana wallet with `ChainKeys.ARBITRUM_MAINNET` is a TypeScript error. Cast EVM addresses at the boundary: `(await wp.getWalletAddress()) as \`0x${string}\``.
- **`raw` discriminates the payload.** `{ raw: false, walletProvider }` for signing, `{ raw: true }` for unsigned.
- **`deadline` is Unix seconds, not milliseconds.** Use `BigInt(Math.floor(Date.now() / 1000) + 300)`.
- **No allowances on Solana, Sui, Stellar, Bitcoin, ICON, Injective, NEAR, Stacks.** Only EVM sources gate through `isAllowanceValid` + `approve`.
- **`sodax.moneyMarket.data` is a sub-namespace.**
- **Reserve-data pipeline order matters.** `getReservesHumanized` → `buildReserveDataWithPrice` → `formatReservesUSD` → `buildUserSummaryRequest` → `formatUserSummary`.
- **Solana intents via `createIntent + submit` need relay extra data.** The one-shot `sodax.swaps.swap(...)` handles it. If splitting for a backend flow, submit `relayData.payload` (a string) to `sodax.api.swaps.submitTx`, not the full `relayData` object.
- **Same-token partner-fee claim is validated closed.** Bridge the wrapped hub asset off Sonic; do not `createIntentAutoSwap` with the fee token as output.
- **`sodax.config` is the only source of truth for config after overrides.** Direct imports of `spokeChainConfig` / `sodaxConfig` from `@sodax/types` / `@sodax/sdk` are packaged-default snapshots and miss both `initialize()` updates and `new Sodax(config)` overrides.
- **Cross-chain destination quirks.** Stellar destinations need a trustline set for the receiving asset. NEAR needs NEP-141 storage registration. Bitcoin uses PSBT.
- **Supplied collateral on money market is NOT counted twice for TVL.** Explain to the user if they see MM supplied assets alongside vault TVL and expect double-counting.
- **`sodax.hubProvider.getUserHubWalletAddress` resolves to an address**, not `Result<T>`. Await it and use the value; do not branch on `.ok`.
- **`getPartnerFee` exists twice.** `sodax.swaps.getPartnerFee(inputAmount: bigint): bigint` is synchronous; `sodax.api.swaps.getPartnerFee(query)` is async and Result-wrapped. Same for `getSupportedSwapTokens` on `sodax.config` and `sodax.swaps`.
- **`sodax.migration.balnSwapService` still throws.** Wrap `claim`, `claimUnstaked`, `stake`, `unstake`, `cancelUnstake`, `getDetailedUserLocks` in `try / catch`; every other migration method returns `Result<T>`.

## Verify

Read-only smoke test (no wallet required): after `sodax.config.initialize()`, call `sodax.swaps.getQuote(...)` for a small SOL→USDC quote (Solana → Arbitrum). If `quote.value.quoted_amount` prints as a `bigint`, the SDK, config init, and solver connectivity are all working. If `!quote.ok`, read `quote.error.detail.message`.

- Docs — [Quickstart](https://docs.sodax.com/solana/quickstart.md) (has the runnable version)
- Granular skill — [`sodax-sdk/SKILL.md`](https://raw.githubusercontent.com/icon-project/sodax-sdks/main/packages/skills/skills/sodax-sdk/SKILL.md)

## Version notes

Version-gated behaviour and v1→v2 migration crosswalk. Refresh from source before relying on any specific version.

- **Multi-RPC failover** (`hub: { rpcUrls: [...] }` and per-chain `rpcUrls`): requires `@sodax/sdk >= 2.1.0-rc.3`. Without it, only single-endpoint construction is available.
- **`ROBINHOOD_MAINNET` (`'robinhood'`) is the newest spoke.** Present from `@sodax/sdk` 2.2.0-rc.1. Guard with `sodax.config.isValidSpokeChainKey(...)` if you must support older pins.
- **`ChainKeys` string values are stable across versions**; enum member names are v2. Do not use v1 `SONIC_MAINNET_CHAIN_ID` etc. Migration crosswalk lives in the v1-to-v2 knowledge subtree of `sodax-sdk`.
- **`sodax.migration.balnSwapService` methods still throw** rather than return `Result<T>` (tech debt tracked; every other migration method returns `Result<T>`).
- **`sodax.backendApi` is aliased as `sodax.api`.** Use `sodax.api` in new code.

## Docs & granular skills

- Full docs index: https://docs.sodax.com/llms.txt
- Granular skill trees on GitHub: https://github.com/icon-project/sodax-sdks/tree/main/packages/skills/skills
- Ideation front-door: [`sodax-build/SKILL.md`](https://raw.githubusercontent.com/icon-project/sodax-sdks/main/packages/skills/skills/sodax-build/SKILL.md)

The intent table above and the per-flow pointers under each Common Flow route to the specific granular skill for depth.

## When SODAX is the wrong tool

Not for chain work that does not involve SODAX. For Solana-native swap-only, use Jupiter. For Solana-native lending, use Kamino, MarginFi, or Solend. For generic message-passing between chains, use Wormhole or LayerZero. For pure bridging without lending / swap / staking overlap, use deBridge or Across. If the user has explicitly named another SDK, defer to it; this skill does not substitute.
