const BlocksPerDay
BlocksPerDay is the length of a check-in window, in blocks. Chosen so a window is a meaningful stretch of chain activity while keeping tests and demos quick to reason about.
Package streak is an on-chain check-in streak tracker: call CheckIn once per "day" to keep a streak alive, miss one a...
⚠️ Experimental — generated with no human supervision by the daily MCP pipeline to exercise gno tooling. Not audited. See r/moul/x/daily.
Call CheckIn() once per "day" to keep a streak alive. Miss one and the current
streak resets to 1 — but your best streak is never lowered, so a broken run
costs the run, not the record.
There is no wall clock on-chain, so a "day" is a fixed window of BlocksPerDay
(1000) blocks: day = ChainHeight() / BlocksPerDay. Every streak decision is
therefore a pure function of block height — deterministic, replayable, and
impossible to game by waiting for a favourable timestamp.
CheckIn() → extends or restarts your streak, returns it
Current(addr) → live streak (0 once the window has lapsed)
Best(addr) → record streak, never lowered
Day() → current day index
/r/moul/x/daily/streak/v0 → leaderboard, ranked by best streak
/r/moul/x/daily/streak/v0:g1... → one address's standing
Current deliberately reports the live truth rather than the stored value:
once a window lapses it returns 0 even though the record still holds the old
number until the next check-in rewrites it.
Checking in twice in the same window is rejected — the streak only moves when
the window does. Only an EOA can check in (IsUserCall), so another realm
can't farm streaks on your behalf.
Built for gno 0.9. Live on both testnets (agent address):
Part of moul/gno-contracts — moul's versioned gno.land contracts. See the repository for the full catalog, build/test tooling, and usage.
Dependency graph:

🧪 Highly experimental — potentially vibe-coded. Not audited; may break, change, or be removed at any time. Do not use with anything of value. Full disclaimer: DISCLAIMER.
Package streak is an on-chain check-in streak tracker: call CheckIn once per "day" to keep a streak alive, miss one and it resets to 1.
There is no wall clock on-chain, so a "day" here is a fixed window of BlocksPerDay blocks: day = ChainHeight() / BlocksPerDay. That makes every streak decision a pure function of block height — deterministic, replayable, and impossible to game by waiting for a favourable timestamp.
State is per-caller and append-only in spirit: an address's best streak is never lowered, so breaking a run costs the current streak but not the record.
This is a stateful app with nothing reusable to extract, so it ships as a lone realm rather than a p/ library + demo pair.
BlocksPerDay is the length of a check-in window, in blocks. Chosen so a window is a meaningful stretch of chain activity while keeping tests and demos quick to reason about.
Best returns addr's record streak, which is never lowered.
CheckIn records a check-in for the caller and returns the resulting streak.
Checking in twice in the same window is rejected — the streak only moves when the window does. A gap of exactly one window continues the streak; any larger gap restarts it at 1.
Current returns addr's live streak — 0 once a window has been missed, even though the stored value only updates on the next check-in.
Day returns the current day index.