Skip to main content

Overview

Delegated signers allow you to add additional signers to a smart wallet, enabling:
  • Multi-signature wallets
  • Session keys for games and applications
  • Hardware wallet integration
  • Passkey-based co-signers
  • Custodial and non-custodial hybrid setups

Add a Delegated Signer

Add a new signer to an existing wallet.

Method Signature

wallet.addDelegatedSigner(params: {
    signer: string | RegisterSignerPasskeyParams;
    options?: AddDelegatedSignerOptions;
}): Promise<void>

Add Address Signer

Add an external wallet address as a delegated signer:
await wallet.addDelegatedSigner({
    signer: "0x1234567890abcdef1234567890abcdef12345678", // EVM address
});

// Or for Solana
await wallet.addDelegatedSigner({
    signer: "SolanaPublicKeyAddress...",
});

// Or for Stellar
await wallet.addDelegatedSigner({
    signer: "GStellarAddress...",
});

Add Passkey Signer (EVM only)

Add a WebAuthn/FIDO2 passkey as a delegated signer:
await wallet.addDelegatedSigner({
    signer: {
        publicKey: {
            x: "0x...", // X coordinate of passkey public key
            y: "0x...", // Y coordinate of passkey public key
        },
    },
});

Prepare-Only Mode

Create the signer registration without immediately executing:
const result = await wallet.addDelegatedSigner({
    signer: "0x...",
    options: {
        experimental_prepareOnly: true,
    },
});

// On Solana/Stellar, this returns a transactionId
if ('transactionId' in result) {
    console.log(result.transactionId);
    await wallet.approve({ transactionId: result.transactionId });
}

// On EVM chains, this returns a signatureId (or undefined if no approval needed)
if ('signatureId' in result && result.signatureId) {
    console.log(result.signatureId);
    await wallet.approve({ signatureId: result.signatureId });
}

Parameters

signer
string | RegisterSignerPasskeyParams
required
The signer to add
options
AddDelegatedSignerOptions

List Delegated Signers

Retrieve all delegated signers for a wallet.

Method Signature

wallet.delegatedSigners(): Promise<DelegatedSigner[]>

Usage

const signers = await wallet.delegatedSigners();

signers.forEach(signer => {
    console.log(signer.signer); // e.g., "external-wallet:0x..."
});

Response Type

signer
string
The signer locator in format external-wallet:address

Complete Example: EVM Multi-Sig

Create a wallet with multiple EVM signers:
import { CrossmintWallets, createCrossmint } from "@crossmint/wallets-sdk";

// Initialize
const crossmint = createCrossmint({ apiKey: "..." });
const crossmintWallets = CrossmintWallets.from(crossmint);

// Create primary wallet
const wallet = await crossmintWallets.getOrCreateWallet({
    chain: "polygon",
    signer: {
        type: "email",
        email: "[email protected]",
        onAuthRequired: async (needsAuth, sendEmailWithOtp, verifyOtp, reject) => {
            if (needsAuth) {
                await sendEmailWithOtp();
                const otp = await promptUserForOtp();
                await verifyOtp(otp);
            }
        },
    },
});

console.log(`Wallet created: ${wallet.address}`);

// Add a hardware wallet as co-signer
await wallet.addDelegatedSigner({
    signer: "0xHardwareWalletAddress...",
});

// Add a passkey as co-signer
await wallet.addDelegatedSigner({
    signer: {
        publicKey: {
            x: "0x...",
            y: "0x...",
        },
    },
});

// List all signers
const signers = await wallet.delegatedSigners();
console.log(`Total signers: ${signers.length}`);
signers.forEach(s => console.log(s.signer));

Complete Example: Solana Session Key

Add a session key for game or dApp usage:
import { CrossmintWallets, createCrossmint } from "@crossmint/wallets-sdk";
import { Keypair } from "@solana/web3.js";

// Initialize
const crossmint = createCrossmint({ apiKey: "..." });
const crossmintWallets = CrossmintWallets.from(crossmint);

// Create primary wallet
const wallet = await crossmintWallets.getOrCreateWallet({
    chain: "solana",
    signer: {
        type: "email",
        email: "[email protected]",
        onAuthRequired: async (needsAuth, sendEmailWithOtp, verifyOtp, reject) => {
            if (needsAuth) {
                await sendEmailWithOtp();
                const otp = await promptUserForOtp();
                await verifyOtp(otp);
            }
        },
    },
});

// Generate a session keypair (could be stored locally)
const sessionKey = Keypair.generate();

// Add session key as delegated signer
await wallet.addDelegatedSigner({
    signer: sessionKey.publicKey.toString(),
});

console.log(`Session key added: ${sessionKey.publicKey.toString()}`);

// Now the session key can sign transactions for this wallet
// Store the session keypair securely in local storage or session storage

Complete Example: Stellar Multi-Signer

Create a Stellar wallet with multiple signers:
import { CrossmintWallets, createCrossmint } from "@crossmint/wallets-sdk";

// Initialize
const crossmint = createCrossmint({ apiKey: "..." });
const crossmintWallets = CrossmintWallets.from(crossmint);

// Create primary wallet
const wallet = await crossmintWallets.getOrCreateWallet({
    chain: "stellar",
    signer: {
        type: "email",
        email: "[email protected]",
        onAuthRequired: async (needsAuth, sendEmailWithOtp, verifyOtp, reject) => {
            if (needsAuth) {
                await sendEmailWithOtp();
                const otp = await promptUserForOtp();
                await verifyOtp(otp);
            }
        },
    },
});

// Add additional Stellar address as co-signer
await wallet.addDelegatedSigner({
    signer: "GBACKUPADDRESS...",
});

// List signers
const signers = await wallet.delegatedSigners();
console.log(`Total signers: ${signers.length}`);

Use Cases

Multi-Signature Wallets

Create wallets requiring multiple approvals:
// Primary email signer
const wallet = await crossmintWallets.getOrCreateWallet({
    chain: "polygon",
    signer: { type: "email", email: "[email protected]", onAuthRequired: async (...) => {...} },
});

// Add co-signers
await wallet.addDelegatedSigner({ signer: "0xCoSigner1..." });
await wallet.addDelegatedSigner({ signer: "0xCoSigner2..." });

Session Keys for Games

Allow temporary signing permissions:
// Main wallet
const wallet = await crossmintWallets.getOrCreateWallet({
    chain: "solana",
    signer: { type: "email", email: "[email protected]", onAuthRequired: async (...) => {...} },
});

// Generate and add session key
const sessionKey = Keypair.generate();
await wallet.addDelegatedSigner({ signer: sessionKey.publicKey.toString() });

// Session key can now sign game transactions

Hardware Wallet Integration

Combine custodial and non-custodial security:
// Email-based wallet for convenience
const wallet = await crossmintWallets.getOrCreateWallet({
    chain: "ethereum",
    signer: { type: "email", email: "[email protected]", onAuthRequired: async (...) => {...} },
});

// Add Ledger/Trezor as co-signer for high-value transactions
await wallet.addDelegatedSigner({ signer: "0xLedgerAddress..." });

Passkey Co-Signing

Add biometric authentication (EVM only):
const wallet = await crossmintWallets.getOrCreateWallet({
    chain: "base",
    signer: { type: "email", email: "[email protected]", onAuthRequired: async (...) => {...} },
});

// Add WebAuthn passkey
await wallet.addDelegatedSigner({
    signer: {
        publicKey: { x: "0x...", y: "0x..." },
    },
});

Chain-Specific Behavior

EVM Chains

  • Delegated signers are managed through ERC-4337 smart account infrastructure
  • Adding a signer may require signature approval
  • Passkeys (WebAuthn) are supported as delegated signers
  • Returns signatureId in prepare-only mode (or undefined if no approval needed)

Solana

  • Delegated signers are added via on-chain transaction
  • Adding a signer requires transaction approval
  • Returns transactionId in prepare-only mode
  • Session keys are commonly used for games and dApps

Stellar

  • Delegated signers modify the account’s signer list
  • Adding a signer requires transaction approval
  • Returns transactionId in prepare-only mode
  • Multi-sig is native to Stellar protocol

Security Considerations

Delegated signers have full signing authority over the wallet. Only add trusted addresses.
  • Verify addresses: Double-check signer addresses before adding
  • Session key rotation: Regularly rotate session keys used in applications
  • Revocation: Currently, signers cannot be removed via the SDK (use chain-native tools)
  • Passkey storage: Passkey private keys are stored in secure enclaves (TPM, Secure Enclave)

Next Steps

Wallet Operations

Learn about common wallet operations

EVM Wallets

EVM-specific features and passkeys

Solana Wallets

Session keys for Solana applications

Stellar Wallets

Multi-sig on Stellar

Build docs developers (and LLMs) love