Skip to content

v3.9.0 - Muxed contract addresses and Soroban auth fixes

Choose a tag to compare

@christian-rogobete christian-rogobete released this 16 Oct 00:01
e36f866

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, and isValidMuxedContractId handle the SEP-23 W... strkey, which carries the 32-byte contract id followed by the 8-byte big-endian id. Address gains TYPE_MUXED_CONTRACT, muxedContractId, forMuxedContractId, and forMuxedContract, and addressFromId resolves a W... strkey. The immutable MuxedContract pairs a contract with an id and converts between the strkey, XdrMuxedContract, and Address (fromMuxedContractId, toXdr, fromXdr, toAddress). Its constructor throws ArgumentError for a contract id that is neither a C... 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). XdrSCAddressType gains SC_ADDRESS_TYPE_MUXED_CONTRACT (5), and XdrSCAddress the arm muxedContract. Address.fromXdr and XdrSCVal.toNative return that arm as a TYPE_MUXED_CONTRACT address, and XDR-JSON renders it as its W... strkey. XdrContractCostType gains nine ML-DSA members, MlDsa44DecodeVerifyingKey (86) through VerifyMlDsa87Sig (94). Both types are constant classes. A switch omitting the new cases and a default skips those values without an analyzer diagnostic. Add cases or a default.
  • 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). XdrStellarValueType gains STELLAR_VALUE_SIGNED_MS (3) and STELLAR_VALUE_EMPTY_TX_SET_MS (4), with the XdrStellarValueExt arms signedMsValue and proposedMsValue that carry closeTimeMs (#207).
  • The Horizon matrix targets Horizon v29.0.0 and the RPC matrix stellar-rpc v29.0.1 (#236).
  • AGENTS.md and CONTRIBUTING.md document 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 toml constraint is >=0.17.0 <0.19.0, so apps can resolve toml 0.17 or 0.18 (#221).

Deprecated

  • TransactionEvents.diagnosticEventsXdr. Read GetTransactionResponse.diagnosticEventsXdr for a single transaction or TransactionInfo.diagnosticEventsXdr for 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

  • GetTransactionResponse reads the top-level diagnosticEventsXdr that SorobanServer.getTransaction returns; before this change, those events went unread (#205).
  • AssembledTransaction.sign stops on every unsigned account that needsNonInvokerSigningBy reports, 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.0

References

Full change list: CHANGELOG