Skip to content

Payment Expiry Guard #504

Description

@Kingsman-99

Description

Invoices carry an expiresAt timestamp, but the SDK does not enforce this on the transaction side by setting timebounds.maxTime on built transactions. A payment submitted after an invoice expires should be rejected at the ledger level, not merely by SDK-side checks. The expiry guard must translate invoice expiry into transaction timebounds and reject submission attempts where the expiry has already passed.

Technical Context

Extend src/txBuilder.ts to set timeBounds using TransactionBuilder.setTimeout() from @stellar/stellar-sdk. Reads InvoiceRecord.expiresAt from src/types.ts. Add PaymentExpiredError to src/errors.ts. Pre-submission check added to src/preflightChecker.ts. src/deadlineEngine.ts provides the remaining-seconds calculation that feeds into setTimeout().

Acceptance Criteria

  • txBuilder.build() automatically calls setTimeout(remainingSeconds) when building a payment for an invoice with expiresAt set
  • Throws PaymentExpiredError synchronously when expiresAt is in the past at build time, before any network call
  • Respects a configurable expiryBufferSeconds (default 30) subtracted from the remaining time to account for clock skew
  • Zero remaining time after buffer causes PaymentExpiredError with a human-readable message including the expired timestamp
  • Unit tests cover: expiry 60 s away (builds OK), expiry 20 s away with 30 s buffer (throws), already-expired (throws)
  • All CI checks (npm test, npm run build, ESLint/TypeScript) pass and the branch has no merge conflicts

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions