Au début de cette année, nous avons dépassé le milliard de dollars en volume total de paiements en stablecoins. Pour mettre les choses en perspective, nous avons traité notre première transaction en stablecoins il y a moins de 12 mois. Tout a commencé avec une poignée de clients qui demandaient quelque chose qui devrait être simple : la possibilité de recevoir des paiements en stablecoins de leurs clients à travers le monde et de disposer de ces fonds. régler en dollars américains- rapidement et de manière prévisible, sans se faire écraser par les frais. Les solutions existantes impliquaient des frais de 1 à 3 %, un règlement sur plusieurs jours et des processus de conformité incroyablement longs et frustrants. Nous avons vu une opportunité et avons créé un MVP en deux semaines. En moins d'un mois, nous avons atteint un volume réel et significatif.
Le défi consistait à le mettre à l'échelle.
Les stablecoins sont réglés en quelques secondes, partout et à tout moment. Les systèmes bancaires traditionnels n'ont pas été conçus pour cela : ils fonctionnent par traitement par lots, avec des délais de clôture les jours ouvrables et des délais de règlement de plusieurs jours. Un client à Singapour vous envoie 50 000 dollars en USDC à 2 heures du matin un samedi. Sur la chaîne, le règlement s'effectue en quelques secondes. Le virement ACH vers votre compte bancaire ne sera pas initié avant lundi, n'arrivera pas avant mercredi et pourrait rester en attente quelque part entre les deux. Pour faire le lien entre ces deux mondes, il faut coordonner des systèmes qui n'ont jamais été conçus pour communiquer entre eux, chacun ayant son propre état.
Cet article traite des deux primitives d'infrastructure que nous avons développées pour que les mouvements de stablecoins se comportent comme des mouvements monétaires de niveau bancaire :
1. Flux financiers: un moteur d'orchestration déclaratif pour les flux de travail financiers multisystèmes à exécution longue
2. Notre Cadre d'exécution sur la chaîne: Un modèle de cycle de vie pour des opérations fiables sur la chaîne
Tout le reste (les rampes de sortie, les rampes d'entrée et nos comptes Global USD sans garde) est construit à partir de ces éléments primitifs. Si vous devez retenir une seule chose de cet article, c'est que les stablecoins sont faciles à utiliser. banque n'est pas.
Flux de fonds
Lorsque vous transférez des fonds via plusieurs systèmes externes, vous avez besoin de plus qu'une simple coordination ad hoc. Vous avez besoin d'un moyen d'exprimer l'ensemble du flux de manière déclarative : ce qui doit se passer, en réponse à quels événements, avec quelles garanties. Et vous avez besoin que ce flux soit vérifiable, reprenable et correct, même lorsque certaines étapes échouent en cours de route. C'est ce que nous offre Flow of Funds.
Le problème lié aux mouvements d'argent
La plupart des défis liés à l'orchestration dans les logiciels consistent à gérer les défaillances avec élégance. L'orchestration financière est soumise à une contrainte plus difficile : l'argent est déjà en mouvement.
Prenons l'exemple d'un dépôt instantané. Un client reçoit 10 000 $ USDC. Nous créditons immédiatement son compte (avant le règlement de l'ACH sous-jacent) afin qu'il puisse utiliser ce capital sans délai. En coulisses, nous avons accordé un prêt. Lorsque l'ACH arrive quelques jours plus tard, nous percevons le remboursement et les frais.
Cela représente quatre opérations sur deux systèmes externes : liquidation cryptographique, versement du prêt, règlement ACH, perception des frais. Chaque étape dépend de la précédente, et chacune d'entre elles peut échouer. Vous ne pouvez pas gérer cela avec des gestionnaires dispersés et ad hoc.
L'abstraction fondamentale
Flow of Funds est un système d'orchestration déclaratif basé sur des règles. L'abstraction centrale comporte trois parties :
Événements sont des signaux indiquant qu'un événement s'est produit : un règlement ACH, la réception de fonds, l'enregistrement d'une autorisation de carte, etc. Les événements peuvent provenir de systèmes externes ou être émis en interne.
Règles définir ce qui doit se passer en réponse à des événements. Chaque règle spécifie une liste d'événements déclencheurs et une séquence d'effets secondaires à exécuter.
Effets secondaires sont les actions que nous entreprenons en réponse à l'événement : initier un transfert, créer une retenue, verser un prêt, percevoir des frais. Une règle ne s'applique qu'une seule fois. La première fois qu'un événement correspondant survient, les effets secondaires s'exécutent dans l'ordre et la règle est consommée. Cela garantit l'idempotence dans le contexte du flux.
Pourquoi déclaratif ?
L'alternative est l'orchestration impérative : des gestionnaires appelant d'autres gestionnaires, des états dispersés dans différentes tables, le « flux » n'existant que dans la coordination implicite entre les morceaux de code.
Cela fonctionne pour les flux simples. Pour les opérations financières sur plusieurs jours et impliquant plusieurs systèmes, avec des suspensions pour conformité et des échecs partiels, cela devient ingérable. La gestion des erreurs est ad hoc. Les chemins de récupération sont implicites. Six mois plus tard, personne ne peut répondre avec certitude à la question « que se passe-t-il si l'étape 3 échoue après la réussite de l'étape 2 ? ».
Les règles déclaratives inversent le modèle. Vous définissez explicitement la machine à états : ceux-ci déclencheurs d'événements ceux-ci actions. Le moteur d'orchestration gère l'exécution, la persistance et la récupération. Le flux est la documentation.
Garanties
FoF nous donne quatre invariants sur lesquels nous pouvons compter :
1. Idempotence - Une règle se déclenche exactement une fois par contexte de flux, indépendamment des événements dupliqués ou des réessais.
2. Rapprochement déterministe - étant donné les mêmes événements, le flux aboutit au même état
3. Auditabilité complète - chaque effet secondaire est suivi en remontant jusqu'à l'événement qui l'a déclenché
4. Composabilité - Les flux complexes sont construits à partir de règles simples qui s'assemblent sans devenir monolithiques.
Suivi de l'exécution
Nous suivons chaque exécution d'effet secondaire via des enregistrements Node, chacun étant lié à son parent, formant ainsi une arborescence d'exécution complète. Lorsque la conformité nécessite une piste d'audit, nous pouvons retracer le chemin exact à travers le système.
Composabilité : règles imbriquées
Les règles peuvent générer des règles enfants. C'est ainsi que des flux complexes en plusieurs étapes se composent sans devenir monolithiques. Lorsqu'une transaction de sortie est créée, la règle initiale n'essaie pas de tout gérer. Elle configure futur règles — auditeurs attendant des événements qui se produiront plus tard :
La logique de règlement n'existe pas sous forme de code mort attendant d'être appelé. Elle existe sous forme de règle, attendant son événement. Lorsque le webhook du fournisseur bancaire arrive quelques jours plus tard, la règle se déclenche et le flux se poursuit. La règle parent est consommée et la règle enfant transmet le contexte.
Cela signifie également que les flux peuvent être composés de manière arbitraire. Vous souhaitez mettre en place des dépôts instantanés ? Rien de plus simple. Ajoutez une règle qui débourse le prêt et définit les règles de remboursement. Chaque élément est isolé, mais tous s'assemblent pour former un flux cohérent.
Contextes d'exécution des effets secondaires
Tous les effets secondaires ne sont pas identiques. Certains doivent être atomiques avec la transaction de la base de données. Certains appellent des API externes. Certains sont de type « fire-and-forget » (lancer et oublier).
La récompense
Le principal avantage réside dans la manière dont FoF modifie la façon dont les ingénieurs écrivent le code d'orchestration chez Slash. Sans cela, chaque ingénieur résout les mêmes problèmes différemment. Tout le monde réinvente la roue, et les roues ont toutes des formes légèrement différentes.
FoF relève le niveau. Vous définissez quoi devrait se produire, pas comment pour gérer tous les modes de défaillance. Le framework gère l'exécution, la persistance et l'observabilité. Les nouveaux ingénieurs peuvent lire une définition de flux et la comprendre sans avoir à parcourir plusieurs couches de code impératif. Il est également plus difficile d'écrire un mauvais code d'orchestration lorsque l'abstraction vous oblige à être explicite sur les événements, les effets secondaires et les transitions d'état.
Rampes : FoF en pratique
Avec FoF comme base pour composer les flux financiers, la création de nos produits phares consistait à définir les règles appropriées pour chaque flux. L'abstraction ne se soucie pas des systèmes qui se trouvent à l'autre bout, elle se contente d'orchestrer.
Les rampes de sortie et d'entrée sont des « flux » orchestrés par ce moteur, qui introduit un nouveau système externe : un fournisseur de cryptomonnaies (ou bureau OTC) qui gère les conversions entre stablecoins et monnaies fiduciaires. Comme tout système externe, ils fournissent des mises à jour d'état selon leurs propres conditions, que nous pouvons utiliser pour déclencher des événements FoF. À partir de là, il ne s'agit plus que d'une composition de flux.
Sorties
Les rampes de sortie permettent aux clients de recevoir des paiements en stablecoins et de les régler en USD sur leur compte Slash. Le processus est simple :
- Le client reçoit des USDC ou des USDT à une adresse de dépôt que nous générons via notre fournisseur de cryptomonnaies.
- Le fournisseur détecte le dépôt, le liquide en USD et lance un virement ACH ou bancaire.
- Notre prestataire bancaire reçoit le virement entrant.
- Nous rapprochons le transfert de la transaction initiale et créditons le compte.
Pour les dépôts instantanés, où nous créditons immédiatement le client et recouvrons le remboursement lorsque l'ACH est réglé, le flux comprend le versement du prêt, le recouvrement du remboursement et la saisie des frais. Chaque préoccupation est une règle distincte, à l'écoute de son événement, qui s'intègre dans un flux unique et cohérent. La définition FoF ressemble à ceci :
Rampes d'accès
Les rampes d'accès fonctionnent à l'inverse : les clients envoient des USD depuis leur compte Slash et reçoivent des stablecoins sur un portefeuille externe. Le flux :
- Le client initie un transfert vers une adresse de portefeuille de destination.
- Nous créons des retenues sur leur compte pour le montant plus les frais.
- Nous envoyons un virement ACH ou bancaire à notre fournisseur de cryptomonnaies conformément à vos instructions de dépôt.
- Le fournisseur reçoit les fonds et livre les stablecoins à leur destination.
Ce qui est remarquable, c'est le peu de nouvelles infrastructures que cela a nécessité. Le cadre FoF et la logique de réconciliation que nous avons mis en place pour les rampes de sortie ont été directement repris. Les rampes d'entrée sont des règles différentes qui écoutent des événements différents, mais le mécanisme sous-jacent reste le même.
Cycle de vie sur la chaîne
FoF a résolu la coordination du côté des monnaies fiduciaires : rails bancaires, fournisseurs, conformité. Mais lorsque nous avons commencé à développer Global USD, nous avons abordé un nouveau domaine : la chaîne elle-même. Effectuer une transaction sur la chaîne, confirmer qu'elle a bien été effectuée, gérer les échecs et les réorganisations de la chaîne, et dériver un état précis à partir des résultats : voilà un problème de coordination différent. Nous avions besoin des mêmes garanties que celles dont nous disposions avec FoF, mais pour l'exécution sur la chaîne.
Le modèle : intention → exécution → réconciliation
Nous utilisons un modèle cohérent pour toutes les opérations de la blockchain :
1. Intention: Déclarer ce que nous essayons de faire
2. Exécuter: Soumettre la transaction et la guider jusqu'à son inclusion dans le bloc.
3 Réconcilier: Traiter les blocs confirmés, mettre à jour l'état interne, déclencher les flux en aval
Si vous venez du monde de la finance traditionnelle, l'analogie est simple :
- Intention ≈ ordre de paiement
- Exécuter ≈ en attente
- Rapprocher ≈ comptabilisé
Chaque phase comporte des responsabilités et des modes de défaillance distincts. Le reste de cette section explique comment nous avons construit chaque couche.
Avant de pouvoir exécuter quoi que ce soit, nous devons définir quoi nous exécutons. Une transaction blockchain est fondamentalement une instruction (une fonction invoquée avec des paramètres), mais la chaîne ne comprend pas les instructions lisibles par l'homme. Tout est encodé dans calldata - un bloc d'octets hexadécimaux qui spécifie la fonction à appeler et les arguments à passer.
Par exemple, un simple transfert USDC (« envoyer 500 USDC à l'adresse X ») devient :
0xa9059cbb0000000000000000000000007e2f5e1fd4d79ed41118fc6f59b53b575c51f182000000000000000000000000000000000000000000000000000000001dcd6500
Les données brutes telles que celles-ci sont opaques et ne vous apprennent rien sur pourquoi argent transféré. Et lorsque vous créez des systèmes qui doivent suivre le contexte commercial, non seulement les actifs transférés, mais aussi le fait qu'il s'agissait d'un prélèvement de frais pour la facture n° 1234, vous devez préserver ce contexte.
Nous résolvons ce problème grâce à un registre de définitions d'appels typés :
Les ingénieurs travaillent en termes de domaine (contrat, destinataire, montant) plutôt qu'en chaînes hexadécimales. Le registre valide les entrées, gère l'encodage et conserve les métadonnées dont nous aurons besoin ultérieurement : catégorie, balises et contexte commercial.
La création d'un appel devient simple :
Chaque appel devient un enregistrement BlockchainCall :
Nous considérons le BlockchainCall comme l'unité atomique de travail. Une transaction peut regrouper plusieurs appels, mais chaque appel représente une seule opération comptable. Le champ de requête conserve l'intégralité de la saisie saisie en plus des octets codés, y compris toutes les métadonnées et le contexte arbitraire. Ces métadonnées nous permettent de répondre à la question « à quoi correspondait ce transfert de 500 dollars ? » lorsque nous rapprochons l'état de la chaîne des opérations commerciales.
Exécution : accompagner les transactions jusqu'à leur finalisation
Soumettre une transaction semble simple. En pratique, il y a un champ de mines entre « envoyer ceci » et « cela est arrivé ».
Lorsque vous soumettez une transaction, celle-ci n'est pas directement intégrée à un bloc. Elle entre dans le mempool- une zone d'attente où les transactions sont conservées jusqu'à ce qu'un producteur de blocs les récupère. Pendant l'attente, les transactions peuvent être abandonnées (mempool plein), surenchéris (quelqu'un a payé des frais plus élevés) ou bloquées (prix du gaz trop bas pour les conditions actuelles du réseau).
Gaz C'est ainsi que les réseaux basés sur Ethereum fixent le prix des calculs. Chaque opération coûte du gaz, et vous payez le gaz avec le jeton natif du réseau. Lorsque vous soumettez une transaction, vous spécifiez le prix maximum du gaz que vous êtes prêt à payer. Si la congestion du réseau augmente après votre soumission, votre prix du gaz pourrait ne plus être compétitif : votre transaction reste dans le mempool, en attente, potentiellement pour toujours.
Même après qu'une transaction ait été enregistrée dans un bloc, elle n'est pas encore définitive. Les blockchains peuvent subir réorganisations (reorgs) - situations dans lesquelles le réseau rejette les blocs récents et les remplace par une chaîne de blocs différente. Une transaction que vous pensiez confirmée peut disparaître. Cela est rare sur les réseaux matures, mais « rare » ne signifie pas « jamais » lorsque vous transférez de l'argent réel.
Chacune de ces défaillances se produit à un niveau différent : estimation du gaz, signature, soumission, confirmation. Et chacune nécessite une solution différente : une transaction bloquée doit être resoumise avec un gaz plus élevé, une signature invalide doit être resignée, une réorganisation nécessite de réessayer l'ensemble du flux.
Nous gérons cela en modélisant le cycle de vie de l'exécution comme une hiérarchie de 4 entités. Au sommet se trouve le résultat commercial que nous essayons d'atteindre. En dessous, des couches de plus en plus spécifiques gèrent la préparation, la signature et la soumission. Chaque couche possède son propre domaine d'échec et peut réessayer indépendamment avant de passer à la couche supérieure :
BlockchainIntent représente le résultat commercial : « transférer 500 USDC à cette adresse en paiement de la facture n° 1234 ». C'est l'orchestrateur de haut niveau qui suit l'ensemble du cycle de vie et peut générer des nouvelles tentatives si nécessaire.
Appel préparé est une transaction immuable et non signée avec des estimations de gaz verrouillées. Si les estimations de gaz expirent (changement des conditions du réseau), nous créons un nouveau PreparedCall.
Exécution d'appel préparé représente une tentative de signature. Pour les opérations côté serveur, nous signons automatiquement. Pour les opérations destinées aux utilisateurs (comme Global USD), l'utilisateur donne son accord via OTP. Dans tous les cas, une fois la signature effectuée, nous sommes prêts à soumettre la demande.
Nœud d'exécution d'appel préparé Il s'agit d'une seule tentative de soumission. Nous envoyons la transaction au réseau et demandons son inclusion. Si elle échoue pour des raisons pouvant faire l'objet d'une nouvelle tentative (délai d'attente réseau expiré, suppression du mempool), nous créons un nouveau nœud et réessayons.
Chaque couche gère son propre domaine de défaillance :
L'idée clé est que les échecs remontent au niveau supérieur lorsqu'un niveau a épuisé toutes ses options de correction. Prenons l'exemple d'une sous-estimation persistante du gaz. La congestion du réseau atteint son pic et les paramètres de gaz verrouillés dans notre PreparedCall ne sont plus compétitifs. Le nœud d'exécution réessaie plusieurs fois, et la congestion finit peut-être par se résorber. Après N échecs, il ne peut plus rien faire. L'échec est transmis à l'exécution, qui atteint un état terminal et est transmis à l'intention. L'intention génère une intention enfant avec des multiplicateurs de gaz plus élevés, construit un nouveau PreparedCall, et le cycle recommence.
Chaque couche gère son propre domaine d'échec, mais l'escalade est explicite. L'intention parentale conserve l'historique complet ; l'intention filiale obtient une nouvelle tentative avec des paramètres ajustés. Nous ne perdons jamais le contexte concernant pourquoi Nous réessayons.
Réconciliation : des événements en chaîne à l'état du produit
Une transaction est incluse dans un bloc. Et maintenant ?
La blockchain ne nous indique pas directement qu'un transfert de 1 000 USDC a eu lieu. Elle nous indique qu'une transaction a été exécutée et a émis une certaine quantité. journaux d'événementsNous devons analyser ces journaux, comprendre leur signification et mettre à jour notre état interne en conséquence.
Les journaux d'événements permettent aux contrats intelligents de communiquer ce qui s'est passé pendant leur exécution. Lorsque vous appelez la fonction transfert fonction sur un contrat USDC, le contrat émet un Transfert événement avec trois données : qui l'a envoyé, qui l'a reçu et pour quel montant. Cet événement est enregistré dans le reçu de transaction sous forme d'entrée de journal.
Mais les journaux sont encodés sous forme de champs de sujet et de données contenant des valeurs encodées en hexadécimal. Leur analyse nécessite de connaître la signature de l'événement et de décoder les paramètres. Un journal de transfert brut ressemble à ceci :
Comment savoir s'il s'agit d'un transfert ? Chaque journal sujets[0] est le hachage keccak256 de la signature de l'événement, dans ce cas, 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef est le hachage de Transfert (adresse indexée depuis, adresse indexée vers, valeur uint256)- l'événement de transfert ERC-20 standard. Les paramètres marqués comme indexé sont stockés dans le tableau topics dans l'ordre de déclaration, après le hachage de signature. Pour cet événement Transfer, de est dans sujets[1] et à dans sujets[2]. Les paramètres non indexés tels que valeur sont codés en ABI dans données.
Extraction des détails du transfert à partir de ce journal :
- de:
sujets[1](32 octets, complétés par des zéros) →0x7e2f5e1fd4d79ed41118fc6f59b53b575c51f182 - à:
sujets[2](32 octets, complétés par des zéros) →0xa6dbc393e2b1c30cff2fbc3930c3e4ddfc9d1373 - valeur:
donnéesdécodé en tant que uint256 →0x4c4b40= 5 000 000 (5 USDC, puisque l'USDC comporte 6 décimales).
La charge mentale liée à la nécessité de savoir analyser chaque type de journal semble être un cauchemar. C'est pourquoi nous avons développé des processeurs de journaux qui savent analyser des types d'événements spécifiques et les transformer en état de domaine :
Le processeur ingère les données brutes du journal, les analyse en champs typés (au lieu de chaînes hexadécimales) et produit des entités de domaine.
Inclusion ou confirmation
Nous gérons deux étapes distinctes du cycle de vie :
- Inclusion - La transaction apparaît d'abord dans un bloc. L'état est provisoire : le bloc pourrait encore être réorganisé.
- Confirmation - Le bloc atteint une profondeur suffisante (suffisamment de blocs suivants pour éliminer la possibilité d'une réorganisation). L'état est définitif.
Cette distinction est importante. Nous pourrions mettre à jour l'interface utilisateur pour afficher un statut en attente lors de l'inclusion, mais nous ne déclencherions pas les flux FoF en aval avant confirmation. Le coût d'une action sur un statut provisoire est illimité.
Les processeurs de journaux traitent les événements individuels, mais nous avons souvent besoin de les coordonner ou d'ajouter un état au niveau de la transaction. Les processeurs de transactions regroupent tout cela : ils reçoivent la sortie fusionnée de tous les processeurs de journaux et peuvent la transformer, y ajouter des éléments ou déclencher des effets supplémentaires en aval. C'est également là qu'apparaît le cycle de vie en deux phases. processTransaction s'exécute à l'inclusion - nous produisons un état provisoire. Confirmation du processus s'exécute une fois que le bloc est finalisé - c'est généralement là que nous achevons les cycles de vie des opérations financières.
Relier les journaux aux appels
Lorsque notre processeur de journaux produit un enregistrement de transfert, il doit renvoyer vers l'appel BlockchainCall d'origine. Le journal nous indique quoi Ce qui s'est passé : les actifs ont été transférés de A vers B. Le BlockchainCall nous indique pourquoi—il s'agissait d'un prélèvement de frais, d'un paiement à un fournisseur ou d'un remboursement. Pour les transactions simples avec un seul appel, cela est facile à déterminer. Pour les transactions groupées, où nous regroupons plusieurs opérations en une seule transaction sur la chaîne afin d'économiser du gaz, cela devient plus difficile. Le reçu nous fournit une liste plate de tous les journaux émis pendant l'exécution, sans indication de l'appel qui a produit tel ou tel journal. Nous résolvons ce problème grâce au traçage des cadres d'appel, que nous abordons dans la section avancée ci-dessous.
Avancé : Attribution de journaux groupés à des appels individuels
Cette section traite d'un défi technique spécifique lié aux transactions groupées. Si vous n'utilisez pas ERC-4337 ou l'exécution groupée, vous pouvez passer directement à la section Global USD. Nous avons mentionné précédemment que le rattachement des journaux à leur BlockchainCall d'origine est simple pour les transactions simples. Ce n'est pas le cas pour les transactions groupées.
Le problème
Lorsque nous regroupons plusieurs opérations en une seule transaction, par exemple un paiement de 500 $ plus des frais de 1 $, les deux s'exécutent de manière atomique. Le reçu de transaction nous fournit une liste plate de tous les journaux émis pendant l'exécution :
Nous obtenons un tableau plat de tous les journaux émis pendant l'exécution. En examinant ce reçu, nous pouvons identifier deux événements de transfert aux indices 1 et 2 du journal (qui partagent tous deux le 0xddf252ad... transfert de signature d'événement dont nous avons parlé précédemment).
Mais lequel correspondait au paiement et lequel aux frais ? Le reçu ne nous le dit pas : les journaux sont attribués à la transaction de niveau supérieur, et non aux appels individuels d'un lot. Vous pourriez penser : il suffit de faire correspondre les journaux aux appels dans l'ordre. Mais cela ne fonctionne que si chaque appel génère exactement un journal. Un simple transfert en génère un ; un échange peut en générer cinq. Sans connaître les limites, vous ne pouvez pas les mapper de manière fiable.
Suivi des trames d'appel
La solution s'est avérée être déboguer_traceTransaction- une méthode RPC du nœud d'archive Geth que la plupart des gens utilisent pour déboguer les transactions ayant échoué. Mais elle fait autre chose : elle rejoue la transaction et renvoie l'arborescence complète des cadres d'appel, avec les journaux joints à la profondeur correcte dans la hiérarchie des appels.
Le résultat est une structure récursive imbriquée de cadres d'appel (simplifiée pour plus de lisibilité).
Nous aplatissons cette structure récursive en un schéma qui préserve les relations arborescentes :
Considérons une opération utilisateur groupée comprenant deux transferts USDC : un paiement de 500 $ et des frais de 1,10 $, représentés par la trace d'exécution ci-dessus. La trace nous donne :

L'ensemble de la transaction peut désormais être représenté sous forme d'arborescence. Cela redéfinit le problème dans son ensemble : au lieu de déduire la structure à partir d'un tableau de journaux plat, nous reconstruisons l'arborescence d'exécution, où la hiérarchie des appels est explicite et où les journaux sont associés aux trames qui les ont émis.
À partir de là, l'attribution est simple. Trouvez le nœud correspondant à la exécuterParLot() appel, itérer à travers ses enfants aux indices 0..N-1, et collecter de manière récursive les journaux de chaque sous-arbre. Chaque index enfant 0..N-1 correspond directement à son BlockchainCall correspondant indexDansLotNous savons désormais exactement quel appel a généré quels journaux.

Étant donné que pratiquement toutes les transactions nécessitent cette attribution, nous l'avons intégrée directement dans notre processeur de journaux. Il reconstruit l'arborescence complète des appels, associe les journaux à leurs trames d'origine et résout tous les BlockchainCalls du lot. Chaque processeur de journaux reçoit ensuite le contexte d'appel et de trame spécifique au journal qu'il traite :
La chaîne d'attribution complète :
USD mondial : le Capstone
Les rampes de sortie et d'entrée ont résolu un problème pour nos clients existants, à savoir les entreprises disposant de comptes bancaires aux États-Unis qui souhaitaient passer de la monnaie fiduciaire à la cryptomonnaie. Mais nous avons continué à recevoir des demandes d'un autre segment : les entreprises internationales qui ont besoin d'accéder au dollar américain, mais qui ne peuvent pas l'obtenir facilement.
Si vous êtes un prestataire informatique en Argentine, un commerçant en ligne au Nigeria ou une entreprise SaaS en Asie du Sud-Est, l'ouverture d'un compte bancaire aux États-Unis nécessite souvent la création d'une entité américaine, ce qui implique des avocats, des agents enregistrés et des mois de frais généraux. De nombreuses entreprises légitimes se retrouvent ainsi exclues de l'économie du dollar, non pas à cause de leurs activités, mais en raison de leur lieu d'implantation.
Les stablecoins changent la donne. Un solde USDC correspond à un solde en dollars. Global USD est notre tentative de construire une infrastructure bancaire sur cette base.
Conçu pour ne pas être gardien
Nous avons conçu Global USD comme un système non dépositaire. Cette décision a été motivée par deux facteurs : la complexité réglementaire et la confiance.
La détention des fonds des clients est soumise à des exigences en matière de licence qui varient selon les juridictions. Une architecture non dépositaire simplifie notre position en matière de licence sur bon nombre de ces marchés. Du point de vue de la confiance, les clients contrôlent leurs propres clés : de par sa conception, Slash ne peut initier de transferts sans l'autorisation cryptographique des signataires du compte.
La primitive de base est le portefeuille intelligent: un contrat intelligent qui agit comme un portefeuille, mais avec un contrôle d'accès programmable.
Chaque compte Global USD est un portefeuille intelligent régi par une signature multiple. Chaque membre autorisé de l'entreprise détient une clé. Les transferts doivent être approuvés avant d'être exécutés. Slash peut préparer une transaction, mais nous ne pouvons pas exécuter sans l'autorisation du signataire.
Signature sans garde
Cela soulève une question relative à l'expérience utilisateur : si les utilisateurs contrôlent les clés, ne doivent-ils pas gérer manuellement les phrases de départ et signer les transactions ?
Nous utilisons l'infrastructure de portefeuille intégrée de Privy et Alchemy. Lorsqu'un utilisateur crée un compte, une clé privée est générée dans une mémoire isolée du matériel (un « environnement d'exécution fiable », ou TEE). La clé existe, mais elle est conçue pour être inaccessible à Slash ou à toute autre personne directement. Lorsqu'un utilisateur initie un transfert, il l'approuve via OTP, qui autorise le TEE à signer en son nom. La transaction signée est ensuite soumise au réseau.
Du point de vue de l'utilisateur, cela s'apparente à l'approbation d'un virement bancaire. Du point de vue de la conservation, nous ne touchons jamais aux clés privées.
Ce que cela débloque
Une entreprise à Lagos peut désormais détenir des dollars, recevoir des paiements de clients américains et payer des fournisseurs internationaux, le tout sans compte bancaire américain, sans risque de garde et avec les mêmes procédures d'audit et de conformité que celles que nous appliquons à tous les clients Slash.
C'est ce que peuvent réellement être les stablecoins : non seulement un moyen de paiement, mais aussi une infrastructure fondamentale pour un système financier plus accessible.
Et ensuite ?
Les primitives que nous avons créées ne servent pas uniquement à transférer des fonds entre les monnaies fiduciaires et les cryptomonnaies. Elles constituent la base de tout ce que nous développons chez Slash. Nous élargissons notre offre de comptes internationaux afin de permettre à davantage d'entreprises d'accéder aux rails USD, quel que soit leur lieu d'implantation. Nous développons également notre carte internationale : une carte à cashback élevé, adossée à une cryptomonnaie stable, qui permet aux clients de dépenser leur solde partout. Ces deux services s'appuient largement sur les mêmes cadres d'orchestration et d'exécution que nous avons décrits ici. Si vous avez lu jusqu'ici et que vous êtes un ingénieur désireux de résoudre des problèmes d'infrastructure complexes pour de vrais clients dans une entreprise en pleine croissance, nous recrutons.