> ## Documentation Index
> Fetch the complete documentation index at: https://shield.fi/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Swap with the TypeScript SDK

> Plan, submit, claim, and recover private swaps with the TypeScript SDK.

A Shield Swap trade has two transactions. The request spends the input record and writes a pending output. The claim delivers the output and any unspent input as token records.

Treat both transactions as one workflow. The user's trade is settled after the claim is accepted and the returned records are available.

## Plan the route

`planSwap` resolves token metadata, requests a route and quote, checks each pool against current chain controls, applies a slippage floor, and fetches the required program imports.

```typescript theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
import { parseUnits } from "@provablehq/shield-swap-sdk"

const from = await client.tokenData("USDCx")
const plan = await client.planSwap({
  from: from.id,
  to: "ETH",
  amountIn: parseUnits("1.5", from.decimals),
  slippageBps: 50,
})
```

Amounts passed to transaction actions are raw base units. `50` basis points means 0.5 percent slippage.

## Submit the request

Use `swap` for one pool and `swapMultiHop` for a route with two or more pools.

```typescript theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
const handle = plan.multiHop
  ? await client.swapMultiHop({
      poolKeys: plan.poolKeys,
      tokenInId: plan.from.id,
      amountIn: plan.amountIn,
      expectedOut: plan.expectedOut,
      slippageBps: plan.slippageBps,
      imports: plan.imports,
    })
  : await client.swap({
      poolKey: plan.poolKeys[0]!,
      tokenInId: plan.from.id,
      amountIn: plan.amountIn,
      expectedOut: plan.expectedOut,
      slippageBps: plan.slippageBps,
      imports: plan.imports,
    })
```

The returned handle contains the data required for the claim. A local client with `fileBlindedIdentityStore` records it before the action returns. If you do not use that store, persist the handle in your own database before leaving the request flow.

Do not submit another request because a confirmation wait timed out. Check the transaction and mapping state first. A second submission can spend another record and create another trade.

## Claim the output

The pending output becomes readable after the request finalizes. Both route types use `claimSwapOutput`.

```typescript theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
import { SwapOutputNotFinalizedError } from "@provablehq/shield-swap-sdk"

async function claimWhenReady() {
  for (let attempt = 0; attempt < 20; attempt++) {
    try {
      return await client.claimSwapOutput({
        handle,
        imports: plan.imports,
      })
    } catch (error) {
      if (!(error instanceof SwapOutputNotFinalizedError)) throw error
      await new Promise((resolve) => setTimeout(resolve, 15_000))
    }
  }

  throw new Error("swap output is still pending")
}

const claim = await claimWhenReady()
console.log(claim.amountOut, claim.amountRemaining)
```

`amountOut` is the received output. `amountRemaining` is the unused portion of the original input. Wrapped assets are paid out as records of the underlying asset.

For a multi-hop route, each later hop must consume its intermediate input. A partial fill in a later hop rejects the route. Only unused original input can appear as the final refund.

## Recover pending claims

Long-running local clients should inspect the configured identity store after startup.

```typescript theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
const pending = await client.getUnclaimedSwaps()

for (const swap of pending.swaps) {
  if (!swap.handle) continue

  await client.claimSwapOutput({
    handle: swap.handle,
    imports,
  })
}
```

`getUnclaimedSwaps` reads `swap_outputs` from chain. It returns per-token totals and handles that can be claimed from the store alone. Older records without a complete handle may require `reconcileSwapHistory()`.

## Run concurrent swaps safely

The composed client reserves a distinct confidential address for each local swap. Use one store and one writer for each local account. A file store protects reservations across restarts, but it does not coordinate multiple processes or machines.

Input token records are a separate source of contention. Two concurrent swaps cannot spend the same record. Using different input tokens avoids that collision. For the same token, serialize record selection and submission or reserve distinct records in your own transaction queue.

A connected wallet manages its own confidential addresses and record requests. Follow the wallet's pending-transaction model and wait for a terminal state before reusing any record.

See [Trader workflow](../trading/trader-workflow), [output claims and refunds](../trading/output-claims-and-refunds), and [failures and recovery](../trading/failures-and-recovery) for the protocol rules behind these actions.
