Skip to content

fix: two-step fee recipient, checked fee arithmetic, slash floor, tok… - #151

Open
Helix-xi wants to merge 1 commit into
stellar-vortex-protocol:mainfrom
Helix-xi:fix/all-issues
Open

fix: two-step fee recipient, checked fee arithmetic, slash floor, tok…#151
Helix-xi wants to merge 1 commit into
stellar-vortex-protocol:mainfrom
Helix-xi:fix/all-issues

Conversation

@Helix-xi

Copy link
Copy Markdown

fix: two-step fee recipient, checked fee arithmetic, slash floor & SEP-41
token probe

Closes #30
Closes #31
Closes #32
Closes #33

──────────────────────────────────────────────────────────────────────────

Summary

This PR addresses four security and correctness issues identified in the
intent settlement contract.

──────────────────────────────────────────────────────────────────────────

#30 — Two-step fee recipient confirmation

set_fee_recipient has been replaced with a propose_fee_recipient /
accept_fee_recipient two-step pattern, mirroring the existing
transfer_admin flow. The admin proposes a new address, and that address
must explicitly authorize the handover before it becomes active. A typo'd
or unreachable address can no longer silently misroute every future
protocol fee and slash payment.

#31 — Explicit checked arithmetic for protocol fee calculation

The fee calculation in fill_intent (fill_amount * PROTOCOL_FEE_BPS /
10_000) now uses checked_mul / checked_div with a dedicated FeeOverflow
error, making the overflow-safety property visible in the code itself
rather than relying solely on the overflow-checks = true release profile
setting in Cargo.toml.

#32 — Minimum slash amount floor

slash_solver now applies .max(1) to the computed slash_amount. Without
this, a bond_amount below 10 (in the token's smallest unit) would round to
a zero slash via integer division, letting a failed fill go economically
unpunished. A non-zero bond now always produces a non-zero slash.

#33 — SEP-41 interface validation in add_allowed_dst_token

Before storing an allowlist entry, add_allowed_dst_token now calls
decimals() on the candidate address as a lightweight SEP-41 interface
probe. If the address doesn't implement the token interface the call traps
and reverts the transaction, surfacing the error at admin time rather than
silently allowing a non-token that would only fail later inside
fill_intent's transfer call.

──────────────────────────────────────────────────────────────────────────

Tests

  • admin_can_transfer_admin updated to use the new propose/accept flow
  • fill_intent_fee_overflow_returns_error — verifies FeeOverflow fires at
    i128::MAX / 5 + 1
  • fill_intent_fee_at_boundary_does_not_overflow — sanity check at the
    exact boundary
  • slash_tiny_bond_always_yields_nonzero_slash — uses direct storage
    injection to place a bond of 5, confirms slash ≥ 1
  • add_allowed_dst_token_rejects_non_token_contract — passes a non-token
    contract address, asserts failure and no storage write
  • add_allowed_dst_token_accepts_real_token — positive case confirming a
    real SAC passes the probe

…en probe

Closes stellar-vortex-protocol#30 - propose_fee_recipient / accept_fee_recipient two-step pattern
replaces set_fee_recipient; admin proposes, new recipient must authorize
to confirm, preventing silent misrouting from a typo'd address.

Closes stellar-vortex-protocol#31 - fill_intent fee calculation uses checked_mul / checked_div
with panic_with_error(FeeOverflow) on overflow, making the safety
property visible in code rather than relying solely on Cargo.toml
overflow-checks = true.

Closes stellar-vortex-protocol#32 - slash_solver applies a .max(1) floor to slash_amount so
a non-zero bond is never economically unpunished due to integer
division rounding to zero on tiny bond values.

Closes stellar-vortex-protocol#33 - add_allowed_dst_token calls token_client.decimals() as a
lightweight SEP-41 interface probe before storing the allowance;
non-token contracts trap and revert, surfacing the error at admin
time rather than silently inside fill_intent later.

Tests: add tests for all four fixes including fee overflow boundary,
tiny bond slash floor via direct storage injection, non-token
contract rejection, and updated admin_can_transfer_admin to use
the new two-step propose/accept flow.
@drips-wave

drips-wave Bot commented Jul 26, 2026

Copy link
Copy Markdown

@Helix-xi Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

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

Labels

None yet

Projects

None yet

1 participant