Skip to content

Methodology

DISCLAIMER // NFA // DYOR

This analysis is based on observations of the contract behavior. We are not smart contract security experts. This document aims to explain what the contract appears to do based on the code. It should not be considered a comprehensive security audit or financial advice. Always verify critical information independently and consult with blockchain security professionals for important decisions.

⊙ generated by robots | curated by humans

METADATA
Contract Address 0xb276f62d...1eac1c (etherscan)
Network Ethereum Mainnet
Analysis Date 2026-08-11
Snapshot Block 25733839

Overview

The contract is verified on Etherscan, so this is a source-level analysis rather than a bytecode reconstruction. The work divided into two halves: reading what the code says it does, and checking against the chain whether it does it.

The first decision shaped everything after it. The protocol publishes source at token-works/fwa-relaunch, and it would have been natural to clone that and read from there. Diffing the repository against the Etherscan-verified source showed they are different programs — the repository is a single-commit snapshot from eight days before deployment, still carrying a Uniswap V4 integration that the deployed contract does not have. Every claim in this analysis is therefore taken from the Etherscan source. The repository was used only to understand design intent, and the divergence itself became a finding.

The second decision was to derive rather than trust. The contract exposes convenient aggregates — totalWeight, feeShareTotal, weightedBackingTotal, activeListingCount — and it would have been easy to report those as facts about the pool. Instead each was recomputed from primitive state: every one of the 149,854 listings was read individually, and the aggregates rebuilt from them. That is what makes the solvency reconciliation meaningful, and it is what surfaced the stale √backing comment, since the reconstructed feeShareTotal could only match if every share were a flat 1.

Reading with the code rather than the comments mattered more than usual here. Four separate NatSpec blocks describe the fee-share basis as the square root of backing; the code assigns a literal 1. Chain state agrees with the code.

Thought Process

mindmap
  root((FWA Analysis))
    Obtain
      Etherscan getsourcecode
        9 source files
        Solidity 0.8.30, runs=1, prague
      Runtime bytecode 21,425 bytes
      Clone public repo
        Diff against deployed
        Divergence found
        Repo used for intent only
    Understand
      Standalone, no proxy
      92 functions
        57 view, 35 state-changing
      Segment tree depth 32
      Staging FIFO
      Sequence ledger
      Dividend accumulator
    Verify Pricing
      Inverse weight NUM/value
      EV = weightedBackingTotal/totalWeight
      Recompute harmonic mean
        from 5,770 backings
        matches to the wei
    Verify Solvency
      Enumerate slots 1..16000
        5,770 occupied
      Read all 149,854 listings
        status distribution
        backing sums
      Read pendingFees per listing
      Read feeCredit per depositor
        2,124 ever, 348 non-zero
      Sum vs contract balance
        surplus 157,011 wei
    Governance
      ConfigSet event history
        43 events
        21 constructor
        22 owner actions
      Storage slot dump
        current vs defaults
      Owner is deployer EOA
        no multisig
        no timelock
    Risk
      Fee asymmetry
        settlement capped 5%
        acquisition capped 100%
      VRF coordinator replaceable
      Exit gate vs owner timing
      Unaudited complexity

Verification Guide

Analysis used Foundry's cast for chain reads, the Etherscan API v2 for source and event history, gh for repository inspection, and Multicall3 for bulk state enumeration. Every figure quoted in the analysis is reproducible with the commands below at block 25733839.

External Resources

  • Etherscan — FWA contract — verified source, ABI, creation transaction, and constructor arguments. The authoritative artifact.
  • Etherscan API v2 — getsourcecode for the source bundle and compiler settings, getcontractcreation for deployer and creation block, and logs/getLogs for the complete ConfigSet history.
  • token-works/fwa-relaunch — public repository, read via gh api. Used to establish design intent and, by diffing, to establish that it is not the deployed code.
  • Chainlink VRF v2.5 documentation — subscription semantics, callback billing behaviour, and the requestRandomWords interface, needed to reason about the timeout and refund paths.
  • Solady — Ownable uses a fixed storage slot rather than a sequential one, which is why the contract's own layout begins at slot 0.
  • Multicall3 — 0xcA11bde0...76CA11 (etherscan), used to batch roughly 160,000 eth_call reads into a few hundred requests. Direct JSON-RPC batching was rate-limited by the provider; Multicall3 was not.

Commandline Tools

Tip

Commands below use cast from the Foundry Toolkit. To run the commands below, you must set the RPC URL environment variable:

export ETH_RPC_URL=https://eth.llamarpc.com

Establish Contract Identity and Provenance

Confirms the contract is standalone rather than a proxy, and identifies who deployed it and when.

# RUNTIME BYTECODE SIZE — CONFIRMS A REAL CONTRACT AND ITS EIP-170 HEADROOM

cast code 0xb276f62db0ce8ca2ca5bc522695be604521eac1c | wc -c


# CONSTRUCTOR ARGUMENTS — COORDINATOR, SUBSCRIPTION, KEY HASH, GAS LIMIT, VRF SERVICE

curl -s "https://api.etherscan.io/v2/api?chainid=1&module=contract&action=getsourcecode\
&address=0xb276f62db0ce8ca2ca5bc522695be604521eac1c&apikey=$ETHERSCAN_API_KEY"


# DEPLOYER AND CREATION BLOCK

curl -s "https://api.etherscan.io/v2/api?chainid=1&module=contract&action=getcontractcreation\
&contractaddresses=0xb276f62db0ce8ca2ca5bc522695be604521eac1c&apikey=$ETHERSCAN_API_KEY"

Verify the Pricing Model

The central mechanical claim is that inverse weighting makes the acquisition price the harmonic mean of all active backings. These reads establish the inputs; the reconstruction below establishes the identity.

# THE THREE POOL AGGREGATES THAT DRIVE PRICE

cast call 0xb276f62db0ce8ca2ca5bc522695be604521eac1c "totalWeight()(uint256)"
cast call 0xb276f62db0ce8ca2ca5bc522695be604521eac1c "weightedBackingTotal()(uint256)"
cast call 0xb276f62db0ce8ca2ca5bc522695be604521eac1c "activeListingCount()(uint256)"


# THE QUOTED PRICE, SPLIT INTO POOL FEE AND VRF SERVICE FEE

cast call 0xb276f62db0ce8ca2ca5bc522695be604521eac1c "quoteAcquisitionPrice()(uint256,uint256,uint256)"


# SEGMENT TREE ROOT MUST EQUAL totalWeight — A TREE-INTEGRITY CHECK

cast call 0xb276f62db0ce8ca2ca5bc522695be604521eac1c "treeRootWeight()(uint256)"

weightedBackingTotal / totalWeight gives the expected value. Because weight = 1e36 / value, that quotient is algebraically n / Σ(1/vᵢ) — the harmonic mean. We confirmed it numerically by computing the harmonic mean of all 5,770 backings independently and comparing: both give 0.079742869391249362 ETH.

Enumerate the Active Pool

The contract has no function returning the set of active listings. Occupied tree slots are the index: slotToListing[slot] is non-zero exactly for active listings, and slots are recycled through a free list, so probing a bounded range finds all of them.

# HOW FAR THE SLOT SPACE HAS EVER EXTENDED (STORAGE SLOT 53 IS nextUnusedSlot)

cast storage 0xb276f62db0ce8ca2ca5bc522695be604521eac1c 53 --block 25733839


# ONE SLOT LOOKUP; REPEAT ACROSS 1..16000 VIA MULTICALL3 TO FIND ALL 5,770

cast call 0xb276f62db0ce8ca2ca5bc522695be604521eac1c "slotToListing(uint256)(uint256)" 2503


# THE FULL LISTING STRUCT FOR ONE ID — HERE THE TOP-BACKED LISTING

cast call 0xb276f62db0ce8ca2ca5bc522695be604521eac1c \
  "listings(uint256)(address,address,address,uint256,uint256,uint256,uint256,uint256,uint256,uint64,uint8)" \
  136185

Probing slots 1 to 16,000 returned exactly 5,770 occupied, matching activeListingCount, with the highest in use at 9,651 — comfortably inside the probe range, so the enumeration is complete rather than truncated.

Reconstruct Every Liability

Solvency was tested by rebuilding all eight obligation components from primitive state and comparing the total to the contract's balance. Three of the four counters below read zero at the snapshot; the top-listing pot did not.

# THE CONTRACT'S ACTUAL ETH

cast balance 0xb276f62db0ce8ca2ca5bc522695be604521eac1c --block 25733839


# THE FOUR AGGREGATE LIABILITY COUNTERS

cast call 0xb276f62db0ce8ca2ca5bc522695be604521eac1c "acquisitionEscrowTotal()(uint256)"
cast call 0xb276f62db0ce8ca2ca5bc522695be604521eac1c "acquisitionRefundCreditTotal()(uint256)"
cast call 0xb276f62db0ce8ca2ca5bc522695be604521eac1c "accruedOwnerFees()(uint256)"
cast call 0xb276f62db0ce8ca2ca5bc522695be604521eac1c "topListingPot()(uint256)"


# PER-LISTING UNCREDITED FEES; SUMMED ACROSS ALL 5,770 ACTIVE LISTINGS

cast call 0xb276f62db0ce8ca2ca5bc522695be604521eac1c "pendingFees(uint256)(uint256)" 136185


# PER-DEPOSITOR CREDITED EARNINGS; SUMMED ACROSS ALL 2,124 DEPOSITORS EVER

cast call 0xb276f62db0ce8ca2ca5bc522695be604521eac1c \
  "feeCredit(address)(uint256)" 0xd092e74d7aba2084cfbf772d29e3d71300e200ec

Backing sums came from reading every listing id from 1 to 149,854 and partitioning by status. The depositor set for feeCredit was taken from the same sweep rather than from event logs, because feeCredit can only ever be credited to an address that deposited at least one listing, and the provider rate-limited wide eth_getLogs ranges.

Reconstruct the Governance History

ConfigSet is emitted by the constructor and by all three owner dispatchers, so the full parameter history is recoverable from one topic.

# THE EVENT TOPIC

cast keccak "ConfigSet(uint256,uint256)"


# EVERY CONFIG CHANGE SINCE DEPLOYMENT — 43 EVENTS

curl -s "https://api.etherscan.io/v2/api?chainid=1&module=logs&action=getLogs\
&address=0xb276f62db0ce8ca2ca5bc522695be604521eac1c&fromBlock=25546793&toBlock=99999999\
&topic0=0x150110afd46e9924086bf85c855aae25722518b293155bf0ae689dd99a2e88cc\
&page=1&offset=1000&apikey=$ETHERSCAN_API_KEY"

Key names were resolved by parsing the constants out of the verified FWAConfigKeys.sol, since the event carries the numeric key rather than a label.

Read Internal Parameters Not Exposed by Getters

Several economically significant parameters — surchargeBps, minBacking, protocolFeeToTokenBps, whitelistManager, and the three mode flags — are declared internal and have no public getter. They were read directly from storage, with slot positions derived from declaration order in the verified source and cross-checked against the public getters that share packed slots.

# surchargeBps (250), minBacking (0.05 ETH), protocolFeeToTokenBps (10000)

cast storage 0xb276f62db0ce8ca2ca5bc522695be604521eac1c 14 --block 25733839
cast storage 0xb276f62db0ce8ca2ca5bc522695be604521eac1c 19 --block 25733839
cast storage 0xb276f62db0ce8ca2ca5bc522695be604521eac1c 51 --block 25733839


# SLOT 11 PACKS BOTH SEQUENCE COUNTERS AND THE THREE MODE BOOLEANS

cast storage 0xb276f62db0ce8ca2ca5bc522695be604521eac1c 11 --block 25733839

Slot 11 decodes as lastIssuedSequence in bytes 0–7, nextSequenceToProcess in bytes 8–15, then acquisitionsEnabled, withdrawOnly and whitelistEnabled in bytes 16, 17 and 18. Both sequence values agree with their public getters, which confirms the offset derivation for the booleans that have none.

Confirm External Dependencies

# THE COORDINATOR IS CHAINLINK'S CANONICAL VRFCoordinatorV2_5, NOT A LOOK-ALIKE

curl -s "https://api.etherscan.io/v2/api?chainid=1&module=contract&action=getsourcecode\
&address=0xd7f86b4b8cae7d942340ff628f82735b7a20893a&apikey=$ETHERSCAN_API_KEY"


# SUBSCRIPTION BALANCE, REQUEST COUNT, OWNER AND CONSUMER LIST

cast call 0xd7f86b4b8cae7d942340ff628f82735b7a20893a \
  "getSubscription(uint256)(uint96,uint96,uint64,address,address[])" \
  0xbe3fb16e567de94add08d0270be5e987eab08ac5cddb073ca79c06e16e0ffd33


# THE REWARDS MODULE AND VRF SERVICE BOTH POINT BACK AT THIS POOL

cast call 0x6a1a1C0CfB3D3C538e13D36d608a5bcaa992fc78 "fwa()(address)"
cast call 0xa084c33Fb7a467307452898b8D58165ebd2E5D9f "fwa()(address)"

Diff the Deployed Source Against the Public Repository

# CLONE FOR LOCAL READS (NOT COMMITTED)

gh api repos/token-works/fwa-relaunch --jq '{created_at,pushed_at,license,default_branch}'
git clone --depth 50 https://github.com/token-works/fwa-relaunch.git


# COMPARE IMPORT SETS — THE FASTEST WAY TO SEE THE DIVERGENCE

grep -n '^import\|^contract ' fwa-relaunch/src/FWA.sol
grep -n '^import\|^contract ' <etherscan-extracted>/src__FWA.sol

The deployed file has 2,372 lines and no Uniswap V4 imports; the repository file has 2,756 and declares contract FWA is Ownable, ReentrancyGuard, IUnlockCallback.


Document Verification

The drafted documents were re-checked before publication in five independent passes, each with a narrow scope and each reading from primary sources rather than from the draft. Running them separately matters: a claim can be correctly formatted, non-redundant, neutral in tone, free of filler, and still be factually wrong, and a single reviewer holding all five concerns at once reliably drops the last one.

DIMENSION WHAT IT CHECKS CHECKED AGAINST
Facts Addresses, block heights, counts, dates, compiler version, selector values, storage slot contents, and every quantitative claim including the solvency reconciliation Live chain state via cast and Multicall3 at block 25733839, Etherscan API v2, and the Etherscan-verified FWA.sol
Standards Address display format, explorer links on every on-chain reference, table casing, section separators, icon semantics, glossary term wrapping, nav registration CLAUDE.md, docs/glossary.md, mkdocs.yml
Redundancy Duplicated tables and paragraphs across the six documents, and the same claim stated with different values in two places The document set itself
Voice Superlatives asserted without a verification clause, opinion adjectives, speculation about intent or users CLAUDE.md writing standards
Filler Rhetorical padding — meta-narration, telegraphed structure, formulaic emphasis CLAUDE.md anti-patterns

Every disagreement the fact pass raised was re-derived from chain or source before any edit was made, on the assumption that the checker is as capable of being wrong as the draft. A claim was only changed where the contradicting value could be reproduced from a command in the Verification Guide above.


Limitations

Scope

Only the FWA pool contract was analysed at source level. FWARewards, FWAToken, FWATokenHook, FWAVRFService, FWAWhitelist and Splitter were read only far enough to establish their addresses, ownership and the interfaces FWA depends on. Depositor and purchaser returns depend materially on the rewards module and the token, neither of which is analysed here.

Snapshot, not proof

The solvency reconciliation holds at block 25733839. It demonstrates that the books balanced at one block; it is not a proof that they balance in every reachable state. No formal verification, symbolic execution, or fuzzing was performed.

No dynamic testing

Nothing was simulated, forked, or executed. No transaction was traced end to end. Conclusions about control flow come from reading the source, and conclusions about state come from reading the chain.

The rounding argument is directional, not exhaustive

We observe that _activateListing ceils checkpoints while _pendingFees floors credits, and that the observed residue is positive and tiny. We did not enumerate every arithmetic path to prove the residue can never go negative.


Assumptions

The Etherscan source matches the deployed bytecode

Etherscan reports an exact-match verification. We did not independently recompile with Solidity 0.8.30 at runs = 1 with via-IR and compare bytecode hashes.

Slot enumeration is complete

Probing tree slots 1 to 16,000 returned exactly activeListingCount occupied entries with the highest at 9,651, and nextUnusedSlot reads 9,653. We take this as complete coverage rather than a truncated scan.

feeCredit holders are a subset of depositors

feeCredit is incremented in exactly three places — _settleAndRemove, updateBacking, and _vacateTop — and in all three the recipient is a listing's depositor. The depositor set swept from all 149,854 listings is therefore a superset of all possible credit holders.

The analysis of timeout, refund and billing paths assumes the coordinator at the configured address is genuine Chainlink infrastructure behaving per its documentation. We verified the contract name on Etherscan but did not audit the coordinator.


Token Cost Breakdown

PHASE DESCRIPTION TOKENS
Phase 0 Obtain the Contract 25 tok
Phase 1 Discovery & Understanding 40 tok
Phase 2 Deep Dive Analysis 95 tok
Phase 3 Risk & Trust Analysis 45 tok
Phase 4 Documentation Generation 95 tok
Phase 5 Verification pass over the drafted documents 1,025 tok
TOTAL Complete Contract Analysis 1.3 mtok

Phase 5 costs more than the other five phases combined, which is expected for this contract. The verification passes do not re-read the draft; they re-derive it. That means a second full Multicall3 sweep of all 149,854 listings, a second feeCredit sweep across all 2,124 depositor addresses, recomputing keccak over all 92 function signatures, dumping all 62 storage slots against declaration order, and pulling the VrfServiceFeePaid log series to establish what purchasers actually paid rather than what a zero-gas-price eth_call reports. Reconstructing the pool twice is the cost of being able to say the numbers reconcile.

Note: Token costs are estimates based on typical conversation lengths and complexity. Actual consumption may vary by ±10-15% depending on API responses, iterative refinement, and verification steps.