Skip to main contentA-REX Foundation

Whitepaper · 08

Estrutura de Segurança

Modelo de ameaças, invariantes, controle de acesso, o limite de confiança dos hooks, gestão das chaves de enforcement, segurança das atualizações e postura de auditoria da implementação de referência do A-REX Core.

A postura de segurança em um parágrafo

O token de referência tem um único ponto de passagem (_update), uma ordem fixa de avaliação, uma trava de reentrância em torno de toda a sequência de hooks, uma autoridade baseada em papéis que nunca deriva de saldos, armazenamento ERC-7201 e uma superfície pequena: oito funções externas que alteram estado, além das do ERC-1155. As capacidades mais poderosas — congelamento, transferência forçada, administração de hooks, atualizações — são papéis separados, destinados a multisigs e timelocks, e todo uso delas é um evento.

Invariantes

InvarianteGarantido porTestado por
totalSupply(id) é igual à soma dos saldos de idERC1155Supply do OpenZeppelin; transform queima e depois cunha por meio de _updatetestes de linhagem (divisão, união, processamento)
status == 255 é terminalsetBatchStatus reverte com ARexInvalidStatusTransitiontestes de status
Um lote baixado não pode ser cunhado nem transferido, apenas queimado_updateteste de lote baixado
amount ≤ balance − frozen para movimentações iniciadas pelo titular_update; forcedTransfer reduz frozen para balance − amounttestes de congelamento/transferência forçada
Nenhum hook pode reentrar em uma função que altera saldostrava de armazenamento definida antes das verificações e liberada depois das notificaçõesteste ReentrantHook
Toda alteração de saldo é avaliada como a sua própria operação, com os seus próprios data_update lê e limpa o contexto da operação antes de qualquer verificação ou chamada externaOpContext.test.js
Os hooks são avaliados na ordem de registro; a remoção preserva a ordemdeslocamento do array em removeHookteste de ordenação
Uma operação rejeitada não altera nenhum saldo e não emite nenhuma transferênciaas verificações são executadas antes de super._updateteste de rejeição (contagem de execuções inalterada)
A autoridade nunca deriva do saldotoda função que altera estado é protegida por papel ou por aprovação do ERC-1155testes "possuir tokens não confere nada"
canTransfer == (transferCheck == 0)canTransfer é definido dessa formatestes de conformidade

Modelo de ameaças

Atores e capacidades

AtorPodeNão pode
Titulartransferir unidades não congeladas a destinatários elegíveis; queimar; reagrupar a mesma commodity/unidade com quantidade conservada para a sua própria conta (to == from)alterar o status, cunhar, processar em outra commodity, reagrupar para outra conta, mover unidades congeladas
Operador aprovadoo mesmo que o titular, em relação à conta que o aprovouqualquer coisa que um titular não possa
ISSUER_ROLEcriar lotesmover tokens de terceiros
TRANSFORMER_ROLEtransformações de processamento, e transformações cujas saídas vão para outra conta, de tokens que detém ou para os quais tem aprovaçãotransformar tokens sem aprovação
STATUS_ROLEalterar o status (inclusive dar baixa), atualizar metadadosmover tokens
ENFORCER_ROLEcongelar qualquer quantidade; forçar qualquer transferênciacontornar os hooks (eles são executados com OP_FORCED_TRANSFER)
HOOK_ADMIN_ROLEadicionar/remover hooksalterar saldos diretamente
PAUSER_ROLEinterromper tudo, exceto as transferências forçadas—
UPGRADER_ROLEsubstituir a implementação— (este é um poder total; ver gestão de chaves)
ATTEST_ADMIN_ROLEdecidir quais emissores são confiáveis para cada tópico de atestação; nas versões de referência até 2.0.0-alpha.5, também revogar qualquer atestação; a partir da 2.0.0-alpha.6, só revoga o emissor ou um revogador que ele tenha delegado (ADR-019, Proposto: uma revogação administrativa NÃO DEVERIA existir na 2.x e NÃO DEVE existir a partir da 3.0)atestar em nome de um emissor
Emissor confiávelatestar lotes para os seus tópicos; revogar as próprias atestações ou delegar a revogaçãoatestar para um tópico em que não é confiável
Contrato de hookrejeitar operações; observá-las; responder sobre elegibilidadereentrar; alterar saldos

Cenários

Hook malicioso ou com defeito (negação de serviço). Um hook que sempre rejeita bloqueia todas as transferências do token; um que reverte em check faz o mesmo. Mitigação: HOOK_ADMIN_ROLE pode remover qualquer hook a qualquer momento (ordem preservada); PAUSER_ROLE pode interromper a operação durante a investigação; as transferências forçadas continuam sendo executadas, de modo que o enforcement não se perde. O registro verifica o suporte a ERC-165 e flags diferentes de zero, e rejeita EOAs. Recomendação: auditar os hooks antes de registrá-los; manter seu número pequeno; colocar a administração atrás de um timelock, para que as mudanças de hooks sejam visíveis antes de entrarem em vigor.

Reentrância de hook. O onExecuted de um hook chama de volta safeTransferFrom. Mitigação: a trava; a chamada reverte com ARexReentrantCall. Observe-se que o callback de recebimento do ERC-1155 (onERC1155Received) é executado depois de a trava ser liberada, como em todo token ERC-1155; o estado do token já é definitivo nesse momento.

Contexto da operação nos callbacks de recebimento. Um contrato destinatário inicia uma transferência ou uma queima de dentro de onERC1155Received. Essa chamada aninhada é um OP_TRANSFER ou um OP_BURN com os seus próprios data, e não parte da operação que entregou os tokens. Até a 2.0.0-alpha.2, o token de referência mantinha a operação externa no armazenamento até o retorno da chamada externa, de modo que uma chamada aninhada após um forcedTransfer era executada como OP_FORCED_TRANSFER (ignorando a pausa, a elegibilidade e os saldos congelados), e uma após uma transform era executada como OP_TRANSFORM, que os hooks que controlam apenas OP_TRANSFER deixam passar. Mitigação: _update lê e limpa o contexto da operação antes de qualquer verificação ou chamada externa, de modo que uma chamada feita a partir de um callback é avaliada como ela mesma; OpContext.test.js usa um destinatário que transfere e queima de dentro do seu callback.

Entrega por reagrupamento. As duas etapas de uma transform executam os hooks com OP_TRANSFORM. Se um titular pudesse reagrupar para outra conta, os bens mudariam de mãos sem as verificações dos hooks que controlam apenas OP_TRANSFER, como uma atestação exigida antes da venda ou unidades travadas para uma entrega. Mitigação: sem TRANSFORMER_ROLE, um reagrupamento só é permitido quando to == from; os bens reagrupados chegam a outro titular por meio de uma transferência comum, que executa todas as regras de transferência (ADR-007, emendado em 2026-10-20).

Escapar de uma trava queimando ou reagrupando. O estado de um hook mantido por id de lote não acompanha o lote nas suas saídas. Um hook que trava unidades e verifica apenas OP_TRANSFER não impede o titular de queimar as unidades travadas, nem de reagrupá-las no lugar em um novo id que a trava não cobre. Mitigação: o DeliveryHook rejeita com IN_TRANSIT qualquer queima ou etapa de entrada de transform que deixaria o saldo abaixo das unidades travadas; as transferências forçadas continuam sem limite, e o hook retorna um código em vez de reverter após uma apreensão. Os hooks que reservam unidades devem verificar OP_BURN e OP_TRANSFORM, além de OP_TRANSFER.

Chave de enforcement comprometida. Quem detém ENFORCER_ROLE pode mover quaisquer tokens. Mitigação: multisig com um procedimento documentado (ordem judicial, contrato de penhor, notificação de sanções); toda ação emite ForcedTransfer/Frozen; os hooks podem exigir uma referência de ordem nos dados da transferência (OP_FORCED_TRANSFER não está isento dos hooks). Pode-se considerar um timelock para o enforcement não urgente.

Atualizador comprometido. Comprometimento total. Mitigação: multisig mais timelock; validações de atualização do OpenZeppelin na CI; armazenamento ERC-7201 para evitar acidentes de layout.

Abuso de status. STATUS_ROLE pode dar baixa em um lote detido por terceiros. Isso é intencional — um armazém, um inspetor ou um regulador declarando um lote impróprio — e deve ser divulgado aos titulares. Mitigação: atribuir a uma instituição responsável; toda mudança é um evento com um motivo.

Fraude do emissor. ISSUER_ROLE pode criar um lote que não existe fisicamente. O token não pode impedir isso; torna o fato atribuível (issuer, originRef, metadataHash) e permite exigir, antes da transferência, atestações de partes independentes (armazém, inspetor, registro) por meio de AttestationHook.

Localização escondida na referência de origem. Um hash, um geohash ou qualquer outra codificação das coordenadas de uma parcela em originRef parece anônimo, mas pode ser recalculado a partir de uma parcela adivinhada, e nunca pode ser apagado do livro-razão. Mitigação: originRef é uma referência a uma evidência ou uma referência aleatória; a geolocalização fica off-chain (para o EUDR, no Sistema de Informação da UE). O rascunho proposto com o ADR-019 (Proposto) torna "nunca derivada da localização" um requisito DEVE; essa já era a decisão do ADR-008.

Referências a montante não verificadas. Um lote feito a partir do lote de outro token o indica na lista upstream dos seus metadados. Isso é uma afirmação do emissor a jusante: ele pode indicar um lote que nunca deteve ou omitir um que deteve. Mitigação: indexadores, auditores e ferramentas de recolhimento confrontam cada referência com o token a montante (o lote existe, o hash dos metadados confere, a transferência ao emissor ocorreu, quando um hash de transação é informado) e exibem como não verificadas as que não conseguiram verificar.

Substituição de metadados. setBatchMetadata altera o hash e a URI. Mitigação: protegida por papel; os eventos BatchMetadataUpdated e URI mantêm o histórico; documentos anteriores continuam verificáveis em relação aos hashes anteriores.

Front-running de transferCheck. Uma verificação prévia pode ficar desatualizada antes de a transação ser executada (o estado de um hook muda). A transação reavalia; o pior caso é uma reversão com um código preciso.

Gas griefing por meio de hooks. Cada hook acrescenta uma chamada externa por id afetado por fase. Um hook com laços ilimitados torna as transferências financeiramente inviáveis. Mitigação: regras de autoria de hooks (check limitado), revisão antes do registro.

Confiança em hooks atualizáveis. Um hook implantado atrás de um proxy pode mudar a política de transferência sem qualquer alteração no token. Mitigação: tratar as chaves de administração dos hooks com o mesmo cuidado dado a HOOK_ADMIN_ROLE; preferir hooks imutáveis em produção.

Modelo de controle de acesso

O AccessControl do OpenZeppelin, com oito papéis no token e um no registro de atestações; DEFAULT_ADMIN_ROLE administra todos eles. Disposição recomendada para produção:

PapelTitular
DEFAULT_ADMIN_ROLE, UPGRADER_ROLE, HOOK_ADMIN_ROLEmultisig de governança atrás de um timelock
ENFORCER_ROLEmultisig de enforcement (conformidade + jurídico)
PAUSER_ROLEchave de resposta a incidentes (rápida)
ISSUER_ROLE, STATUS_ROLE, TRANSFORMER_ROLEserviços operacionais com privilégio mínimo, com rotação
ATTEST_ADMIN_ROLEa governança do token: decide quais emissores são confiáveis por tópico, e não o que eles atestam

initialize concede tudo a um único administrador por conveniência; a lista de verificação de implantação exige a redistribuição antes da produção.

Semântica de enforcement e de pausa

  • A pausa bloqueia cunhagens, transferências, queimas e transformações; não bloqueia as transferências forçadas, de modo que uma ordem legal possa ser executada durante um incidente.
  • As transferências forçadas dispensam canSend/canReceive e a verificação de saldo congelado, reduzem o valor congelado ao que resta e ainda executam os hooks com OP_FORCED_TRANSFER. Os hooks de referência retornam OK para essa operação; um hook que trate de enforcement pode exigir referências de ordem em data.
  • O congelamento pode exceder o saldo (ERC-7943), de modo que um gravame pode cobrir depósitos futuros.

Capacidades no padrão, política em perfis

O ADR-019 (Proposto) traça uma única linha através de todos os recursos de enforcement. O padrão fixa o que existe e o que garante: os papéis, os eventos, o que uma pausa interrompe, os códigos AREX:PAUSED e AREX:SANCTIONED, quem pode revogar uma atestação e as regras de privacidade. Um perfil de política, mantido por jurisdição e por organização e versionado com datas, como uma regulamentação, diz quem pode usar cada capacidade e em que condições:

CapacidadeFixado pelo padrãoDefinido pelo perfil de política
Congelamento e transferência forçadasetFrozenTokens, forcedTransfer, os seus eventos, um papel dedicado separado da administração, hooks executados com OP_FORCED_TRANSFERse o papel pode sequer ser habilitado, quem o detém e com quantos signatários, qual referência legal cada uso deve trazer, quem deve ser notificado
Pausao que uma pausa interrompe, AREX:PAUSED, transferências forçadas ainda permitidasquem pode pausar e retomar, a confirmação e o motivo exigidos, quem é informado
SançõesAREX:SANCTIONED e o significado de canSend / canReceivequais listas oficiais se aplicam (ONU, OFAC, UE, OFSI ou uma combinação), como são mantidas atualizadas e que uma pessoa confirme uma correspondência antes de uma conta ser marcada
Revogação de atestaçõeso emissor revoga, um revogador que ele tenha delegado pode revogar; um papel administrativo não deveria na 2.x e não deve a partir da 3.0; atestar de novo nunca substitui o registro de outro emissor nem reativa um registro revogadoem quais emissores um token confia por tópico; como um operador registra uma contestação
Privacidade da origemoriginRef não contém coordenadas nem identificadores pessoais e não é derivado da localizaçãoqual referência um emissor usa e onde a geolocalização é mantida off-chain

Uma mudança na lei passa então a ser uma atualização do perfil, nunca um novo contrato nem uma nova versão do padrão.

Segurança das atualizações

  • UUPS; _authorizeUpgrade protegido por UPGRADER_ROLE.
  • Estrutura de armazenamento com namespace ERC-7201; somente acréscimos.
  • As validações do plugin de atualizações do OpenZeppelin são executadas nos testes e deveriam ser executadas na CI antes de qualquer transação de atualização.
  • A configuração optimizer.runs = 1 por arquivo mantém a implementação abaixo do EIP-170; uma alteração que a ultrapasse falha em tempo de compilação, com um aviso, e na implantação, com um revert.

Segurança de dependências e de build

  • OpenZeppelin Contracts e Contracts-Upgradeable fixados na versão 5.3.0; lockfile versionado; a CI usa npm ci.
  • Solidity 0.8.22, viaIR, EVM paris (sem dependência de armazenamento transitório, implantável em redes que não adotaram o Cancun).
  • Nenhuma biblioteca externa vinculada; nenhum delegatecall fora do proxy UUPS.

Postura de auditoria

  • 46 testes sobre a implementação de referência, os hooks e as extensões cobrem todas as invariantes acima, inclusive uma execução de invariantes randomizada com semente.
  • O gás e o tamanho são medidos por scripts do repositório.
  • Uma auditoria de terceiros de ARexToken, ARexAttestations e dos hooks de referência é uma pré-condição declarada para uma âncora de produção e para a submissão do ERC (ver Desenvolvimentos Futuros).
  • A verificação formal das invariantes do pipeline está no roteiro; as invariantes são pequenas o bastante para serem enunciadas como propriedades.

Avisos de segurança

AvisoAfetaCorrigido emProblemas
AREX-2026-001implementação de referência até a 2.0.0-alpha.2, inclusive2.0.0-alpha.3o contexto da operação vazava para os callbacks de recebimento do ERC-1155; o reagrupamento sem papel podia entregar bens a outro titular passando ao largo dos hooks de OP_TRANSFER; as travas do DeliveryHook podiam ser contornadas queimando ou reagrupando

A 2.0.0-alpha.3 substitui a 2.0.0-alpha.2. Os proxies de token implantados são atualizados para a nova implementação por meio de UPGRADER_ROLE; o layout de armazenamento não muda. O DeliveryHook não é atualizável: implante a nova versão, registre-a com registerHook, remova a antiga com removeHook e reagende as entregas ativas, porque as suas travas ficam no armazenamento do hook antigo. As integrações que dividem ou unem diretamente na conta de um comprador devem reagrupar no lugar e depois transferir, ou usar uma conta com TRANSFORMER_ROLE. As interfaces do padrão não mudam.

Riscos residuais que o padrão não elimina

  • A existência física e a qualidade de um lote são atestadas, e não comprovadas; o token torna as afirmações atribuíveis, e não verdadeiras.
  • A disponibilidade dos metadados off-chain depende do armazenamento escolhido; o hash garante a integridade, e não a disponibilidade.
  • A governança de hooks e módulos é tão boa quanto as chaves que a controlam.