Le rail Robinhood

Les actions tokenisées que détiennent les vaults vivent sur Robinhood Chain, un L2 Arbitrum Orbit. Le protocole l'atteint par LayerZero, avec l'OFT USDG de Paxos comme jambe cash.

Pourquoi ce rail

Le choix a été arrêté le 2026-09-11, après avoir écarté le rail précédent.

Sur un rail à mint primaire, un contrat vault doit être éligible à détenir l'actif chez l'émetteur : KYB, enregistrement de l'adresse du contrat, et une confirmation écrite que l'émetteur n'a jamais documentée publiquement. C'était le seul blocage vraiment non contournable du projet.

Les pools secondaires de Robinhood Chain n'exigent rien de tel : elles sont ouvertes à tous. StockFun n'a aucune relation avec l'émetteur et n'en a pas besoin.

Le prix payé pour cette liberté est une dépendance cross-chain : un pont, deux hubs, et un stablecoin émis par un tiers qui peut le geler. C'est un risque assumé et documenté, pas un risque évité.

Le circuit

flowchart LR V[TreasuryVault

Ethereum] -->|ETH → USDC

Uniswap v4| U[USDC] U -->|USDC → USDG

Curve| G[USDG] G --> BH[BridgeHub] BH -->|OFT Paxos

LayerZero| RH[RemoteHub

Robinhood Chain] RH --> MV[Vault miroir

CREATE2, un par marché] MV -->|pools v3 / v4| S[Stock Tokens] S -->|adaptateurs d'actions, wrappées| AD[AirdropDistributor

Ethereum] AD -->|réclamations| HO[Holders du token

sur Ethereum]

Le trajet retour de l'USDG, de Robinhood Chain vers Ethereum, ne servait qu'au buyback du créateur ; les deux ont été retirés du code le 2026-09-28.

Depuis le 2026-10-04, le vault miroir envoie ses actions au contrat de l'airdrop sur Ethereum : chaque action est verrouillée dans son adaptateur LayerZero sur Robinhood Chain et frappée wrappée sur Ethereum, où les holders la réclament. Ce chemin ne transporte que des actions. Les adaptateurs, un par action, ne sont pas encore dans le dépôt pour le mainnet ; les tests utilisent des mocks, et le test LayerZero sur testnet du 2026-10-06 a utilisé des adaptateurs de test (plus bas).

Ce qui est permissionless et ce qui ne l'est pas

Composant Statut
Endpoint LayerZero Permissionless
Pools secondaires de Stock Tokens Permissionless — c'est ce que le protocole utilise
Mint / burn primaire Robinhood KYB — non utilisé
USDG Paxos contrôle le mint et le burn, et peut mettre en pause ou geler

Le dernier point est la dépendance la plus dure du rail, et elle est réelle.

Le vault miroir

Chaque marché a un vault miroir sur Robinhood Chain, déployé en CREATE2 à une adresse prédictible depuis Ethereum. Le keeper peut donc le faire pré-déployer par le hub distant avant que l'USDC n'arrive, ce qui évite qu'un transfert atterrisse sur une adresse sans code. Depuis le 2026-10-05, seuls le keeper et l'owner de StockFun le peuvent (predeploy) : jusque-là, n'importe qui le pouvait, même pour un marché qui n'existait pas encore, liant son vault miroir au câblage de ce jour-là. Le hub distant apprend le keeper d'un batch du pont, qui le porte : avant le premier batch, il ne connaît aucun keeper, si bien que l'owner de StockFun pré-déploie le vault miroir du premier marché. Depuis la seconde boucle d'audit du 2026-10-05, un marché dont le keeper ne peut pas pré-déployer le vault miroir (avant le premier batch, ou après un changement de keeper que le hub distant n'a pas encore appris) est laissé hors du batch, avec une alerte, au lieu de partir avec trop peu de gas pour déployer son vault ; les autres marchés passent, et leur batch porte le nouveau keeper.

Depuis le 2026-10-02, chaque vault miroir est un proxy, un MirrorVaultProxy, devant l'implémentation de vault que le hub distant désigne au moment du déploiement du vault. Le constructeur du proxy ne prend aucun argument : son creation code, et avec lui l'adresse de chaque vault miroir, reste prédictible depuis Ethereum quelle que soit l'implémentation. Le basket du vault arrive avec le premier batch, qui, depuis le 2026-10-05, aligne aussi le routeur d'actions et l'oracle du vault sur ceux que le hub distant désigne alors : un vault déployé avant qu'une action soit listée accepte un basket qui la contient. L'owner de StockFun, tel que le hub distant le reflète, upgrade les vaults miroirs un par un, marché par marché, avec effet immédiat.

Les routes de swap ne sont pas codées en dur : elles arrivent en calldata, encodées comme abi.encode(uint8 version, bytes payload) — version 3 pour un chemin Uniswap v3 compacté, version 4 pour un tableau de PathKey v4. Le vault reçoit plusieurs candidats par jambe et exécute sur le premier qui franchit sa borne. Depuis le 2026-10-01, une route qui n'exécute qu'une partie du montant échoue, et le candidat suivant est essayé ; avant, un remplissage partiel sur une route v3 laissait l'USDG non dépensé bloqué dans le routeur.

Depuis le pipeline de sécurité du 2026-10-01, une route v3 s'exécute un pool à la fois. Chaque pool doit prendre toute son entrée, sinon la route échoue ; sa sortie revient au routeur d'actions et devient l'entrée du pool suivant, et le dernier pool paie le vault, sous le minimum de la jambe. Un pool qui échoue annule les pools précédents de la même tentative, et le candidat suivant est essayé. Jusque-là, la vérification ne voyait que le premier pool d'une route : un remplissage partiel plus loin laissait le token intermédiaire dans le routeur v3 d'Uniswap, SwapRouter02, où n'importe qui pouvait le prendre, alors que la jambe réussissait. Une jambe v3 à plusieurs sauts coûte désormais un swap et une approbation par pool.

Chaque jambe ne dépense que l'USDG réservé à son action, aux poids du basket : voir Le TreasuryVault. Sa borne de prix contre le feed de l'action, 200 points de base par défaut, est un réglage que tient le hub distant et que chaque vault miroir lit en direct (setStockMaxSlippageBps). Depuis le 2026-10-05, le vault tient le minimum du keeper, jamais plus lâche que cette borne, sur ce qui est réellement arrivé, et chaque jambe s'exécute à part : une jambe qui échoue — ses routes qui échouent toutes, une action gelée, une sortie sous le minimum — garde sa réservation, avec l'événement LegFailed, et les autres passent ; si aucune ne passe, l'appel échoue avec la raison de la première.

Quand l'oracle retient un prix

Depuis le 2026-10-06, l'oracle des vaults miroirs a deux gardes, que recommande la documentation de Robinhood elle-même ; chacune ne peut que retenir un prix, jamais en changer un.

  • Une opération sur titres. Pendant qu'une action en traverse une (une division, par exemple), son token dit son oracle en pause (oraclePaused()), et son feed Chainlink garde sa dernière valeur, qui peut sembler fraîche alors que le multiplicateur du token change. L'oracle retient alors le prix de cette action : sa jambe d'achat échoue seule (StockOraclePaused), son USDG reste réservé pour elle, et les autres actions du basket sont achetées. Le contrôle est allumé pour chaque action ; l'owner de StockFun peut l'éteindre pour une action (setOraclePauseCheck), dont le prix retombe alors sur les contrôles de son propre feed. Un token qui ne répond pas compte comme non en pause.
  • Le séquenceur. Robinhood Chain est une chaîne Arbitrum à séquenceur unique. Avec le feed de disponibilité du séquenceur L2 de Chainlink posé (setSequencerUptimeFeed), l'oracle retient tous les prix tant que le feed dit le séquenceur arrêté, revenu depuis au plus le délai de grâce (une heure par défaut), ou ne se lit pas : aucune jambe n'achète d'ici là. Aucun feed de ce type n'existe aujourd'hui pour Robinhood Chain : le rail est donc déployé avec ce contrôle éteint, et l'owner de StockFun posera le feed si Chainlink en publie un.

Le keeper voit l'un et l'autre avant de coter quoi que ce soit (voir Le keeper), le Worker dit pourquoi le prix d'une action manque, et la dapp l'affiche (voir La dapp).

L'envoi des actions à l'airdrop

Depuis le 2026-10-04, une fois achetées, les actions ne quittent le vault miroir que d'une façon : sendToAirdrop. Le keeper l'appelle avec la liste des actions à envoyer et paie les frais LayerZero ; ce qu'il paie en trop lui est rendu. Pour chaque action, le vault envoie tout son solde par l'adaptateur de cette action vers le contrat de l'airdrop sur Ethereum, avec l'identifiant du marché en charge utile. Le keeper ne désigne ni le montant ni la destination : l'adaptateur de chaque action (setStockAdapter, qui vérifie que l'adaptateur porte bien ce token) et le contrat de l'airdrop (setAirdrop) sont désignés sur le hub distant par son admin, l'owner de StockFun. Une action listée deux fois ou hors du basket fait échouer l'appel.

Depuis le 2026-10-06, le keeper nomme le gas que chaque livraison reçoit sur Ethereum : sendToAirdrop(stocks, receiveGas, composeGas), le lzReceive de l'OFT de l'action en plus de ce que cet OFT impose, et le compose du contrat de l'airdrop. Le hub distant tient chaque valeur entre le plancher et le plafond que fixe son admin, zéro prenant la valeur par défaut (airdropGas), et le vault construit l'envoi et son devis avec ce que le hub accorde ; l'appel avec les seules actions prend les deux valeurs par défaut. Le keeper choisit les valeurs à partir de simulations de la livraison sur Ethereum (voir Le keeper) : la mise à niveau Glamsterdam d'Ethereum, active sur Sepolia depuis le 2026-10-06, fait coûter à un slot de stockage neuf environ cinq fois plus, et le seul chiffre de compose d'avant, 600 000 gas, a laissé chaque livraison du premier cycle du test LayerZero sur testnet à court de gas. Un hub distant mis à jour depuis une version sans ces bornes refuse tout envoi et tout devis (AirdropGasNotSet) jusqu'à ce que les deux soient posées.

Depuis le 2026-10-05, chaque action part à part : une action sans adaptateur, dont le solde ne se lit pas (BalanceUnreadable, un gel de son émetteur par exemple), ou dont l'envoi échoue — un émetteur qui refuse, un pair manquant, des frais que l'envoi n'apporte pas — reste au vault, avec l'événement AirdropSendFailed, ses frais non dépensés, et les autres partent. Si rien ne part, l'appel échoue et dit pourquoi. Le devis, quoteSendToAirdrop, saute ce qu'il ne sait pas chiffrer au lieu d'échouer.

LayerZero transporte six décimales : moins de 10^12 unités d'une action à 18 décimales, un millionième de token, ne peuvent pas passer et restent au vault pour un envoi suivant.

Sur Ethereum, l'OFT de l'action frappe l'action wrappée au contrat de l'airdrop, puis l'endpoint de LayerZero l'appelle avec la charge utile. Le contrat ne crédite la livraison que si elle vient de son endpoint, d'un OFT d'action que l'owner a enregistré, de Robinhood Chain, et si elle a été envoyée par le vault miroir que le hub de pont dérive pour le marché désigné par la charge utile. Cette livraison s'exécute avec le gas que portait l'envoi (plus haut) ; une livraison à court de gas échoue sans rien perdre, stockée sur l'endpoint de LayerZero, les actions wrappées déjà sur le contrat de l'airdrop quand seul le compose a échoué, et n'importe qui peut la relancer avec plus de gas. Depuis le 2026-10-06, le keeper le fait, depuis sa propre clé, dans une borne, et alerte un second échec. Détail et mesures dans Déploiement et L'airdrop.

Upgrades et câblage

Depuis le 2026-10-02, chaque contrat StockFun du rail est upgradable sauf le déployeur des vaults miroirs, de l'adresse duquel est dérivée celle de chaque vault miroir. Sur Ethereum, le hub de pont et ses adaptateurs répondent à l'owner de la factory. Sur Robinhood Chain, le hub distant est l'autorité d'upgrade : il répond par son admin d'urgence, l'owner Ethereum tel que l'a porté le dernier batch ; le hub distant, les vaults miroirs, le routeur d'actions et l'oracle sont donc upgradés par l'owner de StockFun, avec effet immédiat.

Depuis le 2026-10-05, chaque contrat du rail a un levier pour ce qui y serait coincé. Les deux hubs et les vaults miroirs, qui tiennent des comptes, ont le mode urgence. Les adaptateurs du pont, sur Ethereum, le routeur d'actions et l'oracle, sur Robinhood Chain, qui ne gardent rien de personne entre deux transactions, ont rescue, de l'owner de StockFun. Depuis la cinquième boucle d'audit de ce jour-là, l'implémentation du hub distant, dont l'admin vit dans le stockage du proxy et vaut zéro sur l'implémentation, a pour levier son déployeur, pour un actif envoyé par erreur à sa propre adresse.

Le hub distant est déployé en premier sur sa chaîne, avec un admin initial, qui désigne ensuite le routeur d'actions, l'oracle et l'implémentation des vaults miroirs à venir, et, quand ils sont fournis, la route de l'airdrop et les adaptateurs d'actions. Le premier batch remplace cet admin par l'owner de StockFun.

Le même admin tient les réglages du hub distant, depuis le 2026-10-05 : les enregistrements que paie un sweep, 64 par défaut (setMaxRecordsPerSweep, jamais zéro), la borne de prix des achats des vaults miroirs, et le gas de chaque livraison d'airdrop (setAirdrop) ; et, depuis le 2026-10-06, les deux gardes de l'oracle et les deux bornes de gas des livraisons de l'airdrop sur Ethereum, chacune une valeur par défaut, un plancher et un plafond (setAirdropReceiveGas, 650 000 entre 200 000 et 1 500 000 ; setAirdropComposeGas, 1 250 000 entre 600 000 et 4 000 000 ; un plancher nul, un plancher au-dessus du plafond et une valeur par défaut hors des deux sont refusés). Le hub distant pose les deux à son initialisation, et DeployRemote les pose de nouveau à partir de son environnement. Un oracle de remplacement que nomme l'admin (setOracle) naît gardes éteintes : l'admin les rallume donc pour lui ; les vaults miroirs déjà initialisés gardent l'oracle de leur initialisation.

Sur Ethereum, le hub de pont ne déploie plus son adaptateur : l'adaptateur est déployé contre le hub, puis désigné une fois par l'owner de StockFun (setAdapter), qui en vérifie les épinglages. Un remplacement ultérieur, changeAdapter, est immédiat depuis le 2026-10-05. Il n'accepte qu'un adaptateur dont les épinglages sont exactement ceux de l'actuel : le même hub, la même factory, les mêmes tokens de la jambe cash, le même hub distant, la même chaîne de destination et le même transport. Il peut changer des chiffres de gas, des options ou le pool Curve, jamais une destination ; le hub distant n'accepte toujours les batches que de l'adaptateur pour lequel il a été construit (M-2, voir Le mode urgence). Un adaptateur se change donc en l'upgradant en place, à la même adresse ; une nouvelle adresse demanderait d'abord un upgrade du hub distant pour l'accepter. Ce point a été tranché le 2026-10-05 et laissé tel quel.

Les chiffres des adaptateurs eux-mêmes sont aussi des réglages de l'owner de StockFun : sur le rail USDG, le pire taux USDG par USDC accepté sur Curve, 30 points de base par défaut, et le gas de la dernière étape de la livraison sur Robinhood Chain (setSettings) ; depuis la dixième boucle d'audit, le 2026-10-06, ce gas est une base que demande tout batch, 200 000 par défaut, plus une part par marché du batch, 400 000 par défaut, et un batch porte au plus 17 marchés (setBatchGas ; voir « Le gas du compose d'un batch », plus bas). Jusque-là, un seul chiffre, 1 200 000 par défaut, payait tout batch quel que soit son contenu. Sur le rail canonique, le gas des deux tickets (setTicketGas). Depuis le 2026-10-05, le ticket comptable du rail canonique paie ce que demande l'inbox du pont pour la taille du batch au base fee du moment, le réglage n'en étant que le plancher. Un devis lu hors chaîne, sans prix du gas, voyait un base fee nul et chiffrait ce ticket au plancher seul, si bien qu'un long batch échouait au vrai base fee ; depuis la seconde boucle d'audit du même jour, le keeper demande le devis à un base fee qu'il nomme (quoteBridgeAt), deux fois le dernier, et récupère l'excédent.

Depuis la quatrième boucle d'audit du 2026-10-05, le ticket de dépôt, celui des tokens, se chiffre de la même façon : au plus grand du réglage tokenSubmissionCost et de ce que demande l'inbox pour depositCalldataLength() octets au base fee. bridge le paie au base fee du bloc, quoteBridgeAt au base fee que nomme l'appelant, l'envoi payant exactement ce devis, et quoteBridgeFor au base fee du bloc. La longueur est un réglage de l'owner, setDepositCalldataLength, jamais nul, pris de la configuration du déploiement : 1 024 octets par défaut, la passerelle en envoyant 740 pour l'USDC. Jusque-là, ce coût de soumission était un réglage fixe, que l'inbox compare au base fee : les batches échouaient au-delà d'environ 22 fois le base fee pour lequel il avait été dimensionné.

Des pannes qui restent circonscrites

Depuis le 2026-10-01, après l'audit de sécurité du 2026-09-29 :

  • Un basket refusé ne bloque que son propre marché. Si Robinhood Chain refuse le basket d'un marché, par exemple une action que son routeur ou son oracle ne prend pas en charge, le vault miroir de ce marché reste non initialisé et garde son cash, que le mode urgence peut récupérer. Les autres marchés du même batch de pont passent. Avant, tout le batch échouait, et n'importe qui pouvait grouper des marchés sains avec un marché refusé.
  • Un token distant, un identifiant. Le hub du pont refuse d'associer un second identifiant de basket à un token Robinhood Chain déjà associé.
  • Un hub distant en pause applique quand même les rôles. Chaque batch porte le keeper et l'admin d'urgence en vigueur. Un hub en pause les applique quand même, de sorte qu'un changement d'owner de StockFun atteint toujours Robinhood Chain. Le cash est enregistré marché par marché et payé aux vaults miroirs par un sweep après la levée de la pause.
  • Les enregistrements canoniques sont payés dans l'ordre. Sur le pont canonique Orbit, utilisé en testnet et en solution de repli, les tokens et la comptabilité arrivent en deux tickets séparés. Le hub paie les enregistrements en attente en entier, dans l'ordre d'arrivée de leurs messages, quel que soit celui qui déclenche le sweep. Depuis le pipeline de sécurité du 2026-10-01, un ticket comptable paie au plus autant d'enregistrements qu'il en a mis dans la file, les plus anciens d'abord, qui peuvent appartenir à des batches antérieurs ; le sweep paie le reste, 64 enregistrements au plus par appel par défaut. Avant, un arriéré laissé par une pause ou un dépôt en retard pouvait pousser un ticket au-delà du gas fixe de son exécution automatique, et le batch restait non enregistré à moins que quelqu'un ne rejoue le ticket à la main sous sept jours.

Le second tour de l'audit, le 2026-10-01, avait établi que si le token de la jambe cash refuse un vault miroir, par exemple parce que son émetteur a gelé cette adresse, la file canonique s'arrêtait et, sur les deux rails, tout batch qui groupait ce marché échouait (R2H-2). La première boucle d'audit du 2026-10-05 l'avait atténué ; la quatrième l'a fermé, par une livraison non bloquante (plus bas).

Depuis le 2026-10-05, après les boucles d'audit de ce jour-là :

  • Seul le keeper fait passer le pont. Le batch de pont, bridgeReady, est réservé au keeper. Jusque-là, n'importe qui pouvait en envoyer un : un tiers pouvait glisser un batch au minimum le plus lâche de l'adaptateur entre deux trades à lui sur le pool Curve, ou faire échouer le batch du keeper en faisant passer avant lui l'un de ses vaults.
  • Chaque marché d'un batch à part. Depuis la quatrième boucle, bridgeReady libère chaque marché listé à part. Un vault qui ne peut pas libérer — en pause, vide, refusé par l'émetteur de l'USDC —, un marché inconnu, un vault sans code (celui du protocole avant qu'il soit désigné, depuis la cinquième boucle) ou une charge utile que l'adaptateur ne sait pas construire reste hors du batch, avec l'événement MarketSkipped, et les autres partent. Le minimum du keeper vaut pour le batch listé et baisse en proportion de ce qui part réellement ; l'événement Bridged ne liste que les marchés partis, et un batch dont rien ne part échoue avec la raison du premier marché.
  • Une livraison refusée n'arrête que son marché. Depuis la quatrième boucle, sur le rail USDG, la part d'un vault miroir que le token de la jambe cash refuse reste sur le hub distant, due et couverte, avec l'événement DeliveryRefused, et les autres marchés du batch sont payés ; n'importe qui la lui paie ensuite par un sweep, une fois que le vault reprend le cash. Sur le rail canonique, un enregistrement dont le vault refuse le cash quitte la file pour une réserve à part, que la file ne dépense jamais pour d'autres (undeliverable) : les enregistrements qui le suivent et les tickets suivants sont payés, et le sweep de ce marché le retente. Depuis le 2026-10-06, sur le rail canonique, le keeper clôt aussi les transferts dont un seul sweep a payé d'un coup les enregistrements refusés, ou que l'owner de StockFun a passés au marché, si bien qu'aucun ne reste suivi pour de bon
  • Une urgence sur le hub distant est soldée, pas payée par un autre marché. Sur le rail USDG, le hub refuse de payer ce qu'il doit tant que le cash qui le couvre n'y suffit pas, un compte qu'il tient lui-même depuis la seconde boucle d'audit de ce jour-là, jamais son solde, qui contient aussi le cash de batches encore en route ; le cash revient par restore. Depuis la quatrième boucle, l'owner de StockFun peut charger une urgence à un seul marché, en passant sa perte dans le même appel : ce que le hub doit à ce marché (emergencyTransferFromPending), ou, sur le rail canonique, un enregistrement de la file dont le dépôt est arrivé (emergencyTransferRecord) ; aucun autre marché n'attend. Voir Le mode urgence.
  • Un prix retenu ne retient que ses propres jambes (depuis le 2026-10-06) : une action en pleine opération sur titres fait échouer sa seule jambe, dans chaque vault miroir ; avec le contrôle du séquenceur posé, une panne du séquenceur retient toutes les jambes jusqu'à ce qu'il soit revenu depuis le délai de grâce, et le cash attend dans les vaults (plus haut, « Quand l'oracle retient un prix »).

Le gas du compose d'un batch

Depuis la dixième boucle d'audit, le 2026-10-06. La dernière étape d'un batch du pont sur Robinhood Chain, le compose du hub distant, initialise et crédite le vault miroir de chaque marché : son gas grandit donc avec le batch. Il recevait un seul chiffre fixe, 1 200 000 par défaut, quel que soit le contenu du batch, et quatre nouveaux marchés à cinq actions l'épuisaient. Leur USDG restait alors sur le hub distant sans aucun enregistrement, chaque batch suivant avec les mêmes marchés échouait de même, et seule une relance à la main sur l'endpoint de Robinhood Chain le débloquait. Rien n'était perdu, mais aucun marché du batch n'était acheté ni airdroppé entre-temps.

  • Une base et une part par marché. L'adaptateur USDG donne à un batch de n marchés composeGas + n × composeGasPerMarket de gas de compose, 200 000 plus 400 000 par marché par défaut, pour l'envoi comme pour chaque devis. Le premier batch d'un marché à cinq actions demande environ 294 000 gas (extrapolés d'une à trois actions mesurées), et un marché déjà installé de 21 000 à 39 000, sur un fork du testnet de Robinhood Chain, par l'endpoint de LayerZero lui-même
  • Au plus 17 marchés par batch. LayerZero refuse un message au-delà de la limite de taille du chemin, 10 000 octets par défaut, et chaque marché à cinq actions ajoute au plus 544 octets à celui du batch : 17 marchés tiennent, 18 non. Un batch plus grand est refusé en entier avant que rien ne bouge, chaque vault gardant son USDC. Le keeper n'en envoie pas davantage, les marchés qui attendent depuis le plus longtemps d'abord, et les autres partent à son passage suivant, si bien qu'aucun n'attend pour de bon. Le rail canonique n'a pas ce plafond
  • Dans les limites de Robinhood Chain. Le gas de compose du plus gros batch est au plus de 24 000 000, en dessous des 32 000 000 de gas que Robinhood Chain exécute en une transaction ; les réglages de l'owner ne peuvent pas aller au-delà. Avant le mainnet, l'owner lit la limite de taille du chemin qu'emprunte l'USDG de Paxos, et ajuste le plafond si elle diffère
  • Il coûte peu. L'exécuteur de LayerZero facture le gas en plus au prix du gas de Robinhood Chain : sur le testnet, les frais d'un batch grandissent de 0,00001 ETH par million de gas
  • Un adaptateur d'avant refuse tout batch tant que l'owner n'a pas posé les deux nouveaux réglages, ce que fait son upgrade dans la même transaction. L'adaptateur du testnet a été mis à jour ainsi le 2026-10-06, et son batch suivant a été composé par l'exécuteur de LayerZero à sa nouvelle option, 600 000 gas pour un marché, 115 990 consommés
  • Un compose bloqué le dit. L'alerte du keeper pour un transfert pas crédité à temps lit désormais le message du batch sur l'endpoint de Robinhood Chain : pas encore livré ; composé, le crédit suivant ; ou stocké, son USDG sur le hub distant, en attente d'être relancé à la main avec plus de gas, ce que n'importe qui peut faire, l'alerte donnant le hash du message stocké. Le keeper ne relance toujours pas lui-même un compose du pont

Ce qui a été vérifié, et ce qui ne l'a pas été

L'état actuel d'abord. Aucun déploiement mainnet, aucun transfert de fonds réels n'a eu lieu. Les tests locaux simulent la livraison ; ils ne prouvent pas une livraison LayerZero réelle. Les envois de l'airdrop, codés le 2026-10-04, sont testés contre des mocks de LayerZero et des adaptateurs d'actions.

Le test LayerZero sur testnet, 2026-10-06. Le protocole a été déployé sur Sepolia et sur le testnet de Robinhood Chain (167 transactions de déploiement, toutes réussies) et mené de bout en bout sur les endpoints, le DVN et l'exécuteur réels de LayerZero sur testnet, de 13:50 à 19:07 UTC, par le keeper, en sept fenêtres horaires : l'ETH de chaque fenêtre converti une fois, passé en un batch LayerZero, composé sur le hub distant dans le vault miroir et dépensé en trois actions de test. Six cycles de l'airdrop ont été ouverts, renvoyés par LayerZero et composés sur le contrat de l'airdrop ; les quatre premiers ont été réclamés en entier par les cinq holders, le cinquième en partie, le sixième reste à réclamer, chaque paiement exactement la part calculée indépendamment à partir du module d'enregistrement. Les exercices d'incident (pauses, transferts d'urgence et restore, rescue, un keeper tué avec une transaction en attente, un compose relancé à la main, un feed périmé, une action en pause, la garde du séquenceur, une livraison que le token cash refuse) ont été joués sur des messages réels et rétablis comme documenté, sauf deux moitiés : la pause du hub de pont sur Sepolia, et un compose du pont relancé à la main. Sepolia a activé la mise à niveau Glamsterdam d'Ethereum pendant le test : les premières livraisons de l'airdrop ont manqué de gas chez l'exécuteur de LayerZero et ont été lancées à la main, et le correctif du gas des livraisons (plus haut) a été appliqué par upgrade et a porté les cycles suivants. Le keeper, relancé à 18:25 sur le code de la neuvième boucle d'audit, a mené la dernière fenêtre sans accroc, avec le gas choisi par ses simulations.

Ce que ce test ne prouve pas : l'USDG de Paxos, dont le token de testnet n'a pas de fonction OFT sur ces testnets, si bien qu'un USDG de test sous le MintBurnOFTAdapter de LayerZero, de même forme que la paire mainnet, en tenait lieu, et que ni les DVN de la paire, ni son gel, ni sa pause n'ont été exercés ; les actions de Robinhood et leurs adaptateurs, que remplaçaient des actions de test sous l'OFTAdapter de LayerZero ; de vrais feeds de prix et une vraie liquidité ; le gas, les frais et la finalité du mainnet. Reste un essai sur mainnet, un premier petit cycle sur un vault de vérification.

Les anciens scripts Sepolia utilisent le pont canonique Orbit et ne valident pas LayerZero. Un succès en fork, ou en testnet, n'est pas une preuve de livraison live sur mainnet.