Skip to main contentA-REX Foundation

Whitepaper · 13

Análisis de rendimiento

Gas medido en la implementación de referencia con cero, uno y dos hooks, qué factores determinan el costo y recomendaciones para el despliegue.

Método

Las cifras de esta página salen de ejecutar scripts/gas-report-standard.js en la red local de Hardhat sobre la implementación de referencia compilada (solc 0.8.22, viaIR, optimizer.runs = 1 para ARexToken), en septiembre de 2026. «En caliente» significa que el par remitente/destinatario/id es el mismo de la transferencia anterior, por lo que los slots de almacenamiento ya se usaron en el bloque. Reglas externas (hooks) medidas: EligibilityHook (CHECK + ELIGIBILITY) y ExpiryHook (CHECK). Para reproducir las mediciones, ejecuta:

npx hardhat run scripts/gas-report-standard.js

Resultados

xychart-beta
    title "Gas de una transferencia en caliente según la cantidad de hooks (miles)"
    x-axis ["sin hooks", "Eligibility", "Eligibility + Expiry"]
    y-axis "gas (k)" 0 --> 140
    bar [66.8, 91.2, 119.6]

El costo crece de forma lineal con la cantidad de hooks: cada uno suma una llamada externa a check por id y, si es un hook de habilitación, también canSend y canReceive. La tabla muestra todas las operaciones.

Operación0 hooks1 hook2 hooks
createBatch (id nuevo, acuñación de 1000)264,096283,831299,396
safeTransferFrom (primera, en frío)80,687108,266136,682
safeTransferFrom (en caliente)66,79091,166119,582
transform: dividir 1 → 2 (dos ids nuevos)564,422595,707636,858
setFrozenTokens54,18854,18854,188
forcedTransfer80,15289,90999,569
burn66,62183,00193,395

Transferencia en caliente con un solo hook de cada tipo (costo marginal de cada regla):

xychart-beta horizontal
    title "Gas adicional de un hook en una transferencia en caliente (miles)"
    x-axis ["DeliveryHook", "Traceability (solo emite)", "EligibilityHook", "ExpiryHook", "SeasonalHook", "PerishabilityHook"]
    y-axis "gas adicional (k)" 0 --> 35
    bar [12.3, 17.4, 24.4, 25.2, 27.5, 31.0]

En modo persistente, TraceabilityHook suma 184.5k; no aparece en el gráfico para no distorsionar la escala.

HookGasΔ respecto de sin hook
EligibilityHook91,166+24,376
ExpiryHook92,023+25,233
SeasonalHook94,324+27,534
PerishabilityHook97,813+31,023
DeliveryHook (sin entrega activa)79,076+12,286
TraceabilityHook, solo emite84,152+17,362
TraceabilityHook, persistente251,273+184,483

Qué determina el costo

  • Una transferencia en caliente sin hooks cuesta ~67k: ERC-1155, el seguimiento del suministro total, las lecturas de existencia, estado y congelamiento del lote, y la gestión interna de la cadena de reglas (datos temporales y bloqueo). Ese es el piso.
  • Cada hook suma entre 25k y 30k aproximadamente a una transferencia: una llamada a check (vista, entre contratos) y, en los hooks de habilitación, las llamadas a canSend y canReceive. El costo crece de forma lineal con la cantidad de hooks y con la cantidad de ids de una transferencia múltiple. Consultar con supportsInterface cada capacidad de cada contrato de reglas antes de llamarlo agregaría varias llamadas estáticas por id. Ese sobrecosto no existe, porque los indicadores se guardan en caché al registrar el hook.
  • En createBatch domina el almacenamiento: el struct Batch (seis palabras más un string) y los slots de saldo y de suministro total de ERC-1155. Es un costo único por lote.
  • transform crea ids nuevos: dividir un lote en dos implica pagar dos registros de lote, dos acuñaciones y una quema, más las llamadas a hooks en cada tramo (OP_TRANSFORM). Dividir en n cuesta aproximadamente n × createBatch más una quema; fusionar n en uno cuesta aproximadamente n quemas más un createBatch.
  • Los controles de cumplimiento son baratos: congelar ocupa un solo slot. Una transferencia forzosa cuesta lo mismo que una transferencia, más la escritura que descongela y el evento.
  • transferCheck / canTransfer son vistas: no cuestan nada fuera de la cadena y recorren el mismo código que la transacción.

Qué gana el diseño

Diseño con consulta de capacidadesA-REX Core (ARexToken)
Transferencia con n contratos de reglasids × módulos × (consultas a supportsInterface + llamada al hook) antes de ejecutar cualquier lógicaids × hooks × 1 llamada (+2 en los hooks de habilitación); indicadores en caché desde el registro
Rechazorevert con un string (se copia a memoria, no se puede indexar)error personalizado con la dirección del hook y un código bytes32
Linajeno disponible~280k por lote de salida
Congelar / transferencia forzosano disponible54k / 80k

La columna izquierda describe el diseño que A-REX Core reemplaza (ADR-004, ADR-005). Solo la columna derecha está medida.

Recomendaciones para el despliegue

  • El costo en dinero es gas × gas price × token price, y los dos últimos factores cambian en órdenes de magnitud según la cadena y el día. Solo como ejemplo: a 0.01 gwei y 3,000 USD por ETH, una transferencia en caliente con dos hooks (119,582 gas) cuesta unos 0.0036 USD y un createBatch (264,096 gas), unos 0.008 USD. A 20 gwei en la red principal de Ethereum, las mismas operaciones cuestan unos 7.2 y 15.8 USD. Mide en la cadena de destino antes de definir un modelo de costo unitario.
  • Transferencias múltiples: safeBatchTransferFrom reparte los costos fijos, pero el costo de los hooks sigue creciendo con la cantidad de ids.
  • Orden de los hooks: pon primero los hooks baratos que rechazan con más frecuencia. Un rechazo detiene la cadena de reglas antes de que corran los hooks más caros.
  • Cantidad de hooks: de tres a cinco alcanzan para la mayoría de los emisores. Cada hook adicional es un costo medible en cada transferencia y un elemento más que gobernar.
  • Metadatos: usa un uri corto (un CID o un Digital Link), porque el string se guarda en la cadena.
  • Lecturas fuera de la cadena: llama a transferCheck antes de enviar la transacción. Una transacción revertida también consume gas.

Capacidad de procesamiento

El cuello de botella no es el token, sino la cadena. Una transferencia es una transacción; una transformación con n salidas es una sola transacción con n acuñaciones. Para indexar el linaje basta con leer los eventos BatchTransformed, que se emiten una vez por operación con las listas completas de cantidades. Así, el indexador no tiene que reconstruir nada a partir de los eventos de cada transferencia.

Tamaño de los contratos

ARexToken ocupa 24,136 bytes desplegado (el límite es 24,576), compilado con optimizer.runs = 1. Los demás contratos son pequeños: ARexAttestations ocupa 2,708; los hooks, entre 1,358 (ExpiryHook) y 6,215 (DeliveryHook), con TraceabilityHook en 4,076; las extensiones, entre 3,716 y 4,588. El tamaño limita a propósito lo que se puede agregar al token. Para eso existen los hooks y los contratos complementarios.