Scannez pour télécharger l’application Gate
qrCode
Autres options de téléchargement
Ne pas rappeler aujourd’hui

Développement du système de portefeuille de la bourse — intégration de la chaîne Solana

La dernière fois, nous avons complété le système de gestion des risques pour la plateforme d’échange. Cette fois-ci, nous allons aborder l’intégration du portefeuille de l’échange avec la chaîne Solana. Le modèle de comptes, le stockage des logs et le mécanisme de confirmation de Solana diffèrent considérablement des chaînes basées sur Ethereum. Si l’on applique simplement la même logique qu’Ethereum, cela peut entraîner des erreurs. Voici une synthèse de la démarche globale pour prendre en charge Solana.

Comprendre l’unicité de Solana

Modèle de comptes de Solana

Solana utilise un modèle séparant programme et données, où les programmes sont réutilisables, et les données associées sont stockées dans des comptes PDA (Program Derived Address). Étant donné que les programmes sont partagés, il faut utiliser Token Mint pour distinguer différents tokens. Le compte Token Mint stocke les métadonnées globales du token, telles que mint_authority (autorité de mint), supply (offre totale), decimals (nombre de décimales), etc.
Chaque token possède une adresse unique de Mint, par exemple, pour USDC sur le réseau principal de Solana, l’adresse Mint est EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.

Il existe deux programmes SPL Token : SPL Token et SPL Token-2022. Chacun dispose d’un ATA (Associated Token Account) distinct pour stocker le solde utilisateur. Lors d’un transfert, c’est en réalité une invocation du programme correspondant pour déplacer des tokens entre comptes ATA.

Limites des logs sur Solana

Sur Ethereum, on récupère les transferts de tokens en analysant les logs de transactions passés. Sur Solana, les logs d’exécution ne sont pas conservés de façon permanente par défaut, ils ne font pas partie de l’état du ledger (et il n’y a pas de filtre Bloom pour les logs). De plus, ils peuvent être tronqués lors de l’exécution.
Il ne faut donc pas compter sur la “scanning” des logs pour faire la réconciliation des dépôts, mais utiliser getBlock ou getSignaturesForAddress pour analyser les instructions.

Confirmation et réorganisation sur Solana

Le blocage sur Solana prend environ 400 ms. Après 32 confirmations (environ 12 secondes), le bloc est considéré comme finalisé (finalized). Si la latence n’est pas critique, il suffit de faire confiance aux blocs finalisés.
Pour une meilleure réactivité, il faut gérer le risque de réorganisation, même si cela est rare. Contrairement à Ethereum, le consensus de Solana ne repose pas sur parentBlockHash pour former une chaîne, donc on ne peut pas détecter une bifurcation en comparant parentBlockHash et blockHash dans la base de données.
Comment détecter une réorganisation ?
Lors du scan local, on doit enregistrer le blockhash associé à chaque slot. Si pour un même slot, le blockhash change, cela indique un rollback.

Comprendre ces différences permet de passer à la mise en œuvre. Voici comment modifier la base de données :

Conception des tables

Étant donné qu’il existe deux types de tokens sur Solana, la table tokens doit inclure un champ token_type pour distinguer SPL Token et SPL Token-2022.

Même si les adresses Solana diffèrent de celles d’Ethereum, on peut utiliser la dérivation BIP32/BIP44 avec des chemins différents. La table wallets existante peut donc être conservée. Pour supporter la correspondance ATA et le suivi des blocs, il faut ajouter ces trois tables :

Nom de la table Champs clés Description
solana_slots slot, block_hash, status, parent_slot Enregistrements redondants des slots, pour détecter les bifurcations et déclencher des rollback
solana_transactions tx_hash, slot, to_addr, token_mint, amount, type Détails des dépôts/retraits, tx_hash unique pour le suivi double signature
solana_token_accounts wallet_id, wallet_address, token_mint, ata_address Mappage ATA-utilisateur, pour la recherche interne via ata_address

Détails :

  • solana_slots stocke l’état confirmé/finalisé/ignoré, le scanner décide d’insérer ou de faire un rollback selon le statut.
  • solana_transactions enregistre en lamports ou unité minimale de token, avec un champ type pour différencier dépôt/retrait, et nécessite une signature de contrôle pour les opérations sensibles.
  • solana_token_accounts relie wallets/users et garantit l’unicité ATA (wallet_address + token_mint), c’est l’index principal pour le scan.

Pour la définition précise, voir db_gateway/database.md.

Gestion des dépôts utilisateurs

Le suivi des dépôts nécessite un scan constant des données sur la chaîne. Deux méthodes principales existent :

  1. Scan des signatures : getSignaturesForAddress
  2. Scan des blocs : getBlock

Méthode 1 :
On scanne les signatures associées à une adresse (ATA ou programID). En appelant getSignaturesForAddress(address, { before, until, limit }), on récupère les signatures de transactions impliquant cette adresse. Ces signatures sont ensuite utilisées pour obtenir les détails via getTransaction(signature).
Ce procédé est adapté pour peu de comptes ou de volume. Si le nombre de comptes est élevé, la méthode du scan de blocs est plus efficace.

Méthode 2 :
On récupère le dernier slot, puis on appelle getBlock(slot) pour obtenir toutes les transactions, signatures, et comptes. On filtre ensuite selon les instructions et comptes surveillés.

Note : La forte volumétrie de transactions sur Solana peut saturer le processus de parsing en temps réel. Il est conseillé d’utiliser une file de messages (Kafka, RabbitMQ) pour filtrer rapidement les transferts de tokens et transmettre les événements potentiels de dépôt. Ces événements sont ensuite traités par un consommateur pour insertion en base. Pour accélérer, on peut stocker certains hotspots dans Redis. Si le nombre d’adresses est très élevé, on peut partitionner par ATA pour plusieurs consommateurs.

Une alternative consiste à utiliser un service d’indexation tiers fourni par des RPC, qui offre des webhooks, une surveillance d’account, et une capacité de filtrage avancée, déchargeant la charge du parsing.

Processus de scan de blocs

Nous utilisons la méthode 2, avec le code principal dans scan/solana-scan/blockScanner.ts et txParser.ts. Le flux est :

1. Synchronisation initiale / Récupération historique (performInitialSync)

  • Part du dernier slot scanné, puis parcourt jusqu’au dernier slot
  • Vérifie périodiquement si de nouveaux slots apparaissent, met à jour la cible
  • Utilise une confirmation “confirmed” pour équilibrer rapidité et fiabilité

2. Scan en continu (scanNewSlots)

  • Surveille l’apparition de nouveaux slots
  • Vérifie la cohérence des slots confirmés (détection de rollback)

3. Analyse des blocs (txParser.parseBlock)

  • Appelle getBlock(slot, { commitment: "confirmed", encoding: "jsonParsed" })
  • Parcourt chaque transaction : transaction.message.instructions et meta.innerInstructions
  • Ne traite que celles sans erreur (tx.meta.err === null)

4. Analyse des instructions (txParser.parseInstruction)

  • Transfert SOL : correspondance avec le programme système (SystemProgram) et type transfer, vérification destination dans la liste surveillée
  • Transfert SPL Token : correspondance avec TokenProgram ou Token-2022, vérification si destination est une ATA, puis mappage vers l’adresse portefeuille et le mint du token

En cas de rollback, le programme compare le blockhash du slot avec celui stocké. Si changement, cela indique un rollback.

Exemple de code clé :

// blockScanner.ts - Scan d’un slot
async scanSingleSlot(slot: number) {
  const block = await solanaClient.getBlock(slot);
  if (!block) {
    await insertSlot({ slot, status: 'skipped' });
    return;
  }
  const finalizedSlot = await getCachedFinalizedSlot();
  const status = slot <= finalizedSlot ? 'finalized' : 'confirmed';
  await processBlock(slot, block, status);
}

// txParser.ts - Analyse des instructions
for (const tx of block.transactions) {
  if (tx.meta?.err) continue; // sauter les échecs
  const instructions = [
    ...tx.transaction.message.instructions,
    ...tx.meta.innerInstructions ?? []
  ];
  for (const ix of instructions) {
    // Transfert SOL
    if (ix.programId === SYSTEM_PROGRAM_ID && ix.parsed?.type === 'transfer') {
      if (monitoredAddresses.has(ix.parsed.info.destination)) {
        // traitement
      }
    }
    // Transfert Token
    if (ix.programId === TOKEN_PROGRAM_ID || ix.programId === TOKEN_2022_PROGRAM_ID) {
      if (ix.parsed?.type === 'transfer' || ix.parsed?.type === 'transferChecked') {
        const ataAddress = ix.parsed.info.destination;
        const walletAddress = ataToWalletMap.get(ataAddress);
        if (walletAddress && monitoredAddresses.has(walletAddress)) {
          // traitement
        }
      }
    }
  }
}

Après détection d’un dépôt, on applique la sécurité double signature via DB Gateway + contrôle de risque, puis on inscrit le montant dans la table des flux.

Retrait

Le processus de retrait sur Solana est similaire à celui d’EVM, avec quelques différences :

  1. Il faut distinguer deux tokens : SPL-Token et SPL-Token-2022, qui ont des programID différents. La construction de la transaction doit en tenir compte.
  2. La transaction comporte deux parties : signatures (ed25519) et message (header, comptes, recentBlockhash, instructions).
  3. La recentBlockhash doit être récupérée en temps réel, valable environ 150 blocs (~1 minute). Si la vérification nécessite une approbation manuelle, il faut refaire une requête pour obtenir un nouveau recentBlockhash et signer à nouveau.

Flux de retrait

![image-20240930222847819.png]

Il est conseillé de récupérer le blockhash après la vérification de sécurité, pour garantir la validité.

Code de signature et construction de transaction :

// Instruction de transfert SOL
const instruction = getTransferSolInstruction({
  source: hotWalletSigner,
  destination: solanaAddress.to,
  amount: BigInt(amount)
});

// Instruction de transfert Token
const instruction = getTransferInstruction({
  source: sourceAta,
  destination: destAta,
  authority: hotWalletSigner,
  amount: BigInt(amount)
});

// Construction du message
const transactionMessage = pipe(
  createTransactionMessage({ version: 0 }),
  tx => setTransactionMessageFeePayerSigner(hotWalletSigner, tx),
  tx => setTransactionMessageLifetimeUsingBlockhash({ blockhash, lastValidBlockHeight }),
  tx => appendTransactionMessageInstruction(instruction)
);

// Signature
const signedTx = await signTransactionMessageWithSigners(transactionMessage);
// Encodage pour envoi
const signedTransaction = getBase64EncodedWireTransaction(signedTx);

Envoi via Web3.js :

const solanaRpc = chainConfigManager.getSolanaRpc();
const txSignature = await solanaRpc.sendTransaction(signedTransaction, ...);

Les codes complets sont disponibles dans :

  • Wallet : walletBusinessService.ts (405-754)
  • Signer : solanaSigner.ts (29-122)
  • Script de test : requestWithdrawOnSolana.ts

Deux optimisations à prévoir :

  1. Vérification préalable de l’existence de l’ATA cible avant retrait, sinon création supplémentaire
  2. Augmentation du computeUnitPrice en cas de congestion pour prioriser la transaction

Résumé

L’intégration de Solana ne modifie pas fondamentalement l’architecture globale, mais nécessite d’adapter le modèle de comptes, la structure des transactions et le mécanisme de confirmation.
Pour la gestion des dépôts, il faut maintenir une table de mappage ATA-wallet, surveiller les changements de blockhash pour détecter les réorganisations, et faire évoluer le statut des transactions (confirmed → finalized).
Pour les retraits, il faut récupérer le latestBlockhash, distinguer les tokens SPL et Token-2022, et construire la transaction en conséquence.

SOL2.52%
ETH3.53%
USDC-0.02%
Voir l'original
Cette page peut inclure du contenu de tiers fourni à des fins d'information uniquement. Gate ne garantit ni l'exactitude ni la validité de ces contenus, n’endosse pas les opinions exprimées, et ne fournit aucun conseil financier ou professionnel à travers ces informations. Voir la section Avertissement pour plus de détails.
  • Récompense
  • Commentaire
  • Reposter
  • Partager
Commentaire
0/400
Aucun commentaire
  • Épingler
Trader les cryptos partout et à tout moment
qrCode
Scan pour télécharger Gate app
Communauté
Français (Afrique)
  • 简体中文
  • English
  • Tiếng Việt
  • 繁體中文
  • Español
  • Русский
  • Français (Afrique)
  • Português (Portugal)
  • Bahasa Indonesia
  • 日本語
  • بالعربية
  • Українська
  • Português (Brasil)