# @circle-fin/swap-kit

## 1.3.1

### Patch Changes

- Fix same-chain swaps reporting `progress.status: 'FAILED'` (or `'PENDING'`) instead of `'DONE'` and dropping `amountOut`.

  A same-chain swap completes atomically in its source transaction, which is already confirmed (and checked for revert) before the result is returned. The provider now treats that as a terminal `'DONE'` and briefly polls the status endpoint (a short ~5s budget, returning early as soon as the amount lands) to enrich `amountOut`. Previously a slow, unresolved, or erroneous status response from the service could downgrade an already-successful swap to `'FAILED'`/`'PENDING'` and omit `amountOut`. If the amount is still unresolved when the budget elapses, `swap()` returns `'DONE'` without `amountOut` and the caller can fetch it later via `getSwapStatus`. Cross-chain swaps are unaffected — they still return `'PENDING'` and should be polled to completion with `getSwapStatus`/`waitForSwap`.

## 1.3.0

### Minor Changes

- Add cross-chain swap support to SwapKit, AppKit, and the Stablecoin Service swap provider.
  - `swap` and `estimate` can now route the output token to another supported chain with `to.chain`.
  - Cross-chain swaps can send the output to a recipient on the destination chain with `to.recipientAddress`.
  - `getSwapStatus` and `waitForSwap` can now track cross-chain swaps until they finish, including progress details for source and destination activity.
  - Swap estimates and results include `chainIn`, `chainOut`, and `progress` so apps can show where a swap started, where it will settle, and its current state.
  - Invalid transaction hashes or unsupported chain values are reported as structured validation errors before a status request is sent.

- Add `getTokenRates` to SwapKit and AppKit for fetching USD rates for tokens on a chain.
  - Look up rates by registered token symbol, native token alias (`NATIVE`, `ETH`, `POL`, etc.), raw EVM token address, or Solana mint.
  - Token symbols are resolved through the kit token registry for the requested chain.
  - Native tokens are normalized to the service native-token address before the request is sent.
  - Invalid token or chain values return structured validation errors instead of silently returning an empty rate map or surfacing a raw service error.
  - Each returned rate carries `priceUSD` and `fetchedAt`, plus an optional `decimals` (the token's on-chain precision) when the service reports it.

- **Behavioral change:** the re-exported `isRetryableError` no longer
  treats nonce errors (`4003` / `RPC_NONCE_ERROR`) as retryable.

  A nonce error is genuinely ambiguous — the transaction may already have
  been accepted (the nonce moved on), a concurrent transaction from the
  same key may have consumed the slot, or a local nonce tracker may have
  drifted. Generic automatic retry risks a double-spend or a
  nonce-conflict flip-flop, so `4003` was removed from
  `DEFAULT_RETRYABLE_ERROR_CODES` and callers must now decide explicitly
  whether to refresh the nonce and resubmit.

  For `@circle-fin/app-kit` specifically, the documented resume guard
  `if (isRetryableError(failedStep.error)) await kit.retryBridge(...)` now
  skips bridges that failed on a nonce error; handle code `4003` yourself
  if you want to refresh the nonce and retry.

### Patch Changes

- Canonicalize native-stablecoin token spellings across the swap path. On chains whose native gas token is USDC (e.g. Arc), the `NATIVE` symbol, the EIP-7528 sentinel (`0xEeee…`), and the zero address now all resolve to the USDC contract address. As a result, `NATIVE` and `USDC` are treated as the same asset (so `supportsRoute('NATIVE', 'USDC', Arc)` returns `false`), `getTokenDecimals` resolves native-alias addresses to the chain's native decimals without an on-chain call, and the service never receives a native spelling for what is already canonical as USDC. This is derived generically from chain metadata, so any future native-stablecoin chain is covered automatically. Behavior on all other chains is unchanged.

  `@circle-fin/app-kit`'s `send` now canonicalizes EVM native-alias address spellings (EIP-7528 sentinel `0xEeee…`, zero address) to `'NATIVE'` before routing. Without this, those addresses passed validation as custom token addresses and reached `token.transfer` (the ERC-20 rail) while `getTokenDecimals` returned 18-decimal native amounts — a decimals↔rail mismatch that reverts on Arc. After canonicalization both the rail (`native.transfer`) and the decimals (18) are consistent on EVM chains. On non-EVM chains, those EVM placeholder addresses are left to chain-specific token validation and rejected instead of being promoted to native transfers.

- Error traces from BridgeKit, SwapKit, and UnifiedBalanceKit now carry the
  most recent on-chain transaction hash known to the failing operation,
  when one is available. BridgeKit walks the result steps (including
  pending broadcasts whose receipt has not yet landed). SwapKit and
  UnifiedBalanceKit capture the broadcast hash through a new internal
  `onBroadcast` callback threaded into the swap operation and into the
  gateway provider's `spend()` (as a new optional `options` argument with
  a `SpendOptions.onBroadcast` field).

## 1.2.3

### Patch Changes

- Internal dependency updates. No user-facing changes.

## 1.2.2

### Patch Changes

- Internal dependency updates. No user-facing changes.

## 1.2.1

### Patch Changes

- Internal dependency updates. No user-facing changes.

## 1.2.0

### Minor Changes

- Add unhandled error telemetry reporting.
  - All kits now report unhandled errors to Circle's telemetry endpoint to aid reliability monitoring. Set `disableErrorReporting: true` in the kit config (or `AppKit` config) to opt out.
  - The following fields are included in each error report: error event type, SDK name and version, and where available: source chain name, destination chain name, and token symbol. Error messages, stack traces, wallet addresses, and transaction data are never sent.

## 1.1.1

### Patch Changes

- You can now reference cirBTC by its symbol when looking up tokens on Arc Testnet (e.g. when resolving swap inputs/outputs).
- The block explorer URLs returned in the Sei (mainnet and testnet) chain definitions now point to the current explorers. If you derive transaction or address links from `chain.blockExplorers`, your links will now resolve correctly.

## 1.1.0

### Minor Changes

- Add Arc Testnet support for swap operations.

### Patch Changes

- Fix computeFee callback in custom fee policies to always receive human-readable amounts when set via config, and correctly format stopLimit in swap results
- Swap operations that fail due to slippage or stop limit constraints now return a distinct retryable error instead of a fatal "route not found" error, making it easier to detect and recover by adjusting `slippageBps` or `stopLimit`
- Update HyperEVM mainnet explorer URL to resolve location-restricted access issues
- Improved search discoverability

## 1.0.3

### Patch Changes

- Add support for Solana as a forwarder destination

## 1.0.2

### Patch Changes

- Update HyperEVM explorer URLs to use the official Hyperliquid explorer

## 1.0.1

### Patch Changes

- Internal dependency updates. No user-facing changes.

## 1.0.0

### Major Changes

- Introducing SwapKit — a type-safe SDK for single-chain token swaps across EVM and Solana networks.

  Two-step workflow: `estimate()` to preview swap output and pricing, then `swap()` to execute.

  Key features:
  - Smart routing across DEX liquidity sources
  - 16 supported token aliases (USDC, EURC, USDT, PYUSD, DAI, USDE, WBTC, WETH, WSOL, and more), plus any ERC-20 or SPL token by contract address
  - Built-in ERC-20 allowance management with EIP-2612 permit support
  - Configurable slippage tolerance (default 3%)
  - Developer fee support with percentage-based or callback-based fee policies
  - Comprehensive error classification with type guards (`isRetryableError`, `isInputError`, `isBalanceError`)
  - Works with all existing adapters (Viem, Ethers, Solana, Solana Kit, Circle Wallets)
