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

# Ethereum

With funding methods enabled for your app, MoonKey will prompt users to fund their wallets at two points in their experience:

1. **Manually** - When you call MoonKey's `fundWallet` method
2. **Automatically** - When the user attempts to send a transaction but has insufficient funds

You can configure the chain, asset, and amount that users should fund their wallets with directly in code.

## Manually invoking funding

Once you've enabled funding methods for your app in the Dashboard, use the `useFundWallet` hook to invoke the funding flow:

```tsx theme={null}
import { useWallets, useFundWallet } from '@moon-key/react-auth/ethereum';

function FundWalletButton() {
  const { wallets } = useWallets();
  const { fundWallet } = useFundWallet();
  
  const handleFund = async () => {
    if (wallets.length === 0) return;
    
    const selectedWallet = wallets[0];
    await fundWallet(selectedWallet.address, {
      chain: 'eip155:1',
      amount: '0.1'
    });
  };
  
  return <button onClick={handleFund}>Add Funds</button>;
}
```

Once invoked, the `fundWallet` method will open a modal with funding options for the user. If only one funding method is enabled, MoonKey will navigate directly to that flow.

<Warning>
  Purchases with third-party providers (like MoonPay) are not always instantaneous. There may be some time before the user completes their purchase and the funds are available in their wallet.
</Warning>

## Automatically invoking funding

When a user attempts to send a transaction but doesn't have sufficient funds, MoonKey will automatically show them an "Add funds" button in the transaction modal that enables them to invoke funding flows.

This helps users complete their intended actions without leaving your application.

## Setting funding parameters in code

You can override your Dashboard configuration by passing parameters to `fundWallet`:

### Basic parameters

<ParamField path="address" type="string" required>
  The wallet address to fund.
</ParamField>

<ParamField path="config.chain" type="string">
  The Ethereum chain to fund on. Use `'eip155:1'` for Ethereum mainnet, `'eip155:8453'` for Base, etc.

  If not specified, defaults to the chain configured in your Dashboard.
</ParamField>

<ParamField path="config.amount" type="string">
  The amount of the asset to fund as a decimal string (e.g., `'0.1'`).

  If not specified, defaults to the amount configured in your Dashboard.
</ParamField>

<ParamField path="config.asset" type="'native-currency' | 'USDC' | {erc20: string}">
  The asset to fund with:

  * `'native-currency'` - The chain's native currency (ETH, etc.)
  * `'USDC'` - USDC stablecoin
  * `{erc20: '0x...'}` - Any ERC-20 token by contract address

  Defaults to `'native-currency'`.
</ParamField>

<Note>
  Testnets are not supported. Only use mainnet chain IDs.
</Note>

## Examples

### Fund with ETH

Fund with the native currency (ETH):

```tsx theme={null}
import { useWallets, useFundWallet } from '@moon-key/react-auth/ethereum';

function FundWithETH() {
  const { wallets } = useWallets();
  const { fundWallet } = useFundWallet();
  
  const handleFund = async () => {
    const selectedWallet = wallets[0];
    
    await fundWallet(selectedWallet.address, {
      chain: 'eip155:8453', // Base
      amount: '0.01' // Defaults to 'native-currency' (ETH)
    });
  };
  
  return <button onClick={handleFund}>Fund with 0.01 ETH</button>;
}
```

### Fund with USDC

Fund with USDC stablecoin:

```tsx theme={null}
import { useWallets, useFundWallet } from '@moon-key/react-auth/ethereum';

function FundWithUSDC() {
  const { wallets } = useWallets();
  const { fundWallet } = useFundWallet();
  
  const handleFund = async () => {
    const selectedWallet = wallets[0];
    
    await fundWallet(selectedWallet.address, {
      chain: 'eip155:8453', // Base
      amount: '15',
      asset: 'USDC'
    });
  };
  
  return <button onClick={handleFund}>Fund with 15 USDC</button>;
}
```

### Fund with arbitrary ERC-20

Fund with any ERC-20 token:

```tsx theme={null}
import { useWallets, useFundWallet } from '@moon-key/react-auth/ethereum';

function FundWithCustomToken() {
  const { wallets } = useWallets();
  const { fundWallet } = useFundWallet();
  
  const handleFund = async () => {
    const selectedWallet = wallets[0];
    
    await fundWallet(selectedWallet.address, {
      chain: 'eip155:8453', // Base
      amount: '30',
      asset: {
        erc20: '0x0578d8A44db98B23BF096A382e016e29a5Ce0ffe' // Custom token
      }
    });
  };
  
  return <button onClick={handleFund}>Fund with Custom Token</button>;
}
```

### Fund on different networks

Fund on various EVM networks:

```tsx theme={null}
import { useWallets, useFundWallet } from '@moon-key/react-auth/ethereum';

function NetworkSelector() {
  const { wallets } = useWallets();
  const { fundWallet } = useFundWallet();
  
  const fundOnNetwork = async (chainId: string, chainName: string) => {
    const selectedWallet = wallets[0];
    
    await fundWallet(selectedWallet.address, {
      chain: chainId,
      amount: '0.05'
    });
  };
  
  return (
    <div>
      <button onClick={() => fundOnNetwork('eip155:1', 'Ethereum')}>
        Fund on Ethereum
      </button>
      <button onClick={() => fundOnNetwork('eip155:8453', 'Base')}>
        Fund on Base
      </button>
      <button onClick={() => fundOnNetwork('eip155:137', 'Polygon')}>
        Fund on Polygon
      </button>
      <button onClick={() => fundOnNetwork('eip155:42161', 'Arbitrum')}>
        Fund on Arbitrum
      </button>
    </div>
  );
}
```

## Common chain IDs

| Network           | Chain ID       |
| ----------------- | -------------- |
| Ethereum Mainnet  | `eip155:1`     |
| Base              | `eip155:8453`  |
| Polygon           | `eip155:137`   |
| Arbitrum One      | `eip155:42161` |
| Optimism          | `eip155:10`    |
| Avalanche C-Chain | `eip155:43114` |
| BNB Smart Chain   | `eip155:56`    |

## Callbacks

To understand when users have gone through a funding flow, use the `onUserExited` callback with the `useFundWallet` hook:

```tsx theme={null}
import { useWallets, useFundWallet } from '@moon-key/react-auth/ethereum';
import { useRouter } from 'next/navigation';

function OnboardingWithFunding() {
  const router = useRouter();
  const { wallets } = useWallets();
  const { fundWallet } = useFundWallet({
    onUserExited({ balance }) {
      if (balance < 1000n) {
        router.push('/insufficient-funds');
      } else {
        router.push('/dashboard');
      }
    }
  });
  
  const handleFund = async () => {
    const selectedWallet = wallets[0];
    await fundWallet(selectedWallet.address, {
      chain: 'eip155:1',
      amount: '0.1'
    });
  };
  
  return <button onClick={handleFund}>Fund Wallet</button>;
}
```

### Callback parameters

The `onUserExited` callback receives an object with:

<ResponseField name="address" type="string">
  The wallet address that was funded.
</ResponseField>

<ResponseField name="chain" type="string">
  The chain ID where funding occurred.
</ResponseField>

<ResponseField name="fundingMethod" type="string">
  The funding method used (e.g., `'card'`).
</ResponseField>

<ResponseField name="balance" type="bigint">
  The current balance of the wallet being funded.
</ResponseField>

## Onboarding flow example

Prompt new users to fund their wallet as part of onboarding:

```tsx theme={null}
import { useMoonKey } from '@moon-key/react-auth';
import { useWallets, useFundWallet } from '@moon-key/react-auth/ethereum';
import { useLogin } from '@moon-key/react-auth';
import { useRouter } from 'next/navigation';

export default function LoginWithFunding() {
  const router = useRouter();
  const { wallets } = useWallets();
  const { fundWallet } = useFundWallet({
    onUserExited({ balance }) {
      if (balance < 1000n) {
        router.push('/insufficient-funds');
      } else {
        router.push('/dashboard');
      }
    }
  });
  
  const { login } = useLogin({
    onComplete(user, isNewUser) {
      if (isNewUser && wallets.length > 0) {
        // Prompt new users to fund their wallet
        fundWallet(wallets[0].address, {
          chain: 'eip155:8453', // Base
          amount: '0.05'
        });
      } else {
        router.push('/dashboard');
      }
    }
  });
  
  return <button onClick={login}>Sign In</button>;
}
```

## Customizing the UI

Customize the "Receive funds" screen with the `uiConfig` option:

```tsx theme={null}
import { useWallets, useFundWallet } from '@moon-key/react-auth/ethereum';

function CustomizedFunding() {
  const { wallets } = useWallets();
  const { fundWallet } = useFundWallet();
  
  const handleFund = async () => {
    const selectedWallet = wallets[0];
    
    await fundWallet(selectedWallet.address, {
      chain: 'eip155:8453',
      amount: '0.05',
      uiConfig: {
        receiveFundsTitle: 'Receive 0.05 ETH',
        receiveFundsSubtitle: 'Scan this code or copy your wallet address to receive funds on Base.'
      }
    });
  };
  
  return <button onClick={handleFund}>Add Funds</button>;
}
```

### UI configuration options

<ParamField path="uiConfig.receiveFundsTitle" type="string">
  Custom title for the "Receive funds" screen.
</ParamField>

<ParamField path="uiConfig.receiveFundsSubtitle" type="string">
  Custom subtitle for the "Receive funds" screen.
</ParamField>

## Complete example

Here's a complete example with amount selection and funding:

```tsx theme={null}
'use client';
import { useWallets, useFundWallet } from '@moon-key/react-auth/ethereum';
import { useState } from 'react';

export default function FlexibleFunding() {
  const { wallets } = useWallets();
  const { fundWallet } = useFundWallet({
    onUserExited({ balance, fundingMethod }) {
      console.log('Funding complete');
      console.log('Method:', fundingMethod);
      console.log('New balance:', balance.toString());
    }
  });
  
  const [amount, setAmount] = useState('0.05');
  const [asset, setAsset] = useState<'native-currency' | 'USDC'>('native-currency');
  const [isFunding, setIsFunding] = useState(false);
  
  const handleFund = async () => {
    if (wallets.length === 0) return;
    
    const selectedWallet = wallets[0];
    setIsFunding(true);
    
    try {
      await fundWallet(selectedWallet.address, {
        chain: 'eip155:8453', // Base
        amount,
        asset
      });
    } catch (error) {
      console.error('Funding failed:', error);
    } finally {
      setIsFunding(false);
    }
  };
  
  if (wallets.length === 0) {
    return <div>No wallet found</div>;
  }
  
  return (
    <div className="funding-form">
      <h2>Fund Your Wallet</h2>
      
      <div className="form-group">
        <label>Asset</label>
        <select value={asset} onChange={(e) => setAsset(e.target.value as any)}>
          <option value="native-currency">ETH</option>
          <option value="USDC">USDC</option>
        </select>
      </div>
      
      <div className="form-group">
        <label>Amount</label>
        <input
          type="text"
          value={amount}
          onChange={(e) => setAmount(e.target.value)}
          placeholder="0.05"
        />
      </div>
      
      <button onClick={handleFund} disabled={isFunding}>
        {isFunding ? 'Processing...' : `Fund with ${amount} ${asset === 'native-currency' ? 'ETH' : 'USDC'}`}
      </button>
      
      <p className="wallet-address">
        Wallet: {wallets[0].address}
      </p>
    </div>
  );
}
```

## Best practices

<AccordionGroup>
  <Accordion title="Set appropriate default amounts">
    * Consider typical transaction costs on the target network
    * Use smaller amounts for L2s (Base, Arbitrum, Optimism) where gas is cheap
    * Use larger amounts for Ethereum mainnet where gas is expensive
    * Make amounts easy to adjust before purchase
  </Accordion>

  <Accordion title="Choose the right network">
    * Use L2s for better user experience (lower fees)
    * Match the network to where your contracts are deployed
    * Consider which networks MoonPay supports
  </Accordion>

  <Accordion title="Communicate funding status">
    * Explain that purchases are not instant
    * Show expected delivery times
    * Provide transaction status updates
    * Handle edge cases gracefully
  </Accordion>

  <Accordion title="Use callbacks effectively">
    * Track funding completion with `onUserExited`
    * Navigate users appropriately based on balance
    * Log funding events for analytics
    * Handle insufficient balance scenarios
  </Accordion>
</AccordionGroup>
