Skip to content

send_payment has no self-payment guard, unlike every other stellar_send payment path #11

Description

@abayomicornelius

Problem

ContractConfig (stellar_send/src/lib.rs lines 62-73) has an active: bool field, documented as "Whether new payments are accepted. Set to true by initialize." It's set unconditionally to true in initialize (line 135) and then never read anywhere else in the crate — not in send_payment, send_path_payment, send_batch_payment, fulfill_payment_request, or execute_subscription. There is also no pause()/unpause() function that could ever set it to false.

Why it matters

This is dead state that implies functionality (pausability) which does not exist — directly related to issue #3's README-vs-implementation mismatch, but distinct: even purely at the Rust/storage level (ignoring the README), active is inert. Anyone reading ContractConfig's doc comment or calling get_config and seeing active: true would reasonably assume there's a way to flip it and that payments would then be blocked — neither is true. This is a footgun for integrators building admin tooling against the contract's declared shape.

Detection

grep -n "config.active\|\.active" stellar_send/src/*.rs shows the field is only ever written (in initialize), never read in a conditional, and no test in stellar_send/src/test.rs exercises pausing behavior (because it doesn't exist).

Proposed fix

Either (a) implement it properly — add pause()/unpause() admin-gated functions and an assert_active(&config) check called at the top of every value-moving entrypoint, returning a new StellarSendError::ContractPaused variant, or (b) if pause functionality is out of scope for now, remove the misleading active field entirely until it's actually wired up. Given issue #3 already tracks the README correction and eventual pause/unpause implementation, (a) is likely the better outcome to land alongside that fix rather than duplicating effort — but this issue exists separately because it can be caught and reasoned about purely from the Rust source, without needing to cross-reference the README.

Edge cases

  • If implemented, cancel_subscription/cancel_payment_request should probably remain callable while paused (users should always be able to exit, only new value-movement should block).
  • get_config should still work while paused (read access shouldn't be gated).
  • Pausing mid-batch (send_batch_payment) isn't a real race in Soroban (single-threaded, atomic per invocation) but the guard still needs to be checked once at the top of the call, not per-leg, to avoid wasted work if paused.

Testing strategy

Add test_active_field_currently_unused (documenting today's state, marked to be removed/updated once pause lands) or, preferably, resolve this issue by implementing pause per the sketch above with test_pause_blocks_send_payment, test_unpause_restores_send_payment, and test_paused_contract_allows_cancel_subscription.

Metadata

Metadata

Assignees

No one assigned

    Labels

    GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardOfficial Campaign | FWC26Campaign: Official Campaign | FWC26bugSomething isn't workingcontractsSmart contract logicvery hardVery difficult / senior-level bounty issue

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions