Smart contracts
Interfaces, events and the deployment address table.
On this page
Interfaces are published ahead of deployment so integrators can build against them and reviewers can argue with them. Signatures may change before audit; anything that changes will be listed in the changelog.
Deployment addresses
| Contract | Address | Status |
|---|---|---|
| BankhoodToken | — | Not yet deployed |
| FeeRouter | — | Not yet deployed |
| ReserveVault | — | Not yet deployed |
| Distributor | — | Not yet deployed |
| Timelock | — | Not yet deployed |
| LiquidityLock | — | Not yet deployed |
IFeeRouter
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
interface IFeeRouter {
/// @notice Accept a fee captured by the token's transfer hook.
/// @dev Reverts unless the caller is the token contract.
function collect(address payer, uint256 notional, bool isBuy)
external
payable;
/// @notice Split the pending balance across the four destinations.
/// @return toReserve Wei forwarded to the reserve vault.
function flush() external returns (uint256 toReserve);
/// @notice Basis points of collected ETH earmarked for HOOD.
function hoodAllocationBps() external view returns (uint16);
/// @notice Wei collected but not yet split.
function pending() external view returns (uint256);
event FeeCollected(
address indexed payer,
uint256 notional,
uint256 feeWei,
bool isBuy
);
event Flushed(
uint256 toReserve,
uint256 toLiquidity,
uint256 toOps,
uint256 toBuffer
);
}IReserveVault
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
interface IReserveVault {
struct Fill {
uint256 ethSpent; // wei converted for this fill
uint256 shares; // 18-decimal share count acquired
uint256 avgPriceUsd; // 8-decimal average fill price
uint64 executedAt; // block timestamp of the report
}
/// @notice Signal that the pending balance has cleared the batch threshold.
function requestPurchase() external returns (uint256 ethQueued);
/// @notice Report a completed brokerage fill. Idempotent per orderId.
/// @dev Restricted to the adapter. Advances the distributor's accumulator.
function reportFill(
bytes32 orderId,
uint256 shares,
uint256 avgPriceUsd
) external;
/// @notice Total HOOD shares backing outstanding entitlements.
function totalShares() external view returns (uint256);
/// @notice Shares held but not yet allocated to holders.
function unallocatedShares() external view returns (uint256);
function fillCount() external view returns (uint256);
function fillAt(uint256 index) external view returns (Fill memory);
event PurchaseRequested(uint256 ethQueued, uint64 requestedAt);
event FillReported(
bytes32 indexed orderId,
uint256 ethSpent,
uint256 shares,
uint256 avgPriceUsd
);
event PurchasesPaused(string reason);
}IDistributor
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
interface IDistributor {
/// @notice Credit a settled batch of shares across taxable supply.
/// @dev Restricted to the reserve vault.
function distribute(uint256 shares) external;
/// @notice Withdraw the caller's entire unclaimed entitlement.
/// @dev Reverts while the caller's cooldown is active.
function claim() external returns (uint256 shares);
/// @notice Settle accrual for an account without withdrawing.
/// @dev Called by the token on every balance change.
function settle(address account) external;
function claimable(address account) external view returns (uint256);
function nextClaimAt(address account) external view returns (uint64);
function accSharesPerToken() external view returns (uint256);
function claimIntervalSeconds() external view returns (uint32);
event Distributed(uint256 shares, uint256 accIndex, uint64 at);
event Claimed(address indexed account, uint256 shares, uint64 at);
event Settled(address indexed account, uint256 credited);
}Events
The indexer is built entirely from these events; there is no privileged data source behind the explorer.
| Event | Emitted by | Feeds |
|---|---|---|
| FeeCollected | FeeRouter | Explorer → Fee payments |
| Flushed | FeeRouter | Reserve totals |
| PurchaseRequested | ReserveVault | Pending batch indicator |
| FillReported | ReserveVault | Explorer → Distributions |
| Distributed | Distributor | Accrual index history |
| Claimed | Distributor | Explorer → Claims, app history |
| PurchasesPaused | ReserveVault | Status banner |
Reading state
Everything the interface displays for a connected wallet comes from three view calls. No signature is required to read any of them.
import { useReadContracts } from "wagmi";
const { data } = useReadContracts({
contracts: [
{ address: BANK, abi: hsrAbi, functionName: "balanceOf", args: [account] },
{ address: DISTRIBUTOR, abi: distributorAbi, functionName: "claimable", args: [account] },
{ address: DISTRIBUTOR, abi: distributorAbi, functionName: "nextClaimAt", args: [account] },
],
});
const [balance, claimable, nextClaimAt] = data ?? [];Conventions
Units
- ETH amounts are wei. Never assume a display value has been scaled for you.
- Share counts carry 18 decimals, matching BANK, so fractional entitlements survive arithmetic without precision loss.
- USD prices carry 8 decimals, matching common oracle conventions.
- Rates are basis points. 300 bps is 3%.
Safety
- Every privileged function is restricted to a named contract, not to an EOA.
reportFillis idempotent perorderId, so a replayed report cannot double-credit the reserve.- Claims settle before transferring and revert on over-allocation against the vault.
- Deployment targets Solidity 0.8.24 on Ethereum mainnet with no delegatecall in the value path.