Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .changeset/fix-multi-signer-recovery-fallback.md
Original file line number Diff line number Diff line change
@@ -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.

12 changes: 10 additions & 2 deletions packages/wallets/src/wallets/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ export class Wallet<C extends Chain> {
* 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.
Expand All @@ -176,8 +176,16 @@ export class Wallet<C extends Chain> {
// 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,
Expand Down
Loading