Repository navigation
This release completes Protocol 30 support and closes issue #238, "SDK Updates for Protocol 30 Compatibility". Version 3.9.0 shipped the Protocol 30 XDR: muxed contract addresses with the W... strkey (CAP-0084), the ML-DSA cost types (CAP-0087), and millisecond close times (CAP-0088). That XDR comes from stellar-xdr commit 579a90b on the curr branch, which matches the v30.0 tag (4f524bb) in every production definition. This release adds the Horizon 30 fields of contract credited effects and deprecates an event field that Stellar RPC 30 omits. It refuses a muxed contract address where Protocol 30 accepts none. In addition, it fixes the defects of the Q4 2026 hardening round in XDR nesting depth (#248), getEvents indexes (#246), and Horizon pages in web release builds (#240). The other fixes of that round concern the memo id 0 (#242), SEP-7 links (#244), the status polling deadline (#250), and the ledger entry extension and key (#252).
Protocol 30
ContractCreditedEffectResponse gains contractMuxed and contractMuxedId for a transfer or mint to a muxed contract address, as Horizon 30 reports it (#237). They hold the W... strkey and the muxed id as a decimal string, and are null for other credits.
This release deprecates EventInfo.inSuccessfulContractCall, because Stellar RPC 30 and later omit the field (#237). The SDK still reads it from older servers.
These calls take a contract as a C... strkey or the 64-character hex of a contract id. Any other input throws ArgumentError before any request (#239).
- The contract to invoke: the
InvokeContractHostFunctionconstructor and itscontractIDsetter,AssembledTransaction.build, andbuildWithOpfor the target of its operation. - The contract to load:
SorobanClient.forClientOptions,SorobanServer.loadContractCodeForContractId, andloadContractInfoForContractId. - The contract data owner:
SorobanServer.getContractData.
The message names the role and, for a recognized address, its kind; for a secret seed it names the kind and omits the seed. For a muxed contract it ends with the advice to pass the base C... address, shown here with the address shortened to W...:
The contract to invoke must be a contract (C...) address, got a muxed contract (W...) address: W...; use its base contract (C...) address
getContractData also throws ArgumentError for a key that holds a muxed account or muxed contract address, as itself, as a Vec element, or as a Map key or value:
Contract data keys cannot contain muxed account (M...) or muxed contract (W...) addresses
In 3.9.0 the invoke calls accepted every address kind, and the other calls threw FormatException for a non-contract id. A host function that HostFunction.fromXdr decodes keeps a target of any address kind, and toXdr re-encodes it as decoded. Details: muxed contracts.
Address and MuxedContract compare by value (#254). Two instances are equal when they encode to the same XDR address, whichever accepted spelling of the id they were built from, and they serve as map keys and set members. In 3.9.0 two instances were equal only when they were the same object.
Added
LedgerEntry.ledgerKeyXdrdecodes the entry key as anXdrLedgerKey(#253). It replacesLedgerEntry.keyValue, deprecated because it decodes the key as anXdrSCVal.
Fixed
Decoding and response parsing
- Binary XDR decoding bounds the nesting of recursive types such as
XdrSCVal,XdrClaimPredicate, andXdrSCSpecTypeDefat 500 levels and throws anExceptionpast it (#248). In 3.9.0 deep nesting exhausted the stack. EventInforeadsoperationIndexandtransactionIndexfromgetEventsresponses, soopIndexandtxIndexcarry the indexes the server sends (#246). In 3.9.0 both were null.- Horizon list queries parse in minified web release builds (#240). In 3.9.0 such a build received null in place of the page.
Memos and SEP-7 links
MemoIdaccepts the id 0, so envelopes and Horizon transaction records with that memo decode (#242). SEP-7 links withmemo=0pass validation. In 3.9.0 the id 0 threw anException.URIScheme.isValidSep7Urlreturns an invalid result for atxlink whosexdrfails to decode with aRangeError, such as a truncated envelope or a negative array count (#244). In 3.9.0 theRangeErrorleft the method.URIScheme.addSignaturethrowsArgumentErrorfor a link that carries asignatureparameter in any position, the first one included (#244). In 3.9.0 a link that started with it got a secondsignatureparameter.
Soroban transactions and ledger entries
AssembledTransaction.sendandsignAndSendend status polling whentimeoutInSecondshas elapsed, the time of each status request included (#250). They make a last status request at the deadline, which can take up to three seconds. They retry failed status requests and name the last request error in the timeout exception. In 3.9.0 polling ran past the timeout and never returned when a status request stalled.LedgerEntry.extreads the extension from theextXdrkey of the RPC response (#252). In 3.9.0 it was null for every entry.
Other changes
- The documentation and the agent skill 1.9.0 describe the muxed contract refusals, the bound of 500 levels on binary XDR decoding, and the status polling deadline. The skill describes SEP-30 recovery with two servers, a smart account backup signer, the 48-byte SEP-10 challenge nonce, and a remote signer that checks the invocation it signs. Its examples declare the names they use and print no secret seed or token.
- The skill's API reference lists the public API of 3.10.0. It keeps the type parameters of generic classes in its section headers and omits members annotated
@internal. - The 23 compatibility matrices are regenerated for 3.10.0, with Horizon v30.0.0 and stellar-rpc v30.0.0 as targets.
- The CI workflows pin
anthropics/claude-code-actionv1.0.262 andruby/setup-rubyv1.335.0.
Compatibility
The compatibility matrices cover Horizon v30.0.0, stellar-rpc v30.0.0, and 21 SEPs at 100%. The SDK requires Dart 3.8.0 and Flutter 3.32.0 or later.
dependencies:
stellar_flutter_sdk: ^3.10.0Protocol 30 XDR: stellar-xdr 579a90b (curr), equal to the v30.0 tag 4f524bb except for one test-only struct behind TEST_FEATURE.
References
- Full change list: CHANGELOG
- Protocol 30: issue #238