Skip to main content

How it works

Gift card credits live on Starknet. When a recipient redeems to Solana, USDC is bridged via Circle’s CCTP V2 (Cross-Chain Transfer Protocol):
1. Starknet: USDC burned via TokenMessenger.depositForBurn
2. Circle: attestation signers verify the burn (~5 sec fast mode)
3. Solana: USDC minted to recipient's wallet via receiveMessage
Total time: ~24 seconds end-to-end (burn + attestation + Solana confirmation).

Fast vs Standard mode

Each Gift carries a cctpFast flag that controls Solana redeem speed:
ModeAttestation timeFeeBest for
cctpFast: true (default)~5 seconds~$0.01 per redeemReal-time claims, good UX
cctpFast: false4-8 hoursFreeBatch distributions where speed doesn’t matter
Fast mode pays a small fee to Circle’s attestation service for priority. Standard mode waits for Starknet’s ZK proof to post to Ethereum L1.
Single-create (POST /v1/gifts) does not accept cctpFast in the request today. The gift is always created with cctpFast: true (the schema default). To set cctpFast: false, use the bulk endpoint (POST /v1/gifts/bulk) which accepts the flag, or the dashboard’s bulk-airdrop flow.

Supported chains

DestinationStatusTime
StarknetLiveInstant (direct ERC20 transfer)
SolanaLive~24 sec (CCTP V2)
BaseComing soon
ArbitrumComing soon
EthereumComing soon

Redeem flow for Solana

// 1. Redeem — returns 202 with redeemId
const res = await fetch("https://api.chipipay.com/v1/gifts/claim/CODE/redeem", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    walletAddress: "FZQq6KCS...", // Solana wallet pubkey
    chain: "solana",
  }),
});

const { redeemId, status } = await res.json();
// status = "BRIDGING"

// 2. Poll until SUCCESS
while (true) {
  const statusRes = await fetch(
    `https://api.chipipay.com/v1/gifts/claim/CODE/status/${redeemId}`
  );
  const data = await statusRes.json();

  if (data.status === "SUCCESS") {
    console.log("USDC received on Solana:", data.receiveChainTxHash);
    break;
  }
  if (data.status === "FAILED") {
    console.error("Bridge failed. Burn tx:", data.cctpBurnTxHash);
    break;
  }

  await new Promise(r => setTimeout(r, 5000)); // poll every 5 sec
}

Status flow

PENDING → BRIDGING → ATTESTED → SUCCESS
                  ↘ FAILED (if bridge times out or Solana tx fails)
StatusMeaning
PENDINGRedeem record created, not yet sent
BRIDGINGCCTP burn submitted on Starknet, waiting for Circle attestation
ATTESTEDCircle attestation ready, Solana receive pending
SUCCESSUSDC delivered to recipient’s wallet
FAILEDSomething went wrong — check cctpBurnTxHash for the Starknet burn tx

Technical details

  • CCTP V2 contracts: TokenMessenger on Starknet (0x07d421...), MessageTransmitter on Solana (CCTPV2Sm4...)
  • Domain IDs: Starknet = 25, Solana = 5
  • Mint recipient: must be the Solana USDC Associated Token Account (ATA), not the wallet pubkey
  • Circle attestation API: https://iris-api.circle.com/v2/messages/25?transactionHash={txHash}
  • Server relay: Chipi’s server submits the receiveMessage transaction on Solana and pays the SOL gas fee
The recipient doesn’t need SOL for gas — Chipi’s relay pays for the Solana transaction.