Contract Analysis
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
Analysis Date: 2026-08-11
Metadata
Primary Contract
| PROPERTY | VALUE |
|---|---|
| Contract Address | 0xb276f62d...1eac1c (etherscan) |
| Network | Ethereum Mainnet |
| Snapshot Block | 25733839 |
| Contract Type | Standalone |
| Deployment Date | 2026-07-16 17:42 UTC |
| Deployment Block | 25546793 |
| Contract Creator | 0x019817aD...13E8Cb (etherscan) |
| Creation TX | 0xa711a902...fd3c78 (tx) |
| Compiler Version | Solidity v0.8.30+commit.73712a01, optimizer enabled (runs = 1), EVM version prague |
| Runtime Size | 21,425 bytes (3,151 under the EIP-170 limit) |
| Total Functions | 92 (57 view/pure, 35 state-changing, 12 payable) |
| External Contract Dependencies | 7 (VRF coordinator, VRF service, rewards module, FWAToken, whitelist manager, payout splitter, and each listed ERC-721) |
| Upgrade Mechanism | ☒ None — Not Upgradable |
| Verification Status | ☑ Verified on Etherscan (Exact Match) |
| Audit Status | ☒ No audit published at time of analysis |
Related Addresses
| TYPE | ADDRESS | NOTES |
|---|---|---|
| Owner | 0x019817aD...13E8Cb (etherscan) |
The deployer Externally Owned Account (EOA) itself. Solady Ownable. No multisig or timelock. |
| Payout Address | 0x1C175b9F...373Bfe (etherscan) |
Splitter contract. Set 1 minute after deployment. Receives the non-token slice of protocol fees, currently zero. |
| Whitelist Manager | 0x854352b2...5e17c3 (etherscan) |
FWAWhitelist contract. Can add or remove collections without being owner. |
| Rewards Module | 0x6a1a1C0C...92fc78 (etherscan) |
FWARewards. Wired once via setRewards; cannot be replaced. |
| Token | 0xa0Df17B5...20C845 (etherscan) |
FWAToken. Read from the rewards module, not set directly. |
| VRF Service | 0xa084c33F...2E5D9f (etherscan) |
FWAVRFService. Immutable constructor argument. Collects the purchaser's randomness fee and funds the subscription. |
| Verifiable Random Function (VRF) Coordinator | 0xd7f86b4b...20893a (etherscan) |
Chainlink VRFCoordinatorV2_5. Owner-replaceable while the pool is quiescent. |
| Superseded Pool | 0x6596170e...8a6322 (etherscan) |
Earlier FWA deployed 2026-06-30, still on-chain with 8 active listings. |
Executive Summary
FWA is the acquisition pool behind fwa.fun, a TokenWorks work. It is a randomized NFT marketplace in which the seller sets both the asking price and the odds, and the buyer does not choose what they are buying.
A depositor escrows one ERC-721 together with an amount of ETH they choose, called the backing. That backing does two jobs at once. It sets the listing's selection weight inversely — weight = 1e36 / backing, so a cheaply-backed listing is drawn far more often than a richly-backed one — and it funds an irrevocable standing bid to buy the NFT back. A purchaser pays a fee, receives one randomly selected listing via Chainlink VRF, and then chooses: keep the NFT, or take the depositor's ETH. The two outcomes are mutually exclusive and enforced by a single status transition, so a purchaser can never walk away with both.
The pricing mechanism is the load-bearing piece, and it reproduces independently. Because weight is inversely proportional to backing, the product weight · backing is approximately the same constant for every listing, and the pool's expected value collapses to the Harmonic Mean of all backings. We computed that mean independently from all 5,770 active listings and it reproduces the contract's internal figure to the wei: 0.079742869391249362 ETH at block 25733839. The purchaser pays that expected value plus a surcharge, currently 2.5%.
The intended audience is two-sided. Depositors are people holding NFTs they would sell at a known price, who earn an equal share of every acquisition fee while they wait. Purchasers are people willing to buy a random draw from that pool. As pure ETH arithmetic the purchaser side is negative — pay 1.025 × expected backing, and the ETH exit returns 90% of backing — so the acquisition side is subsidised by FWAToken emissions from a separate rewards module rather than by the pool itself.
The most important thing we verified is solvency. The contract's design claim is that every wei it holds is spoken for and that no listing's backing can be spent on another listing's obligations. We reconstructed all eight liability components from chain state — 5,770 active backings, 56 allocated backings, the uncredited dividend accumulator, 348 addresses with credited fee balances, the top-listing pot, and three counters that were all zero — and compared the total against the contract's ETH balance. The surplus is 157,011 wei, or 1.57 × 10⁻¹³ ETH: rounding dust from an accumulator that deliberately floors credits and ceils checkpoints so it can never over-credit. At the snapshot block the contract is fully backed.
The significant trust assumption is governance, not accounting. The owner is a single externally-owned account with no multisig or timelock, and the fee parameters it controls are not symmetrically bounded. A depositor's principal is protected by a hard-coded 5% cap on the settlement fee, so the settlement cut cannot exceed 5% of backing. A depositor's yield has no such protection: ownerAcquisitionFeeBps is capped only at 100%, so the owner can redirect the entire acquisition fee stream to the protocol at any moment the pool is idle, without warning. That same key holds 1,088 ETH and owns the rewards module, the VRF service, and the VRF subscription.
The public repository at token-works/fwa-relaunch is not the deployed contract. It is a single-commit snapshot from 2026-07-08; the contract deployed eight days later is a substantially refactored version with the Uniswap V4 integration removed and VRF fee logic moved into an external service. This analysis reads the Etherscan-verified source, which is what actually runs.
Architecture
graph TB
subgraph Actors
DEP[Depositor]
PUR[Purchaser]
KEEP[Anyone / keeper]
OWN[Owner EOA]
end
subgraph Core["FWA — 0xb276f62d...1eac1c"]
LIST["Listing store<br/>149,854 ids, 5,770 active"]
TREE["Segment tree<br/>depth 32, weighted selection"]
STAGE["Staging FIFO<br/>anti-steering queue"]
SEQ["Sequence ledger<br/>ordered settlement"]
ACC["Dividend accumulator<br/>flat 1 share per listing"]
TOP["Top-listing slot + pot"]
end
subgraph External
VRFS["FWAVRFService<br/>0xa084c33f...2e5d9f"]
COORD["Chainlink VRFCoordinatorV2_5<br/>0xd7f86b4b...20893a"]
REW["FWARewards<br/>0x6a1a1c0c...92fc78"]
TOK["FWAToken<br/>0xa0df17b5...20c845"]
WL["FWAWhitelist<br/>0x854352b2...5e17c3"]
SPL["Splitter<br/>0x1c175b9f...373bfe"]
NFT["Listed ERC-721 collections<br/>47 active"]
end
DEP -->|listNFT + backing ETH| LIST
LIST --> STAGE
STAGE -->|activate| TREE
PUR -->|acquire + fee| SEQ
SEQ -->|prepareRequests + fee| VRFS
VRFS -->|fund subscription| COORD
SEQ -->|requestRandomWords| COORD
COORD -->|rawFulfillRandomWords| SEQ
SEQ -->|select slot| TREE
SEQ --> ACC
SEQ --> TOP
KEEP -->|processAcquisitions| SEQ
PUR -->|keepNFT / acceptDepositorBid| LIST
LIST -->|transferFrom| NFT
SEQ -->|registerAcquisition / settleAcquisition| REW
REW -->|buyFor| TOK
ACC -->|payoutFees| TOK
ACC -->|payoutFees| SPL
OWN -->|setUint / setBool / setAddr| Core
OWN --> WL
WL -->|setCollectionsWhitelisted| Core
style LIST fill:#e8f0ff
style TREE fill:#e8f0ff
style OWN fill:#ffe1e1
style COORD fill:#fff4e1
System Overview
The contract is a single-file, standalone pool with no proxy and no upgrade path. Its job is to hold NFTs and ETH, price a random draw against them correctly, and settle the result in a fixed order.
- Escrows an ERC-721 and a depositor-chosen ETH backing as one listing, and keeps the two bound together until the listing resolves.
- Prices an acquisition at the harmonic mean of every active listing's backing, times a surcharge, using a depth-32 segment tree that makes weighted selection an
O(32)descent rather than a scan. - Requests randomness from Chainlink per acquisition and assigns each request a local sequence number at request time, so requests are concurrent but settlement is strictly ordered.
- Binds every listing's backing to that listing's own standing bid, which is the design's stated basis for solvency. We reconciled it at one block rather than proving it holds for all states.
- Blocks withdrawals and re-pricing whenever any acquisition is unresolved, because removing weight from the tree would steer a draw that has already been paid for.
- Does not value the NFT. Backing is whatever the depositor typed. The contract prices the backing distribution, not the collection floor, and nothing on-chain checks that a listing's NFT is worth its backing.
- Does not protect depositor yield. The acquisition fee split is an owner parameter with a 100% ceiling.
- Does not hold a treasury of its own. Protocol fees accrue to a counter and are pushed out permissionlessly; at the snapshot that counter is zero and 100% of the flow is routed to the FWAToken buyback reserve.
Design Patterns Used
- Inverse weighting:
weight = INVERSE_WEIGHT_NUMERATOR / valuewith the numerator fixed at1e36. The shared constant cancels between any two listings, so it sets precision only. Its consequence —weight · value ≈ 1e36for every listing — is what makes the pool's expected value a harmonic mean and letsweightedBackingTotaldouble as a listing counter scaled by1e36. - Segment Tree over a mapping:
TREE_DEPTH = 32gives capacity for 2³² concurrent listings without allocating them. Only touched nodes cost storage. Selection walks the tree comparing a target against cumulative left-subtree weight. - Slot recycling with a free list: removed listings release their tree slot onto a LIFO free list (
freeSlotHead,nextFreeSlot), so slot indices stay dense. We observed 5,770 active listings occupying slots up to 9651. - Dividend Accumulator: fees are distributed by incrementing
accFeePerEVrather than iterating depositors. Each listing carries afeeDebtcheckpoint. Checkpoints are ceiled on entry and credits floored on exit, an asymmetry intended to keepΣ credited ≤ Σ collectedand consistent with the positive residue we observed. - Commit-then-request sequencing: the local sequence number and the exact batch of staged listings to activate are both committed before the external VRF call, so a coordinator revert rolls back both.
- Staging FIFO as an anti-steering boundary: deposits made while an acquisition is unresolved do not enter the selection pool. They queue in a doubly-linked list and are reserved to a specific sequence, so no already-issued request can observe a listing that did not exist when it was priced.
- Pull payments throughout: earnings, acquisition refunds, and protocol fees all accrue to counters and are withdrawn by their owner, rather than pushed during settlement.
- Best-effort NFT delivery with a recovery path: a collection that reverts on transfer cannot block the ETH legs; the NFT is recorded against
stuckNFTRecipientfor a later pull. - Generic config dispatchers: the per-knob setters were collapsed into
setUint/setBool/setAddr, together accepting 25 keys drawn from the 28FWAConfigKeysconstants, explicitly to fit under EIP-170.
Access Control
Roles & Permissions
| ROLE | ASSIGNED BY | REVOKABLE | CALL COUNT |
|---|---|---|---|
| Owner | Constructor (_initializeOwner(msg.sender)) |
Yes — transferOwnership or renounceOwnership |
Unlimited |
| Whitelist Manager | Owner via setAddr(WHITELIST_MANAGER) |
Yes — set to zero address | Unlimited |
| VRF Service | Constructor, immutable | No | Unlimited (only configureVrfRequest) |
| VRF Coordinator | Constructor; owner-replaceable via setAddr(VRF_COORDINATOR) |
Yes — while quiescent | Unlimited (only rawFulfillRandomWords) |
| Depositor | Per listing, by calling listNFT |
N/A | Per listing |
| Purchaser | Per acquisition, by VRF allocation | N/A | Per listing |
| Anyone | Permissionless | N/A | Unlimited |
Permission Matrix
| FUNCTION | OWNER | WL MANAGER | DEPOSITOR | PURCHASER | ANYONE |
|---|---|---|---|---|---|
listNFT |
☑ | ☑ | ☑ | ☑ | ☑ |
acquire / acquireBatch |
☑ | ☑ | ☑ | ☑ | ☑ |
withdrawListing |
☒ | ☒ | ☑ own | ☒ | ☒ |
updateBacking |
☒ | ☒ | ☑ own | ☒ | ☒ |
claimTopSpot |
☒ | ☒ | ☑ own | ☒ | ☒ |
claimListingFees |
☒ | ☒ | ☑ own | ☒ | ☒ |
keepNFT |
☒ | ☒ | ☒ | ☑ own | ☒ |
acceptDepositorBid |
☒ | ☒ | ☒ | ☑ own | ☒ |
acceptBidAsTokens |
☒ | ☒ | ☒ | ☑ own | ☒ |
relistNFT |
☒ | ☒ | ☒ | ☑ own | ☒ |
depositorReclaimBacking |
☒ | ☒ | ☑ after window | ☒ | ☒ |
depositorReclaimNFT |
☒ | ☒ | ☑ after window | ☒ | ☒ |
finalizeUnsettled |
☑ after 7 days | ☑ after 7 days | ☑ after 7 days | ☑ after 7 days | ☑ after 7 days |
processAcquisitions |
☑ | ☑ | ☑ | ☑ | ☑ |
activateListings |
☑ | ☑ | ☑ | ☑ | ☑ |
payoutFees |
☑ | ☑ | ☑ | ☑ | ☑ |
withdrawEarnings |
☑ | ☑ | ☑ | ☑ | ☑ |
reconcileUnfulfilledVrfCount |
☑ | ☑ | ☑ | ☑ | ☑ |
recoverStuckNFT |
☒ | ☒ | ☑ if owed | ☑ if owed | ☒ |
setUint / setBool / setAddr |
☑ | ☒ | ☒ | ☒ | ☒ |
setCollectionsWhitelisted |
☑ | ☑ | ☒ | ☒ | ☒ |
setRewards |
☑ once | ☒ | ☒ | ☒ | ☒ |
configureVrfRequest |
☒ | ☒ | ☒ | ☒ | ☒ VRF service only |
Time Locks & Delays
| ACTION | TIME LOCK | CAN CANCEL | PURPOSE |
|---|---|---|---|
| Any owner config change | ☒ None — effective immediately | N/A | ☒ No delay; only a state gate (unsettledAcquisitionCount == 0) |
| Transfer ownership | ☒ None for direct transferOwnership |
N/A | ☒ Solady's two-step handover exists but is optional |
| Purchaser resolution | ☑ 24 hours exclusive (settlementWindow) |
N/A | ☑ Purchaser's exclusive choice period |
| Depositor resolution | ☑ Available after 24 hours | N/A | ☑ Prevents an unresponsive purchaser locking the listing |
| Public finalization | ☑ Available after 7 days (finalizeWindow) |
N/A | ☑ Guarantees neither asset locks permanently |
| VRF word deadline | ☑ 30 blocks (selectionTimeoutBlocks) |
N/A | △ Late callbacks become refunds |
Economic Model
Purchase Flow
flowchart TD
A[Purchaser calls acquire] --> B{Checks}
B -->|withdrawOnly / not enabled / empty pool| Z1[Revert]
B -->|fee > maxAcquisitionFee| Z1
B -->|pool value < minWeightedValue| Z1
B -->|pass| C["Pay fee + VRF service fee<br/>excess refunded"]
C --> D["Commit sequence N<br/>reserve staged batch"]
D --> E[requestRandomWords]
E --> F{Word arrives<br/>within 30 blocks?}
F -->|No| G["Status TimedOut/Expired<br/>pool fee → pull refund<br/>VRF fee not refunded"]
F -->|Yes| H[Cache word, status Ready]
H --> I["processAcquisitions reaches<br/>sequence N in order"]
I --> J{Live fee within<br/>slippage tolerance?}
J -->|No| G
J -->|Yes| K["Select slot via segment tree<br/>target = word mod totalWeight"]
K --> L["Split fee:<br/>token slice → rewards<br/>1% → protocol<br/>1% → top pot<br/>rest → all active listings"]
L --> M[Listing status Allocated]
M --> N{Purchaser choice<br/>within 24h}
N -->|keepNFT| O["NFT → purchaser<br/>99% of backing → depositor"]
N -->|acceptDepositorBid| P["90% of backing → purchaser<br/>NFT → depositor<br/>10% retained → protocol"]
N -->|acceptBidAsTokens| Q["90% of backing buys FWAToken<br/>→ purchaser, NFT → depositor"]
N -->|relistNFT| R["Old depositor paid<br/>NFT re-listed by purchaser"]
N -->|No choice| S["After 24h depositor picks<br/>after 7 days anyone finalizes"]
style Z1 fill:#ffe1e1
style G fill:#fff4e1
Fee Structure
Values are those in force at block 25733839, with the constructor default shown where the owner has changed it.
| FEE | RATE | DEFAULT AT DEPLOY | TAKEN FROM | RECIPIENT |
|---|---|---|---|---|
Acquisition surcharge (surchargeBps) |
2.50% | 10.00% | Purchaser, over expected value | The depositor pool, via the fee split below |
| VRF service fee | ~0.00027 ETH median | N/A | Purchaser, on top of the pool fee | FWAVRFService, funds the Chainlink subscription |
Protocol acquisition cut (ownerAcquisitionFeeBps) |
1.00% | 1.00% | Distributable fee, after the token slice | accruedOwnerFees |
Top-listing share (topListingShareBps) |
1.00% | 5.00% | Distributable fee, after the protocol cut | topListingPot, settles to the top holder |
| Depositor distribution | Remainder | Remainder | Distributable fee | All active listings, equally per listing |
Protocol settlement cut (ownerSettlementFeeBps) |
1.00% | 1.00% | Backing returned to depositor | accruedOwnerFees |
| Settlement retention | 10.00% | 15.00% | Backing, when the purchaser takes ETH | Protocol (retainedToProtocol is true) |
Protocol fee to token (protocolFeeToTokenBps) |
100.00% | 0.00% | accruedOwnerFees at payout |
FWAToken buyback reserve |
ownerSettlementFeeBps is bounded by a hard-coded MAX_OWNER_SETTLEMENT_FEE_BPS = 500, so the settlement cut cannot exceed 5% of backing. ownerAcquisitionFeeBps is bounded only by BPS, so the owner may take up to 100% of the acquisition fee stream. Principal is protected by code; yield is not. Separately, surchargeBps is deliberately uncapped — the source notes an expected-value surcharge above 100% is a meaningful setting.
Because protocolFeeToTokenBps was raised to 100% on 2026-08-06, payoutFees currently sends the entire accrued balance to the FWAToken contract and zero to the payout address.
Funding Sources & Sinks
Inflows are depositor backing (escrowed per listing), purchaser acquisition fees (escrowed until ordered settlement), and purchaser VRF fees (forwarded immediately to the service, never held). Outflows are backing returns, purchaser settlements, depositor earnings withdrawals, acquisition refunds, and protocol fee payouts.
Economic Invariants
The contract's central claim is that its ETH balance always covers every recorded obligation, because each listing's backing settles only that listing's own bid. We tested this independently at block 25733839 by reconstructing every liability from chain state rather than trusting any aggregate the contract reports.
| COMPONENT | WEI | ETH |
|---|---|---|
| Active listing backing (5,770 listings) | 1246219052679687862152 | 1246.219052680 |
| Allocated listing backing (56 listings) | 3788921919190696970 | 3.788921919 |
Uncredited fee accumulator (pendingFees) |
70370386500834949333 | 70.370386501 |
Credited earnings (feeCredit, 348 addresses) |
39895179239947149387 | 39.895179240 |
| Top-listing pot | 9365078075945921140 | 9.365078076 |
| Acquisition fee escrow | 0 | 0.000000000 |
| Acquisition refund credit | 0 | 0.000000000 |
| Accrued protocol fees | 0 | 0.000000000 |
| Total obligations | 1369638618415606578982 | 1369.638618416 |
| Contract ETH balance | 1369638618415606735993 | 1369.638618416 |
| Surplus | 157011 | 0.000000000000157011 |
The 157,011 wei surplus is rounding dust. _activateListing ceils a listing's feeDebt checkpoint and _pendingFees floors the credit, so the accumulator under-credits by sub-wei amounts per listing per distribution. On the paths we read, that asymmetry biases the residue in the contract's favour; we did not enumerate every arithmetic path, so this is directional rather than proven.
Three structural invariants also reproduce exactly:
feeShareTotal(5,770) equalsactiveListingCount(5,770), confirming each listing's fee share is a flat 1. This contradicts theListingstruct's own comment, which describesfeeShareas√backing; the deployed code setsuint256 feeShare = 1. The square-root weighting still exists, but it lives in the separateFWARewardsmodule assqrtBackingTotal.treeRootWeight()equalstotalWeight(72,357,566,815,035,813,943,552), confirming the segment tree root agrees with the flat counter after 149,854 insertions and 144,084 removals.- Summing
weight × valueacross all 5,770 active listings reproducesweightedBackingTotalexactly, and dividing bytotalWeightyields 0.079742869391249362 ETH — the same figure as computing the harmonic mean of the 5,770 backings directly.
Pool Composition
At block 25733839 the pool holds 5,770 active listings across 47 collections from 213 distinct depositors. 2,124 addresses have deposited at some point.
| METRIC | VALUE |
|---|---|
| Backing, minimum | 0.0500 ETH (equals minBacking) |
| Backing, median | 0.0850 ETH |
| Backing, mean (arithmetic) | 0.2160 ETH |
| Backing, harmonic mean (the acquisition price basis) | 0.0797 ETH |
| Backing, maximum | 300.0000 ETH |
| Top 1 depositor share of listings | 8.6% |
| Top 10 depositor share of listings | 58.5% |
The gap between the arithmetic mean (0.2160 ETH) and the harmonic mean (0.0797 ETH) is the inverse weighting doing its work. A purchaser is not buying an average listing; they are overwhelmingly likely to draw a cheap one, and the price reflects that.
The largest collection in the pool by listing count is Ten Thousand Tokens (1,777 listings) — TokenWorks' own NFT. Two more of the top five, FWATokenWrapper (435) and FWAERC20Wrapper (395), are TokenWorks contracts that package other assets into listable ERC-721s. Third-party collections in the top ranks are Art Blocks Explorations (1,314), Nakamigos (558), Collector Crypt (392), fwogs (231) and Otherdeed Expanded (193).
The single top-backed listing is id 136185: a CryptoPunks 721 wrapper token (0x00000000...5C5C2F, etherscan) backed with 300 ETH, holding a 9.365 ETH pot.
Governance Configuration
The contract emitted 43 ConfigSet events: 21 from the constructor and 22 owner actions since. Every parameter change was made by the deployer EOA directly.
| DATE | CHANGE | FROM | TO |
|---|---|---|---|
| 2026-07-16 | Whitelist manager delegated to FWAWhitelist |
— | 0x854352b2...5e17c3 (etherscan) |
| 2026-07-16 | Payout address moved to Splitter |
deployer EOA | 0x1C175b9F...373Bfe (etherscan) |
| 2026-07-20 | Acquisitions opened | disabled | enabled |
| 2026-07-23 | topListingShareBps |
500 (5%) | 100 (1%) |
| 2026-07-29 | minBacking |
0.01 ETH | 0.05 ETH |
| 2026-07-31 | surchargeBps |
1000 (10%) | 500 (5%) |
| 2026-08-04 | protocolFeeToTokenBps |
0 | 8000 (80%) |
| 2026-08-04 | surchargeBps |
500 (5%) | 250 (2.5%) |
| 2026-08-04 | settlementDiscountBps |
8500 (85%) | 9000 (90%) |
| 2026-08-06 | protocolFeeToTokenBps |
8000 (80%) | 10000 (100%) |
Six of those changes were made inside a disable/re-enable window, visible in the log as paired ACQUISITIONS_ENABLED writes minutes apart. The gate is narrower than that pattern suggests: setUint reverts with AcquisitionStateLocked only when unsettledAcquisitionCount != 0, not when acquisitions are enabled, so pausing is a convenient way to drain the queue rather than a requirement. The 2026-08-06 change to protocolFeeToTokenBps was made with no pause at all. Two of the six pauses enclosed no config change. Either way the constraint applies to timing only, not to magnitude.
The direction of travel is consistent: the purchaser's surcharge fell from 10% to 2.5%, their ETH exit improved from 85% to 90% of backing, and protocol revenue was redirected from the payout address entirely into the FWAToken buyback. The net effect is more favourable purchaser economics. We have no statement from the team on the reason.
Summary of Observations
FWA is an NFT pool where a depositor names their own price and their own odds in a single number, and a purchaser buys a random draw against the resulting distribution. The pricing identity holds — the harmonic mean we computed independently matches the contract's figure — and the accounting reconciles against a full reconstruction of chain state. We did not survey comparable designs, so we make no claim about how unusual the mechanism is.
The pool is solvent to within 157,011 wei of dust at block 25733839, with all eight liability components rebuilt from primitive chain state instead of read off the contract's own aggregates, and the rounding bias running in the contract's favour on every path we read. The expected-value pricing claim is verified: computing the harmonic mean of 5,770 backings independently reproduces the contract's internal figure exactly. We found no code path in which one listing's escrow settles another's obligation, which is what makes the reconciliation look structural rather than incidental.
On concerns, the dominant one is governance rather than code. A single externally-owned account with no multisig and no timelock owns the pool, the rewards module, the VRF service, and the Chainlink subscription, and holds 1,088 ETH besides. Its powers over the 1,370 ETH in the pool are bounded asymmetrically: depositor principal is protected by a hard-coded 5% cap on settlement fees, but depositor yield is protected only by a 100% ceiling on the acquisition fee — the owner may take the entire fee stream at any idle moment, effective immediately. The VRF coordinator address is likewise owner-replaceable while the pool is quiescent, which places the integrity of the randomness in the same hands.
Withdrawals and re-pricing are blocked whenever any acquisition is unresolved, which is mechanically necessary — removing weight would steer a paid-for draw — but the pool issued 819 acquisition requests in the eight hours before the snapshot, so depositors should not assume exit is available on demand. And the public repository is not the deployed code: it is a single-commit snapshot from eight days before deployment, missing the refactor that removed the Uniswap V4 integration and moved VRF pricing into an external service. Anyone reviewing FWA from GitHub is reviewing something that was never deployed.
Several mechanisms map directly onto specific attacks: commit-before-request sequencing, the staging queue that keeps new deposits out of an already-priced draw, ordered settlement with per-request slippage tolerances snapshotted at request time, best-effort NFT delivery so a hostile collection cannot block the ETH legs, and pull payments throughout. Against that sits unaudited complexity — a segment tree, a staging FIFO, a sequence ledger, and a dividend accumulator all interacting — and a trust model that concentrates everything in one key.
We read the verified source and reconstructed state from the chain. We did not fuzz, formally verify, or review the external rewards, whitelist, or VRF service contracts in depth. Anyone with money at stake should commission a professional audit and verify the numbers here themselves using the commands in the methodology.
References
| RESOURCE | NOTES |
|---|---|
| Etherscan — FWA verified source | The authoritative source for this analysis. 2,372-line FWA.sol plus Solady and Chainlink dependencies. |
| token-works/fwa-relaunch | Public repository. Single commit, 2026-07-08. Diverges from the deployed contract; used only for design context. |
| Fake World Assets documentation | Protocol's own description of positions, weighting, pricing and settlement. |
| Chainlink VRF v2.5 documentation | Subscription model, callback semantics, and the requestRandomWords interface used here. |
| Solady | Source of ERC721, Ownable, ReentrancyGuard and SafeTransferLib used by the contract. |
| TokenWorks Project Overview | DNZN's umbrella research on TokenWorks and its other works. |
Change Log
| DATE | AUTHOR | NOTES |
|---|---|---|
| 2026-08-11 | Artificial. | Generated by robots. Gas: 1.3 mtok |
| 2026-08-11 | Denizen. | Reviewed, edited, and curated by humans. |