Balance snapshots answer a different question from swaps: “What does this account hold now?” Comparing snapshots can reveal changes even when an event page is unavailable, but the comparison must separate token amount from market value.
Normalize each position
Use networkId:tokenAddress as the key and store amount and price independently.
def normalize_balances(response):
items = response.get("responseObject", {}).get("balances", [])
positions = {}
for item in items:
balance = item.get("balance") or {}
token_result = item.get("tokenFilterResult") or {}
token = token_result.get("token") or {}
address = balance.get("tokenAddress")
network_id = token.get("networkId")
if not address or network_id is None:
continue
positions[f"{network_id}:{address}"] = {
"networkId": network_id,
"tokenAddress": address,
"amount": balance.get("shiftedBalance", 0),
"priceUsd": token_result.get("priceUSD"),
"symbol": token.get("symbol"),
}
return positions
Classify amount transitions
| Previous | Current | Classification |
|---|---|---|
0 | > 0 | Opened |
> 0 | Larger | Increased |
> 0 | Smaller but positive | Reduced |
> 0 | 0 or absent | Closed |
Use decimal arithmetic and a token-specific tolerance. Tiny dust changes should not create high-priority alerts.
Do not compare value alone
USD value can increase because price moved while the amount stayed constant. Track amount change, price change and value change separately. Respect valuation flags before including an item in portfolio equity.
Correlate with events
A matching swap strengthens the interpretation, but other causes remain possible:
- Wallet transfer or deposit
- Withdrawal
- Token rebase
- Decimal or metadata correction
- Delayed indexing
- Cross-network movement
Label unverified changes as observations. Before execution, confirm the related transaction and current state through the target chain.
Store complete snapshots
Write an immutable snapshot with observedAt, source response ID if available and raw payload reference. Derive transitions in a separate table. This allows replay when comparison logic changes and supports historical portfolio charts.
Balance comparison is excellent for monitoring and reconciliation. It should complement, not replace, swap events and onchain verification.