Stellar Flutter SDK 3.10.0 completes Protocol 30 support and guards contract addresses

2 hours ago

Stellar Flutter SDK 3.10.0 completes Protocol 30 support. 3.9.0 shipped the new XDR, including muxed contract addresses, which start with a W instead of a C. This release adds the Horizon 30 fields for them, refuses them where Protocol 30 doesn't accept one, and fixes a round of bugs.

Ask about this presentation

Chapters

  1. 0:00Protocol 30 support is complete
  2. 0:21Contract credits carry the muxed address
  3. 0:40Only a contract address passes
  4. 0:58Where the check runs
  5. 1:18What changes for code that calls them
  6. 1:36Addresses compare by value
  7. 1:53Status polling stops at the deadline
  8. 2:14Fixes you may have hit
  9. 2:38Deprecated
  10. 2:57Upgrade
Show transcript
  1. Stellar Flutter SDK 3.10.0 completes Protocol 30 support. 3.9.0 shipped the new XDR, including muxed contract addresses, which start with a W instead of a C. This release adds the Horizon 30 fields for them, refuses them where Protocol 30 doesn't accept one, and fixes a round of bugs.

    Slide text
    Soneso stellar_flutter_sdk 3.10.0

    Stellar Flutter SDK 3.10.0 completes Protocol 30 support and guards contract addresses

    Horizon 30 fields for muxed contracts, earlier errors for the wrong address, and a round of fixes.

    C
    contract
    W
    muxed contract
  2. When a transfer or mint lands on a muxed contract address, Horizon 30 now reports it. The contract credited effect gains contract muxed, which holds the W address, and contract muxed ID, which holds the ID as a decimal string. For every other credit, both are null.

    Slide text
    Soneso Added · Horizon 30

    Contract credit effects now carry the muxed contract address

    W
    class ContractCreditedEffectResponse { String contract; String? contractMuxed; // W... strkey String? contractMuxedId; // decimal string ... }

    Both are null for every other credit.

  3. Where the SDK needs a contract, it now checks your input before it sends anything. A C address passes, and so does the 64-character hex of a contract ID. Everything else throws an argument error, from an account or a secret seed to a muxed contract that starts with W.

    Slide text
    Soneso Changed · Soroban

    To invoke, load or read a contract, only a contract address passes

    Accepted
    C
    contract, or its 64-character hex id
    ArgumentError, before any request
    G
    account
    M
    muxed account
    B
    claimable balance
    L
    liquidity pool
    S
    secret seed
    W
    muxed contract
  4. That check runs in three places. The contract to invoke, in the host function constructor and the assembled transaction builders. The contract to load, in the Soroban client and the server's contract loaders. And the owner in get contract data, which also refuses a storage key that holds a muxed address.

    Slide text
    Soneso Changed · Soroban

    The check runs in these calls, before any request

    To invoke
    the contract to invoke
    • InvokeContractHostFunction constructor and contractID setter
    • AssembledTransaction.build
    • AssembledTransaction.buildWithOp
    To load
    the contract to load
    • SorobanClient.forClientOptions
    • SorobanServer.loadContractCodeForContractId
    • SorobanServer.loadContractInfoForContractId
    To read data
    the contract data owner
    • SorobanServer.getContractData
    Also refuses a key holding an M… or W… address, inside a Vec or a Map too.
  5. In 3.9.0, the invoke calls took any address, and the load and data calls threw a format exception. Now they all throw an argument error that names the role and the kind of address. The message leaves a secret seed out, and for a muxed contract it says to pass the base C address.

    Slide text
    Soneso Changed · Soroban

    Any other address now throws ArgumentError in each of them

    3.9.0
    Invoke calls accepted every address kind. Load and data calls threw FormatException for a non-contract id.
    3.10.0
    ArgumentError, naming the role and the address kind.
    The contract to invoke must be a contract (C...) address, got a muxed contract (W...) address: W...; use its base contract (C...) address
  6. Address and muxed contract now compare by value. Two instances that encode to the same XDR address are equal, whichever spelling of the ID built them, so they work as map keys and set members. In 3.9.0, they were equal only when they were the same object.

    Slide text
    Soneso Changed · Soroban

    Address and MuxedContract now compare by value

    C
    =
    C
    final a = Address.forContractId(id); final b = Address.forContractId(id); a == b // 3.9.0: false // 3.10.0: true {a, b}.length // 3.10.0: 1

    Equal when they encode to the same XDR address, whichever accepted spelling of the id built them.

  7. If you send transactions through an assembled transaction, send and sign and send now stop polling when your timeout runs out, with one last status request at the deadline that can take up to three seconds. Failed requests are retried, and the timeout error names the last one. In 3.9.0, a stalled request never returned.

    Slide text
    Soneso Fixed · Soroban

    send and signAndSend stop polling at your timeout

    last request, up to 3 s
    sent
    timeoutInSeconds
    3.10.0Failed status requests are retried, and the timeout exception names the last error.
    3.9.0Polling ran past the timeout, and a stalled request never returned.
  8. These fixes come from the hardening round. Event indexes from get events, Horizon pages in minified web builds, and the ledger entry extension were all null in 3.9.0, and now carry their values. A memo ID of zero is accepted, deeply nested XDR stops at 500 levels instead of exhausting the stack, and a broken SEP-7 link is reported as invalid.

    Slide text
    Soneso Fixed

    Fixes you may have hit in 3.9.0

    getEvents opIndex, txIndex
    null → filled from the response
    MemoId(0)
    threw → accepted, and SEP-7 memo=0 validates
    Horizon pages, minified web builds
    null → parsed
    Deeply nested XDR
    exhausted the stack → Exception past 500 levels
    LedgerEntry.ext
    null → read from extXdr
    SEP-7 links
    RangeError escaped → invalid result
  9. Two members are deprecated. Ledger entry key value decodes the key as the wrong XDR type, so use ledger key XDR instead. And in successful contract call is deprecated because Stellar RPC 30 and later leave it out. The SDK still reads it from older servers.

    Slide text
    Soneso Deprecated

    Move off keyValue and inSuccessfulContractCall

    LedgerEntry.keyValue
    →
    LedgerEntry.ledgerKeyXdr
    keyValue decodes the key as an XdrSCVal; ledgerKeyXdr decodes it as an XdrLedgerKey.
    EventInfo.inSuccessfulContractCall
    →
    omitted by Stellar RPC 30 and later
    The SDK still reads it from older servers.
  10. One limit: a host function decoded from XDR keeps whatever target it had, and encodes back unchanged. For everything you build, pass the base C address, and bump the dependency to 3.10.0. It needs Dart 3.8 and Flutter 3.32 or later. That completes Protocol 30 support.

    Slide text
    Soneso stellar_flutter_sdk 3.10.0

    Upgrade to 3.10.0

    dependencies: stellar_flutter_sdk: ^3.10.0
    Dart 3.8.0 and Flutter 3.32.0 or later
    Compatibility matrices: Horizon v30.0.0, stellar-rpc v30.0.0, 21 SEPs
    github.com/Soneso/stellar_flutter_sdk/releases/tag/3.10.0

What happened in AI today, in your inbox

One short email each evening. Read it and you’re caught up.

Built in New York with ❤️