Skip to content

feat(examples): balance-tracker example module (BLEU-847)#19

Open
brunota20 wants to merge 1 commit into
feat/example-price-alert-bleu-846from
feat/example-balance-tracker-bleu-847
Open

feat(examples): balance-tracker example module (BLEU-847)#19
brunota20 wants to merge 1 commit into
feat/example-price-alert-bleu-846from
feat/example-balance-tracker-bleu-847

Conversation

@brunota20

Copy link
Copy Markdown
Collaborator

Summary

Second canonical SDK example: `modules/examples/balance-tracker/`. Subscribes to blocks, reads `eth_getBalance(addr)` for a configured address list, persists each reading under `balance:{addr}` in local-store, and emits a Warn log when the delta against the prior reading exceeds `change_threshold` wei.

What it demonstrates (complementing price-alert)

Pattern price-alert balance-tracker
`chain::request` `eth_call` via sol! function raw `eth_getBalance` (no ABI)
`alloy-sol-types` yes no — keeps wasm small
State (`local-store`) none per-address `balance:{addr}` U256 LE
Diff-against-last-seen n/a core of the module

Numbers

  • 13 host tests pass
  • `cargo clippy --target wasm32-wasip2 -p balance-tracker -- -Dwarnings` clean
  • `.wasm` 99 KB optimised (vs price-alert 206 KB — ~half because there's no sol! / alloy-sol-types pulled in)

Module-internal

  • `Settings { addresses: Vec, change_threshold: U256 }` parsed once at `init`; stored in `OnceLock`.
  • `parse_balance_hex(json)` — strip JSON quotes + `0x` + hex-decode. Handles `"0x"` (zero balance), rejects unquoted / non-hex bodies.
  • `parse_addresses(raw)` — comma-separated with whitespace tolerance + empty-segment skipping; rejects empty list.
  • `abs_diff` / `parse_u256_le` / `u256_to_le_bytes` — pure utilities.

Stacks on #18 (BLEU-846 price-alert example).

Linear: BLEU-847.

Test plan

  • `cargo test -p balance-tracker` — 13 host tests.
  • `cargo clippy --target wasm32-wasip2 -p balance-tracker -- -Dwarnings`.
  • `cargo clippy -p balance-tracker --tests -- -Dwarnings`.
  • `cargo build --target wasm32-wasip2 --release -p balance-tracker` — 99 KB.
  • End-to-end against a Sepolia RPC + 2 EOAs — pending the multi-module supervisor.

New `modules/examples/balance-tracker/` — second canonical SDK
example. Subscribes to blocks, reads `eth_getBalance(addr)` for a
configured address list, persists each reading under
`balance:{addr}` in local-store, and emits a Warn-level log when
the delta against the prior reading exceeds `change_threshold`
wei.

Demonstrates:

- `chain::request` with a non-`eth_call` method (raw JSON-RPC
  with hand-built params), to balance the price-alert example's
  sol! / `eth_call` flow.
- `local-store` `get` / `set` per-key persistence with U256 LE
  serialisation as the wire format.
- The "diff against last seen" pattern reusable across indexer
  modules (transfer monitors, allowance trackers, …).

Module-internal:

- `Settings { addresses: Vec<Address>, change_threshold: U256 }`
  parsed from `[config]` once at `init` and stored in
  `OnceLock<Settings>`.
- `parse_balance_hex(json)` — strips JSON quotes and the `0x`
  prefix, decodes the remaining hex into a U256. Handles `"0x"`
  (zero balance), rejects unquoted / non-hex bodies.
- `parse_addresses(raw)` — comma-separated list with whitespace
  tolerance and empty-segment skipping; rejects empty lists.
- `abs_diff` + `parse_u256_le` + `u256_to_le_bytes` — pure utilities
  with edge-case coverage.

module.toml:

- `capabilities = ["logging", "chain", "local-store"]` (the
  superset that distinguishes this example from price-alert,
  which only needs chain + logging).
- `[[subscription]]` block on Sepolia (chain_id 11155111).
- `[config]` ships defaults pointing at two anvil-style EOAs and
  a 0.1 ETH change threshold.

13 host tests; clippy clean on host + wasm32-wasip2. `.wasm` is
99 KB optimised — about half of price-alert's 206 KB because it
does not pull `alloy-sol-types` into the link tree (no ABI work;
all decoding is hex/U256).
@linear-code

linear-code Bot commented Jun 17, 2026

Copy link
Copy Markdown

BLEU-847

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant