lectern
← /keynote

sepolia dogfood ledger

Every transaction that exercises a contract surface on Base Sepolia. Each entry says what moved and what it proved or clarified about the architecture. Resets on every redeploy.

livechain 84532 · Base Sepolia

Architecture v2 deployed + full dogfood ledger green on Base Sepolia 2026-05-23. 27 broadcasts across 5 flows exercise both custom contracts AND all 3 vetted primitives. Adversarial revert paths covered by the test suite.

redeploy workflow

If any custom contract is redeployed for ANY reason, the ledger resets to step 1. We do not ship partial coverage. Sepolia ledger reflects the most recent contiguous run only.

  1. 1.Custom contracts deploy

    Mock USDC + Mock KEYNOTE + LecternBoostEscrow + LecternStakingVault addresses

    forge script script/Deploy.s.sol --rpc-url base_sepolia --broadcast --verify
  2. 2.Dogfood 1 — StakingVault

    Tier 0→1→2→3 transitions + adversarial revert paths

    forge script script/Dogfood1_Staking.s.sol --rpc-url base_sepolia --broadcast
  3. 3.Dogfood 2 — BoostEscrow

    boost → settle → claim + adversarial revert paths

    forge script script/Dogfood2_BoostEscrow.s.sol --rpc-url base_sepolia --broadcast
  4. 4.Dogfood 3 — Sablier LockupLinear

    Founder stream with 1h cliff + cancel + post-cliff withdraw

    forge script script/Dogfood3_SablierStream.s.sol --rpc-url base_sepolia --broadcast
  5. 5.Dogfood 4 — Sablier MerkleInstant

    Per-epoch Merkle campaign creation + claim + hasExpired check

    forge script script/Dogfood4_MerkleInstant.s.sol --rpc-url base_sepolia --broadcast
  6. 6.Dogfood 5 — 0xSplits PushSplit

    Split creation + USDC + KEYNOTE distribute

    forge script script/Dogfood5_PushSplit.s.sol --rpc-url base_sepolia --broadcast
  7. 7.Ledger refresh

    Updated /keynote/sepolia content with every tx hash + what-moved + what-proved

    ./script/build-dogfood-ledger.sh > lib/keynote-sepolia-ledger.json

If step 1 re-runs (deploy addresses change), steps 2–7 all re-run. The previous ledger entries are archived at /keynote/sepolia/archive/<date> but the live ledger only ever reflects one contiguous run.

dogfood flows (6)

each flow is a single foundry script. ledger entries appear as transactions broadcast on sepolia.

StakingVault tier transitions

green
script: Dogfood1_Staking.s.sol
exercises: LecternStakingVault (custom)

BoostEscrow boost → settle → claim

green
script: Dogfood2_BoostEscrow.s.sol
exercises: LecternBoostEscrow (custom)

Sablier LockupLinear (evaluated as FounderPay candidate, then superseded by OZ VestingWallet)

green
script: Dogfood3_SablierStream.s.sol
exercises: SablierLockup (vetted; not used in current architecture — see /keynote#mainnet)

Sablier MerkleInstant (Pro allocation analog)

green
script: Dogfood4_MerkleInstant.s.sol
exercises: SablierFactoryMerkleInstant (vetted)

0xSplits PushSplit (Pro renewal routing analog)

green
script: Dogfood5_PushSplit.s.sol
exercises: PushSplitFactoryV2.2 + SplitsWarehouse (vetted)

Gnosis Safes (4 multisigs: 3 USDC + 1 KEYNOTE)

green
script: DeploySafes.s.sol + DeployEngagementTokensSafe.s.sol
exercises: Safe v1.4.1 SafeProxyFactory + SafeL2 singleton (vetted)

why this format

tx

Receipt. Block-explorer-verifiable. The thing that actually happened on chain — not a screenshot, not a description.

what moved

State change in plain language. What tokens went where, what flag flipped, what tier was reached.

what it proved

The architectural claim the transaction validates — or the assumption it forces into the open.

Reading the receipt alone is not enough. Reading the description alone is not enough. The third column is where claims get pinned to evidence.

mainnet pre-launch (historical)

The Safes that received USDC routing slices + KEYNOTE-from-renewals were the first mainnet contracts to land, before any custom logic. Same v1.4.1 template + 2-of-3 signer set as the Sepolia mirrors. See /keynote#contracts for the full live footprint that came next.

Base · chain id 8453

pre-launch provisioning

4 Safes deployed 2026-05-23. All are 2-of-3 multisigs with the same {team, ops, advisor} signer set as the Sepolia mirrors. Each Safe is independently verifiable on Basescan via getOwners() + getThreshold().

safes (4)

safe v1.4.1 · 2-of-3 multisig · same signers across all 4

40% USDC slice — hosting, RPC, gas reserves, audit, app store, legal. Owner of both PushSplits.

30% USDC slice — sponsored casts, contests, partner integrations; also catches FounderPay reroute during 60-day cliff

15% USDC slice — opportunistic / emergency / unplanned audit findings (memo required on spend)

Runway-tied % of KEYNOTE-from-renewals — token-denominated contests, bounties, partnerships

push splits (2)

0xsplits v2.2 · immutable params · owner = OperationsTreasury

Receives all USDC inflow (LP fees + Pro USDC subs). Routes 40% to OperationsTreasury, 30% to EngagementBudget, 15% to Reserve, 15% to FounderPay payroll deposit EOA. Owner = OperationsTreasury Safe.

LP-fee KEYNOTE buyback (85/15)
0x53Ee4a31456B0132B033d538C94b6c2933E14AeF

Receives 20% of LP fees as KEYNOTE (auto-bought-back by Liquid via FeePreference.Liquid). Routes 85% to Pro allocation pool EOA, 15% to staker yield pool EOA. Token-agnostic — does not depend on the specific token contract.

pending mainnet artifacts

deployed in sequence ahead of token launch

  • ·KEYNOTE-from-renewals PushSplit (runway-tier-0; recipients = BurnAddress + EngagementTokens Safe + FounderTokens VestingWallet)
  • ·First Pro-allocation Sablier MerkleInstant campaign (epoch 1)

abandoned artifacts (3)

superseded

on-chain artifacts that were deployed before a design pivot; left here for honest accounting (small gas loss, not in active routing)

  • Deployed 2026-05-23 as 2-of-3 USDC accumulator; superseded by OZ VestingWallet design same day. No funds, not in routing.

  • Deployed 2026-05-23 as 2-of-3 KEYNOTE accumulator; superseded by OZ VestingWallet design same day. No funds, not in routing.

  • Placeholder recipient on the USDC PushSplit's 15% slot. Will be replaced with the FounderPay VestingWallet address via OperationsTreasury Safe `updateSplit` action after VestingWallet deploy post-token-launch.

audit surface (what we wrote vs what we vendored)

Two custom contracts; four vetted primitives. The smallest surface area we could draw and still hit the spec.

on-chain footprint

6 things on chain · 2 are ours

~249 lines of code we wrote · the rest is shared infrastructure with billions in tvl

custom · 2
LecternBoostEscrow

Boost · settle · claim

153 loc · solidity 0.8.28

LecternStakingVault

Stake · tier · discount

96 loc · solidity 0.8.28

vetted primitives · 4
OZ VestingWallet

Founder cliff enforcement

Sablier MerkleInstant

Per-epoch Merkle distribution

0xSplits PushSplit

Revenue routing

Safe 2-of-3

Multisig wallets

smaller audit surface · same economic mechanics · primitives are audited shared infrastructure (oz, sablier, 0xsplits, safe)

live testnet inventory

Base Sepolia · chain id 84532

live

Architecture v2 deployed + full dogfood ledger green on Base Sepolia 2026-05-23. 27 broadcasts across 5 flows exercise both custom contracts AND all 3 vetted primitives. Adversarial revert paths covered by the test suite.

custom contracts (2)

solidity 0.8.28 · internal review · audit deferred until $500k tvl

boost(castHash, amount) → admin settleEpoch(epochId, root, total) → claim with Merkle proof (12-week window) → admin reclaim of unclaimed after window. Per-cast running totals back the curated-feed ranking.

loc
153
tests
31

stake / unstake. tierOf / discountBpsOf / isProEligible view ABI for LicenseGate.swift dual-source Pro check.

loc
96
tests
14

vetted primitives (4)

sablier + 0xsplits · same address sepolia + mainnet (deterministic)
OZ VestingWallet OZ 5.x
deploy per-instance (same source)

Founder cliff enforcement — deploy per-instance for FounderPay USDC (60d cliff) + FounderTokens KEYNOTE (12mo cliff). beneficiary = founder cold; start = tokenLaunchTimestamp + cliff; duration = 1s.

mainnet: deploy per-instance from `@openzeppelin/contracts/finance/VestingWallet.sol`
SablierFactoryMerkleInstant airdrops-v3.0
0x863b326Ef7Ce2B82d881931bE577Ba04dd4D58BE

Per-epoch Merkle distribution — weekly Pro allocation + weekly staker yield campaigns. Native 12-week expiration, admin clawback on expiry.

mainnet: 0xD5a361519F6c417Cc4bCfcC15501191C816705a6

Revenue routing — USDC 40/30/15/15 split, LP-fee KEYNOTE 85/15 split, KEYNOTE-from-renewals per-runway-tier splits

mainnet: 0x8E8eB0cC6AE34A38B67D5Cf91ACa38f60bc3Ecf4

Failed-send fallback for PushSplit distributions

mainnet: 0x8fb66F38cF86A3d5e8768f8F1754A24A6c661Fb8

mock tokens (testnet only)

mint() is public — grab some for testing

Test ERC-20 with public mint() — anyone can grab tokens for testnet experimentation. NOT the production token.

Test ERC-20 with public mint() — 6 decimals, mirrors Base mainnet USDC. NOT the production stablecoin.

test coverage

unit tests
52
across 2 custom contracts
line coverage
100%
every executable line tested
branch coverage
100%
every conditional path tested
invariant runs
16k+
random call sequences
forge test · 52/52 passing. forge coverage · 100% lines + 100% branches + 100% functions across LecternBoostEscrow + LecternStakingVault. forge test --match-contract Invariants · 16,384 random calls per run.

internal security review

in progress

Internal uncertified review · 80% common-vector coverage · formal external audit deferred until $500k tvl

  • ·Reentrancy
  • ·Arithmetic overflow / underflow
  • ·Access control / privilege escalation
  • ·Front-running / MEV
  • ·Denial of service / griefing
  • ·Initialization correctness
  • ·Logic and state-transition bugs
  • ·Storage layout / collision
  • ·Token integration assumptions
  • ·Approval and allowance handling
  • ·External call safety
  • ·Boundary input validation