Skip to main content
A deposit always lands in the authenticated owner’s Stellar wallet as native USDC. You choose the route (cctp-deposit for USDC, usdt0-deposit for USDT) and the funding mode.

Before you start

The owner’s Stellar account needs a trustline to Circle’s USDC (and USDT0, for USDT). If it is missing, the first action is stellar_trustline. Handle it with Pesa’s sponsored onboarding, which pays the reserve.

Direct mode

1

Quote and create

Show the quote’s buy_amount and fee.details before the user confirms. Keep the idempotency key: if the request times out, retry with the same key.
2

Verify and sign the calls

3

Submit the burn

Submit only after the burn is mined. The server checks the DepositForBurn log in the receipt.
4

Wait for credit

Poll getTransfer every few seconds until status is completed. Show stage as progress.

Deposit address mode

With a deposit address, the transfer starts at AWAITING_FUNDS and the first action is send_to_address.
When the address holds the amount, the transfer moves to FUNDED and the next action is evm_calls. A Privy smart wallet sends them as one batched transaction. See React Native. At most one open deposit-address transfer can exist per chain and address.

USDT through USDT0

Use route: "usdt0-deposit". The actions come in this order:
  1. stellar_trustline, if the USDT0 or USDC trustline is missing.
  2. evm_calls: an approve (Ethereum only) and the OFT send. Check them with verifyUsdt0Calls. In deposit_address mode, Pesa first tops up the LayerZero fee in native coin.
  3. stellar_tx: the USDT0 to USDC swap on the Stellar DEX, after LayerZero delivers. Check it with verifyStellarSwap, sign, and submit { kind: "stellar_tx", signed_xdr }.
If the price moves, the stage is SWAP_REQUOTE and the swap action carries a lower output. Show the new amount; signing it is the user’s approval.

Errors to handle