Skip to content

Wallet SDK: let useSigner resolve any recovery signer from the list - #2045

Merged
panosinthezone merged 5 commits into
devin/1788361578-recovery-getter-compatfrom
devin/1788363791-arbitrary-recovery-signer
Sep 8, 2026
Merged

Wallet SDK: let useSigner resolve any recovery signer from the list#2045
panosinthezone merged 5 commits into
devin/1788361578-recovery-getter-compatfrom
devin/1788363791-arbitrary-recovery-signer

Conversation

@panosinthezone

@panosinthezone panosinthezone commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Description

Follow-up to #2044. isRecoverySigner only compared against the primary recovery signer (#signerManager.recovery), so calling wallet.useSigner with a secondary recovery signer from a Solana/Stellar recovery list threw Signer "..." is not registered in this wallet. — even though on-chain every recovery signer can authorize on its own.

isRecoverySigner now iterates wallet.recoveryMethods:

for (const [index, recovery] of this.recoveryMethods.entries()) {
    if (recovery.type !== signerConfig.type) continue;
    if (!descriptor.matchesRecovery(signerConfig, recovery, ctx)) continue;
    if (descriptor.adoptsRecoveryConfigOnMatch) {
        index === 0
            ? this.#signerManager.adoptRecoveryConfig(signerConfig)  // primary: unchanged behavior
            : this.#recoverySigners[index] = signerConfig;           // secondary: fuller non-secret config is retained
    }
    return true;
}

A matched secondary recovery method resolves as an admin signer (status: "active", skips the delegated-signer registration check), same as the primary. Single-recovery wallets behave exactly as before since the list has one entry. The public full-list accessor is named recoveryMethods.

Test plan

  • Wallet tests cover secondary recovery method selection, rejection of non-members, and preventing server secrets from being retained in the public recovery method list.
  • pnpm --filter @crossmint/wallets-sdk test:vitest — 704 passed; 68 skipped.
  • pnpm lint completed with the repository's existing Biome diagnostics.

Package updates

  • @crossmint/wallets-sdk.changeset/recovery-signer-list.md documents the recoveryMethods accessor.

Link to Devin session: https://crossmint.devinenterprise.com/sessions/fcb6200e227c4733967916f9fcdc9838
Open in Devin Desktop: https://crossmint.devinenterprise.com/desktop/session/fcb6200e227c4733967916f9fcdc9838?variant=devin
Requested by: @panosinthezone

Co-Authored-By: Panayiotis Halios <panos@paella.dev>
@devin-ai-integration

Copy link
Copy Markdown
Contributor
Original prompt from Panayiotis

Investigate whether the changes in Crossmint/crossmint-sdk PR #2040 (#2040) introduced a breaking change in the wallets SDK recovery API, and ensure both input and output support an object OR an array for backward compatibility.

#``# Background / Context
The wallets SDK recently changed the recovery field so it accepts and returns a list of recovery signers on Solana and Stellar, while EVM still uses a single signer. Key files involved (all in repo Crossmint/crossmint-sdk):

  • packages/wallets/src/wallets/types.ts — defines RecoveryCreateArg&lt;C&gt; and WalletCreateArgs&lt;C&gt;. Currently:
    export type RecoveryCreateArg&lt;C extends Chain&gt; = C extends SolanaChain | StellarChain
        ? RecoverySignerConfigFor&lt;C&gt; | Array&lt;RecoverySignerConfigFor&lt;C&gt;&gt;
        : RecoverySignerConfigFor&lt;C&gt;;
    
    export type WalletCreateArgs&lt;C extends Chain&gt; = WalletArgsFor&lt;C&gt; &amp; {
        /** Recovery signer, or list of recovery signers on Solana and Stellar. */
        recovery: RecoveryCreateArg&lt;C&gt;;
  • packages/wallets/src/utils/recovery.tstoRecoverySignerList normalizes single object or array into an array.
  • packages/wallets/src/wallets/wallet.ts — the wallet.recovery getter (around lines 290-298) now returns Array&lt;RecoverySignerConfigForChain&lt;C&gt;&gt; on ALL chains (including EVM); previously (around lines 77-78) it returned a single SignerConfigForChain&lt;C&gt;. The getter is annotated ``@experimental.
  • packages/wallets/src/wallets/wallet-factory.test.ts — tests expect wallet.recovery to be an array (e.g. wallet.recovery.map((signer) =&gt; signer.type), wallet.recovery[1]).
  • .changeset/recovery-signer-list.md — marks ``@crossmint/wallets-sdk as a `minor` bump.
  • .changeset/recovery-list-providers.md — marks react providers as patch; handles createOnLogin.recovery given as a list.

#``# What to do

  1. Determine the actual diff of PR #2040. Fetch/inspect the PR changes (use git log/git diff on the relevant commi... (2182 chars truncated...)

@changeset-bot

changeset-bot Bot commented Sep 2, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 898ad6a

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 9 packages
Name Type
@crossmint/wallets-sdk Patch
@crossmint/wallets-quickstart-devkit Patch
@crossmint/wallets-playground-react Patch
@crossmint/client-sdk-react-base Patch
@crossmint/client-sdk-react-native-ui Patch
@crossmint/client-sdk-react-ui Patch
@crossmint/wallets-playground-expo Patch
@crossmint/auth-ssr-nextjs-demo Patch
@crossmint/client-sdk-nextjs-starter Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@devin-ai-integration

Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI' or '@devin'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@panosinthezone panosinthezone changed the title feat(wallets): let useSigner resolve any recovery signer from the list Wallet SDK: let useSigner resolve any recovery signer from the list Sep 2, 2026
@greptile-apps

greptile-apps Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor
Prompt To Fix All With AI
### Issue 1
packages/wallets/src/wallets/wallet.ts:1126
**Secondary server secrets persist**

When a secondary server recovery signer is selected, this assignment stores its complete secret-bearing configuration in `#recoverySigners`, while the subsequent `stripSecretFromRecovery()` call sanitizes only the primary recovery entry. The secret therefore remains exposed through the public `wallet.recoverySigners` getter, unnecessarily extending its lifetime and exposure surface.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (1): Last reviewed commit: "feat(wallets): let useSigner resolve any..." | Re-trigger Greptile

Comment thread packages/wallets/src/wallets/wallet.ts
devin-ai-integration Bot and others added 2 commits September 2, 2026 15:52
Co-Authored-By: Panayiotis Halios <panos@paella.dev>
Co-Authored-By: Panayiotis Halios <panos@paella.dev>
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

🔥 Smoke Test Results

Status: Failed

Statistics

  • Total Tests: 5
  • Passed: 3 ✅
  • Failed: 1 ❌
  • Skipped: 1 ⚠️
  • Duration: 4.42 min

Test Details


This is a non-blocking smoke test. Full regression tests run separately.

Co-Authored-By: Panayiotis Halios <panos@paella.dev>
…rbitrary-recovery-signer

Co-Authored-By: Panayiotis Halios <panos@paella.dev>
@panosinthezone
panosinthezone merged commit 4424fd8 into main Sep 8, 2026
4 of 6 checks passed
@panosinthezone
panosinthezone deleted the devin/1788363791-arbitrary-recovery-signer branch September 8, 2026 11:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants