Developers
Withdraw via CCTP
Withdraw an Amplifi balance to native USDC on another chain over Circle's CCTP.
Overview
The return leg of Deposit via CCTP: withdraw an end-user's Amplifi balance to their EOA on another chain as native Circle USDC.
Amplifi does the Polygon-side work — it unwraps the user's pUSD to native USDC and submits a CCTP depositForBurn to your destination chain. The partner relays the mint on the destination chain (receiveMessage), the same role they play relaying the Polygon mint on the deposit side. Amplifi's work ends once Circle's attestation is ready; the partner claims it.
destinationDomain is the Circle CCTP domain of the payout chain. Only destinations enabled on the deployment are accepted; an unsupported domain returns 4xx. A withdrawal sent without destinationDomain is the standard Polygon-direct USDC.e withdrawal and is unchanged.
The flow
1. Get a nonce and sign
Fetch the user's current nonce and the EIP-712 signing info (domain + the CrossChainWithdrawalIntent types) from the crosschain_withdraw intent endpoint:
curl https://api.amplifi.finance/polymarket/positions/nonce/crosschain_withdraw/<END_USER_EOA>
# → { "nonce": 7, "domain": { ... }, "types": { "CrossChainWithdrawalIntent": [ ... ] } }
Use crosschain_withdraw, not withdraw (that returns the Polygon-direct WithdrawalIntent types). Sign with the end-user's EOA over this domain and these types:
domain: { name: "Amplifi", version: "1", chainId: 137, verifyingContract: <amplifi contract> }
CrossChainWithdrawalIntent: [
{ name: "userAddress", type: "address" },
{ name: "destinationAddress", type: "address" }, // recipient on the destination chain
{ name: "usdcAmount", type: "uint256" }, // base units (6 dp)
{ name: "destinationDomain", type: "uint32" }, // Circle domain of the payout chain
{ name: "nonce", type: "uint256" }, // from this endpoint
{ name: "deadline", type: "uint256" } // unix seconds
]
The signed struct binds destinationDomain, so the payout chain can't be swapped after signing.
2. Request the withdrawal
Send the signed fields. nonce is the value from step 1 (it's in the request because the signature is over it — Amplifi verifies the signature against it and consumes it for replay protection):
curl -X POST https://api.amplifi.finance/polymarket/withdrawals \
-H "Content-Type: application/json" \
-d '{
"userAddress": "<END_USER_EOA>",
"destinationAddress": "<RECIPIENT_ON_DESTINATION_CHAIN>",
"usdcAmount": "50.00",
"destinationDomain": <CCTP_DOMAIN>,
"nonce": <NONCE_FROM_STEP_1>,
"deadline": <UNIX_SECONDS>,
"signature": "0x…"
}'
# → { "withdrawalId": …, "amount": "…", "destinationDomain": …, "status": "PENDING" }
amount is the net payout in base units (the protocol withdraw fee is already deducted).
3. Poll until burn-attested
curl https://api.amplifi.finance/polymarket/withdrawals/<END_USER_EOA>
The row advances pending → fee_settled → bridging_to_native_usdc → awaiting_attestation → burn_attested (a few minutes, dominated by the swap + Circle attestation). At burn_attested (status COMPLETED) the claim payload is present:
{
"status": "COMPLETED",
"phase": "burn_attested",
"destinationDomain": "<CCTP_DOMAIN>",
"claim": {
"destinationDomain": "<CCTP_DOMAIN>",
"recipient": "<RECIPIENT_ON_DESTINATION_CHAIN>",
"burnTx": "0x… (Polygon depositForBurn tx)",
"message": "0x… (CCTP message bytes)",
"attestation": "0x… (Circle attestation)"
}
}
4. Relay the mint on the destination chain
Call receiveMessage(message, attestation) on the destination chain's CCTP v2 MessageTransmitter — 0x81D40F21F12A8F0E3252Bccb954D722d4c464B64, the same deterministic address on every CCTP chain. Native USDC lands at recipient. Anyone may relay (the burn sets destinationCaller = 0); the relayer pays the destination-chain gas. Re-relaying the same message/attestation is safe — Circle rejects a double-mint.
Errors
A 4xx is permanent: bad signature/nonce/deadline, a destinationDomain the deployment doesn't support, an amount below the fee, or an active liquidation for the user. A 503 is transient (balance is being recalculated) — retry with backoff. Requests are idempotent on the signed nonce.
Constraints
- Minimum ~$2 per withdrawal (the bridge's per-chain floor).
- The protocol withdraw fee is taken on Polygon before bridging. The delivered amount is the net minus the swap slippage (a built-in ≤10bp guard); there's no Amplifi or CCTP fee on the cross-chain leg.
- The end-user EOA signs every withdrawal.
- Withdrawals are processed serially, so high-volume bursts may queue.
- Amplifi's terminal state is
burn_attested— theclaimpayload is the handoff; it does not track the destination-chainreceiveMessage.
