intrepidshape/elm-web3-ui/4.0.0

Web3.Ui.BlockRefresh

A refresh policy for chain-derived data -- the missing piece between Block.watchBlockNumber and your RemoteCalls.

Chain data goes stale exactly once per block, so refetch cadence should be expressed in blocks, not milliseconds:

type alias Model =
    { ticker : BlockRefresh.Ticker
    , balance : RemoteCall String
    }


-- init
{ ticker = BlockRefresh.init (EveryNBlocks 5), ... }


-- on each { tag = "blockNumber" } port message:
let
    ( ticker, refetch ) =
        BlockRefresh.onBlock number model.ticker
in
if refetch then
    ( { model | ticker = BlockRefresh.markRefreshed number ticker
      , balance = RemoteCall.request "bal-..." model.balance }
    , web3Cmd (Balance.encode ...)
    )
else
    ( { model | ticker = ticker }, Cmd.none )

That worked example IS the balance watcher: balances re-read on-cadence, driven by chain time. Any RemoteCall slots in the same way.

type Policy
= EveryBlock
| EveryNBlocks Int
| Manual

EveryBlock -- refetch on every new block. EveryNBlocks n -- refetch when at least n blocks have passed since the last refresh. Manual -- never fire from block signals (the app refetches explicitly).

type Ticker

Tracks the policy and the block height of the last refresh. Opaque.

Change cadence, keeping the last-refreshed watermark.

onBlock : Int -> Ticker -> ( Ticker, Bool )

Feed a new block number in; the Bool says "fire your refetch now". The first observed block always fires (except under Manual) -- data that has never been fetched is infinitely stale.

Record that the refetch was actually fired at this height. Separate from onBlock so a refetch you decided to skip (e.g. one already in flight) doesn't advance the watermark.