Skip to main content
ph.outflowRate() and ph.inflowRate() return rate statistics for the rolling window that caused a cumulative ERC20 flow trigger to invoke an assertion. The getters take no arguments, do not register a trigger, and do not enforce a rate limit.
An assertion that calls either getter must register AssertionSpec.Experimental; Legacy and Reshiram assertions cannot call them.

Interface

Use each getter only in the matching cumulative trigger callback:

When it runs

After deployment, the cumulative watcher tracks the assertion adopter’s balance changes for the configured ERC20 token. It invokes the registered assertion function when net inflow or outflow is strictly greater than thresholdBps of the window-start balance. During that invocation, ph.inflowRate() or ph.outflowRate() returns rate statistics calculated from the same rolling-window data. The getter does not trigger the assertion by itself.

Directional flow

The executor records both inflow and outflow. It derives the directional values as follows: Opposite-direction flow therefore offsets the watched direction. The per-block rates clamp each bucket independently, while the mean uses net flow across the entire retained window.

Rate calculations

All three rate fields are integer values measured in basis points of tvlSnapshot per second.

Peak rate

For every retained block bucket, the executor calculates: bucket rate = floor(net block flow × 10,000 ÷ (tvlSnapshot × 10 seconds)) peakRateBps is the greatest bucket rate. The denominator always uses 10 seconds; it does not use the chain’s actual block interval.

Latest rate

lastRateBps is the bucket rate for the most recent retained block. A previous spike can therefore remain in peakRateBps while lastRateBps falls to a lower value.

Mean rate

The mean uses the active span between the earliest and latest retained buckets: active span = latest bucket timestamp - earliest bucket timestamp + 10 seconds mean rate = floor(net window flow × 10,000 ÷ (tvlSnapshot × active span)) It does not divide by the full configured window when the retained activity covers a shorter span. With one retained bucket, the active span is 10 seconds, so peak, latest, and mean rates are equal.

Returned fields

Edge cases

Calculation example

For a tvlSnapshot of 100,000 tokens: Both results use the fixed 10-second denominator for each block bucket. The timestamps of the first and last retained blocks determine meanRateBps.

Combined inflow and outflow example

This assertion registers both cumulative directions with a low dispatch threshold, reads the matching cumulative and rate contexts, and rejects when either configured limit is exceeded.
Circuit breakers should be paired with invalidation monitoring and an incident-response plan. See Monitoring and incident response.