Skip to content

Add invoice reminder scheduler, auth-required trustline handler, and SEP-31 initiator - #581

Merged
Kingsman-99 merged 2 commits into
Stellar-split:mainfrom
maztah1:feature/issue-542-541-540-reminders-trustline-sep31
Jul 30, 2026
Merged

Add invoice reminder scheduler, auth-required trustline handler, and SEP-31 initiator#581
Kingsman-99 merged 2 commits into
Stellar-split:mainfrom
maztah1:feature/issue-542-541-540-reminders-trustline-sep31

Conversation

@maztah1

@maztah1 maztah1 commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Implements three independent, additive SDK features requested in issues #542, #541, and #540:

  • InvoiceReminderScheduler (Invoice Due-Date Reminder Scheduler #542) — schedules due-date reminders at configurable offsets before an invoice's due date, persists them so they survive process restarts, and recovers missed reminders within a configurable grace period on startup.
  • TrustlineAuthHandler (Auth-Required Trustline Request Handler #541) — detects AUTH_REQUIRED asset issuers and facilitates the trustline-approval transaction on the issuer's behalf, preferring SetTrustLineFlags (protocol ≥ 18) with a fallback to the legacy AllowTrust operation.
  • Sep31Initiator (SEP-31 Cross-Border Payment Initiator #540) — drives the initiator side of the SEP-31 cross-border direct payment flow: resolves the receiving anchor's DIRECT_PAYMENT_SERVER, reads required fields, submits the payment, and polls for status until a terminal state.

What changed

#542 — Invoice due-date reminder scheduler

  • src/invoiceReminderScheduler.ts — new InvoiceReminderScheduler class, extends the typed-emitter pattern used elsewhere in the SDK (TypedEventEmitter, see src/sep/sep24Handler.ts) and the persist-then-arm-timer approach already used by ScheduledPaymentManager (src/scheduler.ts).
    • .schedule(invoiceId, offsets: number[]) registers one reminder per offset (ms before due date).
    • .cancel(invoiceId) removes all pending reminders for an invoice.
    • On construction, loads persisted schedules and fires any still within gracePeriodMs (default 60_000); older ones are marked expired rather than fired. Recovery fires are deferred one tick (setTimeout(0)) so callers can attach listeners first.
    • Emits invoiceReminderDue with { invoiceId, offsetMs, dueAt }.
  • src/snapshot.ts — added loadReminderSchedules() / saveReminderSchedules(), keyed by invoice, using the same localStorage-backed persistence approach as src/scheduler.ts.
  • src/types.ts — added ReminderSchedule, ReminderEvent, ReminderStatus, and an optional InvoiceRecord.dueAt field.

#541 — Auth-required trustline request handler

  • src/accountFlagsInspector.ts (new) — reads AUTH_REQUIRED/AUTH_REVOCABLE/AUTH_IMMUTABLE/AUTH_CLAWBACK_ENABLED flags for an account via Horizon.
  • src/sorobanFeatureDetector.ts (new) — detects the network's current protocol version (via Horizon.Server.root()) and whether it supports SetTrustLineFlags (protocol ≥ 18).
  • src/preflightChecker.ts — added checkTrustlineAuthRequirement(), composing the new flags inspector, as the preflight integration point.
  • src/trustlineAuthHandler.ts (new) — TrustlineAuthHandler class:
    • .checkAndRequest(recipientId, asset) detects the AUTH_REQUIRED condition and emits trustlineAuthRequired with the issuer's public key.
    • .grantAuth(recipientId, asset, issuerKeypair) builds, signs, and submits the approval operation, emitting trustlineAuthGranted.
  • src/types.ts — added TrustlineAuthRequest, TrustlineAuthStatus, TrustlineAuthOperationType.

#540 — SEP-31 cross-border payment initiator

  • src/sep/sep31Initiator.ts (new) — Sep31Initiator class, mirrors the Sep24Handler shape:
    • .getRequiredFields(anchorDomain, asset) reads the anchor's /info endpoint.
    • .initiate(params) completes the /send call and stores the returned transaction record; the SEP-10 jwt passed here is stored and reused automatically by subsequent polling calls.
    • .pollStatus(transactionId, anchorDomain) is an async generator yielding status updates until a terminal state (completed/error).
    • resolveDirectPaymentServer() resolves DIRECT_PAYMENT_SERVER from the anchor's stellar.toml via StellarToml.Resolver.
  • src/types.ts — added Sep31PaymentRecord, Sep31Status, Sep31StatusChangedEvent, Sep31RequiredFields, Sep31FieldSpec.

All new symbols are exported from src/index.ts following the existing per-module export style. CHANGELOG.md updated under ## Unreleased.

Note on a couple of issue-text deviations

Each issue's "Technical Context" pointed at a couple of files whose actual role in the repo didn't match the description (src/events.ts is a Soroban contract-event replay module, not an emitter; src/token.ts resolves SAC token metadata, not a SEP-10 JWT store). Rather than force a fit, I followed the pattern the codebase already uses for this exact situation — TypedEventEmitter + an instance-held JWT reused across calls, exactly as Sep24Handler does. Flagging this explicitly for reviewers rather than leaving it implicit.

Verification performed

  • npx tsc --noEmit: this repo's main branch currently has 125 pre-existing TypeScript errors (confirmed by diffing before/after — see below). This branch introduces zero net-new errors — verified via a byte-for-byte diff of the full error list before and after these changes.
  • npm run build (tsup): also fails on unmodified main today, from unrelated pre-existing broken imports (e.g. InvoiceIntegrityError missing from src/errors.ts, getCursor/setCursor missing from src/cursorTracker.ts). Reproduced identically on main via git stash before confirming it wasn't introduced by this change.
  • npm test (current script — client.test.ts + retryPolicy.test.ts): 96/96 passing.
  • Full suite (npx vitest run, 150 files / 1635 tests): 1566 passing / 65 failing across 12 files, all pre-existing and unrelated to this change (e.g. ContractInstancePool, OtelExporter, ShortfallAlertEngine, txBuilder, GracefulShutdownHandler, sse/stream/subscription, compression, mockFactory, TokenRefreshInterceptor, InvoicePaymentStreamProcessor). None of these files were touched by this PR, and test/preflightChecker.test.ts (which I extended) still passes 7/7.
  • New tests: 14/14 passing across the 3 new suites, all green in both the targeted run and the full-suite run.

Test plan

  • npx vitest run test/invoiceReminderScheduler.test.ts — 6/6 passing (offset registration + persistence, event emission with correct payload, cancel() behavior, restart recovery within/outside grace period, custom gracePeriodMs)
  • npx vitest run test/trustlineAuthHandler.test.ts — 4/4 passing (trustlineAuthRequired emission on AUTH_REQUIRED, no emission when not required, SetTrustLineFlags on protocol ≥ 18, AllowTrust fallback on protocol < 18)
  • npx vitest run test/sep31Initiator.test.ts — 4/4 passing (/info field schema, DIRECT_PAYMENT_SERVER resolution failure, /send + JWT attachment, full poll-to-completion flow with correct event sequence)
  • npm test (existing script) — 96/96 passing
  • Full suite diffed against pre-existing main failures — no new failures

Closes #542
Closes #541
Closes #540

…SEP-31 initiator

Implements three SDK features:

- InvoiceReminderScheduler (Stellar-split#542): schedules due-date reminders at
  configurable offsets, persists them via snapshot.ts keyed by invoice,
  and recovers missed reminders within a grace period after a restart.
- TrustlineAuthHandler (Stellar-split#541): detects AUTH_REQUIRED issuers via the new
  accountFlagsInspector/preflightChecker integration, and grants trustline
  authorization using SetTrustLineFlags (protocol >= 18) or the legacy
  AllowTrust operation, chosen via the new sorobanFeatureDetector.
- Sep31Initiator (Stellar-split#540): drives the SEP-31 initiator-side flow — resolves
  DIRECT_PAYMENT_SERVER from stellar.toml, reads required fields from
  /info, submits /send, and polls /transaction/:id until a terminal state.

Closes Stellar-split#542, Stellar-split#541, Stellar-split#540
@drips-wave

drips-wave Bot commented Jul 29, 2026

Copy link
Copy Markdown

@maztah1 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

@Kingsman-99
Kingsman-99 merged commit bc2b6e8 into Stellar-split:main Jul 30, 2026
2 checks passed
@grantfox-oss grantfox-oss Bot mentioned this pull request Jul 30, 2026
6 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Invoice Due-Date Reminder Scheduler Auth-Required Trustline Request Handler SEP-31 Cross-Border Payment Initiator

2 participants