Skip to content

Dust accounting / sweep for residual rounding dust (audit L01 follow-up) #2673

Open

Description

@thedavidmeister

Follow-up to audit L01 (#2623), now documented in NatSpec. This tracks the optional mitigation the audit recommends: an explicit dust-accounting or sweep mechanism so the orphaned rounding residue isn't permanent.

Background

pullTokens rounds lossy float→fixed-decimal conversions up (the contract never receives less than it credits); pushTokens rounds down (never sends more than it debits). This keeps the orderbook solvent — real token balance is always ≥ the sum of vault balances — but every lossy conversion leaves a sub-token-unit residue belonging to no vault. Over high volume / unusual decimals this accumulates as orphaned dust with no recovery path. Bounded by < 1 base unit per conversion; never an insolvency risk.

The hard part: there is no per-token total

Vault balances live in sVaultBalances[owner][token][vaultId] (nested mapping); there is no aggregate of total obligation per token, so the sweepable excess balanceOf(this, token) − Σ(vault balances) cannot be computed on-chain today (summing all vaults is infeasible). Any sweep needs a new per-token total-obligation accumulator maintained on every balance-changing path (deposit, withdraw, the pull/push above, the vault-0 settlements, clear) so that

sweepable(token) = IERC20(token).balanceOf(address(this)) − sTotalObligation[token]

is exact and can only ever release the provable excess above all vault obligations.

Design questions

  • Recipient: protocol treasury, a configured address, or a permissionless caller (sweep-as-incentive)?
  • Accumulator correctness (main risk): it must be updated in the fixed-decimal units actually transferred (the rounded amounts, not the float) on every path, so it matches balanceOf. Getting it wrong either traps more dust or — worse — lets a sweep dip into vault-backed balance.
  • Gas: one extra SSTORE per balance change vs. leaving dust orphaned.
  • Rebasing / fee-on-transfer tokens: balanceOf diverges from the accumulator independently of rounding — decide whether sweep covers those or only rounding dust.

Acceptance

  • A sweep/accounting path that can only ever move the provable un-vaulted excess.
  • Invariant test: after arbitrary deposit/withdraw/take/clear sequences, balanceOf ≥ sTotalObligation; sweeping releases exactly balanceOf − sTotalObligation and never breaks a subsequent legitimate withdraw.

Severity: Low (no insolvency; tiny amounts) — accounting/UX quality improvement.

Activity

  1. linear commented on Jun 6, 2026

    @linear
  2. thedavidmeister commented on Jun 10, 2026

    @thedavidmeister
    ContributorAuthor

    it would actually be possible to both account this exactly and also be conservative

    whenever tokens actually move and there is a precision loss the remainder could be tracked per sender/receiver as a future credit to realize the next time tokens move for that user

  3. thedavidmeister commented on Oct 27, 2026

    @thedavidmeister
    ContributorAuthor

    Ruling: the dust credit ledger (#2702) lands in V8, not the V7 release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions