Repository navigation
Conversation
Both testnet cases from the task, as getTransaction answered them, plus the two simulation windows. Red until the code lands. Co-Authored-By: Claude <209825114+claude[bot]@users.noreply.github.com>
…wn code When another transaction used the payer's nonce first, /settle answered transaction_failed or simulation_failed and told the client to sign a new payment, although the payment may have settled there. Now /verify and the settle re-check answer invalid_exact_stellar_payload_nonce_consumed_elsewhere (the payer's nonce entry exists on chain), and a claimed settlement ends with settle_exact_stellar_nonce_consumed_elsewhere when our transaction failed with Error(Auth, ExistingValue) or the pool's simulation failed on a used nonce. Neither carries advice to sign again. Each such record is logged with the fee lost and counted in settlement_nonce_consumed_elsewhere_total. Co-Authored-By: Claude <209825114+claude[bot]@users.noreply.github.com>
The threat model said a reused nonce means the payer signed one payment and it settled; a second entry under the same nonce pays the seller nothing. It now says what a used nonce proves, who can see the entry, why /settle never answers success for another transaction, and the residual. The README lists both new codes and the log; monitoring lists the counter. Co-Authored-By: Claude <209825114+claude[bot]@users.noreply.github.com>
Co-Authored-By: Claude <209825114+claude[bot]@users.noreply.github.com>
…when-entry-landed-elsewhere # Conflicts: # apps/facilitator/src/settlement/reconcile.ts # apps/facilitator/src/settlement/settle.ts
Review fixes for the new answer: - a reopen the checks refused with the nonce-consumed code got 'repeat the same payment' and extra.retryable; both nonce codes now carry no advice at all - /verify's message holds when the nonce was used by our own landing too - the nonce read is bounded to 3 s, as the trustline lookup is, and a failed read is false - resultReason takes the status, so it has no unreachable branch - both testnet cases are pinned through /settle's answer as well Co-Authored-By: Claude <209825114+claude[bot]@users.noreply.github.com>
An RPC without diagnostic events gives the failure no error, so a nonce another transaction used would end as transaction_failed with the old advice. When the cause doesn't tell, /settle now reads the payer's nonce entry: ours failed and wrote none, so an entry means another transaction used it. Co-Authored-By: Claude <209825114+claude[bot]@users.noreply.github.com>
…nswer-when-entry-landed-elsewhere # Conflicts: # lore/1-tasks/active/0141_BUG_settle-answer-when-entry-landed-elsewhere.md
…nswer-when-entry-landed-elsewhere
…its window Co-Authored-By: Claude <209825114+claude[bot]@users.noreply.github.com>
…ts window resultReason decides the final reason in one place and reads the payer's nonce entry when the failure names no Error(Auth, ExistingValue): /settle, its answer after a failed record write, the reconcile sweep and the pool's resolved event. settlement_nonce_consumed_elsewhere_total carries window verify for /verify and /settle's re-check, settle for a record. Co-Authored-By: Claude <209825114+claude[bot]@users.noreply.github.com>
…entation Co-Authored-By: Claude <209825114+claude[bot]@users.noreply.github.com>
The read now has FallbackRpc's per-URL timeout and its failover to the next RPC URL, which the 3 s cut kept from running. A read that still fails keeps the old reason, as before. Co-Authored-By: Claude <209825114+claude[bot]@users.noreply.github.com>
…nswer-when-entry-landed-elsewhere # Conflicts: # lore/1-tasks/active/0141_BUG_settle-answer-when-entry-landed-elsewhere.md
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Anyone who sees the payer's signed auth entry can submit it first in their own transaction. Then our
transaction fails with
Error(Auth, ExistingValue), and/settletold the client "sign a newpayment", although the payment may have settled. This PR answers that case with its own code and no
such advice (task 0141, decisions 2–4).
A used nonce does not prove the payment: the payer can spend it on a second entry. So
/settleneveranswers
successfor a transaction it did not submit.New unit:
apps/facilitator/src/settlement/nonce-used.ts(both codes, the failure test, the nonceread). The final reason for our failed transaction comes from one function,
resultReason, in everywriter that ends a record (
settle.tsand its answer after a failed record write, the reconcilesweep, the pool's
resolvedevent); it reads the nonce entry when the error doesn't tell, as anRPC without diagnostic events gives none. The read has no timeout of its own:
FallbackRpc'sper-URL timeout and failover apply.
Evidence
Both testnet cases from 2026-11-12, as
getTransactionanswered them, are a fixture(
test/fixtures/nonce-consumed-elsewhere.json):bf6c8d21…)233ea749…failed, 8,800 stroopssettle_exact_stellar_transaction_failed, "the auth entry may still land … sign a new payment"settle_exact_stellar_nonce_consumed_elsewhere, no advice, logged withfeeChargedcc5538bd…)09bc7098…failed, 8,800 stroopsUnchanged: the same error in a C-account payer's own frame stays
…_transaction_failed(thewallet's own nested auth); breaker attribution is unchanged. With an error event a used nonce feeds
no breaker; without one it still does, fixed in its own PR after this one (task 0141 decision 9).
test(lore-0141)commite53b511d: the new tests fail (nononce-used.ts).1044 passed | 3 skipped, metrics-catalog31 passed, infra355 passed;format, lint, typecheck, build clean (see below).
Considered and rejected
successwith the other transaction's hash — a buyer can race one entry through twofacilitators to the same seller and be served twice; 0 front-runs in ~4,500 pubnet settlements.
settle_exact_stellar_nonce_already_used— it means "another payload"; here the client mayhave paid, and clients act on the code, not the message.
testnet cases failed in the simulation.
the proof, and it also works after upstream, which drops the RPC's error.
Merge Danger
Door: two-way
Two new
errorReasoncodes reach sellers. A seller that only checkssuccessbehaves as before.Blast Radius: settlement
One more RPC read (
getLedgerEntries) only after a failed simulation, or after our transactionfailed on chain without an error event that names a used nonce.
🤖 Generated with Claude Code