El keeper

Un worker offchain que, una vez cada 24 horas, dispara la conversión de cada tesorería y luego su airdrop. No decide nada. Su bucle hace una pasada cada cinco minutos por defecto y, desde el 2026-10-06, convierte el ETH de un vault una vez por ventana del airdrop, en su primera pasada después de que se cierre la ventana: ver «La cadencia de conversión» más abajo. Su paso del airdrop está escrito desde el 2026-10-05: ver más abajo.

Lo que hace

  • Una vez cada 24 horas, después de que la ventana se cierre, a las 13:00 UTC por defecto, antes de la apertura de la bolsa estadounidense todo el año, detecta los vaults que contienen al menos el umbral de conversión, 0,1 ETH por defecto, en su primera pasada después del cierre; un vault por debajo espera entonces a la ventana siguiente, aunque los trades lo lleven por encima del umbral más tarde ese mismo día. Las compras del ciclo se hacen durante la sesión que sigue, y sus envíos, por defecto, una vez terminada esa sesión. El efectivo que un vault aún tiene de un ciclo anterior, USDC o USDG, sigue adelante, se alcance o no el umbral: desde el sexto bucle de auditoría, el 2026-10-06, el USDC de un vault una vez después de cada una de sus conversiones de ETH y como máximo una vez por ventana en los demás casos, el USDG de un vault espejo en cada pasada (ver «La cadencia de conversión»)
  • Propone rutas de swap y calcula montos mínimos a partir de una cotización fresca; desde el 2026-10-05, los vaults aplican esos mínimos a lo que realmente llega. Desde el 2026-10-06, cada vault de Ethereum se cotiza en su propio router, aquel con el que se creó
  • Dimensiona cada etapa, para que la plataforma de negociación pueda ejecutarla dentro del límite del vault (más abajo)
  • Llama a la conversión, al lote de bridge y luego a la compra en la cadena remota; desde el 2026-10-05, es el único que puede enviar el lote de bridge (bridgeReady). En el rail canónico, pide la comisión del lote al doble de la última tarifa base (quoteBridgeAt), y el exceso se le devuelve. Desde el noveno bucle de auditoría, solo recurre a la cotización de un hub más antiguo cuando el propio hub responde que no la tiene, nunca cuando un nodo se queda en silencio: un silencio retiene el lote una pasada, en el rail canónico, cuya comisión sigue la tarifa base, con una alerta, y en el rail de USDG solo con una advertencia. Desde el décimo bucle de auditoría, el 2026-10-06, un lote en el rail de USDG lleva como máximo el tope de mercados del adaptador, 17 por defecto, que el keeper lee en cada lote: los mercados que más tiempo llevan esperando van primero, y los demás conservan su USDC en sus vaults hasta su siguiente pasada, así que ninguno espera indefinidamente (ver El rail de Robinhood). Hasta entonces, todos los mercados listos iban en el único lote, cuyo gas fijo de compose podía agotar un lote grande
  • Despliega por adelantado el vault espejo de cada nuevo mercado en Robinhood Chain antes de su primer lote (predeploy), algo que desde el 2026-10-05 solo pueden hacer él y el owner de StockFun. El hub remoto se entera de quién es el keeper por un lote, así que antes del primero el owner de StockFun despliega por adelantado el vault del primer mercado. El keeper solo despliega por adelantado cuando su clave de Robinhood Chain es la que el hub remoto conoce como keeper, o la de su admin. Un mercado cuyo vault el keeper no puede desplegar por adelantado (antes del primer lote, tras un cambio de keeper del que el hub remoto aún no se ha enterado, o cuando falla el despliegue por adelantado) queda fuera del lote, con una alerta, y los demás mercados cruzan. Un mercado cuyo vault espejo no puede leer ese día espera al siguiente ciclo, ya que uno enviado a ciegas podría hacer fallar todo el lote
  • Vigila las entregas: una transferencia que no ha llegado, un ticket que reejecutar, un vault espejo aún no desplegado. Una transferencia que no pudo medir en Robinhood Chain cuando salió solo se confirma mediante los propios eventos del hub remoto, nunca mediante un saldo leído más tarde, y en el rail canónico, desde el 2026-10-06, así se confirma toda transferencia: el hub remoto paga sus registros con efectivo común, de modo que un saldo puede crecer con el dinero de otro lote. Lee esos eventos unos pocos fragmentos a la vez, desde donde se detuvo la búsqueda de cada transferencia; desde el séptimo bucle de auditoría, el 2026-10-06, solo hasta unos pocos bloques por debajo del último de la cadena, así que un evento de los bloques más recientes se lee en un ciclo posterior en lugar de perderse detrás de un nodo con uno o dos bloques de retraso. Desde el octavo bucle de auditoría, solo sigue un lote del bridge una vez que el bloque que lo contiene tiene esa misma profundidad en bloques (KEEPER_LOG_LAG_BLOCKS), a partir de su recibo, leído de nuevo entonces: los identificadores de un lote en Robinhood Chain salen de ese bloque, y una reorganización de los bloques más recientes de Ethereum que movía el lote dejaba al keeper vigilando identificadores que nunca existen. Desde el décimo bucle de auditoría, su alerta por una transferencia no abonada a tiempo indica, en el rail de USDG, en qué punto está 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 y sin registrar en ninguna parte hasta que alguien vuelva a ejecutar a mano el último paso con más gas, y la alerta da el hash del mensaje almacenado. Hasta entonces solo daba lo que registra el hub remoto, cuyo cero se leía como «no llegó nada» cuando un último paso sin gas suficiente había dejado el efectivo en el hub
  • Retransmite de inmediato a su webhook de alertas cada transferencia de emergencia que ve, en cada vault, el hub del bridge, el contrato del airdrop, el hub remoto y cada vault espejo. Desde el décimo bucle de auditoría, nombra los contratos que vigila por grupos, una petición de logs por grupo, cada una de las cuales nombra como máximo KEEPER_LOG_MAX_SELECTORS direcciones y valores de evento (1 000 por defecto), y solo avanza más allá de un tramo de bloques una vez leídos todos sus grupos. Hasta entonces, una sola petición los nombraba a todos: una vez que el registro de mercados superó lo que acepta un endpoint (2 000 direcciones y valores de evento en los nodos de Robinhood Chain, nueve direcciones en el endpoint público de Sepolia), cada petición se rechazaba y ya no se retransmitía ninguna transferencia de emergencia
  • Desde el décimo bucle de auditoría, lee lo que cada pasada necesita de cada mercado (el ETH de un vault, su USDC y su ventana, las deudas, el último airdrop) mediante Multicall3, cien mercados por llamada, en el mismo bloque que usaba cada lectura por separado; una lectura que no vuelve se hace por separado, como antes, y nunca se toma por un cero. Hasta entonces, cada mercado creado alguna vez costaba sus lecturas una a una en cada pasada, inactivo o no, y 2 000 mercados inactivos hacían que una pasada durara tanto como el intervalo entre dos
  • En el rail canónico, desde el sexto bucle de auditoría, vigila los dos tickets de cada lote hasta saber que cada uno se ejecutó, sea cual sea el abono de su transferencia, en cada ciclo, en sesión o no, y reejecuta uno que siga vivo. Un ticket del que no se sabe que se haya ejecutado seis horas después de la salida de su lote, por defecto (KEEPER_TICKET_ALERT_HOURS), se alerta una sola vez, y lo mismo uno que desapareció en su plazo límite o después sin que se viera su ejecución, o cuya creación falló. Hasta entonces, el keeper dejaba de vigilar los tickets de un lote en cuanto sus mercados quedaban abonados, lo que podía dejar expirar un depósito que no logró su ejecución automática. Desde el séptimo bucle de auditoría, lee cada ticket en el orden en que lo hace el SDK de Arbitrum: primero el recibo de su creación, luego su ejecución automática, y luego si sigue existiendo en un bloque no anterior a su creación; desde el octavo bucle de auditoría, en un bloque unos pocos por debajo del último (KEEPER_REMOTE_LOG_LAG_BLOCKS), o en su bloque de creación cuando este es posterior, un bloque que tienen todos los nodos de un endpoint. Un depósito creado entre dos de sus lecturas, o visto por dos nodos con un bloque de diferencia, nunca se toma por ejecutado mientras sigue vivo
  • Lanza una alerta tras fallos repetidos en un vault, contando por separado su paso en Ethereum y su paso en Robinhood Chain, de modo que se informa de un vault que falla todos los días en un lado. Desde el séptimo bucle de auditoría, espera como máximo diez segundos a su webhook de alertas y lee su respuesta: una alerta que el webhook no acepta se guarda, cien como máximo, en su archivo de estado, y se vuelve a enviar en los ciclos siguientes, así que llega tarde en lugar de no llegar nunca. El mensaje lleva los campos que leen Slack y Discord, cada uno los suyos. Desde el octavo bucle de auditoría, se guarda una sola entrada por alerta distinta: una alerta que se vuelve a lanzar mientras espera (un vault que falla en cada ciclo) se cuenta, no se guarda dos veces. El mensaje dice cuándo se lanzó la alerta por primera y por última vez y cuántas veces, y una alerta entregada con retraso empieza diciéndolo. Desde el noveno bucle de auditoría, las alertas guardadas salen en el orden en que se lanzaron por última vez: una alerta que se vuelve a lanzar pasa detrás de las demás, así que lo último que se dice de un asunto es su estado más reciente (una vigilancia que falla, se recupera y vuelve a fallar mientras el webhook está caído se entrega con «en fallo» al final, donde antes terminaba en «recuperada»). Pasadas las cien, se descarta primero solo una alerta que se lanza en cada ciclo mientras dura su causa (un vault que no logra convertir, el lote del bridge que falla), así que una alerta puntual, una transferencia de emergencia por ejemplo, y la última palabra de cada episodio nunca se desplazan. Desde el décimo bucle de auditoría, el texto de un error, en su log, sus alertas y su archivo de estado, lleva solo el esquema y el host de una dirección RPC, nunca el resto, donde los proveedores ponen la clave
  • Desde el noveno bucle de auditoría, durante un minuto después de que se mine una de sus propias transacciones, lee lo que esa transacción cambió en su bloque, nunca en el último, y estima allí el gas de lo que envía a continuación. La ejecución en testnet encontró por qué: un lote del bridge enviado justo después de la conversión de la misma pasada se simulaba en un nodo de un endpoint con balanceo de carga que iba un bloque por detrás de la conversión, no veía nada que pasar por el bridge y lanzaba una falsa alerta. Un nodo por detrás de ese bloque responde ahora con un error, y el lote espera una pasada con una advertencia. Cada transacción del keeper sale también con su estimación de gas multiplicada por 1,25, desde que la actualización Glamsterdam de Ethereum hizo más pesadas las llamadas dentro de sus transacciones
  • Desde el noveno bucle de auditoría, una hora leída de una cadena que ninguna fecha puede representar (el inicio de un feed, el final de una ventana, el plazo límite de un ticket) se lee «an unknown time» en lugar de hacer fallar la lectura que la encontró
  • Desde el séptimo bucle de auditoría, comprueba antes de su primer ciclo que cada RPC sirve la cadena que indica su configuración, y si no, se niega a arrancar. Detectada más tarde, una cadena equivocada detiene el trabajo de esa cadena con una alerta; una cadena cuyo identificador no se puede leer espera, y el trabajo de la otra cadena sigue. Desde el octavo bucle de auditoría, los dos identificadores de cadena deben estar configurados (más abajo), y un archivo de estado escrito para otra cadena se deja intacto hasta que el keeper ha leído qué cadena sirve su RPC (ver «Reinicios»)
  • Desde el octavo bucle de auditoría, lee las dos salvaguardas de los feeds de precios del oráculo de los vaults espejo en Robinhood Chain: mientras el oráculo retiene todos los precios por el secuenciador, las compras remotas esperan, con una alerta, y una acción en plena operación corporativa espera sola (ver «Cuando el oráculo retiene los precios»)
  • Paga con un sweep el efectivo que espera en el hub remoto, en ambos rails: los registros cuyos tokens han llegado, y lo que llegó al hub mientras estaba en pausa. En el rail de USDG, se abstiene mientras el hub remoto espera la liquidación de una transferencia de emergencia por parte del owner de StockFun, de lo que informa una sola vez, y retoma el sweep cuando las cuentas quedan saldadas. Desde el 2026-10-05 también hace el sweep de una parte que un vault espejo rechazó, en cuanto ese vault vuelve a aceptar el efectivo; en el rail canónico solo envía ese sweep cuando pagaría algo
  • Dispara el BuybackBurner, contando el saldo del buyback acreditado en el hook, que el burner retira antes de comprar
  • Una vez por ventana, después de la sesión estadounidense por defecto, envía las acciones de cada mercado al contrato del airdrop, sin fijar nunca el reparto: ver más abajo
  • Desde el 2026-10-05, en cada ciclo, sea cual sea la sesión, paga lo que el hook y el lock de liquidez guardan para un destinatario que lo rechazó: lo que el hook debe al vault de un mercado (payTreasury), y las partes de un cobro de comisiones que el lock guarda para un vault o un creador (payOwed). Cada pago se simula primero y solo se envía cuando paga algo. Ambas llamadas están abiertas a cualquiera
  • Desde el 2026-10-05, cobra las comisiones de LP de un pool creado con una (collectFees, abierta a cualquiera), como máximo una vez al día por pool. Los pools de StockFun no cobran comisión de LP por defecto, así que por defecto no hay nada que cobrar

La cadencia de conversión

El fundador decidió el 2026-09-27 que el ETH de un vault se convierte una vez por ciclo diario, justo antes del airdrop, y solo si el vault contiene el umbral en esa comprobación. El keeper se atiene a ello desde el 2026-10-06; hasta entonces convertía el ETH de un vault en cada pasada de la sesión en cuanto el vault contenía el umbral.

  • La ventana. El ciclo es la ventana del airdrop: se cierra cuando lo dice el contrato del airdrop (24 horas que terminan a las 13:00 UTC por defecto), incluido el mercado de $STOCKFUN; mientras la factory no designe ningún contrato del airdrop, según ese horario por defecto
  • Una comprobación por ventana. El bucle sigue haciendo una pasada cada cinco minutos por defecto, y cada pasada termina con un informe del ciclo. El umbral se comprueba en la primera pasada que llega al vault después del cierre de la ventana. Si lo alcanza o lo supera, el ETH se convierte, una sola vez: el registro que el propio vault lleva de su última conversión de ETH, leído de la cadena, informa a las pasadas siguientes, así que un reinicio no cambia nada. Por debajo, el ETH espera a la ventana siguiente, aunque los trades lo lleven por encima del umbral más tarde ese mismo día; el keeper guarda esa comprobación en su archivo de estado. Desde el 2026-10-06 la guarda como el final de la ventana para la que se hizo la comprobación, nunca como la hora de su propio reloj, que un reloj algo desajustado en torno al cierre podía separar de la ventana de la cadena; una comprobación escrita por un keeper anterior no cuenta, así que en la ventana de la actualización ese vault se vuelve a comprobar. Desde el sexto bucle de auditoría, la comprobación lee el saldo del vault después del cierre de la ventana: una pasada que empezaba antes del cierre y terminaba después registraba el saldo que había leído antes de él, y un vault que había superado el umbral a tiempo se saltaba esa ventana
  • Una conversión que no puede salir en la comprobación (un feed ETH/USD sin actualizar, una plataforma de negociación que no puede ejecutarla dentro del límite del vault, una transacción fallida, una ventana que el keeper no puede leer) se vuelve a intentar en las pasadas siguientes de la misma ventana. Una ventana que no puede leer cuenta como un fallo del paso del ETH, que se alerta tras fallos repetidos, y el USDC del vault sigue moviéndose
  • El USDC, desde el sexto bucle de auditoría. El USDC que ya está en un vault sigue adelante, se alcance o no el umbral, a su propio ritmo: su compra en Ethereum, o su liberación en un lote del bridge, sale una vez después de cada una de las conversiones de ETH del vault, y como máximo una vez por ventana en los demás casos (una donación, un reembolso, lo que dejó una etapa fallida o reducida a la mitad). Solo cuenta una etapa que salió adelante; una que falla se vuelve a intentar en las pasadas siguientes. La decisión del fundador del 2026-09-27 alcanza así al USDC: hasta entonces, unas pocas unidades de USDC enviadas a un vault antes de cada pasada hacían que el keeper enviara una compra, o todo un lote del bridge con su comisión, en cada pasada
  • Lo que sale en cada pasada: las compras en Robinhood Chain. El saldo de un vault espejo no distingue una entrega de una donación, y los topes de cada compra reparten a propósito una entrega grande en varias pasadas. El ETH que deja una conversión reducida a la mitad (la plataforma de negociación no pudo ejecutar todo el saldo dentro del límite) espera a la ventana siguiente
  • Las ejecuciones locales y de testnet ponen KEEPER_CONVERT_ONCE_PER_WINDOW en false, y entonces convierten, compran y pasan por el bridge en cada pasada; en cualquier otro lugar sigue activado, su valor por defecto

En el resto de esta página, «en cada ciclo» significa en cada pasada del bucle, como en el informe del ciclo; solo el ciclo diario del airdrop es la ventana.

Un fallo a la vez

Desde el 2026-10-05, los contratos dejan que un tramo, una acción, un mercado o una entrega fallen sin detener a los demás, e informan de lo que falló con un evento. El keeper lee esos eventos y alerta sobre lo que persiste; su propio trabajo se divide de la misma manera.

  • Un tramo de compra. El tramo de cada acción se planifica por separado: un tramo que no se puede planificar se omite, y los demás tramos siguen. Un tramo que el vault informa como fallido (LegFailed) conserva su efectivo reservado para su acción; el keeper nunca lo cuenta como convertido, y alerta tras tres fallos seguidos de esa acción en ese vault (KEEPER_ALERT_AFTER_FAILURES). Cuando no se puede planificar ningún tramo de un vault, el vault falla en su conjunto, como antes
  • Un mercado de un lote del bridge. Un mercado que el hub del bridge deja fuera de un lote (MarketSkipped) conserva su USDC en su vault para un lote posterior. Si queda fuera de tres lotes seguidos (KEEPER_BRIDGE_ALERT_AFTER_SKIPS), se alerta una sola vez, con el motivo decodificado y su solución. Desde el décimo bucle de auditoría, un mercado que el tope del adaptador deja fuera de un lote espera a la siguiente pasada, lo que se indica en el log, y encabeza ese lote; un lote que el adaptador rechaza (por encima de su tope, o un adaptador actualizado sin sus ajustes de lote) se alerta con el motivo indicado y los propios mercados del lote
  • Una entrega rechazada. Una parte que el token de efectivo rechazó a un vault espejo (DeliveryRefused) se alerta una sola vez, con su solución, hasta que el hub remoto ya no deba nada de ella a ese mercado
  • Un vault ilegible. Un vault cuyas propias funciones de lectura no responden, tras un upgrade fallido por ejemplo, queda fuera de ese ciclo; los demás vaults convierten. Se alerta una sola vez tras tres ciclos seguidos (KEEPER_ALERT_AFTER_FAILURES)
  • Una deuda que persiste. Mientras un vault, o el hook para la parte de un creador, siga rechazando el ETH que se le debe, el keeper alerta una vez por episodio de que el pool espera al owner de StockFun (un upgrade que lo corrija), y registra el fin del episodio en cuanto se paga la deuda, por el keeper o por cualquier otro

Lo que solo el owner de StockFun puede resolver queda «a la espera del admin»: una alerta por episodio, nunca contada como un fallo, y el resto sigue mientras tanto.

El informe del ciclo incluye ahora las deudas pagadas y las aún adeudadas, los tramos que fallaron, los pools cuyas comisiones de LP se cobraron y, para el paso del airdrop, los ciclos abiertos, las búsquedas de acciones apartadas realizadas, los vaults que enviaron y las entregas aún en tránsito. Desde el 2026-10-06, un envío a una ventana sin tenencias elegibles, que el contrato del airdrop deja apartado, se cuenta por separado (airdropHeldAside), ya no con los vaults que enviaron; en el rail canónico, cuenta las reejecuciones de tickets enviadas (redeemed) y los tickets aún vigilados (ticketsWatched). Desde el séptimo bucle de auditoría, cuenta también los mercados cuyo envío al airdrop espera a valer lo que cuesta (airdropBelowCost) y las alertas guardadas para el webhook (alertsUndelivered), e indica cuándo el identificador de una cadena aún no está comprobado (deferred: chain-unverified).

Cuando el oráculo retiene los precios

Desde el 2026-10-06, el oráculo de los vaults espejo puede retener un precio (ver El rail de Robinhood), y desde el octavo bucle de auditoría el keeper lo lee antes de cotizar nada:

  • El secuenciador. Una vez por ciclo, pregunta al oráculo qué dice su comprobación del secuenciador. Mientras el secuenciador está caído, ha vuelto hace no más que el periodo de gracia, o su feed de disponibilidad no se puede leer, no se puede valorar ninguna acción: la compra del vault espera, no se cotiza nada y nada cuenta como un fallo. Una alerta abre el episodio, guardada en el archivo de estado para que un reinicio no la vuelva a lanzar, y otra indica cuándo se reanudan las compras. La comprobación está desactivada en Robinhood Chain hasta que Chainlink publique un feed de disponibilidad para ella, así que hoy no puede ocurrir nada de esto
  • Una operación corporativa. Una acción cuyo token pone en pausa su oráculo queda fuera de la compra desde el principio, se indica en el log, y su USDG se guarda para ella; nunca cuenta para la alerta de fallos, y se compran las demás acciones del basket. Un tramo que el vault informa como fallido por ese motivo, entre el plan del keeper y su compra, es algo esperado y tampoco se cuenta
  • El motivo, dicho. Cuando el límite de un tramo no se puede leer porque una salvaguarda retiene su precio, el keeper registra el motivo en el log, en cualquiera de las dos cadenas, en lugar de un vault que no puede valorar el tramo. Una salvaguarda que no puede leer (un oráculo anterior a las salvaguardas) no retiene nada: decide el propio límite de cada tramo, como antes. Desde el noveno bucle de auditoría, también se decodifican los demás errores del oráculo: un feed desactualizado se lee StalePrice en el log y en el motivo de un tramo fallido, donde antes se leía un código sin decodificar

El paso del airdrop

El lado del contrato está codificado desde el 2026-10-04, y el paso del keeper desde el 2026-10-05. En cada ciclo, antes de comprobar la sesión, el keeper sigue primero las entregas ya enviadas. Después, mientras la factory designe un contrato del airdrop, toma cada mercado por turno, incluido el mercado de $STOCKFUN:

  1. Una vez por ventana. Un vault ha terminado con la ventana cuando su último envío (lastAirdropAt) es igual o posterior al final de la ventana en la que caería un envío ahora (currentCycleEnd). Ambos se leen de la cadena, así que un reinicio no cambia nada. Por defecto, el keeper solo envía una vez terminada la sesión estadounidense del día, para que las compras del día vayan en un solo envío, a la ventana que terminó ese día, y solo cuando el vault tiene acciones; desde el séptimo bucle de auditoría, solo las acciones que valen lo que cuesta enviarlas (más abajo). Desde el décimo bucle de auditoría, con ese valor por defecto, un vault leído después del cierre sin nada que enviar solo se vuelve a leer cuando abre la siguiente sesión, o cuando la ventana avanza, en los rails cuyas compras siguen la sesión de Nueva York (no el de Ondo): lo que tiene viene de sus compras, hechas en sesión. No mientras una compra propia siga esperando su recibo, que puede llegar por la noche: ese vault se lee en cada pasada, y lo que trae la compra va a la ventana que terminó ese día
  2. Primero las acciones apartadas, aunque no haya nada que enviar. Si el mercado tiene acciones apartadas, assignUnassigned, como máximo cinco llamadas por ciclo, hasta que queden colocadas, lo que abre el ciclo de la ventana que las recibe, o no quede ninguna ventana terminada por revisar. Desde el 2026-10-06, el keeper hace esta búsqueda tenga o no el vault algo que enviar, y esté o no en pausa el vault: hasta entonces solo la hacía antes de un envío, así que un mercado que tuvo un trade y luego se quedó inactivo mantenía su primer airdrop, apartado, fuera del alcance de sus holders hasta un nuevo trade o hasta que alguien hiciera la búsqueda a mano. Una búsqueda sin terminar retrasa hasta el ciclo siguiente un envío a una ventana sin tenencias elegibles. Desde el sexto bucle de auditoría, mientras el vault no tiene nada que enviar, una búsqueda que no colocaría nada (ninguna ventana puede recibir aún las acciones) solo se envía cuando la búsqueda del mercado va maxWindowsPerAssign ventanas por detrás de la última ventana, 30 por defecto: una búsqueda al mes en lugar de una al día indefinidamente. Una búsqueda que coloca las acciones siempre sale. Desde el séptimo bucle de auditoría, «nada que enviar» significa nada que valga la pena enviar, según la misma regla que el envío: en el rail del bridge, el polvo que el OFT no puede transportar, que cada envío deja en el vault espejo, no cuenta para nada, y el límite también se cumple allí
  3. El ciclo, solo antes de un envío. openCycle, para que cada entrega solo se sume a él; nunca para una ventana a la que no se envía nada, y desde el séptimo bucle de auditoría solo para un envío que valga su costo, incluida la apertura. Una ventana sin tenencias elegibles no es un error: las acciones quedan entonces apartadas
  4. El envío. En el rail local, sendToAirdrop en el TreasuryVault del mercado. En el rail del bridge, sendToAirdrop en el vault espejo, pagando su comisión de LayerZero cotizada (quoteSendToAirdrop) más un margen, un 10 % por defecto; el vault devuelve el excedente. Desde el noveno bucle de auditoría, el envío y cada una de sus cotizaciones llevan el gas que reciben sus entregas en Ethereum, que elige el keeper (más abajo). Antes de ese envío, el keeper comprueba que el hub remoto envía al contrato del airdrop de la factory, que cada acción tiene un adaptador y que ese adaptador responde, y que el OFT de la acción en Ethereum está registrado en el contrato del airdrop. Desde el séptimo bucle de auditoría, el envío solo lista las acciones que valen su costo, con su comisión cotizada de nuevo para ellas
  5. Las entregas. En el rail del bridge, la entrega de cada acción se sigue hasta que el endpoint de LayerZero en Ethereum ha ejecutado su último paso, que abona al contrato del airdrop. Desde el noveno bucle de auditoría, una entrega atascada en ese endpoint la vuelve a ejecutar el propio keeper (más abajo). Una entrega no abonada en 60 minutos por defecto lanza una alerta, que lleva los comandos que ejecutan sus pasos a mano; cualquiera puede ejecutarlos

Cada acción va por separado: una acción cuyo saldo no se puede leer (una congelación del emisor), una sin adaptador o cuyo OFT no está registrado, una cuyo adaptador no responde (peers(): ningún contrato en su dirección, o no es una app de LayerZero; desde el 2026-10-06, hasta entonces hacía fallar todo el envío del mercado), desde el octavo bucle de auditoría una cuya comisión de LayerZero su adaptador no puede cotizar (más abajo), y una que el vault informa que no pudo enviar (AirdropSendFailed) quedan fuera, con una alerta, y las demás siguen. Cada mercado va también por separado: uno que sigue fallando se alerta una sola vez tras tres fallos seguidos, y el siguiente mercado sigue. Desde el 2026-10-06, una búsqueda de acciones apartadas que sigue fallando tiene una alerta propia, que da su solución: cualquiera puede llamar a assignUnassigned para ese mercado.

«A la espera del admin» cubre aquí un contrato del airdrop en pausa, una acción que le falta al contrato del airdrop tras una transferencia de emergencia (esa acción espera en los vaults, las demás siguen), un hub remoto que envía a otro contrato del airdrop que no es el de la factory y, desde el noveno bucle de auditoría, un hub remoto cuyos límites de gas de las entregas no están fijados, o cuyo techo está por debajo de lo que necesita una entrega.

Lo que vale la pena enviar

Desde el séptimo bucle de auditoría, el 2026-10-06, el keeper solo envía lo que vale lo que cuesta enviarlo. Hasta entonces salía cualquier acción por encima de cero: un regalo apenas por encima del polvo al vault de un mercado que nadie opera hacía que el keeper abriera el ciclo de esa ventana y pagara un mensaje de LayerZero, o un envío en Ethereum, cada día.

  • Lo que lleva un envío. Una acción cuyo saldo se puede leer y está por encima de cero; en el rail del bridge, también debe tener un adaptador y una cotización propia por encima de cero. La cotización del vault es cero tanto para el polvo que el OFT no puede transportar como para una acción cuyo adaptador no puede cotizar su envío, así que desde el octavo bucle de auditoría el keeper pregunta al propio adaptador de la acción, sobre el envío que construiría el vault: el polvo nunca se envía ni se alerta; una acción cuya cotización falla, cuyo propio envío fallaría, queda fuera con una alerta que dice por qué; y una acción a la que el keeper no puede preguntar sale como antes, y decide su envío. Hasta entonces, una acción así se tomaba por polvo y se descartaba de todos los envíos sin decir nada
  • Su valor. Cada acción se valora con el propio oráculo de su vault, a la última respuesta de su feed de precios, desactualizada o no, ya que es una estimación y nunca un límite; los costos, pagados en ETH, se convierten en dólares con el feed ETH/USD del mismo oráculo
  • Su propio costo. Cada acción debe valer al menos su propio costo: su comisión de LayerZero en el rail del bridge, donde cada acción es un mensaje propio, o su parte del gas del envío en el rail local. Un regalo que no vale su propio mensaje nunca viaja con un envío real
  • El envío completo. Las acciones que pasan deben valer juntas todo el envío, más la apertura de la ventana (openCycle) cuando su ciclo aún no está abierto. En el rail local, desde el octavo bucle de auditoría, la apertura se cuenta una sola vez: la propia estimación del envío, hecha con el ciclo cerrado, ya la incluye, así que solo se suma el costo base de la transacción de apertura; contada dos veces, retenía durante días un envío que valía algo más de lo que costaba. Si no, no sale ninguna, y el ciclo no se abre
  • Lo que espera. Lo que no sale se queda en el vault y sale en una ventana posterior, con lo que se vaya acumulando. Un mercado cuyo envío espera se cuenta en el informe del ciclo y se registra en el log una vez por ventana
  • Lo que no se puede leer. Un precio, una comisión o un costo de gas que el keeper no puede leer deja salir el envío, como antes de la regla: una lectura que falla nunca retiene un envío real

KEEPER_AIRDROP_MIN_VALUE_BPS fija el múltiplo: 10 000, una vez el costo, por defecto, así que un envío que vale al menos lo que cuesta sale, sea cual sea su tamaño por encima; un valor más alto retiene los envíos más pequeños hasta que valen ese múltiplo, y 0 envía lo que se lleve. La misma regla decide si un vault tiene algo que enviar para la búsqueda de acciones apartadas de más arriba. La auditoría la tomó como su opción por defecto recomendada; solo decide cuándo sale una acción, nunca cuánto, qué ni adónde.

El gas de la entrega en Ethereum

El 2026-10-06, Sepolia activó la actualización Glamsterdam de Ethereum, que hace que un nuevo slot de almacenamiento cueste unas cinco veces su gas anterior, y todas las entregas del airdrop del primer ciclo de la ejecución de LayerZero en testnet se quedaron sin gas en el ejecutor de LayerZero: un envío pagaba solo el gas del último paso de la entrega, y el gas de su primer paso era el que impusiera el owner del adaptador de LayerZero de la acción (el emisor, en mainnet). Desde el noveno bucle de auditoría, por decisión del fundador de ese mismo día:

  • El keeper simula cada entrega en Ethereum antes del envío: el contrato del token de la acción que la recibe, y el contrato del airdrop que la abona, tal como la entrega los encontrará. Pide lo que necesita la acción más pesada multiplicado por 1,25, menos el gas que el adaptador de LayerZero de la acción ya impone para el primer paso
  • Cuando una simulación no puede ejecutarse, toma lo que usaron las últimas entregas del mercado en Ethereum, y si no, los valores por defecto del hub remoto
  • El hub remoto lo acota. El owner de StockFun fija un valor por defecto, un suelo y un techo para cada uno de los dos pasos (ver El rail de Robinhood); lo que pida el keeper se mantiene entre ellos. Una petición que el techo deja por debajo de lo que necesita una entrega queda «a la espera del admin»: el envío sale igualmente, y una entrega que se atasca se vuelve a ejecutar (sección siguiente)
  • Nada cambia para los holders. El keeper solo decide el gas que recibe una entrega, nunca cuánto se envía, adónde ni a quién
  • Se vuelve a elegir solo cuando hace falta. Un par de gas elegido a partir de la simulación de cada acción se conserva para la ventana mientras no cambien las acciones, el estado del ciclo de la ventana ni la posibilidad de que una entrega llegue después del final de la ventana siguiente; uno que una simulación no pudo dar se vuelve a elegir en cada pasada. Desde el décimo bucle de auditoría, un envío que solo lleva el polvo que el bridge no puede transportar no lee nada del entorno de la entrega, y un par simulado una vez abierto el ciclo de la ventana, un estado que nunca vuelve atrás, se reutiliza sin volver a leerlo

Una entrega atascada en Ethereum

Una entrega sin gas suficiente no pierde nada: se queda en el endpoint de LayerZero en Ethereum, con su primer paso verificado y sin ejecutar, o su último paso almacenado y sin ejecutar, hasta que alguien la vuelva a ejecutar con más gas. Desde el noveno bucle de auditoría, lo hace el propio keeper:

  • Lee en cada ciclo el paso de cada entrega en el endpoint. Una vez terminado el turno del ejecutor (su fallo, creído solo si viene del propio ejecutor de LayerZero, o diez minutos), vuelve a ejecutar el paso atascado desde su clave de Ethereum, con lo que necesita según la simulación multiplicado por 1,25, y nunca más de KEEPER_AIRDROP_REEXECUTION_MAX_GAS, 4 000 000 por defecto
  • Una que no puede enviar (su simulación falla, lo que necesita supera el límite, a su clave le falta ETH) se alerta una sola vez, con el comando para ejecutarla a mano, y se vuelve a intentar en cada ciclo
  • Una que vuelve a fallar en la cadena, con el paso aún atascado, es el segundo fallo: se alerta, con el comando, y el keeper no la vuelve a enviar nunca. Solo lo decide con una lectura del paso que responde, y solo una vez que el bloque de la ejecución fallida tiene unos pocos bloques de profundidad (KEEPER_LOG_LAG_BLOCKS), así que ni un nodo con un bloque de retraso ni una reorganización de ese bloque pueden hacer que se rinda
  • La clave de Ethereum del keeper paga estas ejecuciones: con Glamsterdam, un último paso que abre un ciclo necesita alrededor de un millón de gas

El keeper elige cuándo, y el gas de una entrega dentro de los límites del owner, nada más. Un envío que llega después de la siguiente hora de cierre se mide sobre la ventana del día siguiente.

Siete parámetros gobiernan el paso: KEEPER_AIRDROP (activado por defecto), KEEPER_AIRDROP_AFTER_SESSION (activado por defecto; desactivado en una testnet que ignora la sesión), KEEPER_AIRDROP_FEE_MARGIN_BPS (1 000), KEEPER_AIRDROP_TRANSIT_MINUTES (60), desde el séptimo bucle de auditoría KEEPER_AIRDROP_MIN_VALUE_BPS (10 000), y desde el noveno KEEPER_AIRDROP_REEXECUTION_MAX_GAS (4 000 000) y KEEPER_AIRDROP_LZ_EXECUTOR (vacío: el ejecutor de LayerZero en la cadena del keeper, el único llamante cuyas alertas de fallo cree el keeper).

Reinicios: el archivo de estado

Desde el 2026-10-05, el keeper escribe lo que sigue de un ciclo a otro en un archivo de estado (KEEPER_STATE_DIR): las entregas del airdrop y las transferencias del bridge en tránsito, las transacciones a la espera de un recibo, sus episodios de alerta y sus series de fallos; desde el sexto bucle de auditoría, también los tickets del rail canónico que vigila, dónde se detuvo la búsqueda de cada transferencia y cuándo salió por última vez el USDC de cada vault; desde el séptimo, las alertas que su webhook aún no ha aceptado. Un archivo escrito por un keeper anterior se carga tal cual. Escribe el archivo después de cada ciclo y de cada envío, y lo lee una sola vez al arrancar. Un reinicio no olvida nada de ello: una entrega cuyo último paso falla después de un reinicio se sigue alertando, una transacción enviada antes de él nunca se vuelve a enviar, y un episodio ya alertado no se alerta dos veces. Un archivo escrito para otra factory se deja de lado, y el keeper arranca vacío, con una advertencia. Desde el octavo bucle de auditoría, un archivo escrito para otra cadena primero se deja como está, sin leerlo ni sobrescribirlo, hasta que el keeper ha leído qué cadena sirve su RPC: si sirve la cadena configurada, el archivo era de otra cadena y entonces se deja de lado; si no, el error está en el identificador configurado, el keeper se niega a arrancar y, una vez corregido, el keeper recupera su archivo, incluidos los depósitos que vigilaba. Hasta entonces, un identificador mal escrito costaba el archivo antes de que el keeper se negara a arrancar. Las alertas guardadas son una por alerta distinta desde el mismo bucle; un archivo escrito por un keeper anterior se carga tal cual. Desde el noveno bucle de auditoría, el archivo guarda también el paquete de cada entrega del airdrop y sus ejecuciones por el keeper, el gas que usaron las últimas entregas del mercado y la última reejecución que el keeper hizo de cada ticket canónico; un archivo escrito por un keeper anterior se sigue cargando tal cual.

Desde el 2026-10-06:

  • Cada envío está en disco antes de su espera. Cada transacción sale con el nonce que la cadena da a la dirección del keeper justo antes, y se escribe en el archivo de estado, con su hash y su nonce, en cuanto vuelve el hash, antes de esperar su recibo: un keeper interrumpido mientras espera la recupera por su hash al reiniciar en lugar de volver a enviarla
  • Una transacción perdida se abandona. Una que ya ningún nodo conoce cuatro veces KEEPER_RECEIPT_ALERT_MS después de su envío (dos horas por defecto) se descarta con una alerta, para que deje de retener los envíos de su tipo; su nonce sigue libre, y la siguiente transacción del keeper lo toma. La alerta de una transacción aún no minada indica cómo sustituirla
  • Escrito entero. Un disco demasiado lleno para recibir el archivo es un error, que se alerta, y el último archivo bueno se conserva; hasta entonces, una copia truncada podía sustituirlo
  • Un keeper por carpeta. El keeper toma un bloqueo en su carpeta de estado (keeper.lock): un segundo keeper en la misma carpeta se niega a arrancar y nombra al primero. Un bloqueo cuyo keeper ya no existe se toma; uno dejado por un keeper en otra máquina no, y el operador lo borra una vez que ese keeper ya no se ejecuta. Un dry run no toma ningún bloqueo

El tamaño de cada etapa

Desde el 2026-10-01, el vault convierte el monto que indica el keeper, no su saldo completo. El keeper lo dimensiona:

Etapa Monto
ETH → USDC El saldo completo, reducido a la mitad mientras la cotización no alcance el límite del vault, nunca por debajo del umbral de conversión; desde el 2026-10-06, el resto espera a la ventana siguiente
Una acción en pools de Uniswap en Ethereum La reserva de la acción, reducida a la mitad como máximo cuatro veces; un tramo que sigue sin alcanzar el límite espera al siguiente ciclo, con su reserva intacta
Una acción en el rail opcional de Ondo La reserva de la acción, limitada al nocional máximo de la sesión. Desde el 2026-10-06, un tramo que Ondo cotiza por debajo del límite del vault nunca se envía: la cotización gratuita se lee antes de cualquier atestación, y en cuanto una atestación vuelve por debajo del límite, no se pide ninguna más para esa acción hasta la ventana siguiente
Una acción en Robinhood Chain La reserva de la acción, con un tope propio: un techo fijo y, cuando su pool se puede medir, una parte de la profundidad de ese pool

Lo que no se gasta espera en el vault al siguiente ciclo (para el ETH, a la ventana siguiente); el efectivo de una acción sigue reservado para esa acción.

Desde el pipeline de seguridad del 2026-10-01, cada compra retiene n−1 unidades en la última acción del basket, siendo n el número de acciones, en todo rail que compra acciones. Los vaults asignan el residuo del redondeo de los pesos a la última acción, así que unas pocas unidades de efectivo que lleguen entre la lectura del keeper y su transacción pueden reducir esa única reserva hasta en n−2 unidades; gastar el monto leído haría fallar toda la llamada, y cualquiera podía provocarlo con una transferencia de polvo. Lo retenido sigue reservado para la siguiente llamada. Cualquier otro que llame a los vaults debería mantener el mismo margen. Una corrección en los contratos, que cambia la regla de asignación documentada, espera la decisión del owner. Desde el 2026-10-06, un vault que no tiene más que esas pocas unidades de USDC (cuatro como máximo, ya que un basket contiene como máximo cinco acciones) ya no se visita por ellas: esperan al siguiente USDC que traiga su ETH.

El burn de $STOCKFUN se dimensiona de la misma forma: una fracción cuyo impacto en el precio supera el techo del keeper se reduce a la mitad, nunca por debajo del umbral del keeper, y el resto se quema en ciclos posteriores. Desde el pipeline de seguridad del 2026-10-01, una fracción que el pool de $STOCKFUN no puede ejecutar entera también se reduce a la mitad; antes, el burn fallaba en ese ciclo. Ningún otro fallo se reintenta.

Lo que no puede hacer

Elegir un activo fuera del basket. Pasar el efectivo reservado de una acción a otra acción. Relajar un límite de oráculo. Enviar un activo a otro sitio que no sea donde lo envía el contrato. Retirar nada. Elegir quién recibe un airdrop o cuánto lleva, o asignarse una parte a sí mismo.

Su disparo está reservado para evitar los ataques sándwich, no porque se confíe en el keeper: cada llamada que hace se ejecuta dentro de los límites de los vaults.

El ciclo

flowchart TD S[Ciclo diario, después de las 13:00 UTC] --> C{¿Mercado abierto?

calendario NYSE} C -->|no| W[Esperar] C -->|sí| P{¿Contrato en pausa?} P -->|sí| W P -->|no| A{¿Primera comprobación del vault

en esta ventana: ≥ 0.1 ETH?} A -->|no, el ETH espera

a la ventana siguiente| N[Siguiente mercado] A -->|sí| E[ETH → USDC, límite de 50 bps] E --> B[USDC → USDG → bridge] B --> R{¿Llegó a la cadena remota?} R -->|no| M[Vigilar, reejecutar el ticket] R -->|sí| K[Comprar las acciones, límite de 200 bps] K --> AD[Enviar al contrato del airdrop] AD --> N

La hora, el umbral y los límites del diagrama son los ajustes por defecto. El keeper hace una pasada cada cinco minutos; el ETH de un vault se comprueba una vez por ventana, en su primera pasada después del cierre, mientras que el USDC que ya contiene sigue adelante una vez después de cada conversión y como máximo una vez por ventana en los demás casos. El envío al contrato del airdrop se hace una vez por ventana, después de la sesión por defecto; las deudas, las comisiones de LP, las entregas y, desde el sexto bucle de auditoría, los tickets del rail canónico se tratan en cada ciclo, sea cual sea la sesión.

Su configuración

Todo pasa por variables de entorno: los RPC de ambas cadenas, la clave privada del keeper, las direcciones de los contratos, el intervalo y las palancas de seguridad (dry run, ejecución única, exigir mercado abierto). Desde el 2026-10-05, también: los parámetros del paso del airdrop, más arriba; el cobro de las comisiones de LP, KEEPER_COLLECT_FEES (activado por defecto), KEEPER_COLLECT_FEES_HOURS (24) y KEEPER_COLLECT_FEES_MIN_WEI (0); la alerta tras omisiones repetidas, KEEPER_BRIDGE_ALERT_AFTER_SKIPS (3); y la carpeta del archivo de estado, KEEPER_STATE_DIR. Desde el 2026-10-06, KEEPER_CONVERT_ONCE_PER_WINDOW (activado por defecto): el ETH de un vault se convierte una vez por ventana y, desde el sexto bucle de auditoría, su USDC sale una vez después de cada conversión y como máximo una vez por ventana en los demás casos; una ejecución local o de testnet lo desactiva y convierte, compra y pasa por el bridge en cada pasada. Desde el sexto bucle de auditoría, también KEEPER_TICKET_ALERT_HOURS (6): en el rail canónico, las horas tras las cuales se alerta de un ticket del que no se sabe que se haya ejecutado. KEEPER_STOCK_ROUTER, el router que la factory designa para los nuevos vaults, solo determina qué sesión de mercado habilita un ciclo; cada vault se cotiza en su propio router.

Desde el séptimo bucle de auditoría, los identificadores de cadena, KEEPER_CHAIN_ID y KEEPER_REMOTE_CHAIN_ID, se comprueban frente a los RPC antes del primer ciclo: 1 con 4663 en mainnet, 11155111 con 46630 en la testnet. Desde el octavo bucle de auditoría, ambos deben estar configurados: KEEPER_CHAIN_ID siempre, KEEPER_REMOTE_CHAIN_ID con el bridge, y el keeper se niega a arrancar sin ellos (hasta entonces, si se omitían, KEEPER_CHAIN_ID se leía como 11155111 y KEEPER_REMOTE_CHAIN_ID como 4663). Desde el décimo bucle de auditoría, KEEPER_LOG_MAX_SELECTORS (1 000 por defecto, como mínimo 5) limita las direcciones y los valores de evento que nombra una petición de logs, tal como los cuentan los nodos de Robinhood Chain; detrás del endpoint público de Sepolia, que rechaza diez direcciones o más, se fija en 10. Dos parámetros indican a cuántos bloques por debajo del último se detienen sus búsquedas de logs: KEEPER_LOG_LAG_BLOCKS (2, en Ethereum) y KEEPER_REMOTE_LOG_LAG_BLOCKS (12, en Robinhood Chain); desde el octavo bucle de auditoría, el primero es también la profundidad que debe tener el bloque de un lote del bridge antes de que el keeper lo siga, y el segundo, a cuántos bloques por debajo del último se lee un ticket. Las salvaguardas del oráculo no necesitan ningún parámetro: el keeper las lee en el oráculo de cada vault espejo. Un parámetro de número entero que se deja vacío toma su valor por defecto, y uno fuera de su rango detiene el keeper al arrancar.

La clave del keeper es una clave caliente, con fondos solo para el gas, y distinta de la del deployer.

Sus límites

  • En el rail de USDG, una entrega que el token de efectivo rechazó antes de que el keeper arrancara, o mientras estaba detenido, solo aparece como una advertencia cuando hace el sweep; el rail canónico encuentra una parte así en el propio estado del hub remoto
  • Hasta el noveno bucle de auditoría, el keeper no ejecutaba él mismo el último paso de una entrega fallida (lzCompose); desde entonces vuelve a ejecutar un paso atascado, con un límite, y un segundo fallo se deja a una persona, con el comando
  • La vigilancia de emergencias no conserva su posición tras un reinicio: los eventos emitidos mientras el keeper estaba detenido no se examinan
  • Un keeper interrumpido en los pocos milisegundos que hay entre un envío y su escritura en el archivo de estado puede volver a enviar esa transacción al reiniciar; las propias comprobaciones de los contratos hacen fallar la mayoría de esas repeticiones, al costo de su gas
  • La búsqueda de la llegada de una transferencia nunca lee dos veces un bloque: una reorganización que mueve una llegada a un bloque ya leído deja esa transferencia a la alerta de tránsito. Desde el séptimo bucle de auditoría, cada búsqueda de logs se detiene unos pocos bloques por debajo del último, lo que retrasa un abono, y su alerta de tránsito, esos pocos bloques
  • Desde el octavo bucle de auditoría, un lote del bridge se sigue una vez que su bloque tiene unos pocos bloques de profundidad, un ciclo más tarde que antes, y el lote siguiente lo espera; una reorganización más profunda no está cubierta, como en las búsquedas de logs. Un ticket ejecutado en los últimos pocos bloques sigue leyéndose allí como vivo hasta que el último bloque supera su ejecución en esa misma cantidad de bloques: el ciclo siguiente en una cadena con actividad, más ciclos en una tranquila. Desde el noveno bucle de auditoría, uno que borró la propia reejecución del keeper no se vuelve a reejecutar ni se alerta mientras tanto, tampoco después de un reinicio; uno reejecutado por otro en esos bloques se vuelve a intentar, falla en la simulación, y aún puede alertarse como vivo pasadas las horas de la alerta
  • El minuto durante el cual el keeper lee en el bloque de su propia última transacción no cubre un nodo que vaya más de un minuto por detrás de sus pares
  • En el rail local, la apertura de la ventana se cuenta una sola vez, sin lo que repite la segunda transacción (alrededor de un 5 % del costo): un envío puede salir valiendo hasta eso menos de lo que cuesta
  • Desde el décimo bucle de auditoría, una acción dada a un vault después del cierre, fuera de cualquier compra, sale con el envío de la siguiente sesión, a una ventana posterior: el keeper solo vuelve a leer un vault sin nada que enviar en la siguiente sesión. Una compra cuyo recibo leyó el keeper en la última pasada de la sesión también podría leerse vacía en la primera pasada después del cierre desde un nodo con retraso respecto a esa lectura, lo que requiere un intervalo entre pasadas más corto que el retraso de ese nodo (unos cinco segundos en Sepolia), nunca los cinco minutos por defecto

Preflight

Antes de cualquier ejecución real, un comando de preflight comprueba, sin escribir una sola transacción, que las redes responden, que las direcciones tienen código, que los peers de LayerZero del OFT de USDG coinciden, que el USDG no ha sido pausado por su emisor, Paxos, y que los pesos de los baskets son los que deben ser.

Desde el octavo bucle de auditoría, comprueba también las salvaguardas del oráculo. Su manifiesto debe indicar cómo está configurada la comprobación del secuenciador, en un sentido o en otro: sin feed de disponibilidad y sin periodo de gracia (la comprobación desactivada, como hoy), o un feed con un periodo de gracia. Lee ese feed cuando lo hay, y la pausa del oráculo del token de cada acción: un token en plena operación corporativa es una advertencia, que no hace fallar la comprobación; un token sin la señal falla. Tras el despliegue, comprueba que el oráculo desplegado coincide con el manifiesto, que el estado de su secuenciador deja pasar los precios y que la comprobación de pausa de cada acción está activada. El comando inspect del keeper muestra las mismas salvaguardas: la comprobación del secuenciador y su estado, y la comprobación de pausa de cada acción y si su token está ahora en pausa.

Desde el noveno bucle de auditoría, también se ejecuta sobre el despliegue de la ejecución de LayerZero en testnet (Sepolia y la testnet de Robinhood Chain), a partir de los dos archivos de esa ejecución, con RPC nombrados para ese par, de modo que nunca se pregunta a un RPC de mainnet por la testnet; cualquier otro par de cadenas, mezcla incluida, se rechaza. En la testnet no lee ningún router v3 de Uniswap, que esa cadena no tiene, y comprueba el feed ETH/USD frente al heartbeat que recibió el oráculo de la ejecución. En ambos pares comprueba que el router remoto designa el router v3 que indica el manifiesto. Ejecutado sobre el despliegue de testnet: 68 comprobaciones, todas superadas.

Se niega a ejecutarse sin RPC antes que informar de un falso éxito.