Skip to main content

Module pool_open_error

Module pool_open_error 

Source
Expand description

PaymentPool revert decoding: the failure-class taxonomy for the buyer-side openPool path (#966) and the pool-lifecycle reverts.

The buyer open_pool kernel (decdn-client) can fail three ways that an operator must triage differently:

  • InsufficientDeposit — a misconfiguration: the node’s USDC balance or standing allowance cannot cover the deposit; or the deposit is zero — either as requested, or as the balance delta actually received under a fee-on-transfer token; or the credited deposit is below the governance-set minDeposit Sybil floor. (A zero deposit cannot be requested: both the daemon and the CLI validate buyer_working_deposit_micro_usdc / the --working-deposit-micro-usdc flag > 0 at config load, so the reachable zero here is the received-delta one.) The fix is operator-side (fund or resize the deposit), not infrastructure.
  • ContractRevert — any other deterministic on-chain revert (a paused contract, a future revert reason). The deposit was not escrowed; the cause is on-chain state, not this node’s wallet or RPC.
  • RpcError — a transient transport/RPC fault (connectivity, a timed out receipt wait, a transaction-nonce blip — the sender’s tx sequence number, unrelated to a voucher). Retrying typically clears it; the fix is infrastructure-side.

Splitting these lets the node bump the matching decdn_pool_open_failures_{insufficient_deposit,contract_revert,rpc_error}_total sibling counter (a plain counter field carries no label dimension, so each class is its own counter rather than one labeled {reason=…} series) and emit the same reason token as a structured-log field, so a dashboard distinguishes “the operator under-funded the gas/USDC wallet” from “the RPC endpoint is flaky” — the whole point of #966. The classification is driven by the alloy error’s revert data: a deterministic revert carries ABI-encoded error data (caught at gas estimation, so it surfaces on send() before a receipt), whereas a transport fault carries none. A present revert selector is decoded against the known insufficient-deposit error signatures to split InsufficientDeposit from a generic ContractRevert. A token that reverts in the older Error(string) style carries no custom-error selector, so its message is matched for the same shortfall — an under-funded wallet reads as InsufficientDeposit whichever revert style the deployed USDC uses.

The module also decodes topUp’s PoolNotOpen (is_pool_not_open) and the closePool / reclaim reverts (PoolLifecycleRevert).

Structs§

BelowMinDeposit
PaymentPool.openPool reverts this when the credited deposit — the received balance delta — is below the governance-set minDeposit Sybil floor. The fix is operator-side: raise buyer_working_deposit_micro_usdc to at least the network minimum. Custom error with signature BelowMinDeposit(uint256,uint256) and selector 0x0267cc62.
ERC20InsufficientAllowance
OpenZeppelin v5 ERC20: the standing allowance is below the transfer amount. Surfaces when the one-time approve never ran (or was set too low) for the PaymentPool spender. Custom error with signature ERC20InsufficientAllowance(address,uint256,uint256) and selector 0xfb8f41b2.
ERC20InsufficientBalance
OpenZeppelin v5 ERC20: the spender’s balance is below the transfer amount. openPool’s safeTransferFrom bubbles this up verbatim when the node’s USDC balance cannot cover the deposit. Custom error with signature ERC20InsufficientBalance(address,uint256,uint256) and selector 0xe450d38c.
GraceWindowActive
PaymentPool.reclaim reverts this before the pool’s dispute deadline. Declared here only for its 4-byte selector. Custom error with signature GraceWindowActive() and selector 0xad1b69f7.
NotPoolOwner
PaymentPool.topUp and closePool revert this when the caller is not the pool owner. Declared here only for its 4-byte selector. Custom error with signature NotPoolOwner() and selector 0xcfa0ad4e.
PoolNotClosing
PaymentPool.reclaim reverts this when the pool is not Closing. Declared here only for its 4-byte selector. Custom error with signature PoolNotClosing() and selector 0x9a96814d.
PoolNotOpen
PaymentPool.topUp and closePool revert this when the pool is Closing or Closed. Declared here only for its 4-byte selector. Custom error with signature PoolNotOpen() and selector 0x14356134.
ZeroAmount
PaymentPool.openPool reverts this when the requested deposit — or the balance delta actually received, under a fee-on-transfer token — is zero. Declared here only for its 4-byte selector, so the classifier needs no live contract binding.

Enums§

PoolLifecycleRevert
A PaymentPool pool-lifecycle revert that closePool or reclaim can raise. Decoding the selector names the cause, so a caller does not have to guess it from the call that failed.
PoolOpenFailureReason
Which class of failure aborted a buyer openPool attempt (#966). Carried through the anyhow error chain as typed context so the metrics layer can bump the matching decdn_pool_open_failures_{reason}_total sibling counter (one counter per class — a plain counter field carries no label dimension) and attach a structured reason log field, while the human-readable message is preserved for logs.

Functions§

is_erc20_allowance_shortfall
Whether an ERC-20 revert is specifically an allowance shortfall (ERC20InsufficientAllowance) — the one class a just-in-time approve can fix. An insufficient-balance revert, a zero-amount revert, or any other selector returns false: an approve cannot recover those, so the caller must treat them as terminal. A string-revert token spells the same shortfall as Error("ERC20: insufficient allowance"), which counts too. Pass alloy’s Error::as_revert_data().
is_pool_not_open
Whether a topUp revert is PoolNotOpen: the pool is Closing or Closed and accepts no funds. Pass alloy’s Error::as_revert_data().