> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getpara.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Ethereum Transfers with Para

> Learn how to send ETH transactions using Para with both Ethers and Viem libraries

This walkthrough covers sending basic Ethereum transfers using Para with both Ethers v6 and Viem v2. You'll learn transaction construction, gas estimation, and signing patterns for each library.

## Prerequisites

You need an authenticated Para client and basic knowledge of Ethereum transactions.

## Core Dependencies

<Tabs>
  <Tab title="Ethers v6">
    ```bash theme={null}
    npm install @getpara/react-sdk @getpara/ethers-v6-integration ethers
    ```
  </Tab>

  <Tab title="Viem v2">
    ```bash theme={null}
    npm install @getpara/react-sdk @getpara/viem viem
    ```
  </Tab>
</Tabs>

## Provider Setup

### RPC Configuration

<Tabs>
  <Tab title="Ethers v6">
    ```typescript theme={null}
    import { ethers } from "ethers";

    const RPC_URL = process.env.NEXT_PUBLIC_HOLESKY_RPC_URL || 
      "https://ethereum-holesky-rpc.publicnode.com";

    // Create JSON RPC provider
    const provider = new ethers.JsonRpcProvider(RPC_URL);
    ```
  </Tab>

  <Tab title="Viem v2">
    ```typescript theme={null}
    import { createPublicClient, http } from "viem";
    import { holesky } from "viem/chains";

    const RPC_URL = process.env.NEXT_PUBLIC_HOLESKY_RPC_URL || 
      "https://ethereum-holesky-rpc.publicnode.com";

    // Create public client for read operations
    const publicClient = createPublicClient({
      chain: holesky,
      transport: http(RPC_URL)
    });
    ```
  </Tab>
</Tabs>

### Para Signer Setup

<Tabs>
  <Tab title="Ethers v6">
    ```typescript theme={null}
    import { createParaEthersSigner } from "@getpara/ethers-v6-integration";
    import { useAccount, useClient } from "@getpara/react-sdk";

    // Get Para client and account
    const client = useClient();
    const { data: account } = useAccount();

    // Create Para Ethers signer
    let signer: ParaEthersSigner | null = null;

    if (account?.isConnected && provider && client) {
      signer = createParaEthersSigner({ para: client, provider: provider });
    }
    ```
  </Tab>

  <Tab title="Viem v2">
    ```typescript theme={null}
    import { createParaViemAccount, createParaViemClient } from "@getpara/viem";
    import { useAccount, useClient } from "@getpara/react-sdk";

    // Get Para client and account
    const client = useClient();
    const { data: account } = useAccount();

    // Create Para Viem account and wallet client
    let walletClient: any = null;

    if (account?.isConnected && client) {
      const viemAccount = createParaViemAccount(client);
      
      walletClient = createParaViemClient(client, {
        account: viemAccount,
        chain: holesky,
        transport: http(RPC_URL)
      });
    }
    ```
  </Tab>
</Tabs>

## Transaction Construction

### Basic Transaction Parameters

<Tabs>
  <Tab title="Ethers v6">
    ```typescript theme={null}
    import { parseEther, toBigInt } from "ethers";

    const constructTransaction = async (
      toAddress: string, 
      ethAmount: string,
      userAddress: string
    ) => {
      // Get transaction parameters
      const nonce = await provider.getTransactionCount(userAddress);
      const feeData = await provider.getFeeData();
      const gasLimit = toBigInt(21000); // Standard ETH transfer gas
      const value = parseEther(ethAmount);

      // Construct transaction object
      const transaction = {
        to: toAddress,
        value: value,
        nonce: nonce,
        gasLimit: gasLimit,
        maxFeePerGas: feeData.maxFeePerGas,
        maxPriorityFeePerGas: feeData.maxPriorityFeePerGas,
        chainId: 17000, // Holesky chain ID
      };

      return transaction;
    };
    ```
  </Tab>

  <Tab title="Viem v2">
    ```typescript theme={null}
    import { parseEther, parseGwei } from "viem";

    const constructTransaction = (
      toAddress: `0x${string}`,
      ethAmount: string,
      userAddress: `0x${string}`
    ) => {
      // Construct transaction object
      const transaction = {
        account: userAddress,
        to: toAddress,
        value: parseEther(ethAmount),
        chain: holesky,
        maxFeePerGas: parseGwei("100"),        // Custom max fee
        maxPriorityFeePerGas: parseGwei("3")   // Custom priority fee
      };

      return transaction;
    };
    ```
  </Tab>
</Tabs>

## Gas Estimation

### Estimate Transaction Cost

<Tabs>
  <Tab title="Ethers v6">
    ```typescript theme={null}
    import { formatEther } from "ethers";

    const estimateTransactionCost = async (
      userAddress: string,
      ethAmount: string
    ) => {
      // Get current balance
      const balanceWei = await provider.getBalance(userAddress);
      
      // Get fee data
      const feeData = await provider.getFeeData();
      const gasLimit = toBigInt(21000);
      
      // Calculate max gas cost
      const maxGasFee = gasLimit * (feeData.maxFeePerGas ?? toBigInt(0));
      const amountWei = parseEther(ethAmount);
      const totalCost = amountWei + maxGasFee;
      
      return {
        balance: formatEther(balanceWei),
        amount: formatEther(amountWei),
        estimatedGas: formatEther(maxGasFee),
        totalCost: formatEther(totalCost),
        hasSufficientBalance: totalCost <= balanceWei
      };
    };
    ```
  </Tab>

  <Tab title="Viem v2">
    ```typescript theme={null}
    import { formatEther, parseEther } from "viem";

    const estimateTransactionCost = async (
      userAddress: `0x${string}`,
      toAddress: `0x${string}`,
      ethAmount: string
    ) => {
      // Get current balance
      const balance = await publicClient.getBalance({ address: userAddress });
      const amountWei = parseEther(ethAmount);
      
      // Estimate gas for the specific transaction
      const estimatedGas = await publicClient.estimateGas({
        account: userAddress,
        to: toAddress,
        value: amountWei
      });
      
      // Get current gas price
      const gasPrice = await publicClient.getGasPrice();
      const estimatedGasCost = estimatedGas * gasPrice;
      const totalCost = amountWei + estimatedGasCost;
      
      return {
        balance: formatEther(balance),
        amount: formatEther(amountWei),
        estimatedGas: formatEther(estimatedGasCost),
        totalCost: formatEther(totalCost),
        hasSufficientBalance: totalCost <= balance
      };
    };
    ```
  </Tab>
</Tabs>

## Transaction Validation

### Balance and Parameter Checks

<Tabs>
  <Tab title="Ethers v6">
    ```typescript theme={null}
    const validateTransaction = async (
      userAddress: string,
      toAddress: string,
      ethAmount: string
    ) => {
      // Basic parameter validation
      if (!ethers.isAddress(toAddress)) {
        throw new Error("Invalid recipient address");
      }
      
      if (parseFloat(ethAmount) <= 0) {
        throw new Error("Amount must be greater than 0");
      }
      
      // Check balance and gas
      const estimation = await estimateTransactionCost(userAddress, ethAmount);
      
      if (!estimation.hasSufficientBalance) {
        throw new Error(
          `Insufficient balance. Need ${estimation.totalCost} ETH, have ${estimation.balance} ETH`
        );
      }
      
      return true;
    };
    ```
  </Tab>

  <Tab title="Viem v2">
    ```typescript theme={null}
    import { isAddress } from "viem";

    const validateTransaction = async (
      userAddress: `0x${string}`,
      toAddress: string,
      ethAmount: string
    ) => {
      // Basic parameter validation
      if (!isAddress(toAddress)) {
        throw new Error("Invalid recipient address");
      }
      
      if (parseFloat(ethAmount) <= 0) {
        throw new Error("Amount must be greater than 0");
      }
      
      // Check balance and gas
      const estimation = await estimateTransactionCost(
        userAddress, 
        toAddress as `0x${string}`, 
        ethAmount
      );
      
      if (!estimation.hasSufficientBalance) {
        throw new Error(
          `Insufficient balance. Need ${estimation.totalCost} ETH, have ${estimation.balance} ETH`
        );
      }
      
      return true;
    };
    ```
  </Tab>
</Tabs>

## Sending Transactions

### Execute Transfer

<Tabs>
  <Tab title="Ethers v6">
    ```typescript theme={null}
    const sendEthTransfer = async (
      toAddress: string,
      ethAmount: string,
      userAddress: string
    ) => {
      // Validate transaction
      await validateTransaction(userAddress, toAddress, ethAmount);
      
      // Construct transaction
      const transaction = await constructTransaction(toAddress, ethAmount, userAddress);
      
      // Send transaction using Para signer
      const txResponse = await signer.sendTransaction(transaction);
      
      console.log("Transaction sent:", txResponse.hash);
      
      // Wait for confirmation
      const receipt = await txResponse.wait();
      
      console.log("Transaction confirmed:", receipt.hash);
      console.log("Block number:", receipt.blockNumber);
      console.log("Gas used:", receipt.gasUsed.toString());
      
      return {
        hash: receipt.hash,
        blockNumber: receipt.blockNumber,
        gasUsed: receipt.gasUsed.toString(),
        status: receipt.status === 1 ? "success" : "failed"
      };
    };
    ```
  </Tab>

  <Tab title="Viem v2">
    ```typescript theme={null}
    const sendEthTransfer = async (
      toAddress: `0x${string}`,
      ethAmount: string,
      userAddress: `0x${string}`
    ) => {
      // Validate transaction
      await validateTransaction(userAddress, toAddress, ethAmount);
      
      // Send transaction using Para wallet client
      const hash = await walletClient.sendTransaction({
        account: userAddress,
        to: toAddress,
        value: parseEther(ethAmount),
        chain: holesky,
        maxFeePerGas: parseGwei("100"),
        maxPriorityFeePerGas: parseGwei("3")
      });
      
      console.log("Transaction sent:", hash);
      
      // Wait for confirmation
      const receipt = await publicClient.waitForTransactionReceipt({ hash });
      
      console.log("Transaction confirmed:", receipt.transactionHash);
      console.log("Block number:", receipt.blockNumber);
      console.log("Gas used:", receipt.gasUsed.toString());
      
      return {
        hash: receipt.transactionHash,
        blockNumber: receipt.blockNumber,
        gasUsed: receipt.gasUsed.toString(),
        status: receipt.status === "success" ? "success" : "failed"
      };
    };
    ```
  </Tab>
</Tabs>

## Complete Implementation Example

### Full Transfer Function

<Tabs>
  <Tab title="Ethers v6">
    ```typescript theme={null}
    import { ethers, parseEther, formatEther, toBigInt } from "ethers";
    import { createParaEthersSigner } from "@getpara/ethers-v6-integration";

    class EthersTransferService {
      private provider: ethers.JsonRpcProvider;
      private signer: ParaEthersSigner;
      
      constructor(rpcUrl: string, paraClient: any) {
        this.provider = new ethers.JsonRpcProvider(rpcUrl);
        this.signer = createParaEthersSigner({ para: paraClient, provider: this.provider });
      }
      
      async transfer(toAddress: string, ethAmount: string, fromAddress: string) {
        try {
          // Validate inputs
          if (!ethers.isAddress(toAddress)) {
            throw new Error("Invalid recipient address");
          }
          
          // Check balance
          const balance = await this.provider.getBalance(fromAddress);
          const amount = parseEther(ethAmount);
          const feeData = await this.provider.getFeeData();
          const gasLimit = toBigInt(21000);
          const maxGasFee = gasLimit * (feeData.maxFeePerGas ?? toBigInt(0));
          
          if (balance < amount + maxGasFee) {
            throw new Error("Insufficient balance for transfer and gas");
          }
          
          // Construct and send transaction
          const nonce = await this.provider.getTransactionCount(fromAddress);
          
          const transaction = {
            to: toAddress,
            value: amount,
            nonce: nonce,
            gasLimit: gasLimit,
            maxFeePerGas: feeData.maxFeePerGas,
            maxPriorityFeePerGas: feeData.maxPriorityFeePerGas,
            chainId: 17000
          };
          
          const txResponse = await this.signer.sendTransaction(transaction);
          const receipt = await txResponse.wait();
          
          return {
            success: true,
            hash: receipt.hash,
            blockNumber: receipt.blockNumber,
            gasUsed: receipt.gasUsed.toString()
          };
          
        } catch (error) {
          console.error("Transfer failed:", error);
          throw error;
        }
      }
    }
    ```
  </Tab>

  <Tab title="Viem v2">
    ```typescript theme={null}
    import { 
      createPublicClient, 
      createParaViemClient, 
      createParaViemAccount,
      http, 
      parseEther, 
      formatEther, 
      parseGwei,
      isAddress 
    } from "viem";
    import { holesky } from "viem/chains";

    class ViemTransferService {
      private publicClient: any;
      private walletClient: any;
      
      constructor(rpcUrl: string, paraClient: any) {
        this.publicClient = createPublicClient({
          chain: holesky,
          transport: http(rpcUrl)
        });
        
        const account = createParaViemAccount(paraClient);
        this.walletClient = createParaViemClient(paraClient, {
          account,
          chain: holesky,
          transport: http(rpcUrl)
        });
      }
      
      async transfer(
        toAddress: `0x${string}`, 
        ethAmount: string, 
        fromAddress: `0x${string}`
      ) {
        try {
          // Validate inputs
          if (!isAddress(toAddress)) {
            throw new Error("Invalid recipient address");
          }
          
          // Check balance and estimate gas
          const balance = await this.publicClient.getBalance({ address: fromAddress });
          const amount = parseEther(ethAmount);
          
          const estimatedGas = await this.publicClient.estimateGas({
            account: fromAddress,
            to: toAddress,
            value: amount
          });
          
          const gasPrice = await this.publicClient.getGasPrice();
          const estimatedGasCost = estimatedGas * gasPrice;
          
          if (balance < amount + estimatedGasCost) {
            throw new Error("Insufficient balance for transfer and gas");
          }
          
          // Send transaction
          const hash = await this.walletClient.sendTransaction({
            account: fromAddress,
            to: toAddress,
            value: amount,
            chain: holesky,
            maxFeePerGas: parseGwei("100"),
            maxPriorityFeePerGas: parseGwei("3")
          });
          
          const receipt = await this.publicClient.waitForTransactionReceipt({ hash });
          
          return {
            success: true,
            hash: receipt.transactionHash,
            blockNumber: receipt.blockNumber,
            gasUsed: receipt.gasUsed.toString()
          };
          
        } catch (error) {
          console.error("Transfer failed:", error);
          throw error;
        }
      }
    }
    ```
  </Tab>
</Tabs>

## Key Differences

### Library Comparison

| Feature                | Ethers v6                  | Viem v2                                    |
| ---------------------- | -------------------------- | ------------------------------------------ |
| **Provider Setup**     | `JsonRpcProvider`          | `createPublicClient`                       |
| **Wallet Client**      | `ParaEthersSigner`         | `createParaViemClient`                     |
| **Unit Parsing**       | `parseEther()`             | `parseEther()`                             |
| **Gas Estimation**     | `getFeeData()`             | `estimateGas()` + `getGasPrice()`          |
| **Transaction Send**   | `signer.sendTransaction()` | `walletClient.sendTransaction()`           |
| **Receipt Waiting**    | `txResponse.wait()`        | `publicClient.waitForTransactionReceipt()` |
| **Address Validation** | `ethers.isAddress()`       | `isAddress()`                              |

### Gas Strategy Differences

<Tabs>
  <Tab title="Ethers v6">
    ```typescript theme={null}
    // Ethers uses provider fee data
    const feeData = await provider.getFeeData();
    const transaction = {
      maxFeePerGas: feeData.maxFeePerGas,
      maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
    };
    ```
  </Tab>

  <Tab title="Viem v2">
    ```typescript theme={null}
    // Viem allows manual gas price setting
    const transaction = {
      maxFeePerGas: parseGwei("100"),
      maxPriorityFeePerGas: parseGwei("3")
    };
    ```
  </Tab>
</Tabs>

## Best Practices

### Transaction Safety

* **Always validate recipient addresses** before sending
* **Check balance including gas costs** before transaction construction
* **Use appropriate gas limits** (21000 for basic ETH transfers)
* **Handle network errors gracefully** with proper try/catch blocks
* **Wait for receipt confirmation** before considering transaction complete

### Gas Optimization

* **Monitor network conditions** for optimal gas pricing
* **Use EIP-1559 gas parameters** for better fee prediction
* **Estimate gas dynamically** rather than using static values
* **Consider gas limit buffers** for complex operations

### Error Handling

Common errors to handle:

* Invalid recipient addresses
* Insufficient balance
* Network connectivity issues
* Transaction reversion
* Nonce management conflicts

## Next Steps

<CardGroup cols={2}>
  <Card title="ERC-20 Token Transfers" href="/v2/walkthroughs/ethereum-transfers">
    Learn to transfer ERC-20 tokens
  </Card>

  <Card title="Transaction Monitoring" href="/v2/react/guides/sessions">
    Track transaction status and confirmations
  </Card>
</CardGroup>

## Related Walkthroughs

<CardGroup cols={3}>
  <Card title="Solana Transfers" icon="sun-bright" href="/v2/walkthroughs/solana-transfers">
    Intermediate · 20 min · SOL transfers and Solana programs
  </Card>

  <Card title="EIP-712 Typed Data Signing" icon="file-signature" href="/v2/walkthroughs/eip712-typed-data-signing">
    Intermediate · 20 min · Structured data signing
  </Card>

  <Card title="Aave v3 Integration" icon="landmark" href="/v2/walkthroughs/aave">
    Advanced · 45 min · Lending, borrowing, and yield strategies
  </Card>
</CardGroup>
