El rail de Robinhood

Las acciones tokenizadas que contienen los vaults viven en Robinhood Chain, una L2 Arbitrum Orbit. El protocolo llega a ella a través de LayerZero, con el OFT de USDG de Paxos como tramo de efectivo.

Por qué este rail

La elección se zanjó el 2026-09-11, tras descartar el rail anterior.

En un rail de mint primario, el contrato de un vault debe ser elegible ante el emisor para mantener el activo: KYB, registro de la dirección del contrato y una confirmación por escrito que el emisor nunca ha documentado públicamente. Ese era el único bloqueo realmente insalvable del proyecto.

Los pools secundarios de Robinhood Chain no exigen nada de eso: están abiertos a todo el mundo. StockFun no tiene ninguna relación con el emisor y no la necesita.

El precio de esa libertad es una dependencia cross-chain: un bridge, dos hubs y una stablecoin emitida por un tercero que puede congelarla. Es un riesgo aceptado y documentado, no un riesgo evitado.

El circuito

flowchart LR V[TreasuryVault

Ethereum] -->|ETH → USDC

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

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

LayerZero| RH[RemoteHub

Robinhood Chain] RH --> MV[Vault espejo

CREATE2, uno por mercado] MV -->|pools v3 / v4| S[Stock Tokens] S -->|adaptadores de acciones, wrapped| AD[AirdropDistributor

Ethereum] AD -->|reclamaciones| HO[Holders del token

en Ethereum]

El camino de vuelta del USDG, de Robinhood Chain a Ethereum, solo servía al buyback del creador; ambos se eliminaron del código el 2026-09-28.

Desde el 2026-10-04, el vault espejo envía sus acciones al contrato del airdrop en Ethereum: cada acción se bloquea en su adaptador LayerZero en Robinhood Chain y se acuña wrapped en Ethereum, donde los holders la reclaman. Ese camino solo transporta acciones. Los adaptadores, uno por acción, aún no están en el repositorio para mainnet; los tests usan mocks, y la ejecución de LayerZero en testnet del 2026-10-06 usó adaptadores de prueba (más abajo).

Lo que no requiere permisos y lo que sí

Componente Estado
Endpoint de LayerZero Sin permisos
Pools secundarios de Stock Tokens Sin permisos: lo que usa el protocolo
Mint / burn primario de Robinhood KYB: no se usa
USDG Paxos controla el mint y el burn, y puede pausar o congelar

La última fila es la dependencia más dura del rail, y es real.

El vault espejo

Cada mercado tiene un vault espejo en Robinhood Chain, desplegado mediante CREATE2 en una dirección predecible desde Ethereum. Así, el keeper puede hacer que el hub remoto lo despliegue por adelantado, antes de que llegue el USDC, de modo que una transferencia nunca aterrice en una dirección sin código. Desde el 2026-10-05, solo pueden hacerlo el keeper y el owner de StockFun (predeploy): hasta entonces podía hacerlo cualquiera, incluso para un mercado que aún no existía, lo que ligaba su vault espejo a la conexión de ese día. El hub remoto se entera de quién es el keeper por un lote de bridge, que lo lleva: antes del primer lote no conoce ningún keeper, así que el owner de StockFun despliega por adelantado el vault espejo del primer mercado. Desde el segundo bucle de auditoría del 2026-10-05, un mercado cuyo vault espejo el keeper no puede desplegar por adelantado (antes del primer lote, o tras un cambio de keeper del que el hub remoto aún no se ha enterado) queda fuera del lote, con una alerta, en lugar de enviarse sin gas suficiente para desplegar su vault; los demás mercados cruzan, y su lote lleva el nuevo keeper.

Desde el 2026-10-02, cada vault espejo es un proxy, un MirrorVaultProxy, delante de la implementación de vault que el hub remoto designa cuando se despliega el vault. El constructor del proxy no recibe ningún argumento, así que su código de creación, y con él la dirección de cada vault espejo, sigue siendo predecible desde Ethereum sea cual sea la implementación. El basket del vault llega con el primer lote, que desde el 2026-10-05 también actualiza el router de acciones y el oráculo del vault a los que designa entonces el hub remoto: un vault desplegado antes de que se listara una acción acepta un basket con esa acción. El owner de StockFun, tal como lo refleja el hub remoto, hace los upgrades de los vaults espejo uno por uno, mercado por mercado, con efecto inmediato.

Las rutas de swap no están fijadas en el código: llegan en el calldata, codificadas como abi.encode(uint8 version, bytes payload) (versión 3 para una ruta empaquetada de Uniswap v3, versión 4 para un array de PathKey de v4). El vault recibe varias candidatas por tramo y ejecuta con la primera que respeta su límite. Desde el 2026-10-01, una ruta que solo ejecuta una parte del monto falla, y se prueba la siguiente candidata; antes, una ejecución parcial en una ruta v3 dejaba el USDG no gastado atascado en el router.

Desde el pipeline de seguridad del 2026-10-01, una ruta v3 se ejecuta pool a pool. Cada pool debe consumir todo su monto de entrada, o la ruta falla; su salida vuelve al router de acciones y es el monto de entrada del siguiente pool, y el último pool paga al vault, sujeto al mínimo del tramo. Un pool que falla deshace los pools anteriores del mismo intento, y se prueba la siguiente candidata. Hasta entonces, la comprobación solo veía el primer pool de una ruta: una ejecución parcial más adelante dejaba el token intermedio en el router v3 de Uniswap, SwapRouter02, donde cualquiera podía llevárselo, mientras que el tramo tenía éxito. Un tramo v3 de varios saltos cuesta ahora un swap y una aprobación por pool.

Cada tramo gasta solo el USDG reservado para su acción, según los pesos del basket: consulta El TreasuryVault. Su límite de precio frente al feed de la acción, 200 puntos básicos por defecto, es un ajuste que guarda el hub remoto y que cada vault espejo lee en directo (setStockMaxSlippageBps). Desde el 2026-10-05, el vault aplica el propio mínimo del keeper, nunca menos estricto que ese límite, a lo que realmente llegó.

Cuando el oráculo retiene un precio

Desde el 2026-10-06, el oráculo de los vaults espejo tiene dos salvaguardas, que recomienda la propia documentación de Robinhood; cada una solo puede retener un precio, nunca cambiarlo.

  • Una operación corporativa. Mientras una acción pasa por una (un split, por ejemplo), su token indica que su oráculo está en pausa (oraclePaused()), y su feed de Chainlink mantiene su último valor, que aún puede parecer fresco mientras cambia el multiplicador del token. El oráculo retiene entonces el precio de esa acción: su tramo de compra falla solo (StockOraclePaused), su USDG sigue reservado para ella, y se compran las demás acciones del basket. La comprobación está activada para todas las acciones; el owner de StockFun puede desactivarla para una acción (setOraclePauseCheck), y su precio pasa entonces a depender solo de las propias comprobaciones de su feed. Un token que no responde cuenta como no pausado.
  • El secuenciador. Robinhood Chain es una cadena Arbitrum con un único secuenciador. Con el feed de disponibilidad del secuenciador L2 de Chainlink configurado (setSequencerUptimeFeed), el oráculo retiene todos los precios mientras el feed indica que el secuenciador está caído, que volvió hace no más que el periodo de gracia (una hora por defecto), o no se puede leer: hasta entonces ningún tramo compra. Hoy no existe ningún feed así para Robinhood Chain, así que el rail se despliega con esta comprobación desactivada; el owner de StockFun configura el feed si Chainlink publica uno.

El keeper ve ambas antes de cotizar nada (ver El keeper), el Worker indica por qué falta el precio de una acción, y la dapp lo muestra (ver La dapp).

El envío de las acciones al airdrop

Desde el 2026-10-04, una vez compradas, las acciones salen del vault espejo por un solo camino: sendToAirdrop. El keeper lo llama con la lista de acciones que enviar y paga las comisiones de LayerZero; lo que paga de más se le devuelve. Por cada acción, el vault envía todo su saldo a través del adaptador de esa acción hacia el contrato del airdrop en Ethereum, con el identificador del mercado como carga útil. El keeper no designa ni el monto ni el destino: el adaptador de cada acción (setStockAdapter, que comprueba que el adaptador transporta exactamente ese token) y el contrato del airdrop (setAirdrop) los designa en el hub remoto su admin, el owner de StockFun. Una acción listada dos veces o fuera del basket hace fallar la llamada.

Desde el 2026-10-06, el keeper indica el gas que recibe cada entrega en Ethereum: sendToAirdrop(stocks, receiveGas, composeGas), el lzReceive del OFT de la acción además de lo que impone ese OFT, y el compose del contrato del airdrop. El hub remoto ajusta cada valor entre el suelo y el techo que fija su admin, y cero toma el valor por defecto (airdropGas), y el vault construye el envío y su cotización con lo que concede el hub; la llamada solo con las acciones toma los dos valores por defecto. El keeper elige los valores a partir de simulaciones de la entrega en Ethereum (ver El keeper): la actualización Glamsterdam de Ethereum, activa en Sepolia desde el 2026-10-06, hizo que un nuevo slot de almacenamiento costara unas cinco veces más, y la cifra única de compose de antes, 600 000 de gas, dejó sin gas suficiente todas las entregas del primer ciclo de la ejecución de LayerZero en testnet. Un hub remoto que recibe un upgrade desde una versión sin las políticas rechaza todo envío y toda cotización (AirdropGasNotSet) hasta que se fijen ambas.

Desde el 2026-10-05, cada acción va por separado. Una acción sin adaptador, una cuyo saldo no se puede leer y una cuyo envío falla —una congelación del emisor, un peer ausente, una comisión que el pago del keeper no cubre— se quedan en el vault con un evento (AirdropSendFailed), y las demás se envían; cuando no sale nada, la llamada falla e indica el motivo. La cotización, quoteSendToAirdrop, deja fuera lo que no puede cotizar en lugar de fallar.

LayerZero transporta seis decimales: menos de 10^12 unidades de una acción de 18 decimales, una millonésima de token, no pueden cruzar y se quedan en el vault para un envío posterior.

En Ethereum, el OFT de la acción acuña la acción wrapped al contrato del airdrop, y luego el endpoint de LayerZero lo llama con la carga útil. El contrato solo abona la entrega si viene de su endpoint, de un OFT de acción que registró el owner, desde Robinhood Chain, y si la envió el vault espejo que el hub del bridge deriva para el mercado que designa la carga útil. Esa entrega se ejecuta con el gas que llevaba el envío (más arriba); una entrega sin gas suficiente falla sin perder nada, almacenada en el endpoint de LayerZero, con las acciones wrapped ya en el contrato del airdrop cuando solo falló el compose, y cualquiera puede volver a ejecutarla con más gas. Desde el 2026-10-06 lo hace el keeper, desde su propia clave, dentro de un límite, y alerta de un segundo fallo. Detalle y mediciones en Despliegue y en El airdrop.

Upgrades y conexión

Desde el 2026-10-02, todos los contratos de StockFun del rail son upgradeables salvo el deployer de los vaults espejo, de cuya dirección se deriva la de cada vault espejo. En Ethereum, el hub del bridge y sus adaptadores responden ante el owner de la factory. En Robinhood Chain, el hub remoto es la autoridad de upgrade: responde con su admin de emergencia, el owner de Ethereum tal como lo llevó el último lote, así que el hub remoto, los vaults espejo, el router de acciones y el oráculo reciben sus upgrades del owner de StockFun, con efecto inmediato.

El hub remoto se despliega primero en su cadena, con un admin inicial, que después designa el router de acciones, el oráculo y la implementación de los vaults espejo futuros y, cuando se indican, la ruta del airdrop y los adaptadores de acciones. El primer lote sustituye a ese admin por el owner de StockFun.

El mismo admin tiene en sus manos los ajustes del hub remoto, desde el 2026-10-05: los registros que paga un sweep, 64 por defecto (setMaxRecordsPerSweep, nunca cero), el límite de precio de las compras de los vaults espejo y el gas de cada entrega del airdrop (setAirdrop); y, desde el 2026-10-06, las dos salvaguardas del oráculo y las dos políticas de gas de las entregas del airdrop en Ethereum, cada una con un valor por defecto, un suelo y un techo (setAirdropReceiveGas, 650 000 entre 200 000 y 1 500 000; setAirdropComposeGas, 1 250 000 entre 600 000 y 4 000 000; se rechazan un suelo cero, un suelo por encima del techo y un valor por defecto fuera de ellos). El hub remoto fija ambas en la inicialización, y DeployRemote las vuelve a fijar a partir de su entorno. Un oráculo de sustitución que designe el admin (setOracle) empieza con ambas salvaguardas desactivadas, así que el admin las vuelve a activar para él; los vaults espejo ya inicializados conservan el oráculo con el que se inicializaron.

En Ethereum, el hub del bridge ya no despliega su adaptador: el adaptador se despliega apuntando al hub y luego lo designa una sola vez el owner de StockFun (setAdapter), que comprueba sus direcciones fijadas. Una sustitución posterior, changeAdapter, es inmediata desde el 2026-10-05. Solo acepta un adaptador cuyas direcciones fijadas sean exactamente las del actual: el mismo hub, la misma factory, los mismos tokens de efectivo, el mismo hub remoto, la misma cadena de destino y el mismo transporte. Puede cambiar cifras de gas, opciones o el pool de Curve, nunca un destino; el hub remoto sigue aceptando lotes solo del adaptador para el que se construyó (M-2, consulta Modo de emergencia). Por eso, un adaptador se cambia mediante un upgrade en el propio contrato, en la misma dirección; una nueva dirección requeriría primero un upgrade del hub remoto para aceptarla. El 2026-10-05, el owner decidió dejarlo así.

Las cifras propias de los adaptadores también son ajustes del owner de StockFun: en el rail de USDG, el peor tipo USDG por USDC aceptado en Curve, 30 puntos básicos por defecto, y el gas del último paso de la entrega en Robinhood Chain (setSettings); desde el décimo bucle de auditoría, el 2026-10-06, ese gas es una base que necesita todo lote, 200 000 por defecto, más una parte por cada mercado del lote, 400 000 por defecto, y un lote lleva como máximo 17 mercados (setBatchGas; ver «El gas de compose de un lote» más abajo). Hasta entonces, una sola cifra, 1 200 000 por defecto, pagaba todo lote, llevara lo que llevara. En el rail canónico, el gas de los dos tickets (setTicketGas). Desde el 2026-10-05, el ticket de contabilidad del rail canónico paga lo que el inbox del bridge pide por el tamaño del lote a la tarifa base del momento, con el ajuste como suelo. Una cotización leída offchain, sin precio del gas, veía una tarifa base nula y fijaba el precio de ese ticket solo en el suelo, así que un lote largo fallaba con la tarifa base real; desde el segundo bucle de auditoría de ese día, el keeper pide la cotización a una tarifa base que él indica (quoteBridgeAt), el doble de la última, y recupera el exceso. Desde el cuarto bucle, el ticket de depósito se cotiza de la misma manera: lo que el inbox pide por depositCalldataLength() bytes a la tarifa base, con el ajuste tokenSubmissionCost como suelo. Esa longitud también es un ajuste del owner (setDepositCalldataLength, nunca cero): 1 024 bytes por defecto, por encima de los 740 bytes del depósito del gateway para USDC. Hasta entonces, el costo de envío del depósito era un ajuste fijo, y una tarifa base que lo superara hacía fallar todos los lotes.

Fallos que quedan contenidos

Desde el 2026-10-01, tras la auditoría de seguridad del 2026-09-29:

  • Un basket rechazado solo bloquea su propio mercado. Si Robinhood Chain rechaza el basket de un mercado, por ejemplo por una acción que su router o su oráculo no admite, el vault espejo de ese mercado queda sin inicializar y conserva su efectivo, que el modo de emergencia puede recuperar. Los demás mercados del mismo lote de bridge pasan. Antes, fallaba todo el lote, y cualquiera podía agrupar mercados sanos con uno rechazado.
  • Un token remoto, un identificador. El hub del bridge se niega a asociar un segundo identificador de basket a un token de Robinhood Chain que ya está asociado.
  • Un hub remoto en pausa sigue aplicando los roles. Cada lote lleva el keeper y el admin de emergencia actuales. Un hub en pausa los aplica igualmente, así que un cambio de owner de StockFun siempre llega a Robinhood Chain. El efectivo se registra por mercado y se paga a los vaults espejo con un sweep una vez levantada la pausa.
  • Los registros canónicos se pagan en orden. En el bridge canónico de Orbit, usado en testnet y como fallback, los tokens y la contabilidad llegan en dos tickets separados. El hub paga completos los registros en espera, en el orden en que llegaron sus mensajes, sea quien sea quien dispare el sweep. Desde el pipeline de seguridad del 2026-10-01, un ticket de contabilidad paga como máximo tantos registros como añadió a la cola, empezando por los más antiguos, y pueden pertenecer a lotes anteriores; el sweep paga el resto, hasta 64 registros por llamada por defecto. Antes, una acumulación de registros dejada por una pausa o por un depósito tardío podía llevar un ticket más allá del gas fijo de su ejecución automática, y el lote quedaba sin registrar salvo que alguien reejecutara el ticket a mano en un plazo de siete días.

Un fallo solo quedaba contenido en parte. La segunda ronda de la auditoría, el 2026-10-01, constató que, si el token de efectivo rechaza un vault espejo, por ejemplo porque su emisor congeló esa dirección, la cola canónica se detiene y, en ambos rails, todo lote que agrupe ese mercado falla (R2H-2). El segundo bucle de auditoría del 2026-10-05 lo mitigó, y el cuarto lo cerró ese mismo día: una entrega así espera ahora por separado, y el lote sigue (más abajo).

Desde el 2026-10-05, tras el bucle de auditoría de ese día:

  • Solo el keeper envía a través del bridge. El lote de bridge, bridgeReady, es exclusivo del keeper. Hasta entonces, cualquiera podía enviar uno: un tercero podía colar un lote con el mínimo menos estricto del adaptador entre dos trades propios en el pool de Curve, o hacer fallar el lote del keeper pasando antes por el bridge uno de sus vaults.
  • Una emergencia en el hub remoto se salda sin que la pague otro mercado. En el rail de USDG, el hub se niega a pagar lo que debe mientras el efectivo que lo respalda no alcance, una cuenta que lleva él mismo desde el segundo bucle de auditoría de ese día, nunca su saldo, que también contiene el efectivo de lotes aún en camino; el efectivo vuelve mediante restore. En el rail canónico, el owner de StockFun pone en pausa el hub antes de la transferencia, da de baja el registro cuyo efectivo se llevó la emergencia y luego levanta la pausa. Consulta Modo de emergencia.

Desde el cuarto bucle de auditoría del 2026-10-05, que aplica la regla del fundador según la cual un fallo nunca bloquea el resto (consulta Arquitectura):

  • Una entrega rechazada espera por separado. En el rail de USDG, la parte de un vault espejo que el token de efectivo rechaza se queda en el hub remoto, adeudada a ese mercado y respaldada (DeliveryRefused), y los demás mercados del lote cobran. En el rail canónico, un registro así sale de la cola y queda retenido aparte para su mercado (undeliverable), de modo que los registros que van detrás y los tickets siguientes se pagan. En ambos, cualquiera lo paga con sweep(marketId) en cuanto el vault vuelve a aceptar el efectivo. Desde el 2026-10-06, el keeper, en el rail canónico, también cierra las transferencias cuyos registros rechazados pagó de una vez un solo sweep o imputó al mercado el owner de StockFun, para que ninguna quede en seguimiento indefinidamente.
  • Cada mercado de un lote va por separado. bridgeReady deja fuera un mercado de la lista cuyo vault no puede liberar su efectivo —en pausa, vacío, rechazado por el emisor o, desde el quinto bucle, un vault aún sin código, como el del mercado del protocolo antes de ser designado—, un mercado desconocido o uno cuyo payload el adaptador no puede construir (MarketSkipped), y los demás siguen. El mínimo del keeper cubre el lote tal como se listó, y se reduce en proporción a lo que realmente salió; Bridged solo lista los mercados que salieron. Un lote del que no sale nada falla, con el motivo del primer mercado.
  • Cada tramo de compra va por separado, tanto en el vault espejo como en el vault de Ethereum (LegFailed): consulta El TreasuryVault.
  • Una transferencia de emergencia puede imputarse a un solo mercado. El owner de StockFun mueve el efectivo de un mercado y liquida sus cuentas en la misma llamada, para que ningún otro mercado espere: emergencyTransferFromPending toma lo que el hub debe a ese mercado en el rail de USDG, o su parte rechazada en el rail canónico, y emergencyTransferRecord, un registro canónico en cola, entero. Desde el quinto bucle, esta última es para un registro cuyo depósito ha llegado: el efectivo de la cola es común, así que rechaza un monto que supere el efectivo no retenido para partes rechazadas (RecordNotCovered). Un registro cuyo depósito se ha perdido se da de baja (writeOffRecord). En el rail de USDG, una transferencia no imputada a ningún mercado conserva su espera general, por diseño: las cuentas muestran un déficit hasta que el efectivo se restaure o se dé de baja.
  • Un precio retenido solo retiene sus propios tramos (desde el 2026-10-06): una acción en plena operación corporativa hace fallar solo su propio tramo, en cada vault espejo; con la comprobación del secuenciador configurada, una caída del secuenciador retiene todos los tramos hasta que lleva funcionando de nuevo el periodo de gracia, y el efectivo espera en los vaults (más arriba, «Cuando el oráculo retiene un precio»).

El gas de compose de un lote

Desde el décimo bucle de auditoría, el 2026-10-06. El último paso de un lote del bridge en Robinhood Chain, el compose del hub remoto, inicializa y financia el vault espejo de cada mercado, así que su gas crece con el lote. Antes recibía una cifra fija, 1 200 000 por defecto, fuera cual fuera el contenido del lote: cuatro nuevos mercados con baskets de cinco acciones lo dejaron sin gas. Su USDG quedó entonces en el hub remoto sin ningún registro, cada lote posterior con los mismos mercados falló de la misma manera, y solo una ejecución a mano en el endpoint de Robinhood Chain lo desbloqueó. No se perdió nada, pero mientras tanto no hubo compras ni airdrop para ningún mercado del lote.

  • Una base y una parte por mercado. El adaptador de USDG da a un lote de n mercados composeGas + n × composeGasPerMarket de gas de compose, 200 000 más 400 000 por mercado por defecto, tanto para el envío como para cada cotización. El primer lote de un mercado de cinco acciones necesita unos 294 000 de gas (extrapolado de lo medido con una a tres acciones), y un mercado ya configurado de 21 000 a 39 000, en un fork de la testnet de Robinhood Chain a través del propio endpoint de LayerZero
  • Como máximo 17 mercados por lote. LayerZero rechaza un mensaje por encima del límite de tamaño de la ruta, 10 000 bytes por defecto, y cada mercado de cinco acciones añade como máximo 544 bytes al del lote: caben 17 mercados, 18 no. Un lote más grande se rechaza entero antes de que nada se mueva, y cada vault conserva su USDC. El keeper envía como máximo esa cantidad, primero los mercados que más tiempo llevan esperando, y los demás salen en su siguiente pasada, así que ninguno espera indefinidamente. El rail canónico no tiene ese tope
  • Dentro de los límites de Robinhood Chain. El gas de compose del lote más grande es como máximo de 24 000 000, por debajo de los 32 000 000 de gas que Robinhood Chain ejecuta en una transacción; los ajustes del owner no pueden superarlo. Antes de mainnet, el owner lee el límite de tamaño de la ruta que usa el USDG de Paxos y ajusta el tope en consecuencia si difiere
  • Cuesta poco. El ejecutor de LayerZero cobra el gas adicional al precio del gas de Robinhood Chain: en la testnet, la comisión de un lote crece 0,00001 ETH por millón de gas
  • Un adaptador anterior rechaza todo lote hasta que el owner fija los dos nuevos ajustes, cosa que su upgrade hace en la misma transacción. El adaptador de la testnet se actualizó de esta manera el 2026-10-06, y el ejecutor de LayerZero hizo el compose de su siguiente lote con su nueva opción, 600 000 de gas para un mercado, de los que se usaron 115 990
  • Un compose atascado lo dice. La alerta del keeper por una transferencia no abonada a tiempo lee ahora el mensaje del lote en el endpoint de Robinhood Chain: aún no entregado allí; compuesto, con el abono a continuación; o almacenado, con su USDG en el hub remoto, a la espera de que se vuelva a ejecutar a mano con más gas, algo que cualquiera puede hacer, y la alerta da el hash del mensaje almacenado. El keeper sigue sin ejecutar él mismo un compose del bridge

Lo que se ha verificado y lo que no

Primero, el estado actual. No ha habido ningún despliegue en mainnet ni ninguna transferencia de fondos reales. Los tests locales simulan la entrega; no demuestran una entrega real por LayerZero. Los envíos del airdrop, codificados el 2026-10-04, se prueban contra mocks de LayerZero y de los adaptadores de acciones.

La ejecución de LayerZero en testnet, 2026-10-06. El protocolo se desplegó en Sepolia y en la testnet de Robinhood Chain (167 transacciones de despliegue, todas con éxito) y funcionó de punta a punta sobre los endpoints, el DVN y el ejecutor reales de testnet de LayerZero, de 13:50 a 19:07 UTC, con el keeper, en siete ventanas horarias: el ETH de cada ventana se convirtió una vez, pasó por el bridge en un lote de LayerZero, se procesó con compose en el hub remoto hacia el vault espejo y se gastó en las tres acciones de prueba. Se abrieron seis ciclos del airdrop, enviados de vuelta sobre LayerZero y procesados con compose en el contrato del airdrop; los cuatro primeros los reclamaron por completo los cinco holders, el quinto en parte, y el sexto quedó por reclamar, cada pago exactamente la parte calculada de forma independiente a partir del registrador de tenencias. Los simulacros de incidente (pausas, transferencias de emergencia y restore, rescue, un keeper interrumpido con una transacción pendiente, un compose ejecutado a mano, un feed desactualizado, una acción en pausa, la salvaguarda del secuenciador, una entrega que el token de efectivo rechaza) se hicieron sobre mensajes reales y se recuperaron como está documentado, salvo dos mitades: la pausa del hub del bridge en Sepolia, y un compose del bridge ejecutado a mano. Sepolia activó la actualización Glamsterdam de Ethereum durante la ejecución: las primeras entregas del airdrop se quedaron sin gas en el ejecutor de LayerZero y se ejecutaron a mano, y la corrección del gas de las entregas (más arriba) se aplicó mediante upgrade y sirvió para los ciclos siguientes. El keeper se reinició a las 18:25 con el código del noveno bucle de auditoría y ejecutó la última ventana sin problemas, con el gas que eligió a partir de sus simulaciones.

Lo que esa ejecución no demuestra: el USDG de Paxos, cuyo token de testnet no tiene función OFT en estas testnets, así que lo sustituyó un USDG de prueba bajo el MintBurnOFTAdapter de LayerZero, con la forma del par de mainnet, y no se probaron ni los DVN del par, ni su congelación ni su pausa; las acciones de Robinhood y sus adaptadores, sustituidos por acciones de prueba bajo el OFTAdapter de LayerZero; feeds de precios y liquidez reales; el gas, las comisiones y la finalidad de mainnet. Queda una prueba en mainnet, un primer ciclo pequeño en un vault de verificación.

Los scripts más antiguos de Sepolia usan el bridge canónico de Orbit y no validan LayerZero. Un éxito en un fork, o en testnet, no es una prueba de una entrega real en mainnet.