Skip to content
ANVIL · LOCAL DEVNETWallet · Not connected

Documentation

How Forma works

A summary of the protocol specification. The complete, normative version lives in docs/PROTOCOL.md in the repository, alongside SECURITY, ECONOMICS and DEPLOYMENT. Not audited. Testnet only.

TestnetDisclosure

This protocol is deployed on Base Sepolia for testing and demonstration. FORGE and stFORGE have no intended monetary value.

The smart contracts have not undergone an independent security audit. Estimated rates are derived from current testnet state and are not returns.

Do not deposit assets of value.

01

Overview

Forma turns a stake into a position: an on-chain object with its own terms, its own reward stream, its own routing policy and an ERC-721 token representing ownership of all of it. Five contracts: FormaStaking (all accounting and funds), PositionNFT, PositionRenderer (on-chain metadata), LiquidStakingVault (ERC-4626 stFORGE) and ForgeToken (test token with a rate-limited faucet). None are upgradeable.

02

Pools & multipliers

A pool is a lock tier, not a separate reward stream. Every position in every pool shares one stream, split by weight = principal × multiplier. If each pool had its own stream, all positions inside it would carry the same multiplier and it would cancel out.

Terms are snapshotted at stake time: unlock time, multiplier and early-exit penalty. A pool manager changing a pool later affects only new positions. The stake transaction also carries the lock and multiplier you reviewed; if the pool changed in between, it reverts instead of giving you different terms.

03

Reward accounting

Standard accumulator-per-weight accounting with one global stream:

emitted  = rewardRate × Δt / 1e18            (rewardRate = tokens/s × 1e18)
acc     += emitted × 1e30 / totalWeight
pending  = settled + weight × (acc − checkpoint) / 1e30

Every weight change settles the position first, so nothing is counted twice. All divisions round down in the protocol's favour. The reward reserve is tracked separately from principal; payouts only ever come from the reserve. Emissions during periods with no stakers, forfeited rewards and penalties become idle and are re-streamed at the next funding.

Rates you see: emission rate (protocol-wide tokens per second); your reward rate (your weight share of it); estimated APR (on-chain previewStake, annualised while boosted); estimated APY (APR compounded daily, computed in the app). All assume today's emission and total weight persist, which they will not. They are testnet estimates, not returns.

04

Locks & boost expiry

Withdrawal requires the unlock time to have passed. A multiplier rewards being locked, so at unlock the boost expires: the next time the position is touched (claim, compound, withdraw, top-up), or when anyone calls the permissionless expireBoost, its weight drops to 1.00×. Until then it keeps its boosted weight. This lazy expiry is a documented limitation.

05

Emergency withdrawal

Always available, including while paused. It returns principal minus an early-exit penalty (snapshotted, only while locked, waived while the protocol is paused), forfeits all pending rewards, burns the NFT and cannot be undone. Penalties and forfeited rewards go back to the reward reserve for remaining stakers; no admin ever receives them. The app shows the exact on-chain preview before you confirm.

06

Position NFTs

Every position mints an ERC-721 with tokenId = positionId. Positions are transferable, with rights attached to the token: the lock, multiplier and pending rewards stay on the position, so transferring can never bypass a lock. Pending rewards travel with the NFT (a seller can claim first — price accordingly). Metadata and the SVG image are generated on-chain from position state.

07

Reward routing

Keep: claims pay the owner. Compound: anyone may compound for a capped keeper fee. Redirect: claims pay a chosen wallet, which may also trigger them. Only the owner can configure routing. Routing records who set it; if the NFT changes hands, the new owner does not inherit it — effective routing falls back to Keep.

08

Compounding & keepers

Compounding moves pending rewards into principal at the active multiplier; it never extends a lock, and compounded tokens stay locked until unlock. Owners compound for free. Third parties can compound only positions that opted in, and receive min(protocol fee, owner's cap) — the protocol fee is capped at 5% and your cap is snapshotted, so later fee changes cannot charge you more. A minimum amount and per-position cooldown bound griefing.

09

Liquid staking vault (stFORGE)

An ERC-4626 vault that holds one no-lock Forma position and compounds it. totalAssets = idle + position principal + pending rewards, from internal accounting — tokens donated directly to the vault are ignored, so donation/inflation attacks cannot move the share price. Shares use a virtual decimals offset of 6 (stFORGE has 24 decimals), the first deposit must meet the pool minimum, zero-share deposits and zero-asset redemptions revert, and slippage-protected entry points are used by this app.

If FormaStaking is paused, the vault cannot move funds. Its admin can trigger an emergency exit during a pause; after three days of pause anyone can. An exit forfeits the vault's pending rewards and makes redemptions pay pro-rata from idle FORGE. stFORGE is not risk-free.

10

Roles & pause

Separate roles: admin (roles, unpause, recover foreign tokens, set NFT renderer), pool manager (pool terms for new positions), reward manager (fund/re-time the stream, keeper fee within bounds), pauser (pause only). No role can move user principal or withdraw the reward reserve. Pausing disables staking, withdrawals, claims, compounding and funding; emergency withdrawal, routing changes, boost expiry and NFT transfers stay available. A pause can cost pending rewards (if you emergency-exit) but can never trap principal.

11

Risks & limitations

  • Not audited. Automated tests, fuzzing, invariants and static analysis are not an audit.
  • Testnet only. FORGE and stFORGE have no intended monetary value. Do not deposit assets of value.
  • Boosts persist after unlock until the position is touched or kicked.
  • Pending rewards on a transferred NFT can be claimed by the seller before transfer.
  • Funding a new stream resets its schedule; annualised figures assume nothing changes.
  • Indexed activity comes from RPC logs over a bounded range and can be incomplete.
  • Vault holders share one position; an emergency exit forfeits the vault's pending rewards for everyone.

12

Contracts

ANVIL · LOCAL DEVNET · v0.1.0

ForgeToken0x5FbDB2315678afecb367f032d93F642f64180aa3
FormaStaking0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0
LiquidStakingVault0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e
PositionNFT0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512
PositionRenderer0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9

Base Sepolia deployment: pending. The app shows no placeholder addresses until a real deployment manifest exists. Live contract view →