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
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,
bridgeReadylibè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énementMarketSkipped, 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énementBridgedne 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 × composeGasPerMarketde 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.