Whitepaper · 08
Marco de seguridad
Modelo de amenazas, invariantes, control de acceso, límite de confianza de los hooks, gestión de claves de ejecución forzosa, seguridad de las actualizaciones y postura de auditoría de la implementación de referencia de A-REX Core.
Postura de seguridad en un párrafo
El token de referencia tiene un único punto de paso obligado (_update), un orden de evaluación fijo, un bloqueo de reentrada alrededor de toda la secuencia de hooks, una autoridad basada en roles que nunca se deriva de los saldos, almacenamiento ERC-7201 y una superficie reducida: ocho funciones externas que modifican el estado además de las de ERC-1155. Las capacidades más poderosas (congelación, transferencia forzosa, administración de hooks, actualizaciones) son roles independientes destinados a multifirmas y timelocks, y cada uso de ellas es un evento.
Invariantes
| Invariante | Se garantiza mediante | Se prueba con |
|---|---|---|
totalSupply(id) es igual a la suma de los saldos de id | OpenZeppelin ERC1155Supply; transform quema y luego acuña a través de _update | pruebas de linaje (división, fusión, procesamiento) |
status == 255 es terminal | setBatchStatus revierte con ARexInvalidStatusTransition | pruebas de estado |
| Un lote retirado no puede acuñarse ni transferirse, solo quemarse | _update | prueba de lote retirado |
amount ≤ balance − frozen en los movimientos iniciados por el titular | _update; forcedTransfer reduce frozen a balance − amount | pruebas de congelación/forzosas |
| Ningún hook puede reentrar en una función que modifique saldos | bloqueo en el almacenamiento activado antes de las comprobaciones y liberado después de las notificaciones | prueba de ReentrantHook |
| Los hooks se evalúan en orden de registro; la eliminación conserva el orden | desplazamiento del array en removeHook | prueba de orden |
| Una operación rechazada no modifica ningún saldo ni emite ninguna transferencia | las comprobaciones se ejecutan antes de super._update | prueba de rechazo (el recuento de ejecuciones no cambia) |
| La autoridad nunca se deriva del saldo | toda función que modifica el estado está restringida por rol o por aprobación de ERC-1155 | pruebas de «poseer tokens no otorga nada» |
canTransfer == (transferCheck == 0) | canTransfer se define así | pruebas de conformidad |
Modelo de amenazas
Actores y capacidades
| Actor | Puede | No puede |
|---|---|---|
| Titular | transferir unidades no congeladas a destinatarios elegibles; quemar; reagrupar el mismo producto básico/unidad con la cantidad conservada | cambiar el estado, acuñar, procesar para obtener otro producto básico, mover unidades congeladas |
| Operador aprobado | lo mismo que el titular, respecto de la cuenta que lo aprueba | cualquier cosa que un titular no pueda |
ISSUER_ROLE | crear lotes | mover tokens de terceros |
TRANSFORMER_ROLE | transformaciones de procesamiento de los tokens que posee o para los que está aprobado | transformar tokens sin aprobación |
STATUS_ROLE | cambiar el estado (incluido retirar), actualizar los metadatos | mover tokens |
ENFORCER_ROLE | congelar cualquier cantidad; forzar cualquier transferencia | eludir los hooks (se ejecutan con OP_FORCED_TRANSFER) |
HOOK_ADMIN_ROLE | añadir/eliminar hooks | modificar saldos directamente |
PAUSER_ROLE | detener todo salvo las transferencias forzosas | — |
UPGRADER_ROLE | sustituir la implementación | — (es un poder total; véase la gestión de claves) |
| Contrato de hook | rechazar operaciones; observarlas; responder sobre la elegibilidad | reentrar; modificar saldos |
Escenarios
Hook malicioso o defectuoso (denegación de servicio). Un hook que rechaza siempre bloquea todas las transferencias del token; uno que revierte en check hace lo mismo. Mitigación: HOOK_ADMIN_ROLE puede eliminar cualquier hook en cualquier momento (se conserva el orden); PAUSER_ROLE puede detener la operación mientras se investiga; las transferencias forzosas siguen ejecutándose, de modo que no se pierde la ejecución forzosa. El registro verifica la compatibilidad con ERC-165 y los indicadores distintos de cero, y rechaza las EOA. Recomendación: auditar los hooks antes de registrarlos; mantener reducido su número; colocar al administrador detrás de un timelock para que los cambios de hooks sean visibles antes de que surtan efecto.
Reentrada de un hook. El onExecuted de un hook vuelve a llamar a safeTransferFrom. Mitigación: el bloqueo; la llamada revierte con ARexReentrantCall. Cabe señalar que el callback del receptor de ERC-1155 (onERC1155Received) se ejecuta después de liberarse el bloqueo, como en todo token ERC-1155; para entonces el estado del token ya es definitivo.
Clave de ejecución forzosa comprometida. Quien posee ENFORCER_ROLE puede mover cualquier token. Mitigación: multifirma con un procedimiento documentado (orden judicial, contrato de prenda, notificación de sanciones); cada acción emite ForcedTransfer/Frozen; los hooks pueden exigir una referencia de orden en los datos de la transferencia (OP_FORCED_TRANSFER no está exento de los hooks). Considérese un timelock para la ejecución forzosa no urgente.
Clave de actualización comprometida. Compromiso total. Mitigación: multifirma más timelock; validaciones de actualización de OpenZeppelin en CI; almacenamiento ERC-7201 para evitar accidentes de disposición.
Abuso del estado. STATUS_ROLE puede retirar un lote en poder de terceros. Es intencional (un almacén, un inspector o un regulador que declara un lote no apto) y debe comunicarse a los titulares. Mitigación: asignarlo a una institución responsable; cada cambio es un evento con un motivo.
Fraude del emisor. ISSUER_ROLE puede crear un lote que no existe físicamente. El token no puede impedirlo; lo hace atribuible (issuer, originRef, metadataHash) y permite exigir, antes de la transferencia, atestaciones de partes independientes (almacén, inspector, registro) mediante AttestationHook.
Sustitución de metadatos. setBatchMetadata cambia el hash y la URI. Mitigación: restringido por rol; los eventos BatchMetadataUpdated y URI conservan el historial; los documentos anteriores siguen siendo verificables con los hashes anteriores.
Front-running de transferCheck. Una comprobación previa puede quedar obsoleta antes de que se ejecute la transacción (cambia el estado de un hook). La transacción vuelve a evaluar; el peor caso es una reversión con un código preciso.
Gas griefing a través de hooks. Cada hook añade una llamada externa por cada id afectado y por cada fase. Un hook con bucles no acotados hace que las transferencias resulten inasumibles. Mitigación: reglas de autoría de hooks (check acotado), revisión antes del registro.
Confianza en hooks actualizables. Un hook desplegado detrás de un proxy puede cambiar la política de transferencia sin ningún cambio en el token. Mitigación: tratar las claves de administración de los hooks con el mismo cuidado que HOOK_ADMIN_ROLE; preferir hooks inmutables en producción.
Modelo de control de acceso
AccessControl de OpenZeppelin con ocho roles en el token y uno en el registro de atestaciones; DEFAULT_ADMIN_ROLE los administra todos. Disposición recomendada para producción:
| Rol | Titular |
|---|---|
DEFAULT_ADMIN_ROLE, UPGRADER_ROLE, HOOK_ADMIN_ROLE | multifirma de gobernanza detrás de un timelock |
ENFORCER_ROLE | multifirma de ejecución forzosa (cumplimiento + jurídico) |
PAUSER_ROLE | clave de respuesta a incidentes (rápida) |
ISSUER_ROLE, STATUS_ROLE, TRANSFORMER_ROLE | servicios operativos con privilegios mínimos, con rotación |
ATTEST_ADMIN_ROLE | autoridad de certificación o plataforma |
initialize concede todo a un único administrador por comodidad; la lista de verificación de despliegue exige redistribuirlo antes de producción.
Semántica de la ejecución forzosa y de la pausa
- La pausa bloquea las acuñaciones, las transferencias, las quemas y las transformaciones; no bloquea las transferencias forzosas, de modo que una orden legal puede ejecutarse durante un incidente.
- Las transferencias forzosas omiten
canSend/canReceivey la comprobación del saldo congelado, reducen la cantidad congelada a lo que queda y siguen ejecutando los hooks conOP_FORCED_TRANSFER. Los hooks de referencia devuelvenOKpara esa operación; un hook que gobierne la ejecución forzosa puede exigir referencias de orden endata. - La congelación puede superar el saldo (ERC-7943), de modo que un gravamen puede cubrir depósitos futuros.
Seguridad de las actualizaciones
- UUPS;
_authorizeUpgraderestringido porUPGRADER_ROLE. - Estructura de almacenamiento con espacio de nombres ERC-7201; solo se añaden campos al final.
- Las validaciones del plugin de actualizaciones de OpenZeppelin se ejecutan en las pruebas y deberían ejecutarse en CI antes de cualquier transacción de actualización.
- El ajuste
optimizer.runs = 1por archivo mantiene la implementación por debajo de EIP-170; un cambio que la supere falla en tiempo de compilación con una advertencia y en el despliegue con una reversión.
Seguridad de las dependencias y de la compilación
- OpenZeppelin Contracts y Contracts-Upgradeable fijados en 5.3.0; lockfile incluido en el repositorio; CI usa
npm ci. - Solidity 0.8.22, viaIR, EVM
paris(sin dependencia del almacenamiento transitorio, desplegable en cadenas que no han adoptado Cancun). - Sin bibliotecas externas enlazadas; sin delegatecall fuera del proxy UUPS.
Postura de 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.
- El gas y el tamaño se miden mediante scripts del repositorio.
- Una auditoría de terceros de
ARexToken,ARexAttestationsy los hooks de referencia es una condición previa declarada para un despliegue ancla en producción y para presentar el ERC (véase Desarrollos futuros). - La verificación formal de las invariantes de la canalización figura en la hoja de ruta; las invariantes son lo bastante pequeñas como para enunciarse como propiedades.
Riesgos residuales que el estándar no elimina
- La existencia física y la calidad de un lote se atestan, no se prueban; el token hace que las afirmaciones sean atribuibles, no verdaderas.
- La disponibilidad de los metadatos fuera de la cadena depende del almacenamiento elegido; el hash garantiza la integridad, no la disponibilidad.
- La gobernanza de los hooks y los módulos es tan buena como las claves que la controlan.