From c3927e403cf602dc3f00e1c954eb8687aed59566 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Mon, 30 Mar 2026 14:18:15 +0000 Subject: [PATCH] fix: fall back to recovery signer when wallet has multiple delegated signers Co-Authored-By: Agus --- .changeset/fix-multi-signer-recovery-fallback.md | 10 ++++++++++ packages/wallets/src/wallets/wallet.ts | 12 ++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 .changeset/fix-multi-signer-recovery-fallback.md diff --git a/.changeset/fix-multi-signer-recovery-fallback.md b/.changeset/fix-multi-signer-recovery-fallback.md new file mode 100644 index 000000000..6f44f6fea --- /dev/null +++ b/.changeset/fix-multi-signer-recovery-fallback.md @@ -0,0 +1,10 @@ +--- +"@crossmint/wallets-sdk": patch +--- + +fix: fall back to recovery signer when wallet has multiple delegated signers + +Previously, when a wallet had more than one delegated signer, `initDefaultSigner` would leave the signer undefined, requiring an explicit `useSigner()` call. This caused errors like "No signer is set. This wallet has multiple signers configured" in applications that use the wallet directly (e.g. lobster.cash agent setup flow with >1 agents). + +Now the wallet falls back to the recovery signer in the multi-signer case, keeping the wallet usable by default. Users who need a specific delegated signer can still call `useSigner()` to override. + diff --git a/packages/wallets/src/wallets/wallet.ts b/packages/wallets/src/wallets/wallet.ts index d42a94f95..6d9d284a4 100644 --- a/packages/wallets/src/wallets/wallet.ts +++ b/packages/wallets/src/wallets/wallet.ts @@ -149,7 +149,7 @@ export class Wallet { * 2. If no device signer and no pending recovery: fallback based on delegated signer count * - 0 signers: try to use recovery signer * - 1 signer: try to use that signer - * - >1 signers: leave undefined (user must call useSigner) + * - >1 signers: fall back to recovery signer (wallet owner can always sign) * * Note: Server and api-key signers may fail to auto-assemble if required data * is not available in the API response. In those cases, the signer is left undefined. @@ -176,8 +176,16 @@ export class Wallet { // Exactly 1 auto-assemblable signer → use it const internalConfig = this.buildInternalSignerConfig(this.#initialSigners[0]); this.#signer = await this.assembleFullSigner(internalConfig); + } else { + // >1 signers → fall back to recovery signer so the wallet remains usable. + // Users who need a specific delegated signer can call useSigner() to override. + walletsLogger.info("wallet.initDefaultSigner.multipleSignersFallbackToRecovery", { + signerCount: this.#initialSigners.length, + recoveryType: this.#recovery.type, + }); + const internalConfig = this.buildInternalSignerConfig(this.#recovery); + this.#signer = await this.assembleFullSigner(internalConfig); } - // >1 signers → leave #signer undefined, user must call useSigner() } catch (error) { walletsLogger.warn("wallet.initDefaultSigner.autoAssemblyFailed", { recoveryType: this.#recovery.type,