Repository navigation
v3.9.0 - Muxed contract addresses and Soroban auth fixes
This release adds muxed contract addresses (W..., CAP-0084) and the XDR definitions of CAP-0084, CAP-0087, and CAP-0088. It tightens the address rules of ContractSpec and of Soroban signing. It fixes the four defects of the Q4 2026 hardening round. They concern the signature expiration ledger (#231), the pool share asset order (#232), the map key order (#233), and the signer check of sign (#234). Six changes are breaking.
Added
- Muxed contract addresses (#223).
StrKey.encodeMuxedContractId,decodeMuxedContractId, andisValidMuxedContractIdhandle the SEP-23W...strkey, which carries the 32-byte contract id followed by the 8-byte big-endian id.AddressgainsTYPE_MUXED_CONTRACT,muxedContractId,forMuxedContractId, andforMuxedContract, andaddressFromIdresolves aW...strkey. The immutableMuxedContractpairs a contract with an id and converts between the strkey,XdrMuxedContract, andAddress(fromMuxedContractId,toXdr,fromXdr,toAddress). Its constructor throwsArgumentErrorfor a contract id that is neither aC...strkey nor hex, or an id outside the unsigned 64-bit range. The SEP-23 guide describes the format. - XDR definitions at stellar-xdr
579a90b(#223).XdrSCAddressTypegainsSC_ADDRESS_TYPE_MUXED_CONTRACT(5), andXdrSCAddressthe armmuxedContract.Address.fromXdrandXdrSCVal.toNativereturn that arm as aTYPE_MUXED_CONTRACTaddress, and XDR-JSON renders it as itsW...strkey.XdrContractCostTypegains nine ML-DSA members,MlDsa44DecodeVerifyingKey(86) throughVerifyMlDsa87Sig(94). Both types are constant classes. Aswitchomitting the new cases and adefaultskips those values without an analyzer diagnostic. Add cases or adefault. - The SEP-23 compatibility matrix, with the strkey test vectors of the specification (#200, #236).
Changed
Breaking: AssetCode12 in XDR-JSON
The XDR-JSON parser rejects an AssetCode12 string that unescapes to fewer than five bytes, as the reference implementation does since 30.0.0. This covers the asset_code of XdrAssetAlphaNum12 and every other AssetCode12 field. fromXdrJson throws FormatException. Pad a short code with escaped NUL bytes to five bytes, "ABC\\0\\0" in the JSON document. XDR-JSON that the SDK writes already has this form. Before this change, "ABC" decoded to an asset code that the network rejects (#229).
Breaking: muxed credential addresses in Soroban signing
SorobanAuthorizationEntry.sign rejects an entry whose credential address is a muxed account (M...) or muxed contract (W...) address, as it rejects such a forAddress target. It throws Exception naming the address, and the entry stays unsigned. Before this change, the host rejected signatures on muxed credentials. Build the entry for the underlying G... or C... address. A W... forAddress target and a W... delegate of withDelegates fail as an M... address does. Their messages name both muxed kinds (#225, #223).
Breaking: ContractSpec address arguments
ContractSpec.nativeToXdrSCVal and funcArgsToXdrSCValues take for an Address parameter a G... or C... strkey, the 64-character hex of a contract id, or an Address of type account or contract. A MuxedAddress parameter also takes M... and W... strkeys and Address instances of those types. null converts to void; prebuilt XdrSCVal values pass through. Other unsupported inputs throw ContractSpecException naming the parameter type, accepted kinds, and value or runtime type. This covers claimable balance and liquidity pool addresses, a muxed address for an Address parameter, malformed strkeys, and hex of another length. Before this change, a malformed G... or C... strkey threw FormatException. Catch ContractSpecException and update matched messages (#224).
Other changes
- XDR definitions at stellar-xdr
c2612cf(CAP-0088).XdrStellarValueTypegainsSTELLAR_VALUE_SIGNED_MS(3) andSTELLAR_VALUE_EMPTY_TX_SET_MS(4), with theXdrStellarValueExtarmssignedMsValueandproposedMsValuethat carrycloseTimeMs(#207). - The Horizon matrix targets Horizon v29.0.0 and the RPC matrix stellar-rpc v29.0.1 (#236).
AGENTS.mdandCONTRIBUTING.mddocument the build, test, generation, and contribution rules (#228).- The documentation and the agent skill 1.8.0 describe this release. The skill declares the MIT license of the repository instead of Apache 2.0 (#236).
- The
tomlconstraint is>=0.17.0 <0.19.0, so apps can resolvetoml0.17 or 0.18 (#221).
Deprecated
TransactionEvents.diagnosticEventsXdr. ReadGetTransactionResponse.diagnosticEventsXdrfor a single transaction orTransactionInfo.diagnosticEventsXdrfor a transaction list (#205).
Fixed
Breaking: signature expiration ledger
AssembledTransaction.signAuthEntries keeps the stored signatureExpirationLedger of an entry once any node, top-level or CAP-71 delegate, carries a signature, so the signatures on it stay valid. Otherwise it sets validUntilLedgerSeq, or the latest ledger plus 100. A validUntilLedgerSeq that differs from the stored value of a signed entry throws ArgumentError naming both values; later signers omit it. A failure leaves the transaction's auth entries unchanged. Before this change, a changed expiration invalidated earlier signatures (#231). A signature value of void or an empty vector counts as unsigned, which SorobanAuthorizationEntry.carriesSignature checks (#235).
Breaking: map key order
ContractSpec builds every map, including map-encoded structs and maps inferred for SC_SPEC_TYPE_VAL, with its keys in the Soroban host's order. Two keys equal in that order throw ArgumentError naming the key; remove the duplicate. A test that compares encoded XDR with an insertion-ordered map needs the host order. compareScValHostOrder and sortedScMap are public, and decoded XDR keeps its map order. Before this change, the host rejected a map whose keys were out of its order (#233).
Breaking: pool share asset order
AssetTypePoolShare and Asset.fromXdrChangeTrustAsset order two credit assets of the same type and code by the issuers' raw 32-byte public keys, as stellar-core does. The reversed pair throws Exception naming both assets. Before this change, the SDK compared the G... text and rejected the order stellar-core accepts for some pairs. The two orders disagree when the issuers first differ at a digit in one and a letter in the other. Pass such a pair in the other order (#232).
Other fixes
GetTransactionResponsereads the top-leveldiagnosticEventsXdrthatSorobanServer.getTransactionreturns; before this change, those events went unread (#205).AssembledTransaction.signstops on every unsigned account thatneedsNonInvokerSigningByreports, including the top-level account of an entry with delegates, and never on a contract. Before this change, unsigned accounts under delegates passed this check (#234, #235).
Migrating to 3.9.0
The migration guide has one note per situation with its symptom and the action to take.
Compatibility
The compatibility matrices cover Horizon v29.0.0, stellar-rpc v29.0.1, and 21 SEPs at 100%. The SDK requires Flutter 3.32.0 and Dart 3.8.0 or later.
dependencies:
stellar_flutter_sdk: ^3.9.0References
Full change list: CHANGELOG