7.7 KiB
7.7 KiB
ARCHITECTURE.md — System Map
Compressed overview for AI agents. Read this first, drill into source for details.
Contract Architecture
Kraiken.sol (ERC-20 token)
├── liquidityManager: address (set once, immutable after)
│ └── LiquidityManager.sol (ThreePositionStrategy)
│ ├── optimizer: Optimizer (private immutable ref)
│ ├── pool: IUniswapV3Pool
│ ├── kraiken: Kraiken
│ └── Positions: Floor, Anchor, Discovery
├── stakingPool: address
│ └── Stake.sol
│ ├── Staking positions with tax rates
│ ├── Snatch mechanics (competitive staking)
│ └── getPercentageStaked(), getAverageTaxRate()
└── feeDestination: address (protocol revenue — both WETH and KRK fees go HERE, not back to holders)
Optimizer.sol (UUPS Upgradeable Proxy)
├── Reads: stake.getPercentageStaked(), stake.getAverageTaxRate()
├── Computes: sentiment → 4 liquidity params
├── Versions: Optimizer, OptimizerV2, OptimizerV3, OptimizerV3Push3
└── Admin: single address, set at initialize()
Key Relationships
- Kraiken → LiquidityManager: set once via
setLiquidityManager(), reverts if already set - LiquidityManager → Optimizer:
private immutable— baked into constructor, never changes - LiquidityManager → Kraiken: exclusive minting/burning rights
- Optimizer → Stake: reads sentiment data (% staked, avg tax rate)
- Optimizer upgrades: UUPS proxy, admin-only
_authorizeUpgrade() - feeDestination receives both WETH and KRK fees: during
recenter(), Uniswap V3 fee collection produces both tokens. WETH fees AND KRK fees are forwarded tofeeDestination(seeLiquidityManager._scrapePositions()). - feeDestination is a conditional-lock (not set-once):
setFeeDestination()(deployer-only) allows repeated changes while the destination is an EOA, enabling staged deployment and testing. The moment a contract address is set,feeDestinationLockedis set totrueand no further changes are allowed. A CREATE2 guard also blocks re-assignment if the current destination has since acquired bytecode. This differs from Kraiken'sliquidityManager/stakingPoolwhich are strictly set-once. - feeDestination KRK excluded from outstanding supply:
_getOutstandingSupply()subtractskraiken.balanceOf(feeDestination)before computing scarcity, because protocol-held KRK cannot be sold into the floor and should not inflate the supply count. This subtraction only occurs whenfeeDestination != address(0) && feeDestination != address(this)(seeLiquidityManager.sol:324); when feeDestination is unset or is LM itself the balance is not subtracted. - Staking pool KRK excluded from outstanding supply:
_getOutstandingSupply()also subtractskraiken.balanceOf(stakingPoolAddr), because staked KRK is locked and similarly cannot be sold into the floor.
Three-Position Strategy
All managed by LiquidityManager via ThreePositionStrategy abstract:
| Position | Purpose | Behavior |
|---|---|---|
| Floor | Safety net | Deep liquidity at VWAP-adjusted prices |
| Anchor | Price discovery | Near current price, width set by Optimizer |
| Discovery | Fee capture | Borders anchor, ~3x price range (11000 tick spacing) |
Recenter = atomic repositioning of all three positions. Triggered by anyone, automated by txnBot.
Recenter constraints (enforced on-chain):
- 60-second cooldown:
MIN_RECENTER_INTERVAL = 60(LiquidityManager.sol:61). A second recenter cannot succeed until at least 60 seconds have elapsed since the last one. - 300-second TWAP window:
PRICE_STABILITY_INTERVAL = 300(PriceOracle.sol:14).recenter()validates the current tick against a 5-minute TWAP average (±MAX_TICK_DEVIATION = 50ticks). The pool must have at least 300 seconds of observation history; a fallback to a 60 000-second window is used if recent data are unavailable.
Optimizer Parameters
getLiquidityParams() returns 4 values:
capitalInefficiency(0 to 1e18) — capital buffer levelanchorShare(0 to 1e18) — % allocated to anchor positionanchorWidth(ticks) — width of anchor positiondiscoveryDepth(0 to 1e18) — depth of discovery position
Sentiment calculation: sentiment = f(averageTaxRate, percentageStaked)
- High sentiment (bull) → wider discovery, more fee revenue for protocol treasury
- Holder value comes from asymmetric slippage (structural ETH accumulation), NOT from fee reinvestment
- Low sentiment (bear) → tight around floor, maximum protection
Stack
On-chain
- Solidity, Foundry toolchain
- Uniswap V3 for liquidity positions
- OpenZeppelin for UUPS proxy, Initializable
- Base L2 (deployment target)
Indexer
- Ponder (
services/ponder/) — indexes on-chain events - Schema:
services/ponder/ponder.schema.ts - Stats table with 168-slot ring buffer (7d × 24h × 4 segments)
- Ring buffer segments: [ethReserve, minted, burned, tax] (slot 3 being changed to holderCount)
- GraphQL API at port 42069
Landing Page
- Vue 3 + Vite (
landing/) @wagmi/vuefor wallet connection (WalletButton, WalletCard)@tanstack/vue-query— required peer dep for@wagmi/vue; provides TanStack Query context for Wagmi's reactive hooks@harb/web3shared composables (useAccount,useConnect,useDisconnect,useTokenBalance)- Three variants: HomeView (default), HomeViewOffensive (degens), HomeViewMixed
- Docs section: HowItWorks, Tokenomics, Staking, LiquidityManagement, AIAgent, FAQ
- LiveStats component polls Ponder GraphQL every 30s
Staking Web App
- Vue 3 (
web-app/) - Password-protected (multiple passwords in LoginView.vue)
- ProtocolStatsCard shows real-time protocol metrics
Infrastructure
- Docker Compose on 8GB VPS
- Woodpecker CI at ci.niovi.voyage
- Codeberg repo: johba/harb (private)
- Container registry: registry.niovi.voyage
Directory Map
harb/
├── onchain/ # Solidity contracts + Foundry
│ ├── src/ # Contract source
│ ├── test/ # Forge tests
│ └── foundry.toml # via_ir = true required
├── services/
│ ├── ponder/ # Indexer service
│ │ ├── ponder.schema.ts
│ │ ├── src/
│ │ │ ├── helpers/stats.ts # Ring buffer logic
│ │ │ ├── lm.ts # LiquidityManager indexing
│ │ │ └── stake.ts # Stake indexing
│ └── txnBot/ # Automation bot: calls recenter() and payTax() on profitable opportunities
├── landing/ # Landing page (Vue 3)
│ ├── src/
│ │ ├── components/ # LiveStats, KFooter, WalletCard, etc.
│ │ ├── views/ # HomeView variants, docs pages
│ │ └── router/
├── web-app/ # Staking app (Vue 3)
│ ├── src/
│ │ ├── components/ # ProtocolStatsCard, etc.
│ │ └── views/ # LoginView, StakeView, etc.
├── kraiken-lib/ # Shared TypeScript helpers (bigint math, ABIs, encoding) for frontend and indexer
│ └── src/ # abis, format, ids, position, snatch, staking, subgraph, taxRates, version
├── containers/ # Docker configs, entrypoints
├── tools/ # Developer utilities
│ ├── push3-transpiler/ # Compiles Push3 programs to Solidity Optimizer
│ ├── push3-evolution/ # Evolutionary optimizer: fitness, mutation, crossover, seed generation
│ └── deploy-optimizer.sh # Script to deploy a new Optimizer version
├── docs/ # This file, PRODUCT-TRUTH.md
└── .woodpecker/ # CI pipeline configs