Skip to content

Release/6.0.0: Protocol 30 support - #261

Merged
CassioMG merged 13 commits into
mainfrom
release/6.0.0
Nov 6, 2026
Merged

CassioMG merged 13 commits into
mainfrom
release/6.0.0

Conversation

@CassioMG

@CassioMG CassioMG commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

TL;DR

Adds Protocol 30 support and releases it as 6.0.0. All three packages move to @stellar/stellar-sdk 17.4.0, which understands CAP-84 muxed contract (W…) addresses. SEP-7 now accepts a W as a pay destination, and a pay to a C or W can no longer carry a memo, since the Soroban transaction that pays it can't have one.

It's a major release because of four breaking changes: React Native apps that read an anchor's stellar.toml need a TextDecoder that supports fatal, a C destination with a memo is now rejected, SEP-10 sign-in rejects a challenge whose client_domain operation has no source account or uses the server account as its source, and scValByType throws on a map whose keys collide.

Closes stellar/wallet-eng-monorepo#112

Implementation details (for agents)

Every link below is a permalink at 4539a59fffb4ba63cbf4ecd1f47ae8503bb8ee7d.

Commits

  1. 60bf978 feat: support Protocol 30 muxed contract (W) addresses. The SDK bump, W tests in all three packages, and the soroban docs.
  2. a74bfee feat(sep7): accept W pay destinations, and refuse a memo for C and W.
  3. 9bd8bcf test(e2e): check stellar-sdk's strict TextDecoder on React Native.
  4. c198fbc Release 6.0.0. Versions and changelogs: core, key manager, soroban.
  5. 7b0ee79 test(sep7): submit a transfer to a W address from a tx uri on testnet.
  6. b927f55 test(e2e): check Anchor.sep1() needs a strict TextDecoder on React Native.
  7. b7ed127 test: pin the client_domain source checks on SEP-10 challenges.
  8. 62d1e68 docs(changelog): list the client_domain challenge rejection as breaking.
  9. 4539a59 feat(sep7): make Sep7Pay throw on a memo with a C or W destination.

SDK bump

@stellar/stellar-sdk goes from 17.0.1 to 17.4.0, still an exact pin, in all three package.json files. The lockfile also moves stellar-sdk's pinned axios from 1.18.0 to 1.20.0 and form-data from 4.0.5 to 4.0.6, and adds hasown 2.0.4. 17.4.0 is the latest release. Decoding needed no source change, because every ScAddress goes through Address.fromScAddress.

SEP-7

if (type === Sep7OperationType.pay && destination) {
const isContract =
StrKey.isValidContract(destination) ||
StrKey.isValidMuxedContract(destination);
// Checks if it's a valid "G", "M", "C" or "W" Stellar address
const isValidStellarAddress =
StrKey.isValidEd25519PublicKey(destination) ||
StrKey.isValidMed25519PublicKey(destination) ||
isContract;
if (!isValidStellarAddress) {
return {
result: false,
reason:
"the provided 'destination' parameter is not a valid Stellar address",
};
}
// A "C" (contract) or "W" (muxed contract) address can only be paid with
// a Stellar Asset Contract transfer. That's a Soroban transaction, which
// can't have a memo, so a wallet could only drop it. A "W" address's mux
// ID already identifies the payee.
if (isContract && url.searchParams.get("memo")) {
return {
result: false,
reason:
"the 'memo' parameter is not supported for a contract ('C') or muxed contract ('W') 'destination'",
};
}
}

  • A W destination is accepted, checked with StrKey.isValidMuxedContract next to the G, M and C checks.
  • A memo is rejected when the destination is a C or W. Since Protocol 25, stellar-core fails a single-operation InvokeHostFunction transaction that has a memo with txSOROBAN_INVALID (validateSorobanMemo, where it's applied). Testnet, now on Protocol 30, rejects a memo on a transfer to a C or a W with tx_soroban_invalid. A classic payment can't target a contract, so such a URI can't be paid as written.
  • Sep7Pay won't build such a URI either. Its constructor and its destination and memo setters throw Sep7ContractMemoError and leave the URI unchanged, so whichever call creates the combination is the one that throws. The core changelog lists it in the same breaking entry.
  • G and M destinations still accept a memo. An empty memo= counts as no memo, as it does for Sep7Pay.memo.
  • Two existing tests used a C destination with a memo. They now use one without.

Tests

Every W value in the fixtures was cross-checked with an independent strkey encoder against the SEP-23 test vector. The transfer fixture's W argument also has the same bytes as the one testnet recorded for a real transfer to that W.

  • Decoding at each site stellar/wallet-eng-monorepo#112 lists:
  • Soroban:
  • SEP-7 memo rule: C and W destinations, each with a typed, an ID and an untyped memo, and Sep7Pay's constructor and setters, which throw for C and W, build a URI that parses once the memo is cleared, and still take a memo for G and M.
  • Classic operations: transfer, pathPay and accountMerge keep rejecting a W.
  • On testnet: a SEP-7 tx flow for a native SAC transfer to a W. The SDK's builder makes the transfer, RPC prepares it, and it goes through a tx URI. The wallet side signs it, submits it with submitTransaction, and decodes the envelope Horizon recorded, which still pays the W. The rest of the W coverage is unit-level.
  • Red/green: the tests that exercise W failed on 17.0.1 with XdrError … unknown enum value 5, "Unsupported address type", or the W rejected as invalid, and they pass on 17.4.0. Two mutations of the memo rule, checking memo_type instead of memo and removing the rule, each make memo tests fail. The Sep7Pay tests failed with "did not throw" before its check was added. Making Sep7Tx.getTransaction ignore the URI's network passphrase makes the testnet test fail with a 400 from Horizon. On the 5.1.0 bundle the React Native Anchor.sep1() test fails, and with stellar-sdk's two client_domain checks removed, all six SEP-10 cases fail.

React Native, the core package's breaking change

stellar-sdk 17.3 and later decodes stellar.toml and federation responses with new TextDecoder("utf-8", { fatal: true }), which it builds lazily in its bounded fetch. fast-text-encoding, a common React Native TextDecoder, throws for fatal. So with it, Anchor.sep1() rejects and SEP-7 verifySignature() returns false. The same check returns true on the 17.0.x build on main, and the bundles still load with such a decoder. Jest runs on Node, whose TextDecoder supports fatal, so this only shows up on a device or in a sandbox like the one below. A TextDecoder polyfill that can decode strictly fixes it.

The Hermes-like sandbox tests now pin both behaviors:

SEP-10 client_domain checks

stellar-sdk 17.3's WebAuth.readChallengeTx rejects a challenge whose client_domain operation has no source account or uses the server account as its source. SEP-10 requires that source to be the client domain's signing key. Sep10.authenticate, Server.signChallengeTransaction and KeyManager.fetchAuthToken validate challenges with it, so 6.0.0 rejects a challenge that 5.1.0 accepted. The core and key manager changelogs list it as breaking. A test pins it for each, checking the error and, in the two sign-in flows, that nothing was signed or posted:

Verification

Run at 4539a59, with testnet on Protocol 30 (since ledger 5540313 on 2026-11-03):

  • yarn build: all 6 bundles compile
  • yarn test:ci: 401 passed, 5 skipped. Six testnet tests in stellar.test.ts (SponsoringBuilder and Account Modifying) timed out while testnet was slow and passed when re-run.
  • React Native e2e (test:e2e:ci reactNative): 13 of 13 passed
  • eslint . --ext .ts --max-warnings 0 and Prettier on every .ts file: clean
  • tsc on the source of all three packages: clean. The test tsconfigs show the same 10 errors as main.
  • Not run locally: the Playwright browser test, which CI's container has the browsers for, and the Docker integration tests.

Out of scope

  • Classic TransactionBuilder operations keep rejecting W, as stellar/wallet-eng-monorepo#112 says.
  • SEP-10, SEP-6, SEP-12, SEP-24, SEP-38, SEP-30 and the Ledger, Trezor and plaintext handlers have no W-specific changes.

🤖 Generated with Claude Code

CassioMG and others added 4 commits November 2, 2026 16:32
Bump @stellar/stellar-sdk from 17.0.1 to 17.4.0 in all three packages.
17.4.0 decodes and encodes CAP-84 muxed contract (W...) addresses, so a
transaction that contains one decodes in Stellar.decodeTransaction, in
the key manager's Albedo and Freighter handlers, and in the soroban
helpers. On 17.0.1 decoding it threw "unknown enum value 5".

Tests:
- core: decodeTransaction decodes a SAC transfer to a W address, and the
  classic transfer, pathPay and accountMerge builders keep refusing a W
  destination
- soroban: scValByType renders all six ScAddress variants, and the exact W
  for mux IDs 0 and 2^64 - 1; getTokenInvocationArgs returns a W as `to`
  for a transfer and for a mint; scValByType throws on a map whose keys
  collide, as scValToNative does since stellar-sdk 17.3
- km: the Albedo and Freighter handlers return the signed transaction
  with its W recipient intact

Docs: the soroban README and ArgsForTokenInvocation say `to` can be a W
address, and scValByType documents the collision TypeError.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
isValidSep7Uri and parseSep7Uri accept a muxed contract (W...) address
as a `pay` destination, and a `tx` uri whose transaction contains one.

A contract (C...) or W destination can only be paid with a Stellar Asset
Contract transfer. That is a Soroban transaction, and the network rejects
a Soroban transaction that has a memo, so a wallet could only drop the
memo. A `pay` uri with a C or W destination and a memo is now invalid.
Before, a C destination with a memo was accepted. G and M destinations
keep accepting a memo.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Since stellar-sdk 17.3, stellar.toml and federation responses are read
with TextDecoder("utf-8", { fatal: true }), which some React Native
TextDecoders, such as fast-text-encoding, can't build. The Hermes-like
sandbox now checks that every bundle still loads with such a decoder,
and that verifying a SEP-7 signature needs one that can decode strictly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bump all three packages to 6.0.0 and add their changelog sections.

A major release because of three breaking changes: on React Native,
reading a stellar.toml needs a TextDecoder that supports `fatal` (from
stellar-sdk 17.3); a SEP-7 `pay` uri with a C destination and a memo is
now rejected; and scValByType throws on a map whose keys collide. The key
manager has no breaking changes and moves to 6.0.0 to stay in lockstep.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@socket-security

socket-security Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updatednpm/​@​stellar/​stellar-sdk@​17.0.1 ⏵ 17.4.099 +1100100 +1100 +1100

View full report

@CassioMG
CassioMG marked this pull request as ready for review November 3, 2026 01:16
@CassioMG
CassioMG requested a lite review from Copilot November 3, 2026 01:16

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟢 Approval recommended

No active review issues remain; the remaining notes are limited to a moderate test-coverage suggestion and a changelog nit.

No open issues 🎉

What changed in this PR

This pull request releases all three wallet SDK packages as 6.0.0 with Protocol 30/CAP-84 muxed contract (W…) address support through @stellar/stellar-sdk 17.4.0.

Changes:

  • Upgrades package versions, Stellar SDK dependencies, and lockfile resolutions.
  • Adds W… support to SEP-7, transaction decoding, Soroban helpers, and key-manager signing flows.
  • Rejects memos for contract and muxed-contract payment destinations.
  • Documents and tests React Native TextDecoder requirements, Soroban map-key collisions, and muxed-contract behavior.

Review notes:

  • Moderate: The React Native e2e test should also cover Anchor.sep1() with strict and non-strict TextDecoder behavior.
  • Nit: The key-manager changelog should describe KeyManager.fetchAuthToken input rejection as a breaking change.
File Description
yarn.lock Updates Stellar SDK and transitive dependency resolutions.
@stellar/​typescript-wallet-sdk/​test/​transaction.test.ts Verifies classic operations reject W… destinations.
@stellar/​typescript-wallet-sdk/​test/​stellar.test.ts Tests decoding and re-encoding transactions containing W… addresses.
@stellar/​typescript-wallet-sdk/​test/​sep7.test.ts Tests SEP-7 W… destinations and contract memo rejection.
@stellar/​typescript-wallet-sdk/​test/​fixtures/​muxedContract.ts Adds shared muxed-contract address and transaction fixtures.
@stellar/​typescript-wallet-sdk/​test/​e2e/​reactNative.test.ts Tests React Native bundle and strict TextDecoder behavior.
@stellar/​typescript-wallet-sdk/​src/​walletSdk/​Uri/​Sep7Pay.ts Documents contract and muxed-contract payment constraints.
@stellar/​typescript-wallet-sdk/​src/​walletSdk/​Uri/​sep7Parser.ts Accepts W… pay destinations and rejects contract memos.
@stellar/​typescript-wallet-sdk/​package.json Bumps the core package and Stellar SDK versions.
@stellar/​typescript-wallet-sdk/​CHANGELOG.MD Documents 6.0.0 changes and breaking behavior.
@stellar/​typescript-wallet-sdk-soroban/​test/​helpers.test.ts Adds W… token invocation, rendering, and collision tests.
@stellar/​typescript-wallet-sdk-soroban/​src/​Types/​index.ts Documents muxed-contract recipients in token invocation results.
@stellar/​typescript-wallet-sdk-soroban/​src/​Helpers/​scValByType.ts Documents muxed-address rendering and map-collision errors.
@stellar/​typescript-wallet-sdk-soroban/​README.md Documents W… recipients and address rendering.
@stellar/​typescript-wallet-sdk-soroban/​package.json Bumps the Soroban package and Stellar SDK versions.
@stellar/​typescript-wallet-sdk-soroban/​CHANGELOG.MD Documents Soroban 6.0.0 changes.
@stellar/​typescript-wallet-sdk-km/​test/​freighter.test.ts Verifies Freighter preserves W… recipients when signing.
@stellar/​typescript-wallet-sdk-km/​test/​fixtures/​muxedContract.ts Adds key-manager muxed-contract transaction fixtures.
@stellar/​typescript-wallet-sdk-km/​test/​albedo.test.ts Verifies Albedo preserves W… recipients when signing.
@stellar/​typescript-wallet-sdk-km/​package.json Bumps the key-manager package and Stellar SDK versions.
@stellar/​typescript-wallet-sdk-km/​CHANGELOG.MD Documents key-manager 6.0.0 changes.

Review effort: Lite

@CassioMG CassioMG self-assigned this Nov 3, 2026
CassioMG and others added 4 commits November 3, 2026 10:27
Testnet runs Protocol 30 since ledger 5540313, so a W address can now go
on chain. The test builds a native SAC transfer to a W with the SDK's
builder, prepares it with RPC and passes it through a SEP-7 tx uri. The
wallet side signs it and submits it with submitTransaction, then decodes
the envelope Horizon recorded and checks the W.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tive

The changelog's React Native breaking change says Anchor.sep1() rejects
where TextDecoder can't decode strictly, but only verifySignature() had
a sandbox test. The new test reads a stub stellar.toml through
Wallet.anchor().sep1() with each decoder. On the 5.1.0 bundle
(stellar-sdk 17.0.1), sep1() resolves with the non-strict decoder, so
the test fails there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
stellar-sdk 17.3's WebAuth.readChallengeTx rejects a challenge whose
client_domain operation has no source account or uses the server
account. Sep10.authenticate, Server.signChallengeTransaction and
KeyManager.fetchAuthToken validate challenges with it, and 5.1.0
accepted such a challenge. Each test checks the error. The Sep10 and
key manager tests also check that the client domain signer wasn't asked
to sign and nothing was posted back. With the two checks removed from
stellar-sdk, all six cases fail.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
KeyManager.fetchAuthToken, Sep10.authenticate and
Server.signChallengeTransaction reject a challenge that 5.1.0 accepted,
so the entry moves from Changed to BREAKING CHANGES in the core and key
manager changelogs. The key manager no longer says it has no breaking
changes. The core's React Native entry now says each of its two claims
has a sandbox test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔵 Needs a closer look

Human release verification is warranted because the change combines a pinned external SDK upgrade with live testnet, Hermes/browser integration, and downstream bundler compatibility behavior that static review cannot independently validate.

No open issues 🎉

Review effort: Lite

CassioMG and others added 2 commits November 4, 2026 13:10
parseSep7Uri rejects a pay URI that has a memo and a contract (C) or
muxed contract (W) destination, but Sep7Pay could still build one.
Its constructor and its destination and memo setters now throw
Sep7ContractMemoError, so the call that creates that combination fails
and leaves the URI unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both tests funded two accounts with friendbot one after the other, and a
single friendbot call has been taking 13 to 26 seconds, while ledgers
still close every 5 seconds. That alone used up most of their 30 and 45
second limits. They now fund both accounts in parallel and allow 90
seconds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CassioMG and others added 3 commits November 6, 2026 10:50
Its beforeAll funded two accounts with friendbot one after the other
within 30 seconds, and a single friendbot call has been taking 15 to 26
seconds, so the hook timed out and failed all four tests. Friendbot
serves parallel calls at the same time, so the hook now funds both
accounts in parallel and allows 90 seconds, like the account-modifying
tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The SEP-10 header-token test, the SEP-6 setup and the account service
setup each fund a new account with friendbot and then do more testnet
work, all within 30 seconds. A single friendbot call has been taking 15
to 26 seconds, which timed out the SEP-10 test on CI and, in October,
the SEP-6 setup. They now allow 90 seconds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The recovery integration test creates three new accounts, so it always
funded them with friendbot one after the other before doing anything
else, within 60 seconds. A single friendbot call has been taking 15 to
26 seconds, and the test timed out on CI. It now funds them in parallel
and allows 120 seconds. The anchor platform setup makes one friendbot
call within 30 seconds, so it now allows 90 seconds too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@CassioMG
CassioMG merged commit 12b0ce5 into main Nov 6, 2026
11 checks passed
@CassioMG
CassioMG deleted the release/6.0.0 branch November 6, 2026 22:08
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.

3 participants