Circle Internet Financial
Circle Internet Financial Logo

Jan 19, 2026

April 29, 2025

Versements par lots de l'USDC à grande échelle avec Circle Wallets et Thirdweb Engine

what you’ll learn

Découvrez comment envoyer l'USDC à plusieurs destinataires via des chaînes croisées à l'aide de transactions atomiques par lots avec CCTP, Circle Wallets et Thirdweb Engine.

Versements par lots de l'USDC à grande échelle avec Circle Wallets et Thirdweb Engine

Il peut être difficile de payer des personnes dans différents pays, banques ou devises. Vous devez faire face à des retards de règlement, à des frais de conversion de devises et à une infrastructure incohérente. Qu'il s'agisse de gérer la paie, de distribuer des remises en argent ou de financer des récompenses, cela implique souvent de naviguer dans différents systèmes de paiement, de jongler avec les intégrations bancaires et d'absorber des coûts opérationnels élevés.

Même dans le domaine de la cryptographie, l'envoi de fonds à plusieurs destinataires, en particulier via différentes chaînes, peut être lent et coûteux. Chaque transfert constitue sa propre transaction, ce qui signifie plus de frais, plus de signatures et plus de marge de manœuvre. Plus vous ajoutez de destinataires, plus le processus devient fastidieux et sujet aux erreurs.

Et si vous pouviez gérer tout cela en une seule transaction ?

Imaginez effectuer des paiements à plusieurs personnes, même entre blockchains, en un seul appel atomique, où tout s'exécute simultanément ou pas du tout. Aucun transfert partiel. Aucune étape dupliquée. Pas de place pour les erreurs manuelles.

C'est ce que permettent les transactions par lots atomiques.

Avec Circle CCTP (Cross-Chain Transfer Protocol), Circle Wallets et Thirdweb Engine, vous pouvez créer un flux de paiement programmable qui fonctionne entre blockchains, en utilisant l'USDC comme couche de règlement.

Dans ce blog, vous découvrirez comment les transactions atomiques par lots, le CCTP et le moteur Thirdweb s'associent pour permettre des paiements USDC inter-chaînes programmables.

Si vous souhaitez voir la présentation technique complète, regardez la vidéo et essayez-la vous-même avec le Modèle de moteur Thirdweb et le Demande d'échantillons atomiques par lots, tous deux disponibles sur Replit (mais doivent être exécutés localement en raison des exigences de Docker)

Thirdweb Engine en tant que backend

Pour alimenter ce flux, nous utilisons Thirdweb Engine comme serveur principal. Il fournit un ensemble d'API backend qui vous permettent de créer des Circle Wallets, de soumettre des transactions par lots atomiques, de sonder le statut des transactions, etc.

Une fois que le moteur est en marche, il interagit avec le frontend pour gérer l'intégralité du flux de transfert de l'USDC.

Création de portefeuilles tels que des comptes bancaires

Dans cette application, chaque Circle Wallet fonctionne comme un compte bancaire dédié, un pour l'expéditeur et un pour chaque destinataire. Vous pouvez créer et gérer ces portefeuilles par programmation via le backend. Lorsque le frontend doit créer un portefeuille, il envoie une demande à votre Thirdweb Engine.

Voici à quoi cela ressemble :

// From the frontend
const response = await axios.post<WalletResponse>('/api/wallet/create', {
  type: 'smart:circle',
  credentialId: process.env.NEXT_PUBLIC_THIRDWEB_CREDENTIAL_ID,
  label,
  isTestnet: 'true',
});

Cela passe par votre API principale :

// From the backend
const response = await fetch(`${BACKEND_URL}/backend-wallet/create`, {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.NEXT_PUBLIC_THIRDWEB_ENGINE_ACCESS_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(body),
});

Une fois créés, ces portefeuilles peuvent signer et envoyer des transactions, y compris les appels atomiques par lots utilisés pour déplacer l'USDC entre blockchains.

Approuver et brûler l'USDC en une seule transaction atomique

Une fois les portefeuilles de l'expéditeur et du destinataire configurés, la première étape du transfert inter-chaînes de l'USDC consiste à approuver le transfert, puis à graver l'USDC sur la chaîne source. Il s'agit de la première partie du flux CCTP.

Normalement, cela impliquerait plusieurs transactions :

  • Un appel d'approbation ()
  • Et un appel DepositForBurn () pour chaque destinataire

Mais ici, nous utilisons une transaction par lots atomiques pour tout gérer en même temps.

Si l'un de ces appels échoue, rien ne passe. Il s'agit d'une exécution tout ou rien, soumise et signée depuis le Circle Wallet de l'expéditeur via Thirdweb Engine.

Sur le frontend, vous devez d'abord encoder les appels de contrat en un seul lot :

const approveInterface = new Interface([
  'function approve(address spender, uint256 amount)'
]);

const depositForBurnInterface = new Interface([
  'function depositForBurn(uint256 amount, uint32 destinationDomain, bytes32 mintRecipient, address burnToken, bytes32 destinationCaller, uint256 maxFee, uint32 deadline)'
]);

// Helper: Encode approve() call
function encodeApprove(tokenAddress: string, spender: string, amount: bigint | string) {
  return {
    toAddress: tokenAddress,
    data: approveInterface.encodeFunctionData('approve', [spender, amount.toString()]),
    value: "0"
  };
}

// Helper: Encode depositForBurn() call
function encodeDepositForBurn({
  recipientAddress,
  recipientChain,
  amount,
  sourceUSDC,
  tokenMessenger
}: {
  recipientAddress: string,
  recipientChain: string,
  amount: bigint,
  sourceUSDC: string,
  tokenMessenger: string
}) {
  const destinationConfig = getChainConfig(recipientChain);
  const maxFee = amount / BigInt(5000);
  const deadline = 1000;

  return {
    toAddress: tokenMessenger,
    data: depositForBurnInterface.encodeFunctionData('depositForBurn', [
      amount.toString(),
      destinationConfig.domain,
      pad(recipientAddress),
      sourceUSDC,
      "0x0000000000000000000000000000000000000000000000000000000000000000", // destinationCaller
      maxFee.toString(),
      deadline.toString()
    ]),
    value: "0"
  };
}

// Step 1: Encode approve transaction
const approveTransaction = encodeApprove(
  sourceConfig.usdc,
  sourceConfig.tokenMessenger,
  totalAmount
);

// Step 2: Encode depositForBurn transactions
const burnTransactions = recipients.map(recipient =>
  encodeDepositForBurn({
    recipientAddress: recipient.address,
    recipientChain: recipient.chain,
    amount: BigInt(recipient.amount),
    sourceUSDC: sourceConfig.usdc,
    tokenMessenger: sourceConfig.tokenMessenger
  })
);

// Step 3: Combine all transactions
const encodedTransactions = [approveTransaction, ...burnTransactions];

Ce lot est envoyé à votre backend via une route API locale :

await fetch('/api/wallet/transfer', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'x-backend-wallet-address': walletAddress
  },
  body: JSON.stringify({ transactions: encodedTransactions })
});

De là, le backend envoie le lot à Thirdweb Engine :

await fetch('http://localhost:3005/backend-wallet/${chainId}/send-transaction-batch-atomic', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.NEXT_PUBLIC_THIRDWEB_ENGINE_ACCESS_TOKEN}`,
    'Content-Type': 'application/json',
    'X-Backend-Wallet-Address': initiatingWalletAddress
  },
  body: JSON.stringify({ transactions })
});

À ce stade, vous avez soumis une seule transaction atomique qui approuve et brûle l'USDC pour tous les destinataires de la chaîne source.

En attente des attestations Circle

Une fois que la transaction par lots atomiques visant à approuver et à brûler l'USDC est soumise, l'application doit attendre les attestations de Circle. Il s'agit d'un élément crucial du flux CCTP car c'est ainsi que Circle confirme que le brûlage s'est produit et se prépare à être frappé sur la chaîne de destination.

Circle fournit une API permettant d'interroger l'état de chaque transaction de gravure. L'application continue de vérifier ce point de terminaison jusqu'à ce qu'elle reçoive un statut complet pour chaque destinataire.

Voici une version simplifiée de la logique de sondage :

async function waitForAttestation(sourceDomain: number, transactionHash: string): Promise<Attestation> {
  const url = `https://iris-api-sandbox.circle.com/v2/messages/${sourceDomain}?transactionHash=${transactionHash}`;

  for (let i = 0; i < 30; i++) {
    const res = await fetch(url, {
      headers: {
        Authorization: `Bearer ${process.env.NEXT_PUBLIC_CIRCLE_API_KEY}`,
        'Content-Type': 'application/json',
      }
    });

    const data = await res.json();
    const message = data?.messages?.[0];

    if (message?.status === 'complete') {
      return {
        message: message.message,
        attestation: message.attestation,
      };
    }

    await new Promise((resolve) => setTimeout(resolve, 10000)); // wait 10s
  }

  throw new Error('Attestation polling timed out');
}

Chaque transaction de gravure correspond à un identifiant de message unique, et Circle n'autorisera le minting qu'une fois l'attestation associée confirmée.

Une fois que l'application a reçu les attestations de tous les destinataires, elle peut passer à la dernière étape : la frappe par lots atomiques sur la chaîne de destination.

L'USDC est envoyé aux bénéficiaires de la chaîne de destination

Une fois que toutes les attestations Circle ont été reçues, la dernière étape consiste à émettre des Mint USDC pour chaque destinataire de la chaîne de destination. Tout comme l'étape de gravure, cela se fait à l'aide d'une transaction par lots atomiques, de sorte que toutes les monnaies réussissent ensemble, voire aucune.

L'attestation de chaque destinataire est associée à son portefeuille, et l'application crée un lot d'appels ReceiveMessage () à l'aide du contrat MessageTransmitter.

Voici comment le frontend construit le lot :

const messageTransmitterInterface = new Interface([
  'function receiveMessage(bytes message, bytes attestation)'
]);

const receiveMessageTxs = chainRecipients.map((recipient) => {
  return {
    toAddress: destConfig.messageTransmitter,
    data: messageTransmitterInterface.encodeFunctionData('receiveMessage', [
      recipient.attestation.message,
      recipient.attestation.attestation
    ]),
    value: "0"
  };
});

Ils sont envoyés au backend via une route d'API locale :

await fetch('/api/wallet/receive', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'x-backend-wallet-address': sourceWallet.address
  },
  body: JSON.stringify({
    transactions: receiveMessageTxs,
    chain: destConfig.chainId.toString(),
    isDestination: true
  })
});

Et le backend le transmet au point de terminaison des lots atomiques de Thirdweb Engine :

await fetch(`http://localhost:3005/backend-wallet/${chainId}/send-transaction-batch-atomic`, {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.NEXT_PUBLIC_THIRDWEB_ENGINE_ACCESS_TOKEN}`,
    'Content-Type': 'application/json',
    'X-Backend-Wallet-Address': walletAddress
  },
  body: JSON.stringify({ transactions })
});

Cela complète le flux : une transaction atomique à approuver et à graver, une autre transaction atomique à envoyer à plusieurs destinataires, le tout orchestré via CCTP, alimenté par Thirdweb Engine et Circle Wallets.

Conclusion

Ce qui était autrefois un processus complexe en plusieurs étapes (approbations, gravures, attestations et monnayages) peut désormais être traité avec seulement deux transactions atomiques. Que vous gériez la paie mondiale, les distributions de remises en argent ou tout autre type de versement multi-bénéficiaires, vous disposez désormais d'un moyen programmable de transférer de l'argent de manière fiable et efficace entre blockchains.

Essayez-le vous-même

Commencez à utiliser les services pour développeurs de Circle en créant un compte développeur et consultez l'offre spéciale ci-dessous.

Nous sommes ravis d'offrir 100$ en crédits pour les services aux développeurs de Circle - inscrivez-vous dès aujourd'hui pour recevoir automatiquement le vôtre. Cela suffit pour environ un mois de 2 000 portefeuilles actifs, 200 000 appels d'API Smart Contract Platform ou 95$ de frais de réseau sponsorisés

Related posts

AMP: Rethinking Block Building with Multi-Proposer Consensus

AMP: Rethinking Block Building with Multi-Proposer Consensus

May 28, 2026
ChainBench: An LLM Benchmark for Multichain Code Generation

ChainBench: An LLM Benchmark for Multichain Code Generation

May 27, 2026
Concave is the New Linear: The Impossibility of Anti-Plutocratic DAO Governance

Concave is the New Linear: The Impossibility of Anti-Plutocratic DAO Governance

May 20, 2026
Blog
Versements par lots de l'USDC à grande échelle avec Circle Wallets et Thirdweb Engine
batch-usdc-payouts-at-scale-with-circle-wallets-and-thirdweb-engine
April 29, 2025
Découvrez comment envoyer l'USDC à plusieurs destinataires via des chaînes croisées à l'aide de transactions atomiques par lots avec CCTP, Circle Wallets et Thirdweb Engine.
Développeur
No items found.