Skip to main contentA-REX Foundation

Whitepaper · 07

Hooks y módulos de referencia

Cómo agregar funcionalidad a un token conforme sin tocar el estándar: qué debe cumplir un hook, los hooks de referencia, las extensiones complementarias y cómo escribir, probar y registrar tus propios hooks.

Los módulos son demostraciones, no parte del estándar

A-REX Core se relaciona con sus módulos igual que ERC-3643 con los módulos de cumplimiento de T-REX: la interfaz con la que se conectan los módulos está estandarizada; los módulos, no. Un token conforme sin ninguna regla externa (hook) es un token A-REX válido. Cualquier hook, lo escriba quien lo escriba, es compatible con todos los tokens conformes. Por eso el ecosistema puede crecer sin que cambie el estándar.

graph LR
    T["ARexToken<br/>token conforme"] -->|"check / onExecuted / canSend / canReceive"| H1[EligibilityHook]
    T --> H2[ExpiryHook]
    T --> H3[AttestationHook]
    T --> H4["Tu hook"]
    H3 --> A[ARexAttestations]

Qué debe cumplir un hook

CallbackCuándo se llamaDebe
checkantes de que cambien los saldos, por cada id afectado, con los hooks en orden de registro; se detiene en el primer código distinto de ceroser una vista; nunca revertir por motivos de política
onExecuteddespués de que cambien los saldos, por cada id, en ordenno llamar a las funciones del token que modifican saldos (el token está bloqueado)
canSend / canReceiveen cada transferencia y en las vistas ERC-7943 del tokenser vistas

op toma uno de estos valores: OP_MINT (1), OP_TRANSFER (2), OP_BURN (3), OP_FORCED_TRANSFER (4), OP_TRANSFORM (5). En una transformación, las entradas llegan con to == 0 y las salidas con from == 0. data contiene los datos de transferencia de ERC-1155; en las transformaciones es abi.encode(processRef) y en las transferencias forzosas va vacío.

El token que llama es msg.sender. Si un hook necesita los datos del lote, los lee con IARexBatch(msg.sender).batchOf(id).

Hooks de referencia

EligibilityHook — permitir, bloquear, sancionar

Muestra cómo funciona HOOK_ELIGIBILITY. Mantiene una lista opcional de permitidos, una lista de bloqueados y una lista de sanciones. canSend/canReceive devuelven la conjunción de las tres. check devuelve SANCTIONED, SENDER_INELIGIBLE o RECEIVER_INELIGIBLE, para que las interfaces puedan explicar el rechazo. Las transferencias forzosas siempre se permiten: embargar bienes de una cuenta sancionada es justamente el objetivo de los controles de cumplimiento. En producción, las listas se alimentan de un registro de identidad (ONCHAINID, EAS, credenciales verificables) o de un oráculo de sanciones; al hook le da igual cuál.

ExpiryHook — perecibilidad sin un módulo dedicado

No guarda estado. Lee expiresAt y producedAt del lote. Bloquea las acuñaciones y transferencias de lotes vencidos (BATCH_EXPIRED), pero no las quemas (baja contable) ni las transferencias forzosas (controles de cumplimiento). De forma opcional, bloquea las transferencias de lotes que todavía no se produjeron (BATCH_NOT_PRODUCED). Una plataforma que financia la precosecha configura el indicador para permitirlas; un marketplace spot lo configura para bloquearlas. Este único hook cubre la parte de bloqueo de la perecibilidad; las curvas de deterioro pasan a ser una vista auxiliar o una valoración fuera de la cadena.

AttestationHook — requisitos regulatorios por producto

Asocia cada código de producto con el tema de atestación (certificado o constancia verificable) que exige. Antes de una transferencia, lee el lote, busca el requisito y consulta isAttested en el registro de atestaciones; si la atestación no es válida, devuelve ATTESTATION_MISSING. Reglas como «el café necesita una referencia de debida diligencia EUDR», «los lotes con etiqueta orgánica necesitan un certificado orgánico vigente» o «el ganado necesita un certificado sanitario» se configuran cada una con una llamada a setRequirement.

PerishabilityHook — modelos de deterioro

Configura el deterioro por código de producto, con la opción de sobrescribirlo para un lote concreto. Ofrece los modelos NONE, LINEAR (hasta un valor mínimo al vencer), EXPONENTIAL (vida media) y STEP (caída en cada intervalo), y las vistas valueBps, secondsRemaining e isExpired. Bloquea las acuñaciones y transferencias de lotes vencidos (BATCH_EXPIRED) y las transferencias de lotes cuyo valor restante es cero (PERISH:NO_VALUE). Nunca bloquea las quemas ni los controles de cumplimiento.

SeasonalHook — ventanas de cosecha y de comercialización

Define ventanas absolutas [start, end] por producto y por operación (hasta 16 por clave). Si una combinación de producto y operación no tiene ventanas, no tiene restricciones. Uso típico: limitar OP_MINT a la ventana de cosecha y OP_TRANSFER a la ventana de comercialización; fuera de ellas, el hook devuelve SEASON_CLOSED.

DeliveryHook — custodia y liquidación

El remitente programa la entrega de amount unidades a un destinatario a través de un transportista, y esas unidades quedan bloqueadas. El bloqueo usa un contador O(1), así que check nunca recorre el historial. El transportista y los sensores registran la recogida, el tránsito y las lecturas de temperatura (con un indicador de desvío). El destinatario confirma la entrega, y las disputas pasan a un árbitro. La liquidación es la propia transferencia ERC-1155: del remitente al destinatario, por la cantidad exacta y con data = abi.encode(deliveryId). check solo la permite cuando la entrega está en DELIVERED, y onExecuted la marca como SETTLED y libera las unidades. Las unidades libres (no bloqueadas) siguen circulando.

TraceabilityHook — registro de eventos con formato EPCIS

Observa cada operación del token y la clasifica según los pasos de negocio de CBV (commissioning, shipping, destroying, transforming) y sus disposiciones (active, in_transit, destroyed, seized). RECORDER_ROLE registra eventos críticos de seguimiento ajenos al token (enfriamiento, empaque, recepción) con readPoint y bizLocation. Tiene dos modos: solo emisión (unos +17 k de gas por transferencia; un indexador reconstruye el registro) o persistencia (unos +184 k; getEvents responde en la cadena, con paginación).

Extensiones complementarias

Hay tres necesidades que nunca tuvieron que ser reglas de transferencia. Se resuelven con contratos simples que leen o escriben atestaciones:

ExtensiónQué hace
CommodityPriceOraclelos informantes envían precios por producto; las rondas están numeradas y se cierran por quórum con la mediana, o manualmente cuando se alcanza un mínimo; latestAnswer, isStale
CarbonImmobilizationWrapperregistra créditos inmovilizados en un registro (registro, rango de seriales, vintage, toneladas, prueba), vincula toneladas con lotes, replica el retiro y la liberación, y escribe la atestación AREX:CARBON:IMMOBILIZED; nunca acuña créditos
ParametricInsurancepool ERC-20; una póliza por lote, con un tema que actúa como disparador; la indemnización se paga cuando el disparador se atesta antes del vencimiento

Escribir tu propio hook

El ejemplo completo contracts/examples/SeasonHook.sol se mantiene en el repositorio. test/standard/ImplementationGuide.test.js lo pone a prueba para quienes tienen acceso. SeasonalHook es el módulo de referencia cuando necesitas varias ventanas por producto y por operación.

Reglas prácticas:

  1. Los símbolos OK y OP_FORCED_TRANSFER están definidos en el texto normativo.
  2. El comportamiento de la quema está definido en el texto normativo.
  3. El callback check está definido en el texto normativo.
  4. Los nombres de código como ARexCodes.code("MYNS", "NAME") están definidos en el texto normativo.
  5. Los valores de los indicadores están definidos en el texto normativo.
  6. Los callbacks onExecuted y check están definidos en el texto normativo.

Registro y orden

Pon primero las reglas baratas y con más probabilidad de rechazo. HOOK_ADMIN_ROLE debería quedar detrás de una multifirma o un timelock: quien controla la cadena de reglas decide qué transferencias son posibles.

Pruebas

test/standard/helpers.js despliega la pila de referencia. RecordingHook registra cada callback y se puede configurar para rechazar con cualquier código. ReentrantHook intenta volver a entrar al token desde onExecuted y demuestra que el bloqueo funciona. DomainHooks.test.js y Extensions.test.js cubren los hooks y las extensiones portados. Invariants.test.js ejecuta una secuencia aleatoria de operaciones a partir de una semilla y verifica tres cosas: que se conserva la emisión total, que el estado terminal se respeta y que canTransfer anticipa cada resultado.

Interoperabilidad con el cumplimiento de ERC-3643

Un módulo de cumplimiento de ERC-3643 expone moduleCheck(from, to, value, compliance). Un hook que lo llama en OP_TRANSFER y traduce false a un código permite reutilizar en tokens de lote las restricciones por país, los límites de saldo y los bloqueos temporales escritos para security tokens. El camino inverso, exponer un hook de A-REX a un token ERC-3643, es igual de mecánico. El Automated Compliance Engine de Chainlink se integra con el mismo patrón: su motor de políticas se convierte en un hook.