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

# Fund a trading account

> Fund your trading account, prepare assets for swaps, and withdraw to another chain.

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

<div id="developers" data-trade-view="developers" role="region" aria-labelledby="trade-developers-option">
  ## How funding works

  Shield Swap runs on the Aleo network and uses token records for private trading. Each record holds an amount your account can spend in a swap.

  To fund your trading account from a supported EVM chain or Solana, you bridge assets to Aleo, then convert the received public balance into token records. This conversion is called shielding. USDC can be bridged directly into USDCx records, without a separate shielding step.

  Once trading is complete, you can bridge your funds out to another supported chain. If your account already holds spendable token records, you can go straight to [getting a quote](./quote).

  ## Check spendable funds

  **Prerequisites:** Your account and trading clients from [Setup](./configure): `client` for TypeScript, `dex` for Python, or a configured CLI profile. For practice with test assets, use the separate [testnet funding flow](#request-testnet-tokens).

  Check your USDCx balance to decide whether you need funding or record preparation.

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

      const token = await client.tokenData("USDCx")
      const balances = await client.getBalances({ tokens: [token.id] })
      const privateBalance = formatUnits(balances[token.id]?.private ?? 0n, token.decimals)
      ```

      `privateBalance` is a decimal string in USDCx units. For example, `"1"` means 1 USDCx, not one base unit.
    </Tab>

    <Tab title="Python">
      ```python theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      balances = dex.get_balances()
      token = dex.api.get_token("USDCx")
      can_swap = dex.has_swap_balance(token.address, "1")
      ```

      `balances` reports your holdings. `can_swap` is `True` when one record covers 1 USDCx; it is `False` when record preparation or funding is needed.
    </Tab>

    <Tab title="CLI">
      ```bash theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      shield-swap balances --network mainnet --all --json
      ```

      The JSON response reports your balances, including the `private` amount held in records.
    </Tab>
  </Tabs>

  Your total record balance can be sufficient even when no single record covers the swap. For example, two records of 0.5 USDCx total 1 USDCx, but neither covers a 1 USDCx input. [Prepare a covering record](./preparing-token-records) before swapping.

  If you have a public balance, configure the bridge client in [step 1](#1-configure-access), then continue to [shielding](#shield-public-balances). If your funds are on another chain, follow the bridge steps below.

  ## Bridge assets

  Use these **mainnet** examples to transfer ETH between Ethereum and Aleo through Hyperlane. Choose TypeScript, Python, or REST, and use the same interface through delivery so you can track one transfer throughout.

  For the supported pairs and examples covering Solana, USDCx delivery modes, frontend integration, and embedded wallets, see the [Bridging integration guide](../developers/bridging). Use the Shield Swap CLI to check balances before and after funding.

  ### 1. Configure access

  You need a source account that can sign the transfer and a destination address to receive it. Keep funds for network fees in the source account in addition to the transfer amount. When funding, use your mainnet Aleo account from [Setup](./configure) as the recipient.

  The examples below use private keys managed by your application. For a Dynamic or Privy signer, follow [Use Embedded Wallets for bridging](../developers/bridging#use-embedded-wallets-for-bridging), then continue at [route discovery](#2-discover-assets-and-routes).

  Your application must supply the keys, RPC URL, and wallet addresses from an external source, such as its configuration or a secret manager. The examples below use environment variables:

  | Input | Where to get it | Used by |
  | - | - | - |
  | `ALEO_PRIVATE_KEY` | The private key for your mainnet trading account from Setup. | TypeScript and Python. |
  | `EVM_PRIVATE_KEY` | The private key for your Ethereum source account. TypeScript expects 32 bytes as `0x`-prefixed hex. | TypeScript and Python. |
  | `ETHEREUM_RPC_URL` | An Ethereum mainnet RPC URL from your RPC provider. | TypeScript and Python. |
  | `SOURCE_ADDRESS` | The address of the wallet sending the transfer. | REST. |
  | `DESTINATION_ADDRESS` | The address shown by the wallet receiving the transfer. | REST. |

  <Tabs>
    <Tab title="TypeScript">
      Install the packages in an ES module application using Node.js 22 or later:

      ```bash theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      npm install --legacy-peer-deps @provablehq/aleo-bridge-sdk@0.12.1 @provablehq/veil-aleo-sdk@0.12.1 @provablehq/veil-aleo-devnode@0.12.1
      ```

      `--legacy-peer-deps` avoids a conflict between the bridge package's optional Solana and server-wallet peers in npm.

      Connect your Aleo trading account and Ethereum signer to the bridge. Your Ethereum RPC connection handles chain reads and transaction submission:

      ```typescript theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      import { loadNetwork } from "@provablehq/veil-aleo-sdk"
      import {
        createAleoClient, createBridgeClient, createEvmClient, evmHttp, evmPrivateKey,
      } from "@provablehq/aleo-bridge-sdk"

      const aleoKey = process.env.ALEO_PRIVATE_KEY
      const evmKey = process.env.EVM_PRIVATE_KEY
      const rpc = process.env.ETHEREUM_RPC_URL
      if (!aleoKey || !evmKey || !rpc) throw new Error("Set both keys and ETHEREUM_RPC_URL")
      if (!/^0x[0-9a-fA-F]{64}$/.test(evmKey)) throw new Error("EVM_PRIVATE_KEY must be a 32-byte hex key")

      const aleo = await loadNetwork("mainnet")
      const { publicClient, walletClient, account } = aleo.createAleoClient({ privateKey: aleoKey })
      const bridge = createBridgeClient({
        environment: "mainnet",
        clients: {
          ethereum: createEvmClient({ transport: evmHttp(rpc), account: evmPrivateKey(evmKey as `0x${string}`) }),
          aleo: createAleoClient({ publicClient, account: walletClient }),
        },
      })
      ```

      You now have a mainnet `bridge` client and Aleo `account`. Keep both in the same session for the TypeScript steps that follow.
    </Tab>

    <Tab title="Python">
      Install the SDK in a Python 3.11 or later environment:

      ```bash theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      python -m pip install "aleo-bridge-sdk==0.6.1"
      ```

      Connect your accounts and register the Aleo record scanner so it can find records for withdrawals. Registration shares your account's view key with the hosted scanner, which can read every record belonging to that account.

      `FileCheckpointStore` saves transfer progress locally so you can recover after a restart. Keep its directory between sessions.

      ```python theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      import os
      from aleo import Aleo, HTTPProvider
      from aleo_bridge import Bridge, Ethereum, FileCheckpointStore

      aleo = Aleo(HTTPProvider("https://edge.provable.com/api", network="mainnet"))
      aleo.default_account = aleo.account.from_private_key(os.environ["ALEO_PRIVATE_KEY"])
      registration = aleo.records.register(aleo.default_account)
      if not registration.get("ok"):
          raise RuntimeError(registration.get("error", "Record scanner registration failed"))

      ethereum = Ethereum(
          os.environ["ETHEREUM_RPC_URL"], private_key=os.environ["EVM_PRIVATE_KEY"],
      )
      store = FileCheckpointStore(".bridge/checkpoints")
      bridge = Bridge(aleo, ethereum=ethereum, checkpoints=store)
      ```

      On success, `registration["ok"]` is `True`. You now have the mainnet `bridge`, `ethereum`, and `store` objects used by the Python steps.
    </Tab>

    <Tab title="REST">
      Use `curl` and `jq` to request quotes and transfer instructions from the wallet services API. Your source wallet signs transactions; you do not send its private key to this API.

      ```bash theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      export WALLET_API=https://wallet.api.provable.com
      : "${SOURCE_ADDRESS:?Set the source wallet address}"
      : "${DESTINATION_ADDRESS:?Set the destination wallet address}"
      ```

      Your shell now has the wallet services URL and both addresses. This host handles bridging; the Shield Swap API in Setup handles trading data.

      Send `X-Client-Type: programmatic` for this workflow. Wallet integrations use their supported `X-Wallet-*` capability headers instead; do not combine the two header sets.
    </Tab>
  </Tabs>

  ### 2. Discover assets and routes

  **Prerequisites:** The `bridge` client or REST shell configuration from [Configure access](#1-configure-access).

  A route identifies the asset and the provider that can move it between two chains. Discover routes to check where you can send your funds. Use the returned chain and asset identifiers when quoting; a symbol alone does not identify an asset across chains.

  <Tabs>
    <Tab title="TypeScript">
      ```typescript theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      const assets = bridge.registry.getAssets()
      const inboundRoutes = bridge.registry.getRoutes({
        environment: "mainnet", sourceChainId: "ethereum", destinationChainId: "aleo",
      })
      const outboundRoutes = bridge.registry.getRoutes({
        environment: "mainnet", sourceChainId: "aleo", destinationChainId: "ethereum",
      })
      ```

      `assets` lists the registered assets; `inboundRoutes` and `outboundRoutes` list routes in each direction. Check availability before quoting: `metadata-required` means deployment metadata is still needed.
    </Tab>

    <Tab title="Python">
      ```python theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      inbound_routes = bridge.routes(source_chain="ethereum", destination_chain="aleo")
      outbound_routes = bridge.routes(source_chain="aleo", destination_chain="ethereum")
      ```

      `inbound_routes` and `outbound_routes` contain the matching routes. Check the returned route's availability before quoting.
    </Tab>

    <Tab title="REST">
      ```bash theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      curl --fail-with-body --silent --show-error "$WALLET_API/common/assets" |
        jq '.data[] | {code, chain, symbol, decimals, supportedDestinations}'
      ```

      Each output object contains `code`, `chain`, `symbol`, `decimals`, and `supportedDestinations`. Use `code` and `chain` in your quote; `supportedDestinations` shows where you can send the asset.
    </Tab>
  </Tabs>

  For the ETH examples, the identifiers are:

  | Interface | Ethereum ETH | Aleo ETH |
  | - | - | - |
  | REST chain and asset | `EVM:1`, `ETH_MAINNET` | `ALEO`, `ETH_ALEO` |
  | SDK chain and asset | `ethereum`, `eth` | `aleo`, `eth` |

  For an Aleo-to-Ethereum withdrawal, Hyperlane spends your public balance. If your ETH is held in records, [unshield the withdrawal amount](#shield-public-balances) and wait for acceptance before quoting.

  ### 3. Request and review a quote

  **Prerequisites:** The client or REST shell configuration from [Configure access](#1-configure-access), a supported route from [Discover assets and routes](#2-discover-assets-and-routes), and your recipient address.

  Request a quote to see how much your recipient can expect and the route fees before you move funds. Choose one direction below. Each example requests **0.01 ETH in display units**, not base units.

  For an Ethereum destination, replace `ETHEREUM_RECIPIENT` with the receiving wallet's Ethereum address. For an Aleo destination, the SDKs use your configured trading account. In REST, set `SOURCE_ADDRESS` and `DESTINATION_ADDRESS` to the wallets for your chosen direction.

  <Tabs>
    <Tab title="TypeScript">
      | Parameter | Type and unit | Required or default |
      | - | - | - |
      | `source`, `destination` | Objects with `chain` and `asset` identifier strings. | Required; no default. |
      | `bridgeProtocol` | Protocol identifier string. | Optional when the route is unambiguous; this example selects `"hyperlane"`. |
      | `amount` | Decimal string in source-asset display units. | Required; no default. |
      | `recipient` | Destination address string. | Required; no default. |

      Ethereum to Aleo:

      ```typescript theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      const quote = await bridge.quote({
        source: { chain: "ethereum", asset: "eth" },
        destination: { chain: "aleo", asset: "eth" },
        bridgeProtocol: "hyperlane", amount: "0.01", recipient: account.address,
      })
      ```

      Aleo to Ethereum, with your destination address in place of `ETHEREUM_RECIPIENT`:

      ```typescript theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      const quote = await bridge.quote({
        source: { chain: "aleo", asset: "eth" },
        destination: { chain: "ethereum", asset: "eth" },
        bridgeProtocol: "hyperlane", amount: "0.01", recipient: "ETHEREUM_RECIPIENT",
      })
      ```

      `quote.plan` contains the selected route, amount, and recipient. Review the returned fees and transfer details before using that plan to submit.
    </Tab>

    <Tab title="Python">
      | Parameter | Type and unit | Required or default |
      | - | - | - |
      | `source_chain`, `source_asset` | Source chain and asset identifier strings. | Optional if you supply a route instead; supplied here. |
      | `destination_chain`, `destination_asset` | Destination identifier strings. | Optional when route selection is unambiguous; supplied here. |
      | `amount` | Decimal string in source-asset display units. | Required unless you supply `amount_atomic`; no default amount. |
      | `sender` | Source address string. | Defaults to `None`; required for this Ethereum quote, so supply it explicitly. |
      | `recipient` | Destination address string. | Required; no default. |

      Ethereum to Aleo:

      ```python theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      quote = bridge.quote(
          source_chain="ethereum", source_asset="eth",
          destination_chain="aleo", destination_asset="eth",
          amount="0.01", sender=ethereum.require_address(), recipient=bridge.aleo_address(),
      )
      ```

      Aleo to Ethereum, with your destination address in place of `ETHEREUM_RECIPIENT`:

      ```python theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      quote = bridge.quote(
          source_chain="aleo", source_asset="eth",
          destination_chain="ethereum", destination_asset="eth",
          amount="0.01", sender=bridge.aleo_address(), recipient="ETHEREUM_RECIPIENT",
      )
      ```

      Review `quote.amount_out` and `quote.fees`. Keep `quote.plan`, which contains the transfer details you will submit.
    </Tab>

    <Tab title="REST">
      For Ethereum to Aleo, use the chain and asset identifiers below. These request parameters describe the quote:

      | Parameter | Type and unit | Required or default |
      | - | - | - |
      | `srcChain`, `destChain` | Chain identifier strings from route discovery. | Required; no default. |
      | `srcAsset`, `destAsset` | Asset code strings from route discovery. | Required; no default. |
      | `amountIn` | Decimal string in source-asset display units. | Required; no default. |
      | `slippageBps` | Numeric string in basis points. | Optional; omitted unless supplied. This example requests `50`, or 0.5%. |
      | `fromAddress`, `refundAddress` | Source wallet address strings. | Optional in the API; supply both for this workflow. |
      | `recipientAddress` | Destination wallet address string. | Optional in the API; supply it for this workflow. |

      ```bash theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      export SRC_CHAIN=EVM:1 SRC_ASSET=ETH_MAINNET
      export DEST_CHAIN=ALEO DEST_ASSET=ETH_ALEO
      export AMOUNT=0.01

      QUOTES=$(curl --fail-with-body --silent --show-error --get "$WALLET_API/bridge/quotes" \
        -H 'X-Client-Type: programmatic' \
        --data-urlencode "srcChain=$SRC_CHAIN" \
        --data-urlencode "srcAsset=$SRC_ASSET" \
        --data-urlencode "destChain=$DEST_CHAIN" \
        --data-urlencode "destAsset=$DEST_ASSET" \
        --data-urlencode "amountIn=$AMOUNT" \
        --data-urlencode 'slippageBps=50' \
        --data-urlencode "fromAddress=$SOURCE_ADDRESS" \
        --data-urlencode "refundAddress=$SOURCE_ADDRESS" \
        --data-urlencode "recipientAddress=$DESTINATION_ADDRESS")
      printf '%s\n' "$QUOTES" | jq '.data | to_entries[] | {index: .key, quote: .value}'
      ```

      For Aleo to Ethereum, set `SRC_CHAIN=ALEO`, `SRC_ASSET=ETH_ALEO`, `DEST_CHAIN=EVM:1`, and `DEST_ASSET=ETH_MAINNET`. Change the source and destination addresses, then repeat the request.

      You receive indexed quote objects with the provider, `amountOut`, any `minAmountOut`, fees, and estimated time. Review those values and the recipient before selecting an index. An empty list means no quote is available.
    </Tab>
  </Tabs>

  ### 4. Submit the reviewed transfer

  **Prerequisites:** Your client from [Configure access](#1-configure-access) and the `quote` or `QUOTES` response you reviewed in [Request and review a quote](#3-request-and-review-a-quote).

  Submission moves funds into the bridge. Save a reference so you can check delivery after a restart: the SDKs use checkpoints, while REST uses an order ID.

  <Warning>
    **Recover an uncertain submission before sending again.** A timeout does not prove that funds stayed in your source account; another submission could send them twice. Use [Recover an interrupted transfer](#6-recover-an-interrupted-transfer) to check the original transfer.
  </Warning>

  <Tabs>
    <Tab title="TypeScript">
      Supply `saveCheckpoint`, your storage callback, before running this example. It receives a `BridgeCheckpoint` and must persist it before returning; it can return `void` or `Promise<void>`. The SDK has no default persistent store for this callback.

      ```typescript theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      const execution = await bridge.execute({
        plan: quote.plan, onCheckpoint: saveCheckpoint,
      })
      ```

      You receive `execution.receipt`, which identifies the submitted work for the delivery check. Some token routes require an approval before the transfer.
    </Tab>

    <Tab title="Python">
      Submit your reviewed plan with the `FileCheckpointStore` configured in [Configure access](#1-configure-access). The SDK saves checkpoints there as submission advances:

      ```python theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      progress = bridge.execute(quote.plan)
      checkpoint_id = progress.plan.journal_id
      ```

      Keep `checkpoint_id` to reload this transfer. If the call is interrupted before it returns, use `store.list()` to find the saved checkpoint by its route and transaction details.
    </Tab>

    <Tab title="REST">
      Set `QUOTE_INDEX` to the integer index you reviewed in the quote response; `0` selects the first result. Creating an order returns funding instructions without signing or submitting a transaction.

      The order copies its provider, integration type, chain and asset identifiers, amount, and quote ID from that quote. `walletAddress` is your destination address; `refundAddress` is your source address. The example supplies the same 50-basis-point tolerance as the quote.

      ```bash theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      export QUOTE_INDEX=0
      ORDER_REQUEST=$(printf '%s\n' "$QUOTES" | jq -e --argjson i "$QUOTE_INDEX" \
        --arg recipient "$DESTINATION_ADDRESS" --arg refund "$SOURCE_ADDRESS" \
        '.data[$i] | select(.quoteId != null) | {
          providerId: .provider.id,
          integrationType,
          srcChain, destChain, srcAsset, destAsset, amountIn, quoteId,
          slippageBps: "50",
          walletAddress: $recipient,
          refundAddress: $refund
        }')
      ORDER=$(curl --fail-with-body --silent --show-error "$WALLET_API/bridge/orders" \
        -H 'X-Client-Type: programmatic' -H 'Content-Type: application/json' \
        --data-binary "$ORDER_REQUEST")
      ORDER_ID=$(printf '%s\n' "$ORDER" | jq -er '.data.orderId')
      printf '%s\n' "$ORDER" | jq '.data'
      ```

      You receive `data.orderId` and `data.instructions`. Save `orderId` before sending funds so you can find the same transfer after a restart.

      Follow the action for your returned `data.instructions.type`:

      | Type | Action |
      | - | - |
      | `ONCHAIN_DEPOSIT` | Send the exact returned asset and amount to the returned address, including its memo when present, before expiry. |
      | `SIGN_TRANSACTIONS` | Fetch unsigned transactions, review them, and sign with the source account. |
      | `OFFCHAIN_WIDGET` | Continue through the provider's returned widget instructions. |

      For `SIGN_TRANSACTIONS`, fetch the unsigned transactions immediately before signing so you can check their expiry:

      ```bash theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      curl --fail-with-body --silent --show-error \
        "$WALLET_API/bridge/orders/$ORDER_ID/transactions" \
        -H 'X-Client-Type: programmatic' | jq '.data | {unsignedTxs, quoteExpiresAt}'
      ```

      You receive `unsignedTxs` and `quoteExpiresAt`. Each entry's `kind` identifies its chain format. Process the entries in order, checking the chain, sender, recipient, amount, and call. For Solana, preserve any existing signatures when adding your wallet's signature.

      Fetch fresh transaction data if a Solana blockhash expires while the order is still valid. An expired order needs a new quote and order; fetching its transactions again will fail. Before replacing an order, check that its source transaction was never broadcast.

      If your wallet returns signed bytes without broadcasting, supply `SIGNED_TRANSACTIONS` as a JSON string containing a `signedTxs` array. Fill that array with the wallet's signed transactions in execution order: `0x`-prefixed hex for EVM or base64 for Solana.

      <Warning>
        **Submit only transactions your wallet has not broadcast.** If it already broadcast them, use the confirmation request below to report the original transaction.
      </Warning>

      ```bash theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      : "${SIGNED_TRANSACTIONS:?Set the wallet-signed transaction JSON}"
      curl --fail-with-body --silent --show-error \
        "$WALLET_API/bridge/orders/$ORDER_ID/transactions" \
        -H 'X-Client-Type: programmatic' -H 'Content-Type: application/json' \
        --data-binary "$SIGNED_TRANSACTIONS"
      ```

      After submission, check the saved order ID in [Check delivery](#5-check-delivery). Submission alone does not confirm that the destination received funds.

      If your wallet broadcasts, including for an Aleo source, report its original bridge transaction ID. Hyperlane also needs a source-account signature to confirm ownership.

      Replace `ORDER_ID` with the saved order ID and `TX_ID` with the wallet's broadcast transaction ID. Have the source wallet sign this UTF-8 message:

      ```text theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      hyperlane-confirm-v1
      ORDER_ID
      TX_ID
      ```

      Join the lines with newline characters and no trailing newline. The signer must match your refund address. Use EIP-191 `personal_sign` for EVM, a base58 Ed25519 signature for Solana, or an Aleo signature.

      Supply `TX_ID` from your wallet's broadcast result and `OWNER_SIGNATURE` from that signing operation, then confirm:

      ```bash theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      jq -n --arg txId "$TX_ID" --arg signature "$OWNER_SIGNATURE" \
        '{txId: $txId, phase: "SWAP", ownerSignature: $signature}' |
        curl --fail-with-body --silent --show-error \
          "$WALLET_API/bridge/orders/$ORDER_ID/transactions/confirm" \
          -H 'X-Client-Type: programmatic' -H 'Content-Type: application/json' \
          --data-binary @-
      ```

      This example sets the optional `phase` string to `"SWAP"`, the source phase for a single-transaction bridge order. Report the bridge deposit or withdrawal transaction ID, not a preceding ERC-20 approval. Check the order status to follow delivery.
    </Tab>
  </Tabs>

  ### 5. Check delivery

  **Prerequisites:** Your configured client and the submission result from [Submit the reviewed transfer](#4-submit-the-reviewed-transfer): `quote.plan` and `execution.receipt` for TypeScript, `progress` for Python, or `ORDER_ID` for REST.

  Your source transaction can be confirmed while delivery is still pending. Check the existing transfer to see whether the destination has received the funds. These calls do not sign another transaction.

  <Tabs>
    <Tab title="TypeScript">
      ```typescript theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      const progress = await bridge.wait({
        progress: { next: "wait", plan: quote.plan, receipt: execution.receipt },
      })
      ```
    </Tab>

    <Tab title="Python">
      ```python theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      progress = bridge.wait(progress)
      ```
    </Tab>

    <Tab title="REST">
      ```bash theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      curl --fail-with-body --silent --show-error \
        "$WALLET_API/bridge/orders/$ORDER_ID" |
        jq '.data | {orderId, status, currentStepKey, finalStatus: .finalStatus.key, providerStatus}'
      ```

      The API's `status` uses lowercase values such as `pending` and `completed`. The optional `finalStatus.key`, flattened to `finalStatus` above, uses uppercase values such as `COMPLETED`. Repeat the request while the order is in progress; review `FAILED`, `REFUNDED`, or `EXPIRED` before starting another transfer.

      When present, `providerStatus.txHash` identifies your source transaction and `providerStatus.destinationTxHash` identifies delivery. Providers may also return `depositTxHash` and `withdrawalTxHash`. Check the available receipts on their respective chains.
    </Tab>
  </Tabs>

  For either SDK, use the returned `progress.next` to decide what to do:

  | Result | Meaning |
  | - | - |
  | `done` | Check the destination receipt and balance; delivery has completed. |
  | `wait` | Check the same transfer again; delivery is pending. |
  | `failed` | Review the returned error before taking further action. |
  | `resume` | Continue unfinished source work using the route's packaged example. |
  | `complete` | Complete the destination transaction using the route's packaged example, such as a Circle USDCx mint. |

  For Hyperlane withdrawals from Aleo, both SDKs can use the recipient's balance increase to detect delivery. Spending from that destination account before the check can leave a delivered transfer marked as pending; unrelated incoming funds can also make the balance check misleading. Confirm the original transfer in the [Hyperlane explorer](https://explorer.hyperlane.xyz/) and check its destination transaction before resubmitting or treating the balance change as proof.

  After inbound Hyperlane delivery, [shield your public balance](#shield-public-balances) to prepare it for trading. After a withdrawal, check the destination receipt and recipient balance.

  ### 6. Recover an interrupted transfer

  **Prerequisites:** Recreate the client from [Configure access](#1-configure-access) with the same account, then load the checkpoint or order ID saved during [submission](#4-submit-the-reviewed-transfer).

  You can inspect an interrupted transfer without sending funds again. Recovery uses its saved reference to find how far the original transfer progressed.

  <Warning>
    **Recover the original transfer before calling `execute` again.** Another execution can submit a second transfer instead of finishing the first.
  </Warning>

  <Tabs>
    <Tab title="TypeScript">
      Load `checkpoint`, the `BridgeCheckpoint` object saved by your `saveCheckpoint` callback. Pass that object to your recreated client:

      ```typescript theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      let recovered = await bridge.recover({ checkpoint })
      if (recovered.next === "wait") recovered = await bridge.wait({ progress: recovered })
      ```
    </Tab>

    <Tab title="Python">
      Replace `CHECKPOINT_ID` with the journal ID saved during submission, or find it with `store.list()`. Use the same `FileCheckpointStore` directory to reload it:

      ```python theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      checkpoint_id = "CHECKPOINT_ID"
      recovered = bridge.recover(store.load(checkpoint_id))
      if recovered.next == "wait":
          recovered = bridge.wait(recovered)
      ```
    </Tab>

    <Tab title="REST">
      Restore `ORDER_ID` from your saved submission result and repeat the [delivery check](#5-check-delivery). You can also inspect the order's audit events:

      ```bash theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      curl --fail-with-body --silent --show-error \
        "$WALLET_API/bridge/orders/$ORDER_ID/audit" | jq '.data'
      ```

      The response contains your order details, workflow steps, and `providerEvents`. If your wallet broadcast the transaction but reporting failed, repeat the confirmation request with the same transaction ID and owner signature.
    </Tab>
  </Tabs>

  Read `recovered.next` using the [delivery result table](#5-check-delivery). If it requests `resume` or `complete`, follow the route's [packaged example](#run-packaged-examples). A Circle mint using a secret nonce also needs the original nonce; retain it separately because checkpoints and public transaction history cannot reconstruct it.

  ## Shield public balances

  **Prerequisites:** Your `bridge` client from [Configure access](#1-configure-access), plus a public ETH balance for shielding or a sufficient ETH record for unshielding.

  Shield the amount you want to trade after Hyperlane delivers it to your public balance. To withdraw through Hyperlane, unshield that amount instead. Unshielding exposes the recipient and amount in public balance state.

  Each example converts **0.01 ETH in display units** and submits a separate transaction with a fee. The CLI and wallet services order endpoints do not provide this conversion.

  <Tabs>
    <Tab title="TypeScript">
      Use your configured mainnet client to shield 0.01 ETH:

      ```typescript theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      const conversion = await bridge.shield({
        asset: { chain: "aleo", asset: "eth" }, amount: "0.01",
      })
      ```

      To unshield, supply `record` as an encoded plaintext string from your account's record scanner. It must be an unspent ETH record covering at least 0.01 ETH:

      ```typescript theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      const conversion = await bridge.unshield({
        asset: { chain: "aleo", asset: "eth" }, amount: "0.01", record,
      })
      ```

      You receive `conversion.transactionId`. Wait for acceptance before spending the converted amount. A connected wallet that supports record requests can select the record if you omit it; the local-key example supplies it explicitly.
    </Tab>

    <Tab title="Python">
      After inbound delivery, shield 0.01 ETH and wait for acceptance:

      ```python theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      receipt = bridge.shield("aleo/eth", amount="0.01").delegate(wait=True)
      ```

      Before an outbound transfer, unshield 0.01 ETH and wait for acceptance:

      ```python theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      receipt = bridge.unshield("aleo/eth", amount="0.01").delegate(wait=True)
      ```

      You receive `receipt.transaction_id` after acceptance. Your configured scanner can select a sufficient record; optionally supply a specific record with `record=`.
    </Tab>
  </Tabs>

  After shielding is accepted, repeat the [balance check](#check-spendable-funds) with ETH in place of USDCx. Your received ETH is ready for a swap when a record covers the input amount. Circle's supported record-based USDCx withdrawal can burn records directly and does not need this Hyperlane conversion.

  ## Request testnet tokens

  **Testnet prerequisites:** The separate account and clients from the [Quickstart](./quickstart#2-get-test-tokens): `client` and `account` for TypeScript, `shield_swap_client` for Python, or the CLI testnet profile. For the Python examples below, set `dex = shield_swap_client`.

  Use the faucet to practice without transferring mainnet assets. The SDK calls wait for the faucet transfer and its token records. With the Quickstart's delegated proving setup, you do not need a public ALEO balance.

  A faucet job can deliver USDCx even if another asset transfer fails. Check the same account's USDCx records before requesting more tokens; an available record covering your input is enough to continue the testnet swap.

  <Tabs>
    <Tab title="TypeScript">
      ```typescript theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      const funding = await client.api.confirmAirdrop(account.address)
      ```

      On success, check your testnet balance to confirm the received funds. If the call times out, set `jobId` to the job ID reported by the timeout, then inspect that request:

      ```typescript theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      const job = await client.api.getAirdropStatus(jobId)
      ```
    </Tab>

    <Tab title="Python">
      ```python theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      funding = dex.confirm_airdrop()
      ```

      On success, check your testnet balance to confirm the received funds. If the call times out, set `job_id` to the job ID reported by the timeout, then inspect that request:

      ```python theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      job = dex.api.get_airdrop_job(job_id)
      ```
    </Tab>

    <Tab title="CLI">
      Run setup for your testnet profile. If the account has no holdings, the CLI requests faucet tokens and saves the job ID so it can resume after an interruption:

      ```bash theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      shield-swap setup --network testnet
      ```

      Setup can skip the faucet when you hold another asset, even if you lack the asset you want to trade. In that case, use an SDK funding example for the same account.
    </Tab>
  </Tabs>

  A completed faucet job can still be waiting for record indexing. Check your balance before requesting more funds; you can trade when a record covers your intended input.

  ## Next steps

  ### Get a trading quote

  Use the [Quote guide](./quote) to find a pool and review a swap once your input is available in a record.

  ### Run packaged examples

  Run a complete **mainnet** example for your chosen route. Each repository documents the accounts and connections you need.

  <Tabs>
    <Tab title="TypeScript">
      Follow the [Veil bridge examples](https://github.com/ProvableHQ/veil/tree/main/packages/bridge/examples) README to configure your accounts, then run the ETH example for your direction from its example directory:

      ```bash theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      npx tsx eth-to-aleo.ts
      npx tsx eth-to-ethereum.ts
      ```

      You receive a quote without submitting funds. To execute, supply the acknowledgement documented in the example. The same directory covers USDC/USDCx routes and checkpoint recovery.
    </Tab>

    <Tab title="Python">
      The [Python bridge examples](https://github.com/ProvableHQ/python-sdk/tree/master/bridge-sdk/examples) ship with the installed package. Read the help for the route or recovery operation you need:

      ```bash theme={"languages":{"custom":["/languages/leo.tmLanguage.json"]}}
      python -m aleo_bridge.examples.quote_transfer --help
      python -m aleo_bridge.examples.bridge_wbtc_to_ethereum --help
      python -m aleo_bridge.examples.recover_from_journal --help
      ```

      The help lists the required accounts, amount units, and recovery inputs. Quote commands do not submit transactions; `--execute`, `--action resume`, or `--action complete` authorize the corresponding transaction.
    </Tab>
  </Tabs>
</div>

<div id="web-app" data-trade-view="web-app" role="region" aria-labelledby="trade-web-app-option" hidden>
  The [Fund page](https://swap.shield.fi/fund) moves assets from an Ethereum or Solana wallet into Shield Wallet so you can trade them. You can reverse the direction on the same page to bridge assets out.

  Shield Swap trades from your confidential balance. USDC arrives as USDCx without a separate shielding step. For other assets, funding includes shielding the received balance. The source-chain transfer remains public; see the [risk disclosures](https://shield.fi/risk).

  ## Connect your wallets

  **Before you start**

  You'll need:

  * Shield Wallet installed with your account selected. [Setup](./configure#web-app) covers creating or importing an account.
  * A compatible Ethereum or Solana wallet, such as MetaMask, Brave Wallet, or Phantom, holding the asset you want to bridge and funds for network fees.

  The external wallet sends your funds; Shield Wallet receives them. The asset you select determines which network and wallet options appear.

  1. Open [Fund Wallet](https://swap.shield.fi/fund).
  2. If you're sending SOL, select **SOL** in the asset selector to use the Solana wallet options.
  3. Under **You send**, select **Connect Wallet** and choose your external wallet.
  4. Approve the connection in that wallet.
  5. Under **You receive**, select **Connect Wallet** to connect Shield Wallet.
  6. Read the terms in **Connect Shield Wallet** before selecting **Agree and Connect**.
  7. Approve the connection request in Shield Wallet after checking that the site is swap.shield.fi.
  8. Sign the challenge in Shield Wallet. It records acceptance of the terms shown in the app; signing this message creates no transaction.

  Both wallets are connected, and Shield Wallet is the destination for your transfer.

  ## Bridge assets into Shield Wallet

  1. Select an available asset, such as **USDC**, **ETH**, or **WBTC**, under **You send**. **You receive** shows the corresponding destination asset.
  2. Enter the amount to send.
  3. Review the fees and estimated time shown by the app.
  4. Select the bridge button to open **Review bridge**.

  <Warning>
    **Check the recipient address before confirming.** It must match the account you intend to fund in Shield Wallet.
  </Warning>

  5. Select **Confirm & Bridge** when the amount and recipient are correct.
  6. Approve the requests in your source wallet. An asset approval may be required before the transfer.
  7. Wait for the bridge and any shielding step to finish.

  **Your Bridging History** at the bottom of the page lets you check the transfer with both wallets connected. If a transfer is still pending, check its status before starting another one.

  ## Check the funds available for trading

  Open [Portfolio](https://swap.shield.fi/portfolio) to see the assets available to trade. If a non-USDC transfer arrived but its shielding step failed, the asset can remain in your public balance. You can finish shielding it in Shield Wallet:

  1. Open Shield Wallet and select **Shield**.
  2. Select the received asset.
  3. Enter the amount with **Shield** selected.
  4. Select **Next**.
  5. Review the fee and balance changes, then select **Continue**.
  6. Select **Confirm**.

  The wallet's **Private** balance shows the shielded amount. Return to **Portfolio** to check the asset is available for trading. The [Shield Wallet shielding guide](https://support.shield.app/en/articles/13226405-shielding-and-unshielding-tokens-in-shield) covers these screens.

  ## Bridge assets out

  The direction control on [Fund Wallet](https://swap.shield.fi/fund) reverses the transfer: Shield Wallet sends the asset, and your Ethereum or Solana wallet receives it.

  Keep enough public ALEO in Shield Wallet for the bridge fee on Hyperlane routes. The app shows the required fee before submission.

  1. Select the arrow between **You send** and **You receive**. The panel changes to **Bridge from Shield Swap**.
  2. Select the asset and enter the amount to withdraw.
  3. Connect the receiving wallet under **You receive**.
  4. Review the destination address and fee before confirming the bridge.
  5. Approve the request in Shield Wallet.

  Follow the transfer in **Your Bridging History** until it reaches the receiving wallet.

  ## Continue to a trade

  Once your funds appear in **Portfolio**, [Quote](./quote#web-app) shows how to review a trade before submitting it.
</div>


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