Summary
A Guardian account's authentication component (built by @openzeppelin/miden-multisig-client) is not recognized by the Miden SDK's AccountInterface, so Account.getPublicKeyCommitments() returns [] for Guardian accounts. Any consumer that derives an account's public key through the SDK gets nothing back for Guardian accounts, while plain single-sig accounts work fine.
Environment
@openzeppelin/miden-multisig-client@0.15.0-rc.0
@miden-sdk/miden-sdk@0.15.2 (links miden-standards / miden-protocol 0.15.3)
Root cause
AccountInterface::from_account (miden-standards) classifies an account's components by exact MAST-root subset containment against a fixed set of bundled standard component templates, whose procedures live in the miden::standards::auth::* namespace.
A Guardian account's auth component is compiled at runtime from OZ's own MASM (auth_tx_multisig_guardian_ecdsa, using openzeppelin::auth::multisig_ecdsa / openzeppelin::auth::guardian_ecdsa). That is a different implementation in a different namespace, so its procedure MAST roots don't match any standard template — the component is bucketed as Custom. Custom is not an auth component, so interface.auth() is empty and account.getPublicKeyCommitments() returns [].
(Note: miden-standards does ship an AuthGuardedMultisig template, but it's a different implementation — miden::standards::auth::*, different exported procedures — so its roots can't match the OZ component.)
Reproduction
- Create a Guardian account via
MultisigClient.create(...).
- Fetch it and call
account.getPublicKeyCommitments() → [].
A plain AuthSingleSig (BasicWallet) account returns its commitment as expected, so this is specific to the OZ component.
Impact
Anything that reads a Guardian account's public key via the SDK breaks. In the Miden wallet this surfaced as dApp connections failing with NOT_GRANTED (the connect flow derives a session public key from getPublicKeyCommitments()), plus the reveal-private-key and public-key display views. Third-party dApps / SDK users reading a Guardian account's key hit the same.
Request
Either:
- Expose an accessor on
MultisigClient / Multisig (or the account inspector) to read a Guardian account's signer public-key commitments (hot/cold) directly, so consumers don't reach into storage; or
- Ship the component so miden-standards'
AccountInterface recognizes it — align with a standard guarded-multisig template, or provide a registration hook so from_account can classify the OZ component and return its approver commitments.
Wallet-side workaround we shipped
For accounts the SDK can't classify, we read the hot signer's commitment directly from the openzeppelin::multisig::signer_public_keys storage map (index 0). It works, but it hardcodes OZ's storage layout, which we'd rather not depend on long-term — hence this request.
Summary
A Guardian account's authentication component (built by
@openzeppelin/miden-multisig-client) is not recognized by the Miden SDK'sAccountInterface, soAccount.getPublicKeyCommitments()returns[]for Guardian accounts. Any consumer that derives an account's public key through the SDK gets nothing back for Guardian accounts, while plain single-sig accounts work fine.Environment
@openzeppelin/miden-multisig-client@0.15.0-rc.0@miden-sdk/miden-sdk@0.15.2(linksmiden-standards/miden-protocol0.15.3)Root cause
AccountInterface::from_account(miden-standards) classifies an account's components by exact MAST-root subset containment against a fixed set of bundled standard component templates, whose procedures live in themiden::standards::auth::*namespace.A Guardian account's auth component is compiled at runtime from OZ's own MASM (
auth_tx_multisig_guardian_ecdsa, usingopenzeppelin::auth::multisig_ecdsa/openzeppelin::auth::guardian_ecdsa). That is a different implementation in a different namespace, so its procedure MAST roots don't match any standard template — the component is bucketed asCustom.Customis not an auth component, sointerface.auth()is empty andaccount.getPublicKeyCommitments()returns[].(Note: miden-standards does ship an
AuthGuardedMultisigtemplate, but it's a different implementation —miden::standards::auth::*, different exported procedures — so its roots can't match the OZ component.)Reproduction
MultisigClient.create(...).account.getPublicKeyCommitments()→[].A plain
AuthSingleSig(BasicWallet) account returns its commitment as expected, so this is specific to the OZ component.Impact
Anything that reads a Guardian account's public key via the SDK breaks. In the Miden wallet this surfaced as dApp connections failing with
NOT_GRANTED(the connect flow derives a session public key fromgetPublicKeyCommitments()), plus the reveal-private-key and public-key display views. Third-party dApps / SDK users reading a Guardian account's key hit the same.Request
Either:
MultisigClient/Multisig(or the account inspector) to read a Guardian account's signer public-key commitments (hot/cold) directly, so consumers don't reach into storage; orAccountInterfacerecognizes it — align with a standard guarded-multisig template, or provide a registration hook sofrom_accountcan classify the OZ component and return its approver commitments.Wallet-side workaround we shipped
For accounts the SDK can't classify, we read the hot signer's commitment directly from the
openzeppelin::multisig::signer_public_keysstorage map (index 0). It works, but it hardcodes OZ's storage layout, which we'd rather not depend on long-term — hence this request.