Skip to main contentA-REX Core

白皮书 · 16

附录

权威来源:contracts/standard/ .sol(CC0)和 standard/AREX CORE.md。接口 id 可由 npm run interface ids 重现。

附录 A:接口参考

权威来源:contracts/standard/*.sol(CC0)和 standard/AREX-CORE.md。接口 id 可由 npm run interface-ids 重现。

A.1 一致性概览

接口ERC-165 id代币钩子
IERC11550xd9b67a26必须—
IERC7943MultiToken0x41c4fbad必须—
IARexBatch0xe22639e0必须—
IARexHookManager0x964f4861必须(getHooks)—
IARexAttest0xad603a6c应当(代币或配套合约)—
IARexHook0x332afcbb—必须

A.2 IARexBatch

struct BatchInit { bytes32 commodity; bytes32 unit; uint64 producedAt; uint64 expiresAt; bytes32 originRef; bytes32 metadataHash; string uri; }
struct Batch { address issuer; uint64 createdAt; uint8 status; bytes32 commodity; bytes32 unit; uint64 producedAt; uint64 expiresAt; bytes32 originRef; bytes32 metadataHash; string uri; }


event BatchCreated(uint256 indexed id, address indexed issuer, bytes32 indexed commodity, bytes32 unit, uint256 quantity, address to);
event BatchStatusChanged(uint256 indexed id, uint8 previousStatus, uint8 newStatus, bytes32 reason);
event BatchMetadataUpdated(uint256 indexed id, bytes32 metadataHash, string uri);
event BatchTransformed(address indexed operator, uint256[] inputIds, uint256[] inputAmounts, uint256[] outputIds, uint256[] outputAmounts, bytes32 processRef);


error ARexBatchNotFound(uint256 id);
error ARexBatchRetired(uint256 id);
error ARexInvalidBatch(bytes32 reason);
error ARexInvalidStatusTransition(uint256 id, uint8 from, uint8 to);
error ARexLengthMismatch();


function createBatch(BatchInit calldata init, uint256 quantity, address to, bytes calldata data) external returns (uint256 id);
function batchOf(uint256 id) external view returns (Batch memory);
function batchExists(uint256 id) external view returns (bool);
function totalSupply(uint256 id) external view returns (uint256);
function setBatchStatus(uint256 id, uint8 status, bytes32 reason) external;
function setBatchMetadata(uint256 id, bytes32 metadataHash, string calldata uri) external;
function transform(address from, address to, uint256[] calldata inputIds, uint256[] calldata inputAmounts, BatchInit[] calldata outputs, uint256[] calldata outputAmounts, bytes32 processRef) external returns (uint256[] memory outputIds);
function parentsOf(uint256 id) external view returns (uint256[] memory);

A.3 IERC7943MultiToken(ERC-7943,原样)

event ForcedTransfer(address indexed from, address indexed to, uint256 indexed tokenId, uint256 amount);
event Frozen(address indexed account, uint256 indexed tokenId, uint256 amount);
error ERC7943CannotSend(address account);
error ERC7943CannotReceive(address account);
error ERC7943CannotTransfer(address from, address to, uint256 tokenId, uint256 amount);
error ERC7943InsufficientUnfrozenBalance(address account, uint256 tokenId, uint256 amount, uint256 unfrozen);
function forcedTransfer(address from, address to, uint256 tokenId, uint256 amount) external returns (bool result);
function setFrozenTokens(address account, uint256 tokenId, uint256 amount) external returns (bool result);
function canSend(address account) external view returns (bool allowed);
function canReceive(address account) external view returns (bool allowed);
function getFrozenTokens(address account, uint256 tokenId) external view returns (uint256 amount);
function canTransfer(address from, address to, uint256 tokenId, uint256 amount) external view returns (bool allowed);

A.4 IARexHook 与 IARexHookManager

interface IARexHook is IERC165 {
    error ARexHookRejected(address hook, bytes32 code);
    function hookFlags() external view returns (uint8);
    function check(uint8 op, address operator, address from, address to, uint256 id, uint256 amount, bytes calldata data) external view returns (bytes32 code);
    function onExecuted(uint8 op, address operator, address from, address to, uint256 id, uint256 amount, bytes calldata data) external;
    function canSend(address account) external view returns (bool);
    function canReceive(address account) external view returns (bool);
}
interface IARexHookManager {
    event HookRegistered(address indexed hook, uint8 flags, uint256 position);
    event HookRemoved(address indexed hook);
    error ARexHookAlreadyRegistered(address hook);
    error ARexHookNotRegistered(address hook);
    error ARexInvalidHook(address hook);
    function getHooks() external view returns (address[] memory);
    function hookFlagsOf(address hook) external view returns (uint8);
    function registerHook(address hook) external;
    function removeHook(address hook) external;
}

A.5 IARexAttest

struct Attestation { address issuer; bytes32 ref; uint64 issuedAt; uint64 expiresAt; bool revoked; }
event Attested(uint256 indexed id, bytes32 indexed topic, address indexed issuer, bytes32 ref, uint64 expiresAt);
event AttestationRevoked(uint256 indexed id, bytes32 indexed topic, address indexed issuer, bytes32 reason);
event TrustedIssuerUpdated(bytes32 indexed topic, address indexed issuer, bool trusted);
error ARexUntrustedIssuer(bytes32 topic, address issuer);
error ARexAttestationNotFound(uint256 id, bytes32 topic);
function attest(uint256 id, bytes32 topic, bytes32 ref, uint64 expiresAt) external;
function revokeAttestation(uint256 id, bytes32 topic, bytes32 reason) external;
function getAttestation(uint256 id, bytes32 topic) external view returns (Attestation memory);
function isAttested(uint256 id, bytes32 topic) external view returns (bool);
function isTrustedIssuer(bytes32 topic, address issuer) external view returns (bool);

A.6 常量(ARexCodes)

分组取值
操作OP_MINT = 1、OP_TRANSFER = 2、OP_BURN = 3、OP_FORCED_TRANSFER = 4、OP_TRANSFORM = 5
钩子标志HOOK_CHECK = 1、HOOK_EXECUTED = 2、HOOK_ELIGIBILITY = 4
状态STATUS_ACTIVE = 0、STATUS_RETIRED = 255
代码(keccak256("AREX:…"))PAUSED、FROZEN、SENDER_INELIGIBLE、RECEIVER_INELIGIBLE、SANCTIONED、BATCH_NOT_FOUND、BATCH_RETIRED、BATCH_INACTIVE、BATCH_EXPIRED、BATCH_NOT_PRODUCED、LIMIT_EXCEEDED、DOCUMENT_MISSING、SEASON_CLOSED、IN_TRANSIT、ATTESTATION_MISSING
辅助函数commodity(scheme, code)、unit(code)、topic(name)、code(namespace, name)

A.7 参考实现的角色

ARexToken 上的 ISSUER_ROLE、TRANSFORMER_ROLE、STATUS_ROLE、ENFORCER_ROLE、HOOK_ADMIN_ROLE、PAUSER_ROLE、UPGRADER_ROLE、DEFAULT_ADMIN_ROLE(每个均为 keccak256("AREX_<NAME>"));ARexAttestations 上的 ATTEST_ADMIN_ROLE。额外的视图函数:isExpired(id)、transferCheck(from, to, id, amount);额外的函数:burn(from, id, amount);ERC-7201 槽位 0x8ed599b6be05dec05297c009a1279a71df771ad996fe924d0b5a47326ff60900。

A.8 参考钩子与扩展

合约类型主要函数
PerishabilityHook钩子setCommodityDecay、setBatchDecay、valueBps、secondsRemaining、isExpired
SeasonalHook钩子addWindow、clearWindows、windowsOf、isOpen
DeliveryHook钩子schedule、pickUp、markInTransit、recordReading、confirmDelivered、cancel、dispute、resolve、getDelivery、lockedUnits
TraceabilityHook钩子recordEvent、eventCount、getEvents;构造函数标志 persist
CommodityPriceOracle扩展submit、finalizeRound、latestAnswer、getRound、currentRound、isStale、setParameters
CarbonImmobilizationWrapper扩展recordImmobilization、linkToBatch、retire、release、attestBacking、backingOf、linksOf
ParametricInsurance扩展fund、issue、claim、expire、getPolicy、freeCapacity

A.9 元数据模式

standard/schema/batch-metadata.schema.json(JSON Schema 2020-12)。必需字段:schemaVersion、commodity{scheme, code}、unit、quantity。值得注意的可选字段组:traceabilityLotCode、gs1{gtin, lgtin, sscc, glnProducer, digitalLink}、production、origin{country, originRef, eudr{ddsReference}, geohashPrecision, geohash}、quality{gradeScheme, grade, measurements[]}、status.table、attestations[]、documents[]{type, hash, uri, registry, registryId}、epcis{bizStep, disposition, readPoint, bizLocation}、restricted{uri, hash, accessPolicy}、attributes[]。示例见 standard/examples/batch-metadata.example.json。

附录 B:术语表

术语含义
批次带有 Batch 记录的 ERC-1155 代币 id:同一种商品、同一单位、具有相同来源和生产时间的一批货物。
重新分批输出与输入商品和单位相同、数量守恒的 transform(拆分、合并)。在参考实现中对持有人开放。
加工改变商品、单位或数量的 transform。在参考实现中需要 TRANSFORMER_ROLE。
谱系由 BatchTransformed 事件和 parentsOf 构成的图。
钩子实现 IARexHook、注册在代币上、并在每次操作时按顺序求值的合约。
拒绝代码钩子的 check 返回的 bytes32;0 表示允许;约定为 keccak256("NAMESPACE:NAME")。
资格账户层面的发送或接收许可,由标记为 HOOK_ELIGIBILITY 的钩子回答;以 ERC-7943 canSend/canReceive 的形式公开。
冻结余额账户持有但不能移动的单位(setFrozenTokens);可以超过余额。
强制转移ENFORCER_ROLE 在未经持有人同意的情况下移动单位(ERC-7943)。
证明由该主题的可信签发方记录的 (batch, topic) → (issuer, reference, validity)。
主题标识证明所涉事项的 bytes32;开放;可映射到 ERC-735 声明主题和 EAS schema id。
来源引用originRef:指向来源证据的哈希或引用;绝不是坐标。
元数据承诺metadataHash,即位于 uri 的规范链下文档的 keccak256。
状态uint8 生命周期取值;0 为活跃,255 为已注销(终态);1..254 由签发方定义。
CTE / KDE关键追踪事件 / 关键数据元素(FSMA 204)。
DDS尽职调查声明(EUDR)。
EPCISGS1 Electronic Product Code Information Services,可追溯性的事件词汇表(2.0 版)。
CPR / CPR-eCédula de Produto Rural,巴西的作物应收账款;其电子形式在获授权的实体处登记。
EWR美国《仓储法》下的电子仓单。
MLETRUNCITRAL《电子可转让记录示范法》。
ERC-7943 (uRWA)通用现实世界资产接口(Universal Real World Asset):冻结、强制转移、资格;Final,2026 年五月。
ERC-3643 (T-REX)面向 ERC-20 上证券的许可制代币标准;Final,2023 年十二月。
ERC-7201用于可升级合约的命名空间存储布局。

附录 C:参考文献

标准与规范

  • Radomski, W. 等。“EIP-1155: Multi Token Standard.” Ethereum Improvement Proposals,2018 年。
  • Vogelsteller, F., Buterin, V. “EIP-20: Token Standard.” 2015 年。
  • “ERC-165: Standard Interface Detection.” 2018 年。
  • “ERC-3643: T-REX — Token for Regulated EXchanges.” Final,2023 年十二月 15 日。https://eips.ethereum.org/EIPS/eip-3643
  • “ERC-7943: uRWA — Universal Real World Asset Interface.” Final,2026 年五月 27 日。https://eips.ethereum.org/EIPS/eip-7943
  • “ERC-7201: Namespaced Storage Layout.” 2023 年。
  • “ERC-735: Claim Holder.” 2017 年(草案)。
  • Ethereum Attestation Service 文档。
  • GS1. “EPCIS and CBV Standard 2.0.” 2022 年。GS1 US. “EPCIS Recommendations for FSMA 204 Critical Tracking Events.” 2024 年。
  • UN/CEFACT. “Recommendation No. 20: Codes for Units of Measure Used in International Trade.”
  • IETF RFC 8785. “JSON Canonicalization Scheme (JCS).” 2020 年。
  • OpenZeppelin Contracts 5.x 文档;OpenZeppelin 与 T-REX Network 合作公告,2026 年七月。

监管与法律

  • FDA. “Requirements for Additional Traceability Records for Certain Foods.” 最终规则,联邦公报 87(219),2022 年;“Compliance Date Extension,” 联邦公报,2025 年八月 7 日。
  • 条例 (EU) 2023/1115(毁林);条例 (EU) 2025/2650(修订);欧盟理事会新闻稿,2025 年十二月 18 日。
  • 条例 (EU) 2023/1114(MiCA);ESMA《关于将加密资产界定为金融工具的指南》,2024 年十二月。
  • 欧洲数据保护委员会。“Guidelines 02/2025 on processing of personal data through blockchain technologies,” 2.0 版,2026 年七月 7 日。
  • SEC。公告编号 33-11412,2026 年三月 17 日。SEC v. W.J. Howey Co.,328 U.S. 293 (1946)。
  • GENIUS Act,公法 119-27(2025);实施条例,联邦公报,2026 年八月 18 日。
  • 《统一商法典》2022 年修订,第 12 编(可控电子记录)。
  • 美国《仓储法》;7 CFR Part 869(电子仓单)。
  • UNCITRAL. “Model Law on Electronic Transferable Records.” 2017 年。英国,《2023 年电子贸易单据法》。
  • Comisión Nacional de Valores(阿根廷)。Resolución General 1150/2026。Ley 9.643(权证)。
  • 巴西。Lei 8.929/1994、Lei 13.986/2020(CPR);Lei 11.076/2004(CDA/WA);CVM Resolução 88 与 Consulta Pública SDM 05/2025。
  • Verra. “Verra Addresses Crypto Instruments and Tokens.” 2022 年;VCS Program Guide。
  • 指令 (EU) 2024/825(赋能消费者实现绿色转型)。

研究与行业

  • Zhang, P., Schmidt, D. C. “Blockchain Applications in Food Supply Chain Management: A Systematic Review.” Journal of Food Engineering,279,2020 年。
  • Caro, M. P. 等。“Blockchain-based Traceability in Agri-Food Supply Chain Management.” IEEE,2018 年。
  • FAO. “The State of Food and Agriculture.” 2023 年。
  • World Bank. “Future of Food: Harnessing Digital Technologies to Improve Food System Outcomes.” 2022 年。
  • ERC3643 Association. “History of ERC-3643”;ISO TC 307 标准化倡议公告。
  • Chainlink. “Automated Compliance Engine (ACE): Technical Overview.” 2025–2026 年。

附录 D:模板

D.1 最小钩子

来源:contracts/examples/MyHook.sol(导入 ../reference/hooks/ARexHookBase.sol 和 ../standard/IARexBatch.sol)。

contract MyHook is ARexHookBase {
    function hookFlags() public pure override returns (uint8) {
        return ARexCodes.HOOK_CHECK;
    }


    function check(uint8 op, address, address, address, uint256 id, uint256, bytes calldata)
        external
        view
        override
        returns (bytes32)
    {
        if (op != ARexCodes.OP_TRANSFER) return ARexCodes.OK;
        IARexBatch.Batch memory b = IARexBatch(msg.sender).batchOf(id);
        b; // decide from b.commodity, b.producedAt, b.expiresAt, b.status ...
        return ARexCodes.OK;
    }
}

D.2 部署(升级插件)

const token = await upgrades.deployProxy(await ethers.getContractFactory("ARexToken"), [admin, baseURI], { kind: "uups" });
const attestations = await (await ethers.getContractFactory("ARexAttestations")).deploy(admin, await token.getAddress());
await token.registerHook(await (await ethers.getContractFactory("EligibilityHook")).deploy(admin));
await token.registerHook(await (await ethers.getContractFactory("ExpiryHook")).deploy(true));

D.3 元数据骨架

{ "schemaVersion": "1.0.0", "commodity": { "scheme": "HS", "code": "100199" }, "unit": "KGM", "quantity": 250000,
  "traceabilityLotCode": "…", "production": { "producedAt": "…" }, "origin": { "country": "AR", "originRef": "…" },
  "status": { "table": { "1": "IN_STORAGE" } }, "documents": [ { "type": "warehouse_receipt", "hash": "…", "registryId": "…" } ],
  "restricted": { "uri": "…", "hash": "…", "accessPolicy": "…" } }

附录 E:常见问题

A-REX 是 ERC 吗? 尚不是。该规范以 ERC 格式撰写,将在完成生产部署、出现独立实现并通过审计之后提交。尚未分配编号;代码中的名称不使用 ERC 前缀。

我必须使用 ARexToken 吗? 不必。可以用任何方式实现这些接口;参考实现只是其中一种方式。

我必须使用参考钩子吗? 不必。它们只是演示。可以复制、替换,或自行编写。

钩子可以阻止强制转移吗? 它可以针对 OP_FORCED_TRANSFER 返回一个代码,代币随即回滚。参考钩子不会这样做;规范强制执行的钩子(例如要求带有命令引用)则可以。

坐标放在哪里? 放在由元数据引用的受限链下存储中,绝不放在链上。

如何表示未来的收成? producedAt = 0;用 ExpiryHook(allowPreHarvestTransfers) 为转移设门槛。

transform 中的数量是否守恒? 标准并不要求;参考实现在数量守恒时允许任何持有人重新分批,否则需要 TRANSFORMER_ROLE。

代币是证券吗? 标准不作决定,发售才决定。请咨询法律顾问;无论答案如何,强制执行接口都在那里。