Skip to main content

claimSwapOutput

Claims a private swap's output — phase two of the swap lifecycle.

Reads the chain-computed result from the swap_outputs mapping, never from an off-chain service, because these amounts gate money movement. It then proves ownership of the blinded identity and submits claim_swap_output on shield_swap_v3.aleo. The output and any refund arrive as private records owned by the signer; the mapping entry is consumed. Hits the network for one mapping read plus the transaction; signs, and on the local path proves locally.

Signer paths mirror swap: a local account passes the handle's literal blindingFactor; a wallet account gets resolve-mode derived requests targeting the handle's blindedAddress and re-derives the blinding factor itself.

Usage

Local account

The handle from swap already carries swapId and blindedAddress, so no extra recovery step is needed before claiming.

import { loadNetwork } from '@provablehq/veil-aleo-sdk'
import { shieldSwapActions } from '@provablehq/shield-swap-sdk'

const aleo = await loadNetwork('testnet')
const scanner = aleo.createRemoteScanner({
url: 'https://api.provable.com/scanner',
consumerId: CONSUMER_ID,
apiKey: DPS_API_KEY,
})
const { walletClient } = aleo.createAleoClient({
privateKey: PRIVATE_KEY,
networkUrl: 'https://api.provable.com/v2',
provingMode: 'delegated',
proverUrl: 'https://api.provable.com/prove/testnet',
apiKey: DPS_API_KEY,
consumerId: CONSUMER_ID,
records: scanner,
})
const client = walletClient.extend(shieldSwapActions())

const { amountOut, amountRemaining } = await client.claimSwapOutput({ handle })
// { transactionId: 'at1…', amountOut: 987654321000000000n, amountRemaining: 0n }

Wallet account

The wallet filled the blinding slots at request time, so the handle came back without swapId/blindedAddress. Recover them from the confirmed request transaction first — swapId is the transition's first public output, and the blinded address is also readable from api.getSwap(...).recipient — set them on the handle, then claim. The wallet re-derives the blinding factor from the blinded address, so the dapp never holds it.

handle.swapId = swapIdFromConfirmedTx
handle.blindedAddress = blindedAddressFromConfirmedTx

const { amountOut, amountRemaining } = await client.claimSwapOutput({ handle })

If claiming throws SwapOutputNotFinalizedError, the request transaction has not finalized yet — retry after a few blocks. The same error after a successful claim means the output was already collected; claiming consumes the on-chain entry.

Returns

Promise<ClaimSwapOutputReturnType>

  • transactionIdstring. The claim transaction's id.
  • amountOutbigint. Raw atomic amount received (u128), as computed on chain.
  • amountRemainingbigint. Raw atomic input refund (u128), non-zero when the swap partially filled at the price limit.

Parameters

handle

  • Type: SwapHandle

The handle returned by swap. Local-signer handles are complete; wallet-path handles need swapId and blindedAddress resolved from the confirmed request transaction first.

imports

  • Type: Record<string, string>

Program sources for dynamic-dispatch dependencies ({ 'token.aleo': source }). The prover cannot discover IARC20@(...) callees statically, so the involved token programs' sources must be passed when proving locally or via a service that requires them.

program

  • Type: string
  • Default: the handle's program.

shield_swap program override.

Errors

Throws SwapOutputNotFinalizedError when the output is not readable yet (the request has not finalized — retry) or was already claimed. Also throws when the handle is missing the fields its signer path needs, and on transport or proving errors.