Skip to main contentA-REX Foundation

Whitepaper · 08

Marco de seguridad

Modelo de amenazas, invariantes, control de acceso, frontera de confianza de los hooks, gestión de las claves de cumplimiento, actualizaciones seguras y estado de auditoría de la implementación de referencia de A-REX Core.

La seguridad en un párrafo

Todo cambio de saldo del token de referencia pasa por un único punto (_update). El orden de evaluación es fijo y un bloqueo antirreentrada cubre toda la secuencia de reglas externas (hooks). La autoridad depende de roles y nunca de los saldos, el almacenamiento sigue ERC-7201 y la superficie es pequeña: ocho funciones externas que modifican el estado, además de las de ERC-1155. Las capacidades más sensibles (congelar, transferencia forzosa, administrar hooks, actualizar) son roles separados, pensados para multifirmas y timelocks, y cada uso genera un evento.

Invariantes

InvarianteQuién la garantizaCómo se prueba
totalSupply(id) es igual a la suma de los saldos de idERC1155Supply de OpenZeppelin; transform quema y luego acuña a través de _updatepruebas de linaje (dividir, fusionar, procesar)
status == 255 es un estado finalsetBatchStatus revierte con ARexInvalidStatusTransitionpruebas de estado
Un lote retirado no se puede acuñar ni transferir, solo quemar_updateprueba de lote retirado
amount ≤ balance − frozen cuando el movimiento lo inicia el titular_update; forcedTransfer baja frozen a balance − amountpruebas de congelamiento y de transferencia forzosa
Ningún hook puede volver a entrar en una función que modifica saldosun bloqueo en el almacenamiento se activa antes de las verificaciones y se libera después de las notificacionesprueba con ReentrantHook
Cada cambio de saldo se evalúa como su propia operación, con sus propios data_update lee y borra el contexto de la operación antes de cualquier verificación o llamada externaOpContext.test.js
Los hooks se evalúan en el orden en que se registraron; quitar uno no altera el ordendesplazamiento del arreglo en removeHookprueba de orden
Una operación rechazada no cambia ningún saldo ni emite transferenciaslas verificaciones corren antes de super._updateprueba de rechazo (el contador de ejecuciones no cambia)
Tener saldo nunca da autoridadcada función que modifica el estado exige un rol o una aprobación de ERC-1155pruebas de «tener tokens no habilita nada»
canTransfer == (transferCheck == 0)canTransfer se define exactamente asípruebas de conformidad

Modelo de amenazas

Actores y capacidades

ActorPuedeNo puede
Titulartransferir unidades no congeladas a cuentas habilitadas; quemar; reagrupar en lotes del mismo producto y unidad sin alterar la cantidad total, en su propia cuenta (to == from)cambiar el estado, acuñar, procesar hacia otro producto, reagrupar en otra cuenta, mover unidades congeladas
Operador aprobadolo mismo que el titular, sobre la cuenta que lo aprobónada que el titular no pueda hacer
ISSUER_ROLEcrear lotesmover tokens de otras cuentas
TRANSFORMER_ROLEprocesar tokens que tiene o para los que tiene aprobación, y transformarlos con salidas hacia otra cuentatransformar tokens sin aprobación
STATUS_ROLEcambiar el estado (incluido retirar el lote) y actualizar los metadatosmover tokens
ENFORCER_ROLEcongelar cualquier cantidad; forzar cualquier transferenciasaltarse los hooks (se ejecutan con OP_FORCED_TRANSFER)
HOOK_ADMIN_ROLEagregar y quitar hookscambiar saldos directamente
PAUSER_ROLEdetener todo, salvo las transferencias forzosas—
UPGRADER_ROLEreemplazar la implementación— (es control total; consulta la gestión de claves)
ATTEST_ADMIN_ROLEdecidir qué emisores son de confianza para cada tema de atestación; en las versiones de referencia hasta 2.0.0-alpha.5, también revocar cualquier atestación; a partir de 2.0.0-alpha.6 solo revoca el emisor o un revocador en quien delegó (ADR-019, Propuesto: una revocación administrativa NO DEBERÍA existir en 2.x y NO DEBE existir a partir de 3.0)atestar en nombre de un emisor
Emisor de confianzaatestar lotes en sus temas; revocar sus propias atestaciones o delegar la revocaciónatestar en un tema para el que no es de confianza
Contrato de hookrechazar operaciones; observarlas; responder si una cuenta está habilitadavolver a entrar; cambiar saldos

Escenarios

Hook malicioso o con errores (denegación de servicio). Un hook que siempre rechaza bloquea todas las transferencias del token, y uno que revierte en check tiene el mismo efecto. Mitigación: HOOK_ADMIN_ROLE puede quitar cualquier hook en cualquier momento sin alterar el orden de los demás. PAUSER_ROLE puede detener el token mientras se investiga. Las transferencias forzosas siguen funcionando, así que no se pierden los controles de cumplimiento. Al registrar un hook, el token verifica que soporte ERC-165 y que sus flags no sean cero, y rechaza las EOA. Recomendación: audita los hooks antes de registrarlos, mantén pocos y pon al administrador detrás de un timelock para que cualquier cambio sea visible antes de entrar en vigor.

Reentrada desde un hook. El onExecuted de un hook vuelve a llamar a safeTransferFrom. Mitigación: el bloqueo hace que la llamada revierta con ARexReentrantCall. Ten en cuenta que el callback de recepción de ERC-1155 (onERC1155Received) corre después de liberar el bloqueo, como en cualquier token ERC-1155. Para ese momento, el estado del token ya es definitivo.

Contexto de la operación en los callbacks de recepción. Un contrato destinatario inicia una transferencia o una quema desde dentro de onERC1155Received. Esa llamada anidada es un OP_TRANSFER o un OP_BURN con sus propios data, no forma parte de la operación que entregó los tokens. Hasta 2.0.0-alpha.2, el token de referencia guardaba la operación exterior en el almacenamiento hasta que terminaba la llamada exterior, así que una llamada anidada tras un forcedTransfer se ejecutaba como OP_FORCED_TRANSFER (saltándose la pausa, la habilitación y los saldos congelados), y una tras un transform se ejecutaba como OP_TRANSFORM, que dejan pasar los hooks que solo controlan OP_TRANSFER. Mitigación: _update lee y borra el contexto de la operación antes de cualquier verificación o llamada externa, de modo que una llamada hecha desde un callback se evalúa como lo que es; OpContext.test.js usa un destinatario que transfiere y quema desde dentro de su callback.

Entrega mediante reagrupación. Los dos tramos de un transform ejecutan los hooks con OP_TRANSFORM. Si un titular pudiera reagrupar en otra cuenta, los bienes cambiarían de manos sin las verificaciones de los hooks que solo controlan OP_TRANSFER, como una atestación exigida antes de la venta o unidades bloqueadas para una entrega. Mitigación: sin TRANSFORMER_ROLE, la reagrupación solo se permite cuando to == from; los bienes reagrupados llegan a otro titular mediante una transferencia ordinaria que aplica todas las reglas de transferencia (ADR-007, enmendado el 2026-10-20).

Eludir un bloqueo quemando o reagrupando. El estado que un hook guarda por id de lote no sigue al lote en sus salidas. Un hook que bloquea unidades y solo verifica OP_TRANSFER no impide que el titular queme las unidades bloqueadas, ni que las reagrupe en su propia cuenta en un id nuevo que el bloqueo no cubre. Mitigación: DeliveryHook rechaza con IN_TRANSIT cualquier quema o tramo de entrada de un transform que deje el saldo por debajo de las unidades bloqueadas; las transferencias forzosas siguen sin límite, y el hook devuelve un código en lugar de revertir después de un embargo. Los hooks que reservan unidades deberían verificar OP_BURN y OP_TRANSFORM además de OP_TRANSFER.

Clave de cumplimiento comprometida. Quien tenga ENFORCER_ROLE puede mover cualquier token. Mitigación: una multifirma con un procedimiento documentado (orden judicial, contrato de prenda, aviso de sanciones). Cada acción emite ForcedTransfer o Frozen, y los hooks pueden exigir una referencia a la orden en los datos de la transferencia, porque OP_FORCED_TRANSFER no está exenta de hooks. Para medidas de cumplimiento que no sean urgentes, considera un timelock.

Clave de actualización comprometida. El control es total. Mitigación: multifirma con timelock, validaciones de actualización de OpenZeppelin en CI y almacenamiento ERC-7201 para evitar errores de layout.

Abuso del estado. STATUS_ROLE puede retirar un lote que está en manos de otros. Es intencional: un almacén, un inspector o un regulador puede declarar que un lote no es apto. Los titulares deben saberlo. Mitigación: asigna este rol a una institución que rinda cuentas; cada cambio queda como evento con su motivo.

Fraude del emisor. ISSUER_ROLE puede crear un lote que no existe físicamente. El token no lo puede impedir, pero sí deja claro quién lo hizo (issuer, originRef, metadataHash). Además, con AttestationHook puedes exigir atestaciones (certificados o constancias verificables) de terceros independientes, como un almacén, un inspector o un registro, antes de cualquier transferencia.

Ubicación oculta en la referencia de origen. Un hash, un geohash o cualquier otra codificación de las coordenadas de una parcela en originRef parece anónimo, pero se puede recalcular a partir de una parcela adivinada y nunca se puede borrar del registro. Mitigación: originRef es una referencia a una evidencia o una referencia aleatoria; la geolocalización queda fuera de la cadena (para el EUDR, en el Sistema de Información de la UE). El borrador propuesto con ADR-019 (Propuesto) convierte «nunca derivada de la ubicación» en un requisito obligatorio (MUST); ya era la decisión de ADR-008.

Referencias a lotes de otros tokens sin verificar. Un lote hecho a partir del lote de otro token lo nombra en la lista upstream de sus metadatos. Eso es una afirmación del emisor del lote posterior: puede nombrar un lote que nunca tuvo u omitir uno que sí tuvo. Mitigación: indexadores, auditores y herramientas de retiro del mercado contrastan cada referencia con el token de origen (que el lote exista, que el hash de metadatos coincida y, cuando se indica un hash de transacción, que la transferencia al emisor haya ocurrido) y muestran como no verificadas las que no pudieron comprobar.

Sustitución de metadatos. setBatchMetadata cambia el hash y la URI. Mitigación: la función exige un rol, y los eventos BatchMetadataUpdated y URI conservan el historial. Los documentos anteriores se pueden seguir verificando contra los hashes anteriores.

Front-running de transferCheck. Una verificación previa puede quedar desactualizada antes de que se ejecute la transacción, por ejemplo si cambia el estado de un hook. La transacción vuelve a evaluar todo; en el peor caso, revierte con un código preciso.

Gas griefing mediante hooks. Cada hook agrega una llamada externa por cada id afectado y por cada fase. Un hook con bucles sin límite puede encarecer tanto las transferencias que nadie pueda pagarlas. Mitigación: reglas para escribir hooks (check con costo acotado) y revisión antes de registrarlos.

Confianza en hooks actualizables. Un hook desplegado detrás de un proxy puede cambiar la política de transferencias sin que cambie nada en el token. Mitigación: protege las claves de administración de los hooks con el mismo cuidado que HOOK_ADMIN_ROLE y, en producción, prefiere hooks inmutables.

Modelo de control de acceso

El token usa AccessControl de OpenZeppelin con ocho roles, y el registro de atestaciones tiene uno más. DEFAULT_ADMIN_ROLE administra todos. Esta es la distribución recomendada para producción:

RolQuién lo tiene
DEFAULT_ADMIN_ROLE, UPGRADER_ROLE, HOOK_ADMIN_ROLEmultifirma de gobernanza detrás de un timelock
ENFORCER_ROLEmultifirma de cumplimiento (áreas de cumplimiento y legal)
PAUSER_ROLEclave de respuesta a incidentes (de acción rápida)
ISSUER_ROLE, STATUS_ROLE, TRANSFORMER_ROLEservicios operativos con privilegios mínimos y claves rotadas
ATTEST_ADMIN_ROLEla gobernanza del token: decide qué emisores son de confianza por tema, no qué atestan

Por comodidad, initialize otorga todos los roles a un solo administrador. La checklist de despliegue exige redistribuirlos antes de pasar a producción.

Controles de cumplimiento y pausa

  • La pausa bloquea acuñaciones, transferencias, quemas y transformaciones. No bloquea las transferencias forzosas, de modo que una orden legal se puede ejecutar aunque haya un incidente en curso.
  • Las transferencias forzosas omiten canSend/canReceive y la verificación del saldo congelado, y bajan el monto congelado a lo que queda. Aun así, ejecutan los hooks con OP_FORCED_TRANSFER. Los hooks de referencia devuelven OK para esa operación; un hook que regule los controles de cumplimiento puede exigir referencias a la orden en data.
  • El monto congelado puede superar el saldo (ERC-7943), así que un gravamen puede cubrir depósitos futuros.

Capacidades en el estándar, políticas en perfiles

ADR-019 (Propuesto) traza una misma línea a través de todas las funciones de cumplimiento. El estándar fija qué existe y qué garantiza: los roles, los eventos, qué detiene una pausa, los códigos AREX:PAUSED y AREX:SANCTIONED, quién puede revocar una atestación y las reglas de privacidad. Un perfil de políticas, definido por jurisdicción y por organización y versionado con fechas como una norma, indica quién puede usar cada capacidad y en qué condiciones:

CapacidadLo fija el estándarLo fija el perfil de políticas
Congelamiento y transferencia forzosasetFrozenTokens, forcedTransfer, sus eventos, un rol dedicado separado de la administración, hooks ejecutados con OP_FORCED_TRANSFERsi el rol se puede habilitar, quién lo tiene y con cuántos firmantes, qué referencia legal debe llevar cada uso, a quién se notifica
Pausaqué detiene una pausa, AREX:PAUSED, las transferencias forzosas siguen permitidasquién puede pausar y reanudar, qué confirmación y qué motivo se exigen, a quién se avisa
SancionesAREX:SANCTIONED y el significado de canSend / canReceivequé listas oficiales se aplican (ONU, OFAC, UE, OFSI o una combinación), cómo se mantienen al día y que una persona confirme una coincidencia antes de marcar una cuenta
Revocación de atestacionesel emisor revoca, un revocador en quien delegó puede hacerlo; un rol administrativo no debería hacerlo en 2.x y no debe hacerlo a partir de 3.0; volver a atestar nunca reemplaza el registro de otro emisor ni reactiva uno revocadoen qué emisores confía un token para cada tema; cómo registra un operador una disputa
Privacidad del origenoriginRef no contiene coordenadas ni identificadores personales y no se deriva de la ubicaciónqué referencia usa un emisor y dónde se guarda la geolocalización fuera de la cadena

Así, un cambio de ley se convierte en una actualización del perfil, nunca en un contrato nuevo ni en una versión nueva del estándar.

Actualizaciones seguras

  • UUPS; _authorizeUpgrade exige UPGRADER_ROLE.
  • Struct de almacenamiento con espacio de nombres ERC-7201; los campos nuevos solo se agregan al final.
  • Las validaciones del plugin de actualizaciones de OpenZeppelin corren en las pruebas y deben correr en CI antes de cualquier transacción de actualización.
  • El ajuste optimizer.runs = 1 por archivo mantiene la implementación dentro del límite de EIP-170. Si un cambio lo supera, la compilación emite una advertencia y el despliegue revierte.

Seguridad de dependencias y compilación

  • OpenZeppelin Contracts y Contracts-Upgradeable fijados en la versión 5.3.0; el lockfile está en el repositorio y CI usa npm ci.
  • Solidity 0.8.22, viaIR, EVM paris: no depende del almacenamiento transitorio y se puede desplegar en cadenas que aún no adoptaron Cancun.
  • No hay bibliotecas externas enlazadas ni delegatecall fuera del proxy UUPS.

Estado de la auditoría

  • 46 pruebas sobre la implementación de referencia, los hooks y las extensiones cubren todas las invariantes anteriores, incluida una ejecución aleatoria de invariantes con semilla fija.
  • Scripts del repositorio miden el gas y el tamaño de los contratos.
  • Una auditoría externa de ARexToken, ARexAttestations y los hooks de referencia es requisito declarado para un despliegue ancla en producción y para presentar el ERC (consulta Desarrollos futuros).
  • La verificación formal de las invariantes de la cadena de reglas está en la hoja de ruta. Las invariantes son lo bastante acotadas como para expresarlas como propiedades.

Avisos de seguridad

AvisoAfecta aCorregido enProblemas
AREX-2026-001implementación de referencia hasta 2.0.0-alpha.2 inclusive2.0.0-alpha.3el contexto de la operación se filtraba a los callbacks de recepción de ERC-1155; la reagrupación sin rol podía entregar bienes a otro titular eludiendo los hooks de OP_TRANSFER; los bloqueos de DeliveryHook se podían eludir quemando o reagrupando

2.0.0-alpha.3 sustituye a 2.0.0-alpha.2. Los proxies del token ya desplegados se actualizan a la nueva implementación mediante UPGRADER_ROLE; la disposición del almacenamiento no cambia. DeliveryHook no es actualizable: despliega la nueva versión, regístrala con registerHook, elimina la anterior con removeHook y vuelve a programar las entregas activas, porque sus bloqueos viven en el almacenamiento del hook anterior. Las integraciones que dividen o fusionan directamente en la cuenta de un comprador deben reagrupar en la propia cuenta y después transferir, o usar una cuenta con TRANSFORMER_ROLE. Las interfaces del estándar no cambian.

Riesgos residuales que el estándar no elimina

  • La existencia física y la calidad de un lote se atestan, no se demuestran. El token hace que cada afirmación tenga un responsable, no que sea verdadera.
  • La disponibilidad de los metadatos fuera de la cadena depende del almacenamiento elegido. El hash garantiza la integridad, no la disponibilidad.
  • La gobernanza de hooks y módulos es tan sólida como las claves que la controlan.