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

# Verifiers

> Check every action against what the user picked, before the wallet prompt.

A wrong field in a CCTP burn or an OFT send loses funds permanently. So the client never trusts the server on those fields. Each verifier decodes what the user is about to sign and compares it with the chain registry and with what the user picked or typed. It throws on any mismatch.

<Warning>
  Pass the values from your own UI and the SDK's registry, never from the server's response. A verifier that compares the server with itself proves nothing.
</Warning>

## verifyCctpCalls

```ts theme={null}
verifyCctpCalls(
  calls: { to: Hex; data: Hex; value: bigint }[],
  expected: { chain: CctpEvmChain; stellar: StellarCctp; recipient: string; amount6: bigint },
): DecodedCctpBurn
```

Checks a CCTP deposit's `evm_calls`:

* exactly `approve` then `depositForBurnWithHook`, with no native value;
* the approve is on the chain's USDC, for TokenMessengerV2, for the amount;
* the burn targets TokenMessengerV2 with destination domain 27;
* `mintRecipient` and `destinationCaller` are both Circle's Stellar forwarder;
* the hook data decodes to `recipient`, the user's own Stellar address;
* the burn token is USDC, the amount is `amount6`, `maxFee` is 0 and `minFinality` is 2000.

```ts theme={null}
const calls = action.calls.map((c) => ({ ...c, value: BigInt(c.value) }));
verifyCctpCalls(calls, {
  chain: findEvmChain("mainnet", "eip155:8453"),
  stellar: STELLAR_CCTP.mainnet,
  recipient: user.stellarAddress,
  amount6: 20_000_000n,
});
```

## verifySendToAddress

```ts theme={null}
verifySendToAddress(action: Action, expected: { chain: string; address: Hex; amount: string }): void
```

Checks that a `send_to_address` action is on the picked chain, is the user's own smart wallet, and asks for the quoted amount. It does not check the asset, so build the token transfer from your own USDC constant.

## verifyStellarPayment

```ts theme={null}
verifyStellarPayment(
  xdr: string,
  expected: { passphrase: string; source: string; destination: string; issuer: string; amount7: bigint },
): Transaction
```

Checks a Stellar send: a plain transaction (not a fee-bump) from the owner, with one USDC `payment` to the destination for the amount. Returns the `Transaction` to sign. Sign that object, not the raw XDR.

## Verifiers for the other routes

| Verifier | Route | Checks |
| - | - | - |
| `verifyUsdt0Calls(calls, { chain, recipient, amount6, refundAddress })` | `usdt0-deposit` | `approve` (Ethereum adapter only), then OFT `send` with `dstEid` 30600, `to` = the owner's ed25519 key, `amountLD` = `minAmountLD` = the amount, no options or compose message, `value` = the native fee, refund to the user's own wallet |
| `verifyStellarSwap(xdr, { owner, send, sendAmount7, dest, minOut7 })` | USDT0 routes | One `pathPaymentStrictSend` from and to the owner, for the expected assets and amount, with `destMin` no lower than what the user was shown |
| `verifyStellarApprove(xdr, { owner, stellar, amount7 })` | `cctp-withdraw` | The USDC `approve` from the owner, spender TokenMessengerMinterV2, exact amount |
| `verifyStellarBurn(xdr, { owner, stellar, chain, recipient, amount7 })` | `cctp-withdraw` | `deposit_for_burn` from the owner: whole 6-decimal amount, the picked chain's domain, `mint_recipient` = the typed EVM address padded to 32 bytes, zero `destination_caller`, `max_fee` 0, finality 2000 |
| `verifyStellarOftSend(xdr, { owner, chain, recipient, amount7 })` | `usdt0-withdraw` | OFT `send` from the owner: the picked chain's endpoint ID, `to` = the typed EVM address padded to 32 bytes, `amount_ld` = `min_amount_ld`, no options, a bounded XLM fee, refund to the owner |

## Envelope rules for Stellar transactions

Every Stellar verifier also checks the envelope:

* no memo;
* an expiry no more than 30 minutes away, and not valid more than 60 seconds in the future;
* a fee of at most 10,000 stroops for a payment, or 1 XLM for a contract call (its resource fee is included);
* no extra signers, ledger bounds or sequence preconditions;
* for contract calls, one call with only source-account authorization rooted at it.


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