Skip to main contentA-REX Core

Whitepaper · 13

Performance Analysis

Measured gas of the reference implementation with zero, one and two hooks; what drives the cost; and deployment guidance.

Method

Numbers below are from scripts/gas-report-standard.js run on Hardhat's in-process network against the compiled reference implementation (solc 0.8.22, viaIR, optimizer.runs = 1 for ARexToken), September 2026. "Warm" means the same sender/receiver/id pair as the previous transfer (storage slots already touched in the block). Hooks: EligibilityHook (CHECK + ELIGIBILITY) and ExpiryHook (CHECK). Reproduce with:

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

Results

xychart-beta
    title "Warm transfer gas by number of hooks (thousands)"
    x-axis ["no hooks", "Eligibility", "Eligibility + Expiry"]
    y-axis "gas (k)" 0 --> 140
    bar [66.8, 91.2, 119.6]

Cost grows linearly with the number of hooks: each one is one external check call per id, plus canSend and canReceive for an eligibility hook. The table gives every operation.

Operation0 hooks1 hook2 hooks
createBatch (new id, mint 1000)264,096283,831299,396
safeTransferFrom (first, cold)80,687108,266136,682
safeTransferFrom (warm)66,79091,166119,582
transform split 1 → 2 (two new ids)564,422595,707636,858
setFrozenTokens54,18854,18854,188
forcedTransfer80,15289,90999,569
burn66,62183,00193,395

Warm transfer with exactly one hook of each kind (marginal cost of the rule):

xychart-beta horizontal
    title "Marginal gas of one hook on a warm transfer (thousands)"
    x-axis ["DeliveryHook", "Traceability (emit)", "EligibilityHook", "ExpiryHook", "SeasonalHook", "PerishabilityHook"]
    y-axis "gas added (k)" 0 --> 35
    bar [12.3, 17.4, 24.4, 25.2, 27.5, 31.0]

TraceabilityHook in persisted mode adds 184.5k and is left out of the chart for scale.

HookGasΔ vs. no hook
EligibilityHook91,166+24,376
ExpiryHook92,023+25,233
SeasonalHook94,324+27,534
PerishabilityHook97,813+31,023
DeliveryHook (no active delivery)79,076+12,286
TraceabilityHook, emit-only84,152+17,362
TraceabilityHook, persisted251,273+184,483

What drives the cost

  • A transfer with no hooks costs ~67k warm, i.e. ERC-1155 plus supply tracking plus the batch existence/status/frozen reads and the pipeline bookkeeping (data stash, lock). This is the floor.
  • Each hook adds roughly 25–30k on a transfer: one check call (view, cross-contract) plus, for eligibility hooks, canSend and canReceive calls. Cost is linear in the number of hooks and in the number of ids in a batch transfer. Probing every rule contract for every capability with supportsInterface before calling it would add several static calls per id; that overhead does not exist because flags are cached at registration.
  • createBatch is dominated by storage: the Batch struct (six words plus a string) and the ERC-1155 balance and supply slots. It is a one-time cost per lot.
  • transform creates new ids: a split into two pays two batch records plus two mints plus one burn, plus hook calls on every leg (OP_TRANSFORM). A split into n is roughly n × createBatch plus a burn; merging n into one is roughly n burns plus one createBatch.
  • Enforcement is cheap: freezing is one slot; a forced transfer costs what a transfer costs plus the unfreeze write and the event.
  • transferCheck / canTransfer are views: free off-chain, and the same code path as the transaction.

What the design buys

Capability-probe designA-REX Core (ARexToken)
Transfer with n rule contractsids × modules × (supportsInterface probes + hook call) before any logic runsids × hooks × 1 call (+2 for eligibility hooks); flags cached at registration
Rejectionstring revert (copied to memory, not indexable)custom error with hook address and bytes32 code
Lineagenot available~280k per output batch
Freeze / forced transfernot available54k / 80k

The left column describes the design A-REX Core replaces (ADR-004, ADR-005); only the right column is measured.

Deployment guidance

  • Cost in money is gas × gas price × token price, and the last two change by orders of magnitude between chains and days. As an illustration only, at 0.01 gwei and 3,000 USD per ETH a warm transfer with two hooks (119,582 gas) costs about 0.0036 USD and a createBatch (264,096 gas) about 0.008 USD; at 20 gwei on Ethereum mainnet the same operations cost about 7.2 and 15.8 USD. Measure on the target chain before committing to a unit economics model.
  • Batch transfers: safeBatchTransferFrom amortizes fixed costs; hook cost still scales with the number of ids.
  • Hook ordering: place high-rejection, cheap hooks first; a rejection stops the pipeline before more expensive hooks run.
  • Number of hooks: three to five covers most issuers; each additional hook is a measurable per-transfer cost and a governance surface.
  • Metadata: keep uri short (a CID or a Digital Link); the string is stored on-chain.
  • Off-chain reads: use transferCheck before submitting; a reverted transaction still costs gas.

Throughput

The token itself is not the bottleneck; the chain is. A single transfer is one transaction; a transformation with n outputs is one transaction with n mints. Indexing lineage requires reading BatchTransformed events, which are emitted once per operation with full quantity lists, so an indexer does not need to reconstruct anything from per-transfer events.

Contract size

ARexToken deploys at 24,136 bytes (limit 24,576), compiled with optimizer.runs = 1. The other contracts are small: ARexAttestations 2,708; hooks between 1,358 (ExpiryHook) and 6,215 (DeliveryHook), TraceabilityHook 4,076; extensions between 3,716 and 4,588. Adding functionality to the token itself is size-constrained by design — that is what hooks and companion contracts are for.