# see-through
Detection Templates
Full transparency into every detection template ChainAlert offers. This page documents the exact math, algorithms, RPC methods, and inputs for all 18 templates — so you know precisely what is running on your contracts and why an alert fired.
Blockchain Concepts
ChainAlert templates rely on four fundamental EVM primitives. A quick primer before diving into the templates:
Event Logs — when a smart contract emits an event (e.g. Transfer(address,address,uint256)), the EVM writes a log entry into the transaction receipt. These are indexed and queryable via eth_getLogs.
Storage Slots — every contract has 2^256 storage slots, each holding a 32-byte value. Readable via eth_getStorageAt. Standards like ERC-1967 assign well-known slots to proxy metadata.
ABI Encoding — the Application Binary Interface defines how function calls and event parameters are encoded into bytes. ChainAlert uses ABI definitions to decode raw log data into typed arguments like addresses, uint256 values, and bytes32 hashes.
Balance Queries — eth_getBalance returns the native token balance (ETH, MATIC, etc.) and eth_call can invoke read-only functions like balanceOf without submitting a transaction.
Token Activity
Templates that monitor ERC-20 token transfer events for volume and frequency anomalies.
Large Transfer
freehighERC-20 Transfer events where the transferred value exceeds a user-defined threshold.
How it works
Listens for Transfer(address,address,uint256) events on the monitored contract. When one is emitted, decodes the value argument and compares it against the configured threshold as a BigInt.
Inputs: threshold, tokenAddress (optional)
Repeated Transfer
promediumN or more Transfer events sent to the same recipient within a rolling time window.
How it works
Uses a Redis sorted set keyed by recipient address. Each Transfer event adds a timestamped entry. Before evaluating, stale entries outside the window are pruned. If the remaining count meets or exceeds the threshold, the detection fires.
Inputs: countThreshold, windowMinutes
Balance
Templates that poll on-chain balances and alert on drops, thresholds, or anomalies.
Fund Drainage
freecriticalToken or native balance dropping by X% or more within a rolling time window.
How it works
The state poller records balance snapshots at each poll interval. Within the configured window, the maximum recorded balance is compared to the current balance. If the percentage drop (in basis points) meets or exceeds the threshold, the alert fires.
Inputs: dropPercent, windowMinutes, tokenAddress (optional)
Balance Low
freemediumToken or native balance falling below an absolute threshold value.
How it works
The state poller reads the current balance via eth_getBalance or an ERC-20 balanceOf call. If the value is less than the configured minimum, the detection fires.
Inputs: minBalance, tokenAddress (optional)
Native Balance Anomaly
freehighBidirectional native balance changes — both sudden drops and unexpected surges — beyond a percentage threshold.
How it works
Tracks the maximum and minimum native balance within a rolling window. Computes both a drop percentage (from the max) and a rise percentage (from the min). If either exceeds the configured threshold, the detection fires.
Inputs: dropPercent, windowMinutes, pollIntervalMs
Governance
Templates that detect ownership changes, role mutations, proxy upgrades, pause toggles, and storage-level state changes.
Ownership Transfer
freecriticalOwnershipTransferred and OwnershipTransferStarted events from OpenZeppelin-style Ownable contracts.
How it works
Listens for both OwnershipTransferred(address,address) and OwnershipTransferStarted(address,address) event signatures. Any match triggers an alert immediately with the previous and new owner addresses.
Inputs: none
Role Change
freehighRoleGranted and RoleRevoked events from AccessControl-style contracts, with optional filtering to a specific role hash.
How it works
Listens for RoleGranted(bytes32,address,address) and RoleRevoked(bytes32,address,address) events. If a roleHash filter is provided, only events matching that specific role trigger an alert.
Inputs: roleHash (optional)
Proxy Upgrade (Event)
freecriticalUpgraded(address) events emitted by UUPS and Transparent proxies during an upgrade.
How it works
Listens for the Upgraded(address) event signature defined by ERC-1967. Any match triggers an alert with the new implementation address.
Inputs: none
Multisig Signer Change
freehighAddedOwner and RemovedOwner events from Gnosis Safe / Safe multisig wallets.
How it works
Listens for AddedOwner(address) and RemovedOwner(address) event signatures used by Safe contracts. Any match triggers an alert with the affected signer address.
Inputs: none
Pause State Change
freehighPaused and Unpaused events from OpenZeppelin Pausable contracts.
How it works
Listens for Paused(address) and Unpaused(address) event signatures. Any match triggers an alert indicating the contract was paused or unpaused and by whom.
Inputs: none
Proxy Upgrade (Storage Slot)
freecriticalChanges to the ERC-1967 implementation storage slot, including silent upgrades that bypass event logs.
How it works
Polls the well-known ERC-1967 implementation slot via eth_getStorageAt at a configurable interval. Compares the current 32-byte value to the previously recorded value. If they differ, the detection fires.
Inputs: pollIntervalMs (optional, default 60s)
Storage Anomaly
prohighA storage slot value suddenly deviating from its rolling average, indicating potential parameter manipulation.
How it works
Maintains a rolling window of the last 100 storage snapshots. Computes the mean and measures the percentage deviation of the current value. If the deviation exceeds the configured threshold, the detection fires.
Inputs: slot, percentThreshold, pollIntervalMs
Custom
Flexible templates for monitoring any event, storage slot, view function, or transaction pattern with user-defined parameters.
Custom Event
freemediumAny event matching a user-provided signature, with optional parameter filtering using comparison operators.
How it works
Listens for the event matching the provided signature hash. When decoded, optionally evaluates a single parameter against a filter condition (eq, gt, lt, gte, lte, neq).
Inputs: eventSignature, eventName, filterField, filterOp, filterValue
Custom Storage Slot
prohighChanges or threshold crossings on any user-specified EVM storage slot.
How it works
Polls the provided storage slot via eth_getStorageAt. Evaluates one of three condition types: simple change detection, above-threshold, or below-threshold comparison.
Inputs: slot, conditionType, conditionValue, pollIntervalMs
Custom View Function
promediumChanges or threshold crossings on the return value of any read-only contract function.
How it works
Calls the specified view function via eth_call at each poll interval. Decodes the return value and evaluates it against the configured condition: change detection, threshold comparison, or windowed percent change from a rolling mean.
Inputs: functionSignature, args, returnType, conditionType, conditionValue, pollIntervalMs
Custom Function Call
freehighTop-level transactions calling a specific function on the monitored contract.
How it works
Computes the 4-byte function selector from the provided signature via keccak256. For each transaction to the monitored address, compares the first 4 bytes of tx.input against the selector. Optionally filters on decoded parameters.
Inputs: functionSignature, functionName, filterField, filterOp, filterValue
Custom Event Frequency
promediumA user-defined event being emitted N or more times within a rolling window, optionally grouped by a parameter.
How it works
Uses the same Redis sorted-set windowed counting mechanism as Repeated Transfer, but for any event signature. Optionally groups counts by a decoded parameter field.
Inputs: eventSignature, eventName, countThreshold, windowMinutes, groupByField
Event Frequency Spike
prohighA sudden spike in event emission rate compared to a longer baseline period.
How it works
Maintains two sliding windows: a short observation window and a longer baseline window. Computes the average rate over the baseline, then measures the percentage increase of the observation count over that baseline average. Fires if the spike percentage exceeds the threshold and the baseline has sufficient data.
Inputs: eventSignature, observationMinutes, baselineMinutes, increasePercent, minBaselineCount
Summary Table
All 18 templates at a glance — mechanism, expected latency, and the primary RPC method used.
| Template | Mechanism | Latency | RPC Method |
|---|---|---|---|
| Large Transfer | Event log | Same block | eth_getLogs |
| Repeated Transfer | Event log + Redis window | Same block | eth_getLogs |
| Fund Drainage | Balance polling | Poll interval | eth_getBalance / eth_call |
| Balance Low | Balance polling | Poll interval | eth_getBalance / eth_call |
| Native Balance Anomaly | Balance polling | Poll interval | eth_getBalance |
| Ownership Transfer | Event log | Same block | eth_getLogs |
| Role Change | Event log | Same block | eth_getLogs |
| Proxy Upgrade (Event) | Event log | Same block | eth_getLogs |
| Multisig Signer Change | Event log | Same block | eth_getLogs |
| Pause State Change | Event log | Same block | eth_getLogs |
| Proxy Upgrade (Storage Slot) | Storage polling | Poll interval | eth_getStorageAt |
| Storage Anomaly | Storage polling + rolling avg | Poll interval | eth_getStorageAt |
| Custom Event | Event log | Same block | eth_getLogs |
| Custom Storage Slot | Storage polling | Poll interval | eth_getStorageAt |
| Custom View Function | eth_call polling | Poll interval | eth_call |
| Custom Function Call | Transaction matching | Same block | eth_getLogs (trace) |
| Custom Event Frequency | Event log + Redis window | Same block | eth_getLogs |
| Event Frequency Spike | Event log + dual window | Same block | eth_getLogs |
Known Limitations
Transparency means being upfront about what these templates cannot do.
Polling latency is not instant — storage, balance, and view-function templates depend on poll intervals. A change between polls is detected at the next poll, not at the moment it occurs. Default interval is 60 seconds.
Event templates miss silent writes — if a contract modifies state without emitting an event, event-based templates will not detect it. Use storage slot monitoring as a complementary layer.
Windowed templates need warm-up — Fund Drainage, Native Balance Anomaly, Storage Anomaly, and Event Frequency Spike all rely on historical data. They will not fire until enough snapshots or events have been collected to fill the baseline window.
BigInt precision, not floating point — all threshold comparisons use BigInt arithmetic (integer math). Percentage calculations use basis points (10000 = 100%) to avoid rounding errors. Thresholds must be specified in the token's smallest unit (e.g. wei, not ETH).
RPC provider reliability — all templates depend on RPC responses. If a provider is down or returns stale data, detection may be delayed. ChainAlert uses redundant providers and automatic failover, but brief gaps are possible.
Cooldowns suppress duplicates — after an alert fires, subsequent matches within the cooldown window are suppressed. This prevents alert fatigue but means rapid repeat incidents may only generate one notification.
Internal transactions are not covered — Custom Function Call matches top-level tx.input data only. Function calls made via internal transactions (contract-to-contract) are not matched by this template.