Core concepts
The vocabulary you need to read the rest of the docs.
Basket
A basket is a smart-contract vault (the Basket contract) that holds 2–20 tokenized stocks and issues its own ERC-20 shares. Owning shares means owning a proportional claim on everything the vault holds. A basket is created by a creator, who sets the constituents, weights, and fees, and earns 90% of the fees the basket charges.
Shares
Shares are standard 18-decimal ERC-20 tokens minted by the basket. Your slice of the vault is yourShares / totalSupply. Shares are minted when you buy and burned when you redeem.
DEAD_SHARES(1e15) — at creation, a tiny fixed amount of shares is minted to a dead address and locked forever. This bootstraps a non-zero supply floor and protects against first-depositor / inflation attacks.
Constituents, weights, and trackedBalance
The constituents are the underlying tokens the basket holds. Each has a weight (in basis points, summing to 10,000) that the creator picks at deploy. The vault records how much of each token it holds in trackedBalance — its own internal accounting, which is what mint/redeem math uses (not the raw ERC-20 balance, so stray tokens sent directly to the vault can't distort accounting).
NAV and price-per-share
- NAV (Net Asset Value) — the total USD value of everything the vault holds:
Σ trackedBalance_i × price_i(normalized by each token's decimals). Prices come from Chainlink via OracleLib. - Price-per-share —
NAV / totalSupply.
Important: NAV is used only for display, zap pricing, and fee accounting. It never gates deposits or withdrawals. If a price feed is stale, NAV is flagged stale and that constituent contributes 0 — but in-kind mint and redeem keep working, because they don't use prices at all.
Two ways to buy: in-kind vs. zap
| In-kind | Zap (one-click) | |
|---|---|---|
| You provide | The underlying tokens, in the vault's current ratio | A single stablecoin (USDG) |
| Mechanism | mintInKind — deposit tokens, get shares |
HoodZapRouter.zapIn — swaps USDG into every constituent, then mints |
| Pricing | Oracle-free, pro-rata | Depends on Uniswap v4 liquidity for each constituent |
| Always available? | Yes | Only if every constituent has a usable swap route |
The reverse works too: redeem in-kind to get the underlying tokens back, or zap out to swap them all to USDG in one transaction.
Fees
Three fees, all capped and all split 90% creator / 10% protocol (PROTOCOL_CUT_BPS = 1000):
| Fee | Cap | When charged |
|---|---|---|
| Entry | 3% (300 bps) | On every mint (in-kind or zap) |
| Exit | 1% (100 bps) | On every redeem |
| Management | 3%/yr (300 bps) | Streamed continuously via share dilution |
The management fee accrues as newly-minted shares over time, split to creator/treasury; it slightly dilutes existing holders rather than charging them directly.
The wire-format contract (for API/app developers)
Every on-chain numeric amount is represented as a raw base-10 integer string — digits only, no decimal point — in the value's smallest unit. Divide by the token's scale to display:
- Shares, NAV, USD values → 18 decimals (divide by 1e18).
- USDG amounts → 6 decimals (divide by 1e6).
- Basis-point fields, returns,
chainId, timestamps → plain JSON numbers / ISO strings, not raw integers.
Never parse a raw-integer field as a JavaScript number — use a big-integer type. This is the single most common integration mistake.
USDG
USDG is the stablecoin used as the entry/exit asset for zaps. It has 6 decimals (so 1000000 = 1 USDG). It is itself a whitelisted token so its price feed is available for accounting.