Skip to content

fix(settlement): enforce MAX_FEE_BPS ceiling independent of governance config (#521) - #589

Merged
therealjhay merged 4 commits into
Betta-Pay:mainfrom
Hollujay:fix/521-max-fee-bps-settlement
Aug 19, 2026
Merged

fix(settlement): enforce MAX_FEE_BPS ceiling independent of governance config (#521)#589
therealjhay merged 4 commits into
Betta-Pay:mainfrom
Hollujay:fix/521-max-fee-bps-settlement

Conversation

@Hollujay

Copy link
Copy Markdown
Contributor

Closes #521

Problem

bettapay_common::constants::MAX_FEE_BPS = 5_000 (50%) was documented as intended for settlement adoption, but settlement's setters only checked against BPS_DENOMINATOR (10_000 / 100%):

if rule.platform_fee_bps > BPS_DENOMINATOR || rule.network_fee_bps > BPS_DENOMINATOR {
    panic_with_error!(env, SettlementError::InvalidFeeBps);
}

The tighter 50% ceiling was only ever enforced by validate_fee_against_governance, which calls into the governance contract's get_fee_config and is a no-op when governance hasn't configured a FeeConfig yet:

if fee_config.is_void() {
    return; // no ceiling to enforce
}

So before governance is configured, set_settlement_rule / set_default_rule would accept a per-fee value up to 100% — twice the intended 50% ceiling — and the two contracts enforced inconsistent fee ceilings.

Fix

Added an explicit MAX_FEE_BPS check alongside the existing MIN_FEE_BPS/BPS_DENOMINATOR checks in:

  • settlement_contract/src/settlement.rs — the public set_settlement_rule and set_default_rule entry points.
  • settlement_contract/src/admin.rs — the internal _set_settlement_rule / _set_default_rule used by the scheduled-operation execution path (these had the same gap and no governance validation at all).

Both now reject any per-fee value above MAX_FEE_BPS, independent of whether a governance FeeConfig exists. validate_fee_against_governance still tightens the ceiling further once governance does configure one — it's a floor for the ceiling, not the source of it.

Also updated the MAX_FEE_BPS and SettlementError::InvalidFeeBps doc comments, which previously described the pre-fix behavior.

Test plan

  • Added to settlement_contract/src/tests/admin_tests.rs:
    • set_settlement_rule_rejects_platform_fee_above_max_fee_bps
    • set_settlement_rule_rejects_network_fee_above_max_fee_bps
    • set_settlement_rule_accepts_fee_at_max_fee_bps_ceiling (5000 bps still valid)
    • set_default_rule_rejects_fee_above_max_fee_bps
  • cargo test --workspace passes (33 governance + 20 settlement tests)
  • cargo build --workspace --target wasm32-unknown-unknown --release succeeds for both contracts

…e config (Betta-Pay#521)

bettapay_common::constants::MAX_FEE_BPS (5000 bps / 50%) was intended
for settlement adoption per its doc comment, but settlement only
capped each fee at BPS_DENOMINATOR (10000 bps / 100%). The tighter
50% ceiling was enforced solely through validate_fee_against_governance,
which is a no-op until a governance FeeConfig exists - so before
governance is configured, set_settlement_rule and set_default_rule
would accept a per-fee value up to 100%, twice the intended ceiling.

Add an explicit MAX_FEE_BPS check to both settlement.rs's public
set_settlement_rule/set_default_rule entry points and admin.rs's
internal _set_settlement_rule/_set_default_rule (used by the
scheduled-operation execution path), so the ceiling holds regardless
of whether governance has configured anything yet.

Closes Betta-Pay#521

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@therealjhay

Copy link
Copy Markdown
Contributor

Kindly fix the merge conflicts in this pull request.

Hollujay and others added 3 commits August 17, 2026 08:57
Merging main left duplicate SettlementError discriminants
(InvalidFeeBps defined twice, MerchantMissing colliding with Paused)
and admin.rs calling the events:: module/AdminTransferred without
importing them, breaking the CI build.

Closes Betta-Pay#521
@Hollujay

Copy link
Copy Markdown
Contributor Author

Ci failure fixed @therealjhay

@therealjhay
therealjhay merged commit f010741 into Betta-Pay:main Aug 19, 2026
1 check passed
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.

MAX_FEE_BPS (5000) in common constants is enforced only by governance

2 participants