Skip to content

feat(stellar): add Stellar (STL) SDK provider - #427

Open
chybisov wants to merge 9 commits into
mainfrom
feat/stellar-provider
Open

feat(stellar): add Stellar (STL) SDK provider#427
chybisov wants to merge 9 commits into
mainfrom
feat/stellar-provider

Conversation

@chybisov

@chybisov chybisov commented Jul 13, 2026

Copy link
Copy Markdown
Member

🔗 Linear: EMB-463 · Stellar: Add support on widget/SDK

Part of EMB-463 (Stellar on widget/SDK). Phase 1 — address validation + balances; transaction execution follows in Phase 2.

What

  • New @lifi/sdk-provider-stellar package:
    • isAddress — valid G-address; rejects muxed M / contract C (backend requires G-address senders)
    • resolveAddress — SEP-2 Federation
    • getBalance — reads each token's SAC balance() over Soroban RPC (matches the SAC C-address token model, EXBE-245)
    • getStepExecutor — throws for now; execution is Phase 2, gated on backend tx-generation (EXBE-227)
  • Registers ChainType.STL in getClientStorage so STL chains + RPC URLs load.
  • Uses only @stellar/stellar-sdk (no third-party wallet libs).

Verified

✅ type-check · build · unit tests (isAddress G/M/C cases + getClientStorage) pass.

Note

Draft. This must be published to npm before the widget PR (lifinance/widget) can install / pass CI.

Introduces the @lifi/sdk-provider-stellar package (address validation,
Federation resolution, and SAC-based balance reads) and registers
ChainType.STL in the SDK client's chain fetching. Transaction execution
is not yet implemented.
@changeset-bot

changeset-bot Bot commented Jul 13, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: c328023

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 7 packages
Name Type
@lifi/sdk-provider-stellar Minor
@lifi/sdk Minor
@lifi/sdk-provider-bitcoin Patch
@lifi/sdk-provider-ethereum Patch
@lifi/sdk-provider-solana Patch
@lifi/sdk-provider-sui Patch
@lifi/sdk-provider-tron Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

chybisov added 2 commits July 15, 2026 11:02
Resolve pnpm-lock.yaml conflict by regenerating from merged package.json
files (base: main's lockfile + Stellar provider deps).

Align sdk-provider-stellar with main's TypeScript 7 migration (#428):
bump typescript devDep ^6.0.3 -> ^7.0.2. Verified: check:types, unit
tests, and build pass under tsc 7.0.2; pnpm install --frozen-lockfile
is consistent.
getClientStorage registers STL, so getChains is now called with STL in
chainTypes. Update the stale unit assertion to match (was failing on the
branch independently of the main merge).
@chybisov chybisov added release-preview Publish a 0.0.0-preview-<sha> build of this PR to npm and removed release-preview Publish a 0.0.0-preview-<sha> build of this PR to npm labels Jul 15, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📦 Preview published under the preview dist-tag.

Install the exact version(s) — @preview moves with the newest preview across PRs:

npm i @lifi/sdk-provider-bitcoin@0.0.0-preview-5e098f3
npm i @lifi/sdk-provider-ethereum@0.0.0-preview-5e098f3
npm i @lifi/sdk-provider-solana@0.0.0-preview-5e098f3
npm i @lifi/sdk-provider-stellar@0.0.0-preview-5e098f3
npm i @lifi/sdk-provider-sui@0.0.0-preview-5e098f3
npm i @lifi/sdk-provider-tron@0.0.0-preview-5e098f3
npm i @lifi/sdk@0.0.0-preview-5e098f3

@github-actions github-actions Bot removed the release-preview Publish a 0.0.0-preview-<sha> build of this PR to npm label Jul 15, 2026
chybisov added 2 commits July 29, 2026 11:49
Signs the backend-generated Soroban envelope with the connected wallet,
submits it over Stellar RPC, waits for on-chain confirmation, then hands
off to the shared LI.FI status wait.

Two Stellar-specific constraints shape the pipeline:

- A Stellar envelope embeds the sender's account sequence number and
  timebounds [0, now+300s], so it cannot be reused. Unlike the base
  PrepareTransactionTask, StellarPrepareTransactionTask always re-fetches
  the step transaction, since the quote path carries a transactionRequest
  into the route and would otherwise sign a stale envelope.
- Granting a SAC allowance consumes the sender's sequence number, so the
  allowance tasks run before the transaction is prepared and the approval
  is confirmed on-chain before the route envelope is requested.

The approval spender is taken from step.estimate.approvalAddress only when
it is a valid Soroban C-address; the backend currently sends placeholders
for Stellar steps (a G-address fallback wallet, or the EVM diamond), which
must not be approved. A provider-level override is available until the
backend emits the router address.

Adds getStellarBalance.int.spec.ts, skipped for now: the LI.FI API does not
yet serve Stellar chains, so no RPC URLs resolve for ChainId.XLM.
@chybisov chybisov added release-preview Publish a 0.0.0-preview-<sha> build of this PR to npm and removed release-preview Publish a 0.0.0-preview-<sha> build of this PR to npm labels Jul 29, 2026
…tion

Two defects found in review of the executor:

- createPipeline offered only two resume entry points (copied from Sui and
  Solana), so a step whose hash was persisted but never confirmed restarted
  at CheckBalanceTask, re-prepared, and signed a SECOND envelope — executing
  the swap twice. Adopt Bitcoin's three-way entry and resume at the
  confirmation poll instead, re-submitting the persisted envelope first
  since Soroban submission is idempotent by hash (DUPLICATE = success).
  This makes the previously write-only txHex load-bearing and closes the
  crash-between-persist-and-submit window too.

- submitStellarTransaction and waitForStellarTransaction threw their
  classified TransactionErrors from inside the callStellarRpcsWithRetry
  callback, which collapses everything into an AggregateError. Every mapping
  in parseStellarErrors was therefore unreachable for submit and confirm
  failures. Only the transport call now goes through the failover wrapper;
  classification happens outside it.

Also: derive the approval hash locally, as the route transaction does, so it
is recorded even if the submit response is lost; set pollingIntervalMs on the
context so it is not permanently the module default; classify readAllowance's
simulation failure (its message contained "allowance" and mis-mapped to
AllowanceRequired); split submit/wait into separate helper modules; and trim
the barrel to the provider surface the siblings expose.

Adds specs for the unconditional-refetch invariant, the resume entry points,
and the rebroadcast-on-resume path.
@chybisov chybisov added release-preview Publish a 0.0.0-preview-<sha> build of this PR to npm and removed release-preview Publish a 0.0.0-preview-<sha> build of this PR to npm labels Jul 29, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📦 Preview published under the preview dist-tag.

Install the exact version(s) — @preview moves with the newest preview across PRs:

npm i @lifi/sdk-provider-bitcoin@0.0.0-preview-207d898
npm i @lifi/sdk-provider-ethereum@0.0.0-preview-207d898
npm i @lifi/sdk-provider-solana@0.0.0-preview-207d898
npm i @lifi/sdk-provider-stellar@0.0.0-preview-207d898
npm i @lifi/sdk-provider-sui@0.0.0-preview-207d898
npm i @lifi/sdk-provider-tron@0.0.0-preview-207d898
npm i @lifi/sdk@0.0.0-preview-207d898

@github-actions github-actions Bot removed the release-preview Publish a 0.0.0-preview-<sha> build of this PR to npm label Jul 29, 2026
…started

The cross-task invariant that matters is that SetAllowance does not hand
control back until the approval has settled — the next task fetches the route
envelope from a live getAccount read. Task ordering alone would still pass if
the confirmation were ever made fire-and-forget.

Also corrects the readAllowance comment: the classification matters because
parseStellarErrors passes a BaseError through untouched, not because of the
word 'allowance' in the message.
@chybisov
chybisov marked this pull request as ready for review July 29, 2026 10:37
@chybisov chybisov changed the title feat(stellar): add Stellar (STL) SDK provider (Phase 1) feat(stellar): add Stellar (STL) SDK provider Jul 29, 2026
import { ChainId, LruMap, type SDKClient } from '@lifi/sdk'
import { rpc } from '@stellar/stellar-sdk'

const stellarRpcs = new LruMap<rpc.Server>(12)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Module-level 'stellarRpcs' LruMap caches rpc.Server instances across requests; consider scoping cache to client/context or clearly documenting intentional shared cache.

Details

✨ AI Reasoning
​A new module-level variable 'stellarRpcs' (an LruMap of rpc.Server) is created and populated with RPC Server instances resolved per client. In a long-running Node.js process this object persists across requests and users. While caching RPC clients can be intentional, it may unintentionally retain request-specific or tenant-specific state, leading to cross-request data leakage or stale/incorrect server instances if different clients expect different RPC URL sets. The variable is declared at module scope and mutated by ensureStellarRpcs, making it a shared mutable global cache.

🔧 How do I fix it?
Avoid storing request-specific data in module-level variables. Use request-scoped variables or explicitly mark shared caches as intentional.

Reply @AikidoSec feedback: [FEEDBACK] to get better review comments in the future.
Reply @AikidoSec ignore: [REASON] to ignore this issue.
More info

Every other provider's declared range matches its resolved version exactly;
sdk-provider-stellar was the only one trailing (^16.0.1 already resolved to
16.1.0). No installed version changes.

No new changeset: the existing .changeset/stellar-provider.md minor already
covers this package's introduction in the same release.
@chybisov chybisov added the release-preview Publish a 0.0.0-preview-<sha> build of this PR to npm label Jul 29, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📦 Preview published under the preview dist-tag.

Install the exact version(s) — @preview moves with the newest preview across PRs:

npm i @lifi/sdk-provider-bitcoin@0.0.0-preview-3a18dab
npm i @lifi/sdk-provider-ethereum@0.0.0-preview-3a18dab
npm i @lifi/sdk-provider-solana@0.0.0-preview-3a18dab
npm i @lifi/sdk-provider-stellar@0.0.0-preview-3a18dab
npm i @lifi/sdk-provider-sui@0.0.0-preview-3a18dab
npm i @lifi/sdk-provider-tron@0.0.0-preview-3a18dab
npm i @lifi/sdk@0.0.0-preview-3a18dab

@github-actions github-actions Bot removed the release-preview Publish a 0.0.0-preview-<sha> build of this PR to npm label Jul 29, 2026
@chybisov chybisov added the release-preview Publish a 0.0.0-preview-<sha> build of this PR to npm label Aug 10, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📦 Preview published under the preview dist-tag.

Install the exact version(s) — @preview moves with the newest preview across PRs:

npm i @lifi/sdk-provider-bitcoin@0.0.0-preview-c328023
npm i @lifi/sdk-provider-ethereum@0.0.0-preview-c328023
npm i @lifi/sdk-provider-solana@0.0.0-preview-c328023
npm i @lifi/sdk-provider-stellar@0.0.0-preview-c328023
npm i @lifi/sdk-provider-sui@0.0.0-preview-c328023
npm i @lifi/sdk-provider-tron@0.0.0-preview-c328023
npm i @lifi/sdk@0.0.0-preview-c328023

@github-actions github-actions Bot removed the release-preview Publish a 0.0.0-preview-<sha> build of this PR to npm label Aug 10, 2026
chybisov added a commit to lifinance/widget that referenced this pull request Aug 10, 2026
Matches the SDK branch head (lifinance/sdk#427, c3280231), which refines the
Stellar approval handling. The previous pin (3a18dab) predated that commit.

All seven @lifi/sdk* pins move together, as they must: the provider tarballs
hard-pin @lifi/sdk to their own preview version, and a second copy of @lifi/sdk
breaks route execution because executionState is a module-level singleton.
Verified one copy resolves across widget, widget-provider, widget-provider-stellar
and wallet-management. Example pins stay on published versions.
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.

2 participants