Motivation for v2

  • Simplify the Wallets SDK and reduce web3-specific jargon
  • Unify wallet types and signer configs across chains
  • Provide better defaults for common use cases
  • Make wallet integration faster and less error-prone
  • Enable advanced features via optional parameters when needed

Wallets SDK

Signer types and locators

Signer types and locators have been consolidated and simplified:

BeforeNow
evm-keypair solana-keypairexternal-wallet
evm-passkeypasskey
solana-fireblocks-custodial evm-fireblocks-custodialapi-key

getOrCreateWallet updated input arguments

// Before
const wallet = await crossmintWallets.getOrCreateWallet("evm-smart-wallet", {
    chain: "base-sepolia",
    adminSigner: {
        type: "evm-passkey",
    },
});

// Now
const wallet = await crossmintWallets.getOrCreateWallet({
    chain: "base", // base-sepolia will be inferred by the api key being from staging
    signer: {
        type: "passkey",
    },
});

Change #1: Wallet type

Wallet type is not an argument anymore. All wallets are smart wallets and type is inferred from the chain passed

Change #2: Signers configs

Signers configs are now a single argument.

//////////////////////
// Passkey signer
//////////////////////
// Before
{
  type: "evm-passkey";
  name?: string;
  signingCallback?: PasskeySigningCallback;
  creationCallback?: PasskeyCreationCallback;
};

// Now
{
    type: "passkey";
    name?: string;
    onCreatePasskey?: (name: string) => Promise<{ id: string; publicKey: { x: string; y: string } }>;
    onSignWithPasskey?: (message: string) => Promise<PasskeySignResult>;
};

//////////////////////
// Keypair signer
//////////////////////
// Before
{
  type: "evm-keypair";
  address: string;
  signer:
    | {
     type: "provider";
      provider: EIP1193Provider; // From viem
     }
    | {
     type: "viem_v2";
     account: Account; // From viem
   };
}

{
    type: "solana-keypair";
    address: SolanaAddress;
    signer: {
        signMessage: (message: Uint8Array) => Promise<Uint8Array>;
        signTransaction: (transaction: VersionedTransaction) => Promise<VersionedTransaction>;
    };
}
// Now
export type BaseExternalWalletSignerConfig = {
    type: "external-wallet";
    address: string;
};

export type EvmExternalWalletSignerConfig = BaseExternalWalletSignerConfig & {
    provider?: GenericEIP1193Provider | ViemEIP1193Provider;
    viemAccount?: Account;
};

export type SolanaExternalWalletSignerConfig = BaseExternalWalletSignerConfig & {
    onSignTransaction: (transaction: VersionedTransaction) => Promise<VersionedTransaction>;
};

//////////////////////
// Fireblocks
//////////////////////
// Before
{
    type: "solana-fireblocks-custodial";
};

// Now
{ type: "api-key" } // works for both EVM and Solana

Change #3: LinkedUser is now owner

LinkedUser field is now called owner.

// Before
const wallet = await crossmintWallets.getOrCreateWallet("evm-smart-wallet", {
    chain: "base-sepolia",
    linkedUser: "email:dev@company.com",
    adminSigner: {
        type: "evm-passkey",
    },
});

// Now
const wallet = await crossmintWallets.getOrCreateWallet({
    chain: "base-sepolia",
    owner: "email:dev@company.com",
    signer: {
        type: "passkey",
    },
});

SolanaSmartWallet and EVMSmartWallet get consolidated into Wallet

Change #1: getOrCreateWallet just returns a Wallet object

// Before
const wallet: SolanaSmartWallet = await crossmintWallets.getOrCreateWallet("solana-smart-wallet", {
    adminSigner: {
        type: "solana-fireblocks-custodial",
    },
});

const wallet: EVMSmartWallet = await crossmintWallets.getOrCreateWallet("evm-smart-wallet", {
    chain: "base",
    adminSigner: {
        type: "evm-passkey",
    },
});

// Now
const wallet: Wallet = await crossmintWallets.getOrCreateWallet({
    chain: "base", // or "solana"
    signer: {
        type: "passkey",
    },
});

The Wallet object has common methods for all chains including checking the balance, adding delegated signers and sending any kind of token.

Change #2: Balances

Balances now return an object with nativeToken, usdc and tokens. USDC and nativeToken balances are always fetched.

// Before
await wallet.getBalances(["sol", "usdc"]);

// Now
await wallet.balances();

Change #3: Sending transactions and signing messages

To create transactions that are not transferring any kind of token you now need to do the following:

// Before
wallet.sendTransaction({});

// Now
// EVM
const wallet: Wallet = // ...
const evmWallet: EVMWallet = EVMWallet.from(wallet);
evmWallet.sendTransaction(...);
evmWallet.signMessage(...);
evmWallet.signTypedData(...);

// Solana
const wallet: Wallet = // ...
const solanaWallet: SolanaWallet = SolanaWallet.from(wallet);
solanaWallet.sendTransaction(...);

Change #4: Delegated signer type

Delegated signer type is now a method on the Wallet object.

// Before
wallet.getDelegatedSigners();
await wallet.addDelegatedSigner(`solana-keypair:${newSigner}`);
wallet.send("email@gmail.com", "usdc", "1.2");

// Now
wallet.delegatedSigners();
await wallet.addDelegatedSigner({ signer: `external-wallet:${newSigner}` });