Skip to content

SDK: rpc.multisigChangeThreshold is missing #203

Open

Description

@aelmanaa

The SDK has no rpc.multisigChangeThreshold, although the instruction and transaction builders exist (added in #99) and the other controlled-multisig config instructions have all three:

$ node -e 'const m = require("@sqds/multisig"); console.log(typeof m.rpc.multisigChangeThreshold, typeof m.rpc.multisigSetTimeLock, typeof m.transactions.multisigChangeThreshold)'
undefined function function      # @sqds/multisig 2.1.4

So changing the threshold of a controlled multisig through the SDK means building, signing and sending the transaction by hand, unlike multisigSetTimeLock, multisigAddMember, multisigRemoveMember and the rest.

Also, transactions.multisigChangeThreshold declares a required spendingLimit: PublicKey parameter that it never uses, so callers have to pass a placeholder key.

Activity

  1. exocognosis commented on Oct 15, 2026

    @exocognosis

    Noted the same gap from the builder side. Question on the dead param: is spendingLimit in the transaction builder's signature just leftover from the other config builders, or does anything downstream (serializers, IDL consumers) depend on the parameter list matching across builders? If it is pure leftover, dropping it in the same change as the rpc wrapper saves a second breaking release.

  2. aelmanaa commented on Oct 15, 2026

    @aelmanaa
    Author

    @exocognosis It's a leftover. Nothing downstream depends on it.

    transactions.multisigChangeThreshold never reads spendingLimit, so it never reaches the serializer. The instruction has no such account either: its accounts are multisig, configAuthority, rentPayer and systemProgram, in the IDL and in the program's MultisigConfig struct. The other config builders, such as multisigSetTimeLock and multisigAddMember, don't take it. The file looks copied from multisigRemoveSpendingLimit, which was added in the same change (#97).

    Dropping it is a one-line change, but it breaks TypeScript callers at compile time. Today they all have to pass it, and an inline { ..., spendingLimit, ... } fails with TS2345 once the property is gone. JavaScript callers aren't affected. #204 makes it optional so it can ship without a breaking release. If the maintainers would rather remove it outright, I can change #204 to do that.

    How I checked

    On main at af94153 and on #204 at 61d8b53, with the SDK built from source.

    1. Serialized bytes. Built the transaction with transactions.multisigChangeThreshold four times, changing only spendingLimit: two random keys, PublicKey.default, and no key. The four serialized transactions are byte-identical, and identical to one built from instructions.multisigChangeThreshold. The spendingLimit key is not among the transaction's 4 account keys. The instruction's keys match the IDL's accounts for multisigChangeThreshold.

    2. Types. Compiled three callers with tsc 4.9.4 against the SDK's built .d.ts: an inline object that passes spendingLimit, a prebuilt args object that passes it, and an inline object that omits it.

      • main: only the caller that omits it fails.
      • feat(sdk): add rpc.multisigChangeThreshold #204 (optional): all three compile.
      • Property removed: only the inline caller that passes it fails, with TS2345 ('spendingLimit' does not exist in type).

      yarn ts in sdk/multisig passes in all three states.

    3. On chain. Built the program with cargo build-sbf --features testing, loaded it at the test program id in solana-test-validator 3.1.10 with the Anchor.toml fixture, and ran mocha tests/index.ts on a fresh ledger each run. feat(sdk): add rpc.multisigChangeThreshold #204's new test changes the threshold of a controlled multisig with a transaction built without spendingLimit, and it passes.

      The 3 failures expect Transaction signature verification failure, while Solana 3.1 reports Transaction did not pass signature verification. feat(sdk): add rpc.multisigChangeThreshold #204 does not change programs/.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions