Skip to content

Feat/issue 196 claimable balance fallback#249

Merged
Kingsman-99 merged 4 commits into
Stellar-split:mainfrom
Atisan12:feat/issue-196-claimable-balance-fallback
Jun 25, 2026
Merged

Feat/issue 196 claimable balance fallback#249
Kingsman-99 merged 4 commits into
Stellar-split:mainfrom
Atisan12:feat/issue-196-claimable-balance-fallback

Conversation

@Atisan12

Copy link
Copy Markdown

closes #196

Atisan12 and others added 4 commits June 25, 2026 17:37
…lar-split#195)

Introduces Sep41Adapter, a thin normalisation layer over Soroban token
contracts that may or may not implement the full SEP-41 spec.  Lazy
capability probing (same FunctionNotFound pattern as featureDetection)
gates allowance/approve calls and returns null with a console.warn for
unsupported methods.  Exports wired into src/index.ts.  Unit tests cover
full SEP-41, transfer-only, and missing-method token shapes.

Closes Stellar-split#195

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Stellar-split#198)

Introduces HorizonFallbackReader (src/horizonFallback.ts) that wraps
Horizon.Server and normalises getAccount / getAccountBalances responses
into SDK-wide NormalizedAccount and NormalizedBalance shapes.

StellarSplitClientConfig gains an optional horizonUrl field. When set, the
client creates a HorizonFallbackReader and wires the two new public methods
(getAccount, getAccountBalances) through a FallbackChain so that a failing
Soroban RPC getAccount call automatically retries against Horizon. Write
paths are unaffected and continue to require a live Soroban RPC endpoint.

NormalizedAccount and NormalizedBalance are exported from src/index.ts.
11 unit/integration tests cover: normalised shapes, RPC-healthy path,
RPC-failure → Horizon fallback, missing-horizonUrl error paths.

Closes Stellar-split#198

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Stellar-split#197)

Introduces buildSponsoredOnboarding (src/sponsorship.ts) which wraps
caller-provided operations between beginSponsoringFutureReserves and
endSponsoringFutureReserves so that a brand-new payer account can fund
an invoice without first acquiring XLM.

Operation ordering enforced: begin (source=sponsor) → inner ops → end
(source=newAccount). Both accounts must co-sign the returned unsigned
transaction before submission.

When config.horizonUrl is set the function fetches the sponsor's live XLM
balance via Horizon.Server.loadAccount and verifies that the available
balance covers the sponsor's own minimum (1 XLM) plus one base reserve
(0.5 XLM) per wrapped operation. Two typed errors are exported:
MissingSponsorAccountError (config.sponsorAccount absent) and
InsufficientReserveError (balance too low, exposing availableStroops and
requiredStroops).

StellarSplitClientConfig gains sponsorAccount?: string.
buildSponsoredOnboarding, MissingSponsorAccountError, and
InsufficientReserveError are exported from src/index.ts.
11 unit tests cover op ordering, missing config, insufficient balance,
balance check skip, and reserve math scaling with op count.

Closes Stellar-split#197

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…irmed refunds (Stellar-split#196)

Introduces src/claimableBalanceFallback.ts with three exports:

isRefundTransferError(error) — returns true when a Soroban error message
indicates a failed token transfer due to a missing account or missing
trustline (op_no_trust, op_no_destination, AccountMissing, TrustNotFound,
etc.).

createClaimableRefund(payer, amount, asset, sourceAddress, config) —
builds and submits a classic Stellar createClaimableBalance operation via
Horizon.Server, making the refund claimable by payer at any time.  Extracts
the balance_id from the created operation record; falls back to a synthetic
ID prefixed with zeros when the operations endpoint is unavailable.  Emits a
distinguishable [StellarSplitClient] claimable-refund fallback log entry.

getClaimableRefunds(payer, config) — queries Horizon claimableBalances for
all pending balances claimable by payer.

StellarSplitClient gains two public methods:
  refundInvoice(invoiceId, creator, payerAddress?) — calls refund_invoice
  on the contract; on trustline/account errors with horizonUrl configured,
  automatically retries via createClaimableRefund, emits a console.warn, and
  returns { fallback: true, balanceId, txHash }.  Normal path returns
  { fallback: false, txHash }.
  getClaimableRefunds(payer) — delegates to the module function above.

StellarSplitClientConfig is unchanged (horizonUrl added in Stellar-split#198 is reused).
All exports wired into src/index.ts.
21 unit + integration tests cover: trustline error detection (8 patterns),
successful submission, correct amount string (stroops→decimal), synthetic
balance ID fallback, missing horizonUrl throws, empty/multi-entry listing,
normal refund path, fallback trigger, no-horizonUrl rethrow.

Closes Stellar-split#196

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@drips-wave

drips-wave Bot commented Jun 25, 2026

Copy link
Copy Markdown

@Atisan12 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 5316eba into Stellar-split:main Jun 25, 2026
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.

Build claimable balance fallback for unconfirmed refunds

2 participants