Skip to main content

Overview

The EVMWallet class extends the base Wallet with EVM-specific functionality including:
  • Custom transaction execution
  • Message signing
  • EIP-712 typed data signing
  • Smart contract interactions
  • Viem integration

Create an EVM Wallet Instance

Cast a base Wallet to EVMWallet for EVM-specific operations:
import { EVMWallet } from "@crossmint/wallets-sdk";

// Assuming you have a wallet instance
const evmWallet = EVMWallet.from(wallet);
The EVMWallet.from() method will throw an error if the wallet is not on an EVM chain.

Send Custom Transactions

Execute custom transactions on EVM chains.

Method Signature

evmWallet.sendTransaction(params: EVMTransactionInput): Promise<Transaction>

Send Raw Transaction

Send a serialized transaction:
const tx = await evmWallet.sendTransaction({
    transaction: "0x...", // Serialized transaction hex
});

console.log(tx.hash);
console.log(tx.explorerLink);

Send with Call Data

Send a transaction with explicit call data:
const tx = await evmWallet.sendTransaction({
    to: "0xContractAddress...",
    value: 0n, // Value in wei (bigint)
    data: "0x...", // Encoded function call
});

Send with ABI

Use contract ABI for type-safe contract interactions:
const ERC20_ABI = [
    {
        name: "transfer",
        type: "function",
        inputs: [
            { name: "to", type: "address" },
            { name: "amount", type: "uint256" },
        ],
        outputs: [{ name: "", type: "bool" }],
        stateMutability: "nonpayable",
    },
];

const tx = await evmWallet.sendTransaction({
    to: "0xTokenContractAddress...",
    abi: ERC20_ABI,
    functionName: "transfer",
    args: ["0xRecipient...", 1000000n], // 1 USDC (6 decimals)
    value: 0n,
});

Prepare-Only Mode

Create a transaction without executing:
const preparedTx = await evmWallet.sendTransaction({
    to: "0xContractAddress...",
    data: "0x...",
    options: {
        experimental_prepareOnly: true,
    },
});

console.log(preparedTx.transactionId);

// Approve later
const completedTx = await wallet.approve({
    transactionId: preparedTx.transactionId,
});

With Custom Signer

const tx = await evmWallet.sendTransaction({
    to: "0xContractAddress...",
    data: "0x...",
    options: {
        experimental_signer: "external-wallet:0x...",
    },
});

Parameters

to
string
required
Recipient address (contract or EOA)
value
bigint
Value to send in wei (default: 0n)
data
0x${string}
Encoded transaction data
abi
Abi
Contract ABI for encoding function calls
functionName
string
Function name to call (requires abi)
args
unknown[]
Function arguments (requires abi and functionName)
transaction
string
Serialized transaction (alternative to above fields)
options
TransactionInputOptions

Sign Messages

Sign arbitrary messages with the wallet’s private key.

Method Signature

evmWallet.signMessage(params: SignMessageInput): Promise<Signature>

Basic Usage

const signResult = await evmWallet.signMessage({
    message: "Hello, blockchain!",
});

console.log(signResult.signature);   // "0x..."
console.log(signResult.signatureId); // Signature ID for tracking

Prepare-Only Mode

const preparedSig = await evmWallet.signMessage({
    message: "Hello, blockchain!",
    options: {
        experimental_prepareOnly: true,
    },
});

console.log(preparedSig.signatureId);

// Approve later
const completedSig = await wallet.approve({
    signatureId: preparedSig.signatureId,
});

console.log(completedSig.signature);

Sign Typed Data (EIP-712)

Sign structured data following the EIP-712 standard.

Method Signature

evmWallet.signTypedData(params: SignTypedDataInput): Promise<Signature>

Usage

const signResult = await evmWallet.signTypedData({
    domain: {
        name: "My DApp",
        version: "1",
        chainId: 137n, // Polygon
        verifyingContract: "0xContractAddress...",
    },
    types: {
        Person: [
            { name: "name", type: "string" },
            { name: "wallet", type: "address" },
        ],
        Mail: [
            { name: "from", type: "Person" },
            { name: "to", type: "Person" },
            { name: "contents", type: "string" },
        ],
    },
    primaryType: "Mail",
    message: {
        from: {
            name: "Alice",
            wallet: "0xAlice...",
        },
        to: {
            name: "Bob",
            wallet: "0xBob...",
        },
        contents: "Hello, Bob!",
    },
    chain: "polygon",
});

console.log(signResult.signature);

Permit Example

Sign an ERC20 permit for gasless approvals:
const permitSignature = await evmWallet.signTypedData({
    domain: {
        name: "USD Coin",
        version: "2",
        chainId: 137n,
        verifyingContract: "0xUSDCContractAddress...",
    },
    types: {
        Permit: [
            { name: "owner", type: "address" },
            { name: "spender", type: "address" },
            { name: "value", type: "uint256" },
            { name: "nonce", type: "uint256" },
            { name: "deadline", type: "uint256" },
        ],
    },
    primaryType: "Permit",
    message: {
        owner: wallet.address,
        spender: "0xSpenderAddress...",
        value: 1000000n,
        nonce: 0n,
        deadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
    },
    chain: "polygon",
});

Parameters

domain
TypedDataDomain
required
EIP-712 domain information
types
Record<string, Array<{name: string, type: string}>>
required
Type definitions for the structured data
primaryType
string
required
The primary type being signed
message
Record<string, any>
required
The data to sign
chain
EVMChain
required
The EVM chain (e.g., “polygon”, “ethereum”)
options
SignatureInputOptions

Viem Integration

Get a Viem public client for advanced blockchain interactions.

Method Signature

evmWallet.getViemClient(params?: { transport?: HttpTransport }): PublicClient

Usage

import { http } from "viem";

// Get client with default transport
const viemClient = evmWallet.getViemClient();

// Or provide custom transport
const customClient = evmWallet.getViemClient({
    transport: http("https://polygon-rpc.com"),
});

// Use Viem client for read operations
const blockNumber = await viemClient.getBlockNumber();
const balance = await viemClient.getBalance({ address: wallet.address });

Complete Example: NFT Minting

Here’s a full example of minting an NFT using the EVM wallet:
import { CrossmintWallets, createCrossmint, EVMWallet } from "@crossmint/wallets-sdk";

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

// Get wallet
const wallet = await crossmintWallets.getOrCreateWallet({
    chain: "polygon",
    signer: { type: "email", email: "[email protected]", onAuthRequired: async (...) => {...} },
});

// Cast to EVM wallet
const evmWallet = EVMWallet.from(wallet);

// Mint NFT
const NFT_CONTRACT_ABI = [
    {
        name: "mint",
        type: "function",
        inputs: [{ name: "to", type: "address" }],
        outputs: [],
        stateMutability: "payable",
    },
];

const mintTx = await evmWallet.sendTransaction({
    to: "0xNFTContractAddress...",
    abi: NFT_CONTRACT_ABI,
    functionName: "mint",
    args: [wallet.address],
    value: 0n, // Mint price in wei
});

console.log(`NFT minted! Transaction: ${mintTx.explorerLink}`);

Supported EVM Chains

The SDK supports all major EVM chains including:
  • Ethereum (mainnet, sepolia)
  • Polygon (mainnet, amoy)
  • Base (mainnet, sepolia)
  • Arbitrum (mainnet, sepolia)
  • Optimism (mainnet, sepolia)
  • Avalanche (mainnet, fuji)
  • BNB Chain
  • And many more…

Next Steps

Wallet Operations

Learn about common wallet operations

Delegated Signers

Add multiple signers to a wallet

Solana Wallets

Learn about Solana-specific operations

Stellar Wallets

Learn about Stellar-specific operations

Build docs developers (and LLMs) love