Architecture
The six contracts that move a fee from a swap to a share in your wallet.
On this page
The protocol is deliberately boring: a linear pipeline with one off-chain step, no loops, and no component that can send value anywhere other than the next component in the chain.
The pipeline
- 1TraderActor
Buys or sells BANK in the primary pool.
ETH leg of the swap
- 2BANK tokenContract
ERC-20 with a transfer hook that recognises pool-side trades and exempts wallet-to-wallet moves.
fee, denominated in ETH
- 3Fee routerContract
Accumulates ETH, splits it by the allocation table, and forwards the equity slice once the batch clears the threshold.
batched ETH
- 4Reserve vaultContract
Custodies pending ETH and records the share balance the reserve is known to hold. Has no withdrawal path to an arbitrary address.
conversion request
- 5Brokerage adapterOff-chain
Converts ETH to USD, places the order with the broker, and writes back share count and average fill price with a signed attestation.
shares acquired
- 6DistributorContract
Accrues share entitlements pro rata to BANK balances and enforces the per-address claim cooldown.
claim
- 7HolderActor
Pulls accrued shares whenever their window is open.
Components
BANK token
A standard ERC-20 with one addition: transfers involving a registered pool address route a fee to the router. Every other transfer is a plain ERC-20 transfer with no hook, which keeps wallet-to-wallet movement cheap and predictable.
The pool registry is append-only and behind the timelock. A new pool can be marked taxable, but an existing entry cannot be silently repointed at a different address.
Fee router
Receives ETH, holds it, and splits it according to the allocation parameter. It has exactly four destinations: the reserve vault, the liquidity module, the operations address, and the buffer. It has no function that transfers to an arbitrary recipient, which is what makes the allocation meaningful rather than aspirational.
Reserve vault
Accumulates the 70% earmarked for equity and holds it until a batch clears 0.25 ETH. The vault is the accounting authority for the reserve: it records each fill as a share count and an average price, and it is the only contract the distributor trusts for share supply.
Brokerage adapter
The single off-chain component. A permissioned service with two capabilities: convert vault ETH to USD, and report a fill back to the vault. It cannot mint, cannot move BANK, and cannot withdraw to an address of its choosing — the settlement destination is fixed at deployment.
Distributor
Tracks entitlement per address using an accumulator rather than a per-holder loop, so distribution cost does not scale with holder count. It enforces the claim cooldown and is the only contract that can reduce a holder’s unclaimed balance.
The trust boundary
| Component | Trust required | Enforced by |
|---|---|---|
| BankhoodToken | None | Immutable ERC-20 logic, append-only pool registry |
| FeeRouter | None | Fixed destination set, no arbitrary transfer |
| ReserveVault | None for accounting | On-chain fill records, public balance |
| BrokerageAdapter | Trusted to execute honestly | Multisig control, price collar, third-party attestation |
| Distributor | None | Accumulator maths, per-address cooldown |
Lifecycle of one fee
1 swap trader buys BANK in the pool with 1.00 ETH
2 token transfer hook detects a taxable counterparty
3 router 0.03 ETH captured, FeeCollected emitted
4 router split applied: 0.021 to vault, rest to liquidity/ops/buffer
5 vault balance now 0.184 ETH, still under the batch threshold
6 swap further trades push the vault to 0.26 ETH
7 vault threshold cleared, PurchaseRequested emitted
8 adapter quote taken, 0.26 ETH converted to USD
9 adapter market order placed during Nasdaq hours
10 adapter FillReported: 8.61 shares at an average of 94.88
11 vault share supply increased, accumulator index advanced
12 distributor every holder's entitlement grows pro rata
13 holder claim() called after the cooldown, shares transferredSteps 1 to 7 and 11 to 13 are contract calls anyone can verify. Steps 8 to 10 are the adapter, and each one emits an event with the numbers it acted on so the off-chain leg is auditable after the fact.
Why it is split this way
- The router cannot buy. Separating collection from execution means a bug in the purchase path cannot drain collected fees.
- The vault cannot distribute. The distributor reads share supply but the vault cannot push shares to holders, so a compromised distribution path cannot reach the reserve.
- The adapter cannot account. It reports fills; the vault decides what to record. An adapter that lies produces a discrepancy against the attestation rather than a silent theft.
- The token cannot be upgraded. It is the one component holders cannot exit from, so it has no proxy. See security.