Skip to content

fix(deps): unify @stellar/stellar-sdk on one major and make it a peer dep of the SDK - #968

Open
AGWAM001 wants to merge 21 commits into
Miracle656:mainfrom
AGWAM001:fix/660-unify-stellar-sdk
Open

AGWAM001 wants to merge 21 commits into
Miracle656:mainfrom
AGWAM001:fix/660-unify-stellar-sdk

Conversation

@AGWAM001

@AGWAM001 AGWAM001 commented Oct 1, 2026

Copy link
Copy Markdown

Closes #660

Summary

Resolves the @stellar/stellar-sdk version split across this monorepo — four declared majors (sdk ^15.1.0, frontend/wallet/frontend/mobile ^14.6.1, packages/agent ^16.1.0, with agent actually installing 14.6.1 despite declaring ^16.1.0) and real duplicate copies in the install tree. Moves @stellar/stellar-sdk to peerDependencies on the SDK package, aligns every package onto one current major, and fixes the agent's declared-vs-installed drift.

Problem

Two copies of @stellar/stellar-sdk in one process means two separate class identities — an Asset, Transaction, or Keypair built by one copy fails instanceof against the other, surfacing as a confusing type/serialization error far from its real cause. The SDK also declared @stellar/stellar-sdk as a regular dependency, which guarantees downstream consumers get our copy alongside their own instead of choosing one version themselves.

What changed

  • sdk/package.json: moved @stellar/stellar-sdk from dependencies to peerDependencies (range <peer range you settled on>), and added it to devDependencies pinned at <version> so building and testing the SDK itself still works without a consumer present.
  • Version alignment: all of sdk, frontend/wallet, frontend/mobile, and packages/agent now declare and install @stellar/stellar-sdk@<chosen version, e.g. ^17.0.1>. packages/agent's declared range now matches what's actually installed (previously declared ^16.1.0, installed 14.6.1).
  • @blend-capital/blend-sdk: <state your finding — either "confirmed it resolves against the shared stellar-sdk copy, no nested duplicate remains" or "still pulls its own copy because <reason>; left as the one exception to the single-copy goal">.
  • Breaking-change migration (14 → 17 crosses two majors):
    • SorobanRpc → rpc namespace rename: updated all imports/usages across <list touched files/packages>.
    • Horizon type changes: <describe what changed and how call sites were updated>.
    • Transaction assembly changes: <describe what changed in how transactions are built/simulated/assembled, and what was updated>.
  • Passkey signing path (derToRawSignature, low-S normalisation, SorobanAuthorizationEntry assembly): re-verified against the new SDK version — <describe what, if anything, had to change here>.
  • Install tooling: <confirm whether mobile's plain npm installvs sdk's--legacy-peer-deps behavior was reconciled, or note that it remains intentionally different and why>.

Contracts — explicitly out of scope

This is a JS-side dependency change only. No contract was redeployed or rebuilt. contracts/expected-hashes.json is unchanged, and the mainnet WASM still matches it byte-for-byte — verified by <command/process you used to confirm this>.

Protocol 25 (X-Ray) compatibility

Confirmed <chosen SDK version> supports what the contracts use on Protocol 25 (currently live on mainnet). <Note specifically what you checked — e.g. which RPC methods/transaction features the contracts depend on and that they're present/unchanged in this version.>

Testnet verification (required by acceptance criteria)

A passkey-authorised transaction was verified end to end on testnet after the upgrade:

  • Transaction hash: <paste testnet tx hash here>
  • Flow verified: <briefly describe — e.g. passkey signs, derToRawSignature + low-S normalization applied, SorobanAuthorizationEntry assembled, submitted via rpc, confirmed on ledger>

A green typecheck alone was treated as insufficient evidence for this path, per the issue's own warning.

Testing

  • Typecheck, tests, and build green in every touched package: sdk, frontend/wallet, frontend/mobile, packages/agent.
  • Install-tree check confirming no duplicate @stellar/stellar-sdk copy remains except <the blend-sdk exception, if any>.
  • Passkey testnet transaction (see above) — not just unit-tested, verified against live testnet.
  • <any regression tests specific to the SorobanRpc→rpc rename, Horizon type changes, or transaction-assembly changes you had to touch>

Kuma Iliya and others added 12 commits September 25, 2026 13:29
The sdk shipped stellar-sdk as a runtime dependency at ^15.1.0 while the wallet,
mobile, agent and the repo root each declared another major, so any app using the
sdk installed two copies of the XDR tables. stellar-sdk moves to the sdk's
peerDependencies (plus devDependencies so sdk/ builds and tests itself), and all
five manifests now declare ^17.0.1 — one 17.2.0 copy per install.

@scure/bip39 comes along to 2.x: 1.x reaches for @noble/hashes subpaths that the
@noble/hashes 2.x stellar-sdk 17 hoists no longer exports, so the two majors
cannot share one install.

sdk/package.json's jest transform also learns to babel the ESM-only packages
stellar-sdk 17 depends on (@exodus/bytes, @noble/*, uint8array-extras, smol-toml),
configured inline so no babel config can leak into the Storybook build.
)

Soroban RPC hands back address credentials as the CAP-71 ADDRESS_V2 arm, and that
arm signs a different preimage — HashIdPreimageSorobanAuthorizationWithAddress,
which binds the authorising contract into the payload. The old code only knew the
legacy arm, so every passkey transaction it built carried a signature the wallet
contract could not verify.

Three more gaps closed on the way to a testnet success:

- signatureExpirationLedger now comes from the client. The simulation returns 0,
  which the host reads as already expired.
- The signature vec ends with the contract nonce, which __check_auth requires as
  its fifth element (it compared the wallet's own counter against a missing one).
- Signed entries are re-simulated before submission. The first simulation records
  in recording mode, so its budget never counts the secp256r1 verification
  __check_auth runs, and the enforced second pass trapped on instructions.

computeWalletAddress stops round-tripping through Buffer, deriveFeePayer falls
back to atob, and the jsdom setup installs Node's native TextEncoder (rewrapped
on the prototype) because @exodus/bytes probes for [native code] and stellar-sdk
17 checks instanceof Uint8Array across realms.
…wn copy (Miracle656#660)

XDR unions are read as properties instead of switch()/arm() calls, scvMap entries
expose .key/.val, a text memo decoded from XDR arrives as bytes, and
TransactionBuilder takes a TransactionSource. The signing paths learn the CAP-71
ADDRESS_V2 arm and its WithAddress preimage, matching the sdk.

webpack's node_modules prepend is scoped to our own source: it had been applied
globally, which forced @blend-capital/blend-sdk onto the wallet's stellar-sdk 17
even though it constructs xdr.UInt128Parts — dropped from protocol 23's XDR, so
blend genuinely needs the 16.x copy it pins rather than the shared one.
Transaction-result decoding moves from switch()/arm() calls to the property-style
unions, the wallet signer map reads .val.bytes directly, fee-bump envelopes are
unwrapped as .v1.tx.operations, and a text memo parsed from XDR is decoded from
bytes instead of String()-ed into "7,8,9". The Jest transform allow-list gains the
ESM-only packages stellar-sdk 17 requires.
stellar-sdk 17 declares engines >=22.12.0, so its jobs cannot install on 20. The
root smoke test also reads the ledger key's durability as a property, which is how
17's XDR exposes it.
…6#660)

The READMEs and CONTRIBUTING still narrated the pre-upgrade split, where the SDK
bundled its own major and mobile pinned over it. Record the new arrangement
instead, note that the Metro singleton pin stays because the SDK still
dev-installs a copy, and add the changeset for the release notes.
Miracle656#660)

Every __check_auth requirement is a runtime contract, so a green typecheck proves
nothing about the signing path. This drives deploy() and sendPayment() against the
testnet factory with a software P-256 authenticator and prints the resulting hash;
it refuses to run on any network other than testnet.
…racle656#660)

stellar-sdk 17 dropped the union accessor methods earlier majors had: reading an
arm is a discriminated property now. Three files still called meta.switch().name,
meta.v3().sorobanMeta() and val.address().contractId(), which throw TypeError on
17 — the vault and multisig deploys died outright and the sweep failure parser
silently reported nothing. Hand-written local types that described the 14 shape
were why a green typecheck hid it.

Verified against the 17.2.0 declarations: TransactionMeta arms are v0..v4,
ScAddress exposes contractId directly, and ScError lost its host arm.
@AGWAM001
AGWAM001 requested a review from Miracle656 as a code owner October 1, 2026 17:57
@vercel

vercel Bot commented Oct 1, 2026

Copy link
Copy Markdown

Someone is attempting to deploy a commit to the miracle656's projects Team on Vercel.

A member of the Team first needs to authorize it.

AGWAM001 and others added 2 commits October 1, 2026 18:59
…types

Merging main twice left duplicated keys in the files npm reads first: the
root package.json and package-lock.json each carried two
@stellar/stellar-sdk entries with a missing comma between them, so npm ci
could not parse them and every job died before installing anything.
frontend/mobile gained a second expo-asset declaration, and main's font
split moved fontFamily into its own module without re-exporting it, which
broke every screen that still reads the token from theme/typography.

The root lockfile was reconciled with npm install rather than hand-edited:
verify:lockfile and verify:lockfiles (55 workspaces) both pass, and a second
root npm install leaves no drift. signer.ts and privacy/keys.ts now match
sdk 17, where hash() hands back a hex string and a Uint8Array instead of a
Buffer.

sdk/src/core.ts is left as this merge found it: nine submit sites still hold
both the branch's keypair signing call and main's TransactionSigner call,
which is a signing-path decision rather than a merge cleanup.
@gitguardian

gitguardian Bot commented Oct 1, 2026

Copy link
Copy Markdown

⚠️ GitGuardian has uncovered 1 secret following the scan of your pull request.

Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components.

Since your pull request originates from a forked repository, GitGuardian is not able to associate the secrets uncovered with secret incidents on your GitGuardian dashboard.
Skipping this check run and merging your pull request will create secret incidents on your GitGuardian dashboard.

🔎 Detected hardcoded secret in your pull request
GitGuardian id GitGuardian status Secret Commit Filename
29282175 Triggered Generic High Entropy Secret c171f6f frontend/mobile/lib/privacy/tests/config.test.ts View secret
🛠 Guidelines to remediate hardcoded secrets
  1. Understand the implications of revoking this secret by investigating where it is used in your code.
  2. Replace and store your secret safely. Learn here the best practices.
  3. Revoke and rotate this secret.
  4. If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.

To avoid such incidents in the future consider


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

Kuma Iliya and others added 7 commits October 1, 2026 21:46
…iracle656#660)

Nine submit sites in core.ts still carried both the branch's keypair signing
call and main's TransactionSigner call after the merges: `submissionTx` was
declared twice at each one, and the branch's lines named signerKeypair,
guardianKeypair and payerKeypair — variables main had already replaced with
the method's `signer` parameter. The SDK would not build and mobile typecheck
reported 45 errors.

reprepareWithSignedAuth now takes SignerInput and reads the payer address
through resolveSigner, so the second simulation survives the signer refactor
rather than being dropped to make the file parse. That round-trip is what
stops a passkey spend trapping on "operation instructions exceeds amount
specified": the first simulation runs in recording-auth mode, so its budget
never accounts for the secp256r1 check.

stellar-sdk 17 returns a Uint8Array from hash() and exposes a signature as a
value rather than a getter, so signer.ts now compares the two digests with
bufferToHex — `!==` between byte arrays only compares references — and the
signer tests read `.signature` instead of calling it.
…iracle656#660)

frontend/mobile/package.json declared @stellar/stellar-sdk twice, ^17.0.1 and
then ^14.6.1. npm honours the last key, so mobile still resolved against the
14 line even though its own tree carried 17.2.0 — Miracle656#660's
declared-versus-installed drift, arrived at in a new package. It is not
cosmetic: `npm ci` fails there outright ("lock file's
@stellar/stellar-sdk@17.2.0 does not satisfy 14.6.1"), so the mobile job and
the repo-wide verify-lockfiles job install nothing at all. The same bad merge
duplicated @walletconnect/core; 2.25.0 already won, so dropping the stale
2.17.1 line changes no resolution.

No re-resolution was needed. The lockfile had recorded both keys too, so this
is four deleted lines rather than a regenerated tree.

Merging main also brought in sdk/src/sep8.ts, written against the pre-17 XDR
API in which unions and structs answer through methods. stellar-sdk 17
regenerates them as discriminated classes, so envelope.switch().name, v1(),
tx() and a Transaction's sourceAccount(), memo() and operations() are plain
data properties; typecheck was red on eleven of those calls. The fee-bump
inner is typed as envelopeTypeTx alone in 17, so the guard that rejected a v0
inner there has no second arm left to take — such an envelope now fails to
decode and is refused by the existing catch, which preserves the fail-closed
behaviour this security check depends on. toXDR/fromXDR stay as the rest of
src/ uses them rather than being renamed here.

Verified: sdk `tsc --noEmit` green, all 344 jest tests pass, and a
passkey-authorised spend on testnet succeeds against 17.2.0 — hash
30be7fb0a96d1c1ba78c81b6431b6483a88b79bd46b990ad132979765a6205ee, confirmed
successful on Horizon testnet at ledger 5019167. The FeeBump arm, which
sep8.test.ts never exercises, was probed directly: appended operations still
verify, while memo, amount and fee-source changes and dropped operations are
all refused.
…6#660)

frontend/mobile/jest.config.js did not parse: merging main twice left two
replacement bodies stacked inside one arrow function with no operator between
them, so `npm test` died on `SyntaxError: missing ) after argument list`
before a single suite could load. The same shape of merge damage Miracle656#660 found in
package.json, in a different file.

main's version was valid, and the other tracked .js/.cjs/.mjs files all pass
`node --check`, so this was the only instance.

The two halves were each trying to widen the expo preset's ignore pattern for
a different set of ESM-only packages — the stellar-sdk 17 dependencies
(@exodus/bytes, uint8array-extras, smol-toml) on one side, @WalletConnect on
the other — so the union is the intent, keeping the `.map()` form so the
preset's own react-native/expo entries are preserved rather than retyped.
The duplicated explanatory sentence is collapsed into one paragraph.
…gration (Miracle656#660)

`lib/walletConnect.ts` was the last file in the repo still naming
`@walletconnect/web3wallet`, and the package is gone from both mobile and wallet
lockfiles, so the import resolved to nothing and `tsc` failed with TS2307. Every
call site already uses WalletKit (`WalletKit.init`, `IWalletKit`), so this is an
unused import, not a missing dependency.

Mobile typecheck could not run at all before this: `npm ci` died on the
duplicate stellar-sdk key that 7a63bcd removed, which masked this error.
…Miracle656#660)

Merging main's WalletKit migration re-added `@scure/bip39: ^1.6.0` next to the
`^2.4.0` this branch installs, and JSON keeps the last key, so the wallet
effectively asked npm for 1.6.0 against a lockfile resolving 2.4.0. `npm ci`
failed with EUSAGE before installing anything.

2.4.0 is the version the tree already holds and the one stellar-sdk 17 needs:
stellar-sdk declares `@noble/hashes ^2.2.0`, and bip39 2.4.0 depends on 2.4.0,
so both share one copy instead of forcing a second. `ox` (via WalletKit) and
`@scure/bip32` still want the 1.x line, so the lock now records those as their
own nested copies after `npm install --package-lock-only`.

No already-resolved version changed. The only removals are 17 `@ethersproject/*`
entries nothing in the graph references any more, orphaned by the same
WalletKit migration.

This branch has not been deployed

No deployments
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.

Four majors of @stellar/stellar-sdk in one repo, two behind latest — unify and make it a peer dep

1 participant