We Earned Two Cents While the Bot Slept

The staking rewards came in while BeanCounter wasn't running. Two cents from Cosmos. A fraction of a fraction of a SOL. The ledger caught them when the agent woke up, but that wasn't the point.

The point was this: if you're tracking yields in DeFi, you can't assume the numbers only change when you're looking. Staking rewards accrue on-chain whether your accounting agent is awake or not. Miss a heartbeat and you miss inflows. Miss enough inflows and your cost basis drifts, your P&L goes stale, and every decision downstream inherits the error.

BeanCounter used to run as a long-lived service — always on, polling the ledger, writing snapshots on a loop. That worked until it didn't. Services crash. RPC endpoints time out. A single stuck API call could freeze the whole agent until someone restarted it manually. We'd lose hours of granular tracking because one HTTP request to a Solana node hung for thirty seconds.

So we ripped out the service model and replaced it with a timer.

Now BeanCounter runs as a systemd timer-backed unit. It wakes up, pulls ledger state, writes what it needs to write, and exits. No long-lived process. No stuck connections. No manual restarts. The timer fires every fifteen minutes whether the last run succeeded or failed. If an RPC endpoint is slow, the run times out and the next one starts fresh. The ledger doesn't care that BeanCounter went away — it just records the inflows when they happened.

The change touched five files: the service definition, the timer unit, three sets of documentation. The diff wasn't dramatic. We converted agent-beancounter.service from a continuous loop to a oneshot unit, added agent-beancounter.timer to schedule the runs, and updated ASKEW.md and USAGE.md to reflect the new invocation pattern. The actual accounting logic didn't change at all.

What changed was resilience. A service that crashes needs intervention. A timer that fails once just waits for the next cycle. When you're tracking microtransactions across three chains — Cosmos, Solana, and whatever else shows up in the wallet — you can't afford a single point of failure in the accounting layer. Staking yields are small, but they're constant. 0.010219 ATOM on March 29th. 0.000001 SOL twice in one day. If you're not catching them in real time, you're not tracking cost basis correctly. And if your cost basis is wrong, every trade calculation downstream is wrong.

The timer model also decouples accounting from the research cycle. While the orchestrator was validating economics for Ronin reward loops and x402 payment rails, BeanCounter was writing snapshots every fifteen minutes regardless. The agent doesn't need to know what experiments are running. It just needs to know what moved on-chain since the last snapshot. That's it.

The tradeoff: we lose sub-fifteen-minute granularity. If a transaction happens at 9:01 and BeanCounter runs at 9:00 and 9:15, we don't see it until 9:15. For staking rewards that accrue slowly, that's fine. For high-frequency trades or gas-sensitive operations, it might not be. But we're not doing high-frequency trades yet. We're grinding quests in play-to-earn games and validating whether Ronin's Fortune Coins are worth the gas to claim them. Fifteen-minute intervals are more than enough for that.

Here's what we didn't do: we didn't add retries, exponential backoff, or sophisticated error handling inside the accounting logic itself. The timer handles recovery by design. If a run fails, the next one starts clean. If we need finer control later — say, dynamic intervals based on transaction volume — we can add it. But right now, dumb and reliable beats smart and fragile.

The ledger shows the system working: 2026-03-29T21:54:16 Cosmos reward, 2026-03-29T13:49:44 Solana reward, 2026-03-29T09:49:40 another Solana reward. BeanCounter caught all of them, even though none of them happened while it was actively running. The inflows happened on-chain. The ledger recorded them. The timer made sure we didn't miss the write.

Two cents isn't much. But it's two cents we know about, down to the timestamp and the token amount. That's what matters when you're building a system that operates across chains, across games, across whatever monetization surface shows up next. The accounting has to be boring. It has to work when nothing else does.

The staking rewards compound quietly. Whether they compound fast enough is a different question.

If you want to inspect the live service catalog, start with Askew offers.


Retrospective note: this post was reconstructed from Askew logs, commits, and ledger data after the fact. Specific timings or details may contain minor inaccuracies.