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

> Submit a quoted trade and claim the output in the Shield Swap app or with the SDKs or CLI.

<div className="shield-trade-switch not-prose" role="group" aria-label="Trading guide audience">
  <button type="button" id="trade-developers-option" data-trade-select="developers" aria-pressed="true" aria-controls="developers">Developers</button>
  <button type="button" id="trade-web-app-option" data-trade-select="web-app" aria-pressed="false" aria-controls="web-app">Web App</button>
</div>

This page takes you from a quote to the funds received from a completed swap, in the Shield Swap app or with the TypeScript SDK, Python SDK, or CLI.

## How a swap settles

Every swap finishes in two steps. The swap trades your input asset through the pool and leaves the output waiting to be collected. The claim then delivers the output to your wallet, along with any unused input. In the app, the claim runs on its own after the swap confirms, and the price is final as soon as the swap confirms.

If anything interrupts the claim, the output waits for you. In the app, open **Portfolio**, then **Pending Claims**. With the SDKs or CLI, [recover the existing swap](./history-and-recovery) and finish its claim. You do not need to start another trade, and a second swap opens a new trade instead of finishing the first one.

The settled amounts can differ from the quote. A trade can stop before it spends the full input when the price reaches your limit, and the claim returns the unused amount alongside the output. On a route through two pools, any unused input comes back in the asset you sold, never in the intermediate asset.

The assets traded, the amount, the route, the output, any refund, the price movement, and the timing of each swap are public. Your wallet address stays out of the public market data. See [Public data](../confidentiality/public-data).

<div id="web-app" data-trade-view="web-app" role="region" aria-labelledby="trade-web-app-option" hidden>
  ## In the app

  **Before you start**

  You'll need:

  * Shield Wallet connected to Shield Swap, with a confidential balance of the asset you want to sell. See [Fund your wallet](../start/fund-wallet).
  * A quote on the **Trade** or **Swap** page. See [Quote](./quote#in-the-app).

  **Trade** sells or buys one market's asset against USDCx. **Swap** exchanges any two assets and routes through USDCx when the pair has no direct pool. A routed swap shows both pools' fees combined as one **Swap Fee**, and **History** labels it **Multi-hop**.

  ### Submit the trade

  1. With your quote showing, select the main button. On **Trade** it names the action and asset, such as **Buy ALEO** or **Sell ETH**. On **Swap** it reads **Swap**.
  2. In **Review buy**, **Review sell**, or **Review Swap**, check the amounts, **Max Slippage**, **Price Impact**, **Swap Fee**, and **You Receive At Least**. On **Swap**, the **Quote refresh** bar counts down; if it runs out, select **Review Updated Quote** and check the new amounts.
  3. Select **Confirm & Swap**.

  <Warning>
    **Confirm once.** After you confirm in Shield Wallet, the swap is sent. If the window closes or looks stuck, do not submit the trade again. Open **Portfolio**, then **History** or **Pending Claims**, to see where it is.
  </Warning>

  4. In the **Transaction request** in Shield Wallet, check that the request is from swap.shield.fi and that the amounts match your review, then select **Confirm**. Your assets do not move until you confirm.

  The app shows **Executing buy**, **Executing sell**, or **Executing swap** with a progress circle, and Shield Wallet shows **1 pending transaction** while the swap is in flight. The app then shows **Buy Complete**, **Sell Complete**, or **Swap Complete**. The first completion screen says the price is final and the claim will finish in the background. When the claim finishes, the screen shows **Swap** and **Claim** both marked **Confirmed**, with an **Explorer** link to the public transactions. The received asset appears in your Shield Wallet balance.

  ### Check the result

  Open **Portfolio**, then **History**. The newest row shows the trade with its status, route, and amounts. On the **Trade** page, **Your Trades** under the chart lists the same trades for the current market. See [Swap history and recovery](./history-and-recovery#in-the-app) for the full table and what each status means.

  ### Troubleshooting

  | What you see | Why it happens | What to do |
  | - | - | - |
  | **The quote changed. Review the updated amounts before confirming.** | The market moved while the review window was open, or the quote refresh ran out. | Select **Review Updated Quote**, check the new amounts, then select **Confirm & Swap** again. |
  | The warning under **Slippage** says the swap may fail if the price moves beyond your limit | Your slippage setting is low for the market's current movement. | Raise the setting, or keep it and accept that the swap can fail. A failed swap is rejected before it spends your input, so the asset stays in your wallet. Request a new quote and try again. |
  | **Swap Complete** shows the price is final, but the claim has not finished | The claim is still running in the background. | Wait. If the received asset has not appeared in Shield Wallet after a few minutes, open **Portfolio**, then **Pending Claims**. \[VERIFY: how long a claim can take, and what Pending Claims shows for an unfinished claim] |
  | Shield Wallet shows a public balance of the asset, but the trade panel shows nothing to sell | Shield Swap trades only from the confidential balance. | Shield the asset in Shield Wallet. See [Move a public balance into your confidential balance](../start/getting-started#move-a-public-balance-into-your-confidential-balance). |
</div>

<div id="developers" data-trade-view="developers" role="region" aria-labelledby="trade-developers-option">
  ## Quote, submit, and claim

  **Prerequisites:** Your authenticated mainnet `client` for TypeScript, `dex` for Python, or CLI profile from [Setup](./configure). Your account needs one spendable token record covering **1 USDCx**, plus funds for transaction fees. [Fund your account](./fund-and-bridge) or [prepare a covering record](./preparing-token-records) if needed.

  For services, scripts, and agents, the [optional storage setup](./configure#3-configure-optional-storage) saves the data needed to resume after a restart. Without it, your application must retain the swap handle returned on submission. A handle contains the identifiers and claim data needed to finish that trade.

  These examples trade **1 USDCx for ETH on mainnet**. To practice with test assets, use the [Quickstart](./quickstart).

  ### 1. Review a quote

  Your quote gives you an estimated output and the minimum you'll accept for **1 USDCx on mainnet**. The examples allow 50 basis points (0.5%) below the estimate. Use your authenticated client from [Setup](./configure); [Quote](./quote#request-a-quote) explains the parameter types and defaults.

  <Tabs>
    <Tab title="TypeScript">
      ```typescript theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      import { formatUnits } from "@provablehq/shield-swap-sdk"

      const quote = await client.quote({
        from: "USDCx", to: "ETH", amountIn: "1", slippageBps: 50,
      })
      const expectedOutput = formatUnits(quote.expectedOut, quote.to.decimals)
      const minimumOutput = formatUnits(quote.minOut, quote.to.decimals)
      ```

      `expectedOutput` and `minimumOutput` are decimal strings in ETH units. Review both before submitting. If the time in `quote.expiresAt` has passed, request a fresh quote.
    </Tab>

    <Tab title="Python">
      ```python theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      quote = dex.quote(
          token_in="USDCx", token_out="ETH", amount_in="1", slippage_bps=50,
      )
      ```

      `quote.estimated_amount_out` and `quote.minimum_amount_out` are decimal strings in ETH units. Review both before submitting. Python quotes do not expire automatically, so request a fresh quote if you wait before trading.
    </Tab>

    <Tab title="CLI">
      You can review a trade without submitting it by leaving out `--execute`:

      ```bash theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      shield-swap swap --from USDCx --to ETH --amount 1 --slippage 50 --network mainnet
      ```

      The preview shows `sell`, `buy`, `floor`, and `route`. `--amount 1` is one USDCx, and `--slippage 50` allows 0.5% below the estimated output.
    </Tab>
  </Tabs>

  ### 2. Submit the reviewed quote

  Once you're satisfied with the quote, you can submit the swap. The SDK examples use the mainnet `quote` from [Review a quote](#1-review-a-quote) and preserve its route and minimum output. The CLI requests a fresh quote when you execute the command.

  <Warning>
    **Submit only when you're ready to trade on mainnet.** These calls spend the quoted input. Running them again starts another swap.
  </Warning>

  <Tabs>
    <Tab title="TypeScript">
      ```typescript theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      const handle = await client.swap({ quote })
      ```

      `handle.transactionId` identifies the submitted transaction, and `handle.swapId` identifies the swap to claim. Keep the handle until the claim finishes; a configured file store retains it for recovery.
    </Tab>

    <Tab title="Python">
      ```python theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      handle = dex.swap(quote).delegate(wait=True)
      ```

      `.delegate(wait=True)` submits through the configured proving service and waits for confirmation. `handle.transaction_id` identifies the transaction, and `handle.swap_id` identifies the swap to claim. An attached journal saves the handle for recovery after a restart.
    </Tab>

    <Tab title="CLI">
      Use `--no-claim` to leave collection for the next step. Without this flag, the CLI attempts the claim in the same run.

      ```bash theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      shield-swap swap --from USDCx --to ETH --amount 1 --slippage 50 --network mainnet --no-claim --execute
      ```

      `--execute` submits a fresh quote without another confirmation; the preview does not lock its price. The command reports the swap transaction ID and swap ID, and saves recovery data in the account directory. Keep both IDs for the remaining steps.
    </Tab>
  </Tabs>

  If proving or confirmation times out, check the original transaction before retrying. A timeout leaves its outcome unknown. Your [history and recovery data](./history-and-recovery) let you continue investigating the existing trade.

  ### 3. Claim the output

  After the swap is accepted, its output becomes available to collect. The claim delivers the output and any unused input to your account. Continue with the mainnet account and `handle` from [Submit the reviewed quote](#2-submit-the-reviewed-quote), or the saved CLI account and swap ID.

  If a claim attempt was interrupted, [check its transaction status](./history-and-recovery#establish-the-original-outcome) before submitting another claim.

  <Tabs>
    <Tab title="TypeScript">
      ```typescript theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      await client.waitForSwapOutput({ handle, timeout: 60_000 })
      const claim = await client.claimSwapOutput({ handle })
      ```

      The optional `timeout` is a polling limit in milliseconds; this example allows 60 seconds instead of the default 15 seconds. Waiting does not submit a transaction. Once the output is available, the claim call submits the transaction that delivers it.

      `claim.transactionId` identifies the claim. `claim.amountOut` and `claim.amountRemaining` are `bigint` amounts in output-token and input-token base units, respectively. The latter is zero when no input is refunded.
    </Tab>

    <Tab title="Python">
      ```python theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      claim = dex.claim_swap_output(handle, timeout=60).delegate(wait=True)
      ```

      The optional `timeout` is a polling limit in seconds. This example waits up to 60 seconds for the output; the default of `0` checks once. `.delegate(wait=True)` then submits the claim and waits for confirmation.

      `claim.transaction_id` identifies the claim. `claim.amount_out` and `claim.amount_remaining` are integer amounts in output-token and input-token base units, respectively. Save the latter for refund accounting; the journal records the received amount but does not retain the refund amount.
    </Tab>

    <Tab title="CLI">
      Replace `SWAP_ID` with the ID reported by the submission command, including its `field` suffix. Run this from the same account directory:

      ```bash theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      shield-swap history --claim --swap-id SWAP_ID --network mainnet --execute
      ```

      `--swap-id` selects the original trade; omitting it can claim other pending swaps. `--execute` authorizes the claim transaction. The result includes its transaction ID and the received amount.
    </Tab>
  </Tabs>

  ## Check the result

  Your swap and claim each have a transaction ID. Checking both confirms whether the ledger accepted the trade and its collection. Your account's balance then shows whether record scanning has found the received funds.

  The SDK examples use the `handle` and `claim` from the mainnet steps above. They also use `publicClient` for TypeScript or `aleo` for Python, alongside the trading client from [Setup](./configure#2-setup-a-trading-client). These checks read existing state and do not submit another transaction.

  <Tabs>
    <Tab title="TypeScript">
      ```typescript theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      const swapTransaction = await publicClient.getConfirmedTransaction({
        id: handle.transactionId,
      })
      const claimTransaction = await publicClient.getConfirmedTransaction({
        id: claim.transactionId,
      })
      if (swapTransaction.status !== "accepted" || claimTransaction.status !== "accepted") {
        throw new Error("Swap and claim must both be accepted")
      }

      const balances = await client.getBalances({
        tokens: [quote.from.id, quote.to.id],
      })
      ```

      Both transaction results must have `status: "accepted"`. `balances[quote.to.id]?.private` reports your ETH record balance as a base-unit `bigint`. Use `formatUnits` from the quote example with `quote.to.decimals` to display it in ETH units.
    </Tab>

    <Tab title="Python">
      ```python theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      swap_transaction = aleo.network.get_confirmed_transaction(handle.transaction_id)
      claim_transaction = aleo.network.get_confirmed_transaction(claim.transaction_id)
      if swap_transaction["status"] != "accepted" or claim_transaction["status"] != "accepted":
          raise RuntimeError("Swap and claim must both be accepted")

      balances = dex.get_balances()
      ```

      Both transaction dictionaries must contain `"status": "accepted"`. `balances` reports your account's holdings; the ETH entry includes the amount held in token records.
    </Tab>

    <Tab title="CLI">
      Replace `SWAP_TRANSACTION_ID` and `CLAIM_TRANSACTION_ID` with the IDs from the submission and claim commands. The public lookup checks transaction acceptance; the CLI reads your account's balances:

      ```bash theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      curl --fail-with-body --silent --show-error \
        "https://api.explorer.provable.com/v1/mainnet/transaction/confirmed/SWAP_TRANSACTION_ID"
      curl --fail-with-body --silent --show-error \
        "https://api.explorer.provable.com/v1/mainnet/transaction/confirmed/CLAIM_TRANSACTION_ID"
      shield-swap balances --network mainnet
      ```

      Both lookup responses must report `"status": "accepted"`. The balance command shows received ETH in the `private` column.
    </Tab>
  </Tabs>

  If a transaction lookup fails or remains unconfirmed, repeat the read before deciding whether to retry an operation. Record scanning can also lag behind an accepted claim; a delayed balance update does not mean you need to claim again.

  A total balance does not identify which trade produced it. [Verify swap settlement](./verify-settlement) shows how to match the claim to its exact output record and check that the pending output has been removed from the contract.

  ## Handle partial fills and refunds

  The settled amounts can differ from the quote. A price limit can stop a single-pool trade before it spends the full input; the claim returns the unused amount alongside your output. Record both received output and refunded input when accounting for the trade.

  For a route through several pools, later hops must spend their intermediate input or the route rejects. [Output claims and refunds](./output-claims-and-refunds) and [multi-hop swaps](./multi-hop-swaps) explain these settlement rules.

  ## Next Steps

  ### Recover an interrupted swap

  [Swap History & Recovery](./history-and-recovery) shows how to check an existing trade and finish its claim after a timeout or restart.

  ### Run packaged examples

  The [TypeScript examples](https://github.com/ProvableHQ/veil/tree/main/packages/shield-swap/examples/first-swap) and [Python examples](https://github.com/ProvableHQ/python-sdk/tree/master/shield-swap-sdk/examples/first-swap) include setup, funding, and a complete **1.5 USDCx swap on testnet**. Follow the [Quickstart commands](./quickstart#run-packaged-examples) to run them. Each run starts a new trade.
</div>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.