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
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 :
Scan des signatures : getSignaturesForAddress
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 :
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 :
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.
La transaction comporte deux parties : signatures (ed25519) et message (header, comptes, recentBlockhash, instructions).
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 :
Vérification préalable de l’existence de l’ATA cible avant retrait, sinon création supplémentaire
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.
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.
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
tokensdoit inclure un champtoken_typepour 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
walletsexistante peut donc être conservée. Pour supporter la correspondance ATA et le suivi des blocs, il faut ajouter ces trois tables :Détails :
solana_slotsstocke l’état confirmé/finalisé/ignoré, le scanner décide d’insérer ou de faire un rollback selon le statut.solana_transactionsenregistre en lamports ou unité minimale de token, avec un champtypepour différencier dépôt/retrait, et nécessite une signature de contrôle pour les opérations sensibles.solana_token_accountsreliewallets/userset 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 :
getSignaturesForAddressgetBlockMé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 viagetTransaction(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.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.tsettxParser.ts. Le flux est :1. Synchronisation initiale / Récupération historique (
performInitialSync)2. Scan en continu (
scanNewSlots)3. Analyse des blocs (
txParser.parseBlock)getBlock(slot, { commitment: "confirmed", encoding: "jsonParsed" })transaction.message.instructionsetmeta.innerInstructionstx.meta.err === null)4. Analyse des instructions (
txParser.parseInstruction)SystemProgram) et typetransfer, vérification destination dans la liste surveilléeTokenProgramouToken-2022, vérification si destination est une ATA, puis mappage vers l’adresse portefeuille et le mint du tokenEn cas de rollback, le programme compare le
blockhashdu slot avec celui stocké. Si changement, cela indique un rollback.Exemple de code clé :
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 :
recentBlockhashdoit ê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 nouveaurecentBlockhashet signer à nouveau.Flux de retrait
![image-20240930222847819.png]
Il est conseillé de récupérer le
blockhashaprès la vérification de sécurité, pour garantir la validité.Code de signature et construction de transaction :
Envoi via Web3.js :
Les codes complets sont disponibles dans :
walletBusinessService.ts(405-754)solanaSigner.ts(29-122)requestWithdrawOnSolana.tsDeux optimisations à prévoir :
computeUnitPriceen cas de congestion pour prioriser la transactionRé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.