You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
stellar_send::send_payment (stellar_send/src/lib.rs lines 186-237) never checks from != to. Every other fee-charging entrypoint in the same crate does enforce this: send_batch_payment rejects recipient == from (batch.rs line 46-48, StellarSendError::SelfPaymentNotAllowed), create_payment_request rejects payer == requester (payment_request.rs lines 69-72), and create_subscription rejects payer == recipient (subscription.rs lines 72-74). send_payment — the single most-used entrypoint — is the one place this guard is missing.
Why it matters
This is an inconsistency, not just a missing nicety: three of four payment paths treat self-payment as an explicit error (StellarSendError::SelfPaymentNotAllowed, variant 15 in error.rs), but the primary path silently allows it. A self-payment still charges the protocol fee (transferred to fee_collector) while the "net" amount just goes right back to the sender — functionally a fee-only burn with no economic transfer, which is probably not intended given the other three paths explicitly forbid the pattern. It also means integrators who defensively rely on SelfPaymentNotAllowed being enforced everywhere (reasonable given the other three call sites) will be surprised in production.
Detection
Call send_payment(from: X, to: X, ...) in stellar_send/src/test.rs — it currently succeeds and returns a PaymentRecord, whereas the equivalent self-referential call on any of the other three entrypoints already returns Err(SelfPaymentNotAllowed).
Proposed fix
Add the same guard used elsewhere, right after loading config:
if from == to {returnErr(StellarSendError::SelfPaymentNotAllowed);}
Edge cases
Decide whether this should be a hard error or an intentionally-allowed no-op-ish "fee-only" pattern (some protocols deliberately allow "pay yourself" as a way to test connectivity/pay a fee for an unrelated reason) — given the other three entrypoints already made the "disallow" call, consistency strongly favors disallowing here too, but worth a maintainer sign-off since it's technically a behavior change for existing integrators who may depend on today's permissive behavior.
Add test_send_payment_self_payment_rejected asserting Err(StellarSendError::SelfPaymentNotAllowed), mirroring the existing test_create_subscription_self_payment / equivalent pattern already used for the other three entrypoints (naming inferred from the SelfPaymentNotAllowed usages; verify exact existing test names in stellar_send/src/test.rs and follow the same convention).
Problem
stellar_send::send_payment(stellar_send/src/lib.rslines 186-237) never checksfrom != to. Every other fee-charging entrypoint in the same crate does enforce this:send_batch_paymentrejectsrecipient == from(batch.rsline 46-48,StellarSendError::SelfPaymentNotAllowed),create_payment_requestrejectspayer == requester(payment_request.rslines 69-72), andcreate_subscriptionrejectspayer == recipient(subscription.rslines 72-74).send_payment— the single most-used entrypoint — is the one place this guard is missing.Why it matters
This is an inconsistency, not just a missing nicety: three of four payment paths treat self-payment as an explicit error (
StellarSendError::SelfPaymentNotAllowed, variant 15 inerror.rs), but the primary path silently allows it. A self-payment still charges the protocol fee (transferred tofee_collector) while the "net" amount just goes right back to the sender — functionally a fee-only burn with no economic transfer, which is probably not intended given the other three paths explicitly forbid the pattern. It also means integrators who defensively rely onSelfPaymentNotAllowedbeing enforced everywhere (reasonable given the other three call sites) will be surprised in production.Detection
Call
send_payment(from: X, to: X, ...)instellar_send/src/test.rs— it currently succeeds and returns aPaymentRecord, whereas the equivalent self-referential call on any of the other three entrypoints already returnsErr(SelfPaymentNotAllowed).Proposed fix
Add the same guard used elsewhere, right after loading
config:Edge cases
send_path_payment(a fifth payment path) has the same gap — it never checksfrom == toeither, and arguably matters even more there once issue send_path_payment simulates DEX swaps 1:1 instead of calling a real router — no actual price discovery #2's real router lands, since a self-directed path swap could be used to launder slippage/fee asymmetries. Should be fixed in the same PR.Testing strategy
Add
test_send_payment_self_payment_rejectedassertingErr(StellarSendError::SelfPaymentNotAllowed), mirroring the existingtest_create_subscription_self_payment/ equivalent pattern already used for the other three entrypoints (naming inferred from theSelfPaymentNotAllowedusages; verify exact existing test names instellar_send/src/test.rsand follow the same convention).