Skip to content

fix: reject limit == i128::MAX in TokenTransferPolicy - #120

Open
alberto-crossmint wants to merge 1 commit into
mainfrom
fix/token-transfer-limit-max
Open

fix: reject limit == i128::MAX in TokenTransferPolicy#120
alberto-crossmint wants to merge 1 commit into
mainfrom
fix/token-transfer-limit-max

Conversation

@alberto-crossmint

Copy link
Copy Markdown
Collaborator

Summary

TokenTransferPolicy arithmetic in extract_transfer_total and check_spending_limit uses saturating adds (checked_add(...).unwrap_or(i128::MAX)). That design is safe for any limit < i128::MAX, because the subsequent new_total > limit comparison correctly rejects saturated values.

It is not safe for limit == i128::MAX:

  • new_total = tracker.spent.checked_add(total_amount).unwrap_or(i128::MAX)
  • if new_total > limitif i128::MAX > i128::MAXfalse
  • Every spend passes, the tracker saturates at i128::MAX, and it stays there.

So limit = Some(i128::MAX) silently degenerates into unlimited spending.

validate_policy already rejects limit <= 0. Extend the guard to also reject limit == i128::MAX, using the same InvalidPolicy error code (the surface to integrators is unchanged: pass a sensible positive bound).

Test plan

  • New test_on_add_rejects_i128_max_limit — registering a signer with limit = Some(i128::MAX) panics with InvalidPolicy (#80).
  • Existing test_on_add_rejects_zero_limit / test_on_add_rejects_negative_limit still pass — same code path, same error.
  • Full suite: 40 token_transfer_policy_test cases pass (39 existing + 1 new).

Risk

Trivial. Anyone who had configured i128::MAX on purpose was misconfigured (unlimited spending dressed up as a tracked cap). If that's the intent, the correct configuration is limit: None, which bypasses the tracker entirely.

extract_transfer_total and check_spending_limit both use
checked_add(...).unwrap_or(i128::MAX) — saturating on overflow. That is
safe as long as the configured limit is strictly less than i128::MAX,
because the subsequent `new_total > limit` check rejects overflowed
values correctly.

But `limit == i128::MAX` degenerates into unlimited spending:
`i128::MAX > i128::MAX` is false, so every spend is approved and the
tracker saturates and stays saturated.

validate_policy already rejects `limit <= 0`; extend it to also reject
`limit == i128::MAX`. Same error code (InvalidPolicy) since the surface
to integrators is unchanged: pass a sensible positive bound.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant