Add invoice reminder scheduler, auth-required trustline handler, and SEP-31 initiator - #581
Merged
Kingsman-99 merged 2 commits intoJul 30, 2026
Conversation
…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
|
@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! 🚀 |
6 tasks
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
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) — detectsAUTH_REQUIREDasset issuers and facilitates the trustline-approval transaction on the issuer's behalf, preferringSetTrustLineFlags(protocol ≥ 18) with a fallback to the legacyAllowTrustoperation.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'sDIRECT_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— newInvoiceReminderSchedulerclass, extends the typed-emitter pattern used elsewhere in the SDK (TypedEventEmitter, seesrc/sep/sep24Handler.ts) and the persist-then-arm-timer approach already used byScheduledPaymentManager(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.gracePeriodMs(default60_000); older ones are markedexpiredrather than fired. Recovery fires are deferred one tick (setTimeout(0)) so callers can attach listeners first.invoiceReminderDuewith{ invoiceId, offsetMs, dueAt }.src/snapshot.ts— addedloadReminderSchedules()/saveReminderSchedules(), keyed by invoice, using the samelocalStorage-backed persistence approach assrc/scheduler.ts.src/types.ts— addedReminderSchedule,ReminderEvent,ReminderStatus, and an optionalInvoiceRecord.dueAtfield.#541 — Auth-required trustline request handler
src/accountFlagsInspector.ts(new) — readsAUTH_REQUIRED/AUTH_REVOCABLE/AUTH_IMMUTABLE/AUTH_CLAWBACK_ENABLEDflags for an account via Horizon.src/sorobanFeatureDetector.ts(new) — detects the network's current protocol version (viaHorizon.Server.root()) and whether it supportsSetTrustLineFlags(protocol ≥ 18).src/preflightChecker.ts— addedcheckTrustlineAuthRequirement(), composing the new flags inspector, as the preflight integration point.src/trustlineAuthHandler.ts(new) —TrustlineAuthHandlerclass:.checkAndRequest(recipientId, asset)detects the AUTH_REQUIRED condition and emitstrustlineAuthRequiredwith the issuer's public key..grantAuth(recipientId, asset, issuerKeypair)builds, signs, and submits the approval operation, emittingtrustlineAuthGranted.src/types.ts— addedTrustlineAuthRequest,TrustlineAuthStatus,TrustlineAuthOperationType.#540 — SEP-31 cross-border payment initiator
src/sep/sep31Initiator.ts(new) —Sep31Initiatorclass, mirrors theSep24Handlershape:.getRequiredFields(anchorDomain, asset)reads the anchor's/infoendpoint..initiate(params)completes the/sendcall and stores the returned transaction record; the SEP-10jwtpassed 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()resolvesDIRECT_PAYMENT_SERVERfrom the anchor's stellar.toml viaStellarToml.Resolver.src/types.ts— addedSep31PaymentRecord,Sep31Status,Sep31StatusChangedEvent,Sep31RequiredFields,Sep31FieldSpec.All new symbols are exported from
src/index.tsfollowing the existing per-module export style.CHANGELOG.mdupdated 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.tsis a Soroban contract-event replay module, not an emitter;src/token.tsresolves 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 asSep24Handlerdoes. Flagging this explicitly for reviewers rather than leaving it implicit.Verification performed
npx tsc --noEmit: this repo'smainbranch 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 unmodifiedmaintoday, from unrelated pre-existing broken imports (e.g.InvoiceIntegrityErrormissing fromsrc/errors.ts,getCursor/setCursormissing fromsrc/cursorTracker.ts). Reproduced identically onmainviagit stashbefore confirming it wasn't introduced by this change.npm test(current script —client.test.ts+retryPolicy.test.ts): 96/96 passing.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, andtest/preflightChecker.test.ts(which I extended) still passes 7/7.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, customgracePeriodMs)npx vitest run test/trustlineAuthHandler.test.ts— 4/4 passing (trustlineAuthRequiredemission on AUTH_REQUIRED, no emission when not required,SetTrustLineFlagson protocol ≥ 18,AllowTrustfallback on protocol < 18)npx vitest run test/sep31Initiator.test.ts— 4/4 passing (/infofield schema,DIRECT_PAYMENT_SERVERresolution failure,/send+ JWT attachment, full poll-to-completion flow with correct event sequence)npm test(existing script) — 96/96 passingmainfailures — no new failuresCloses #542
Closes #541
Closes #540