Wallets

Sign Transactions on EVM chains

Learn how to create EVM wallets, build transactions, and sign them with our server-side SDK.

This tutorial walks you through creating a developer-controlled wallet to sign transactions on EVM chains.

Before you begin:

When creating a developer-controlled wallet, pass EVM-TESTNET or EVM in the blockchains field. This wallet can be used to sign transactions on any EVM chain.

The following example code shows how to create a wallet using the Circle Developer SDK.

const response = await circleDeveloperSdk.createWallets({
  accountType: "EOA",
  blockchains: ["EVM-TESTNET"],
  count: 2,
  walletSetId: "<wallet-set-id>",
});

To build a transaction, connect to an Ethereum node and prepare your transaction object as shown in the following example code.

const { createPublicClient, http, parseEther, parseGwei } = require("viem");

// Connect to an Ethereum node
const client = createPublicClient({
  chain: "mainnet",
  transport: http("https://mainnet.infura.io/v3/YOUR-PROJECT-ID"),
});

async function buildTransactionObject() {
  // Sender's address
  const senderAddress = "0x1234..."; // Replace with the sender's address

  // Recipient's address
  const recipientAddress = "0x5678..."; // Replace with the recipient's address

  // Amount to send in wei
  const amountToSend = parseEther("0.01");

  try {
    // Get the nonce
    const nonce = await client.getTransactionCount({
      address: senderAddress,
    });

    // Estimate gas limit
    const estimateGas = await client.estimateGas({
      from: senderAddress,
      to: recipientAddress,
      value: amountToSend,
    });

    // Get the current gas price
    const gasPrice = await client.getGasPrice();

    // Calculate max fees with some premium
    const maxFeePerGas = (gasPrice * 120n) / 100n; // Add 20% premium
    const maxPriorityFeePerGas = parseGwei("2"); // Set fixed priority fee

    // Prepare the transaction object
    const txObject = {
      nonce: nonce,
      to: recipientAddress,
      value: amountToSend.toString(),
      gas: estimateGas.toString(),
      maxFeePerGas: maxFeePerGas.toString(),
      maxPriorityFeePerGas: maxPriorityFeePerGas.toString(),
      chainId: 1,
    };

    return JSON.stringify(txObject); // Return the transaction object in JSON string
  } catch (error) {
    console.error("Error building transaction object:", error);
    throw error; // Rethrow the error for further handling
  }
}

The following example code shows how to sign a transaction.

const responseObject = await circleDeveloperSdk.signTransaction({
  walletID: "<wallet-id>",
  transaction: txObjectString, // Pass the transaction object
});
Did this page help you?
© 2023-2025 Circle Technology Services, LLC. All rights reserved.