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

# EVM Integration

> Signing and submitting transactions on Ethereum, Polygon, and Base

## EVM Integration (Ethereum, Polygon, Base)

On EVM chains, the signing and submission flow differs from Solana. This guide covers the key differences.

### Multi-Transaction Operations

On EVM chains, supply operations return **two transactions** that must be signed and submitted in order:

1. **Approve transaction** — Authorizes the protocol to spend your USDC
2. **Supply transaction** — Deposits USDC into the yield strategy

### Unsigned Transaction Format

EVM unsigned transactions are returned as JSON objects with these fields:

| Field                  | Type     | Description                               |
| ---------------------- | -------- | ----------------------------------------- |
| `to`                   | `string` | Contract/recipient address                |
| `data`                 | `string` | Encoded call data (hex string)            |
| `value`                | `string` | Native token value in wei (usually `'0'`) |
| `gasLimit`             | `string` | Gas limit                                 |
| `maxFeePerGas`         | `string` | EIP-1559 max fee per gas                  |
| `maxPriorityFeePerGas` | `string` | EIP-1559 priority fee per gas             |
| `nonce`                | `number` | Transaction nonce                         |
| `chainId`              | `number` | Chain ID for replay protection            |

### Signing with ethers.js

```typescript theme={null}
import { ethers } from 'ethers';
import { RebelfiClient } from '@rebelfi/sdk';

const client = new RebelfiClient({ apiKey: process.env.REBELFI_API_KEY });

// 1. Plan the supply
const operation = await client.operations.supply({
  walletAddress: '0xYourWalletAddress',
  strategyId: strategy.strategyId,
  amount: '1000000', // 1 USDC
  tokenAddress: strategy.tokenAddress
});

// 2. Sign and submit each transaction in order
for (const tx of operation.transactions) {
  const wallet = new ethers.Wallet(privateKey, provider);
  const signedTx = await wallet.signTransaction({
    to: tx.to,
    data: tx.data,
    value: tx.value || '0x0',
    gasLimit: tx.gasLimit,
    maxFeePerGas: tx.maxFeePerGas,
    maxPriorityFeePerGas: tx.maxPriorityFeePerGas,
    nonce: tx.nonce,
    chainId: tx.chainId
  });

  // Submit to RebelFi
  await client.transactions.submitSigned({
    operationId: operation.operationId,
    transactionId: tx.id, // Required for multi-tx operations
    signedTransaction: signedTx // Hex-encoded
  });
}
```

### Key Differences from Solana

|                           | Solana         | EVM                    |
| ------------------------- | -------------- | ---------------------- |
| Transactions per supply   | 1              | 2 (approve + supply)   |
| Transaction format        | Base64-encoded | Hex-encoded            |
| `transactionId` on submit | Optional       | Required               |
| Gas token                 | SOL            | ETH / POL / ETH (Base) |

<Info>
  The `transactionId` parameter is **required** when submitting EVM transactions because operations contain multiple transactions. It tells RebelFi which transaction you are submitting. For Solana single-transaction operations, it is optional.
</Info>

### Complete EVM Example

```typescript theme={null}
import { ethers } from 'ethers';
import { RebelfiClient } from '@rebelfi/sdk';

const client = new RebelfiClient({ apiKey: process.env.REBELFI_API_KEY });
const provider = new ethers.JsonRpcProvider('https://polygon-mainnet.infura.io/v3/YOUR_KEY');
const signer = new ethers.Wallet(process.env.PRIVATE_KEY, provider);

async function supplyOnEVM(walletAddress: string, strategyId: number, amount: string, tokenAddress: string) {
  // Plan the supply
  const operation = await client.operations.supply({
    walletAddress,
    strategyId,
    amount,
    tokenAddress
  });

  console.log(`Operation ${operation.operationId}: ${operation.transactions.length} transactions`);

  // Sign and submit each transaction sequentially
  for (const tx of operation.transactions) {
    console.log(`Signing: ${tx.description}`);

    const signedTx = await signer.signTransaction({
      to: tx.to,
      data: tx.data,
      value: tx.value || '0x0',
      gasLimit: tx.gasLimit,
      maxFeePerGas: tx.maxFeePerGas,
      maxPriorityFeePerGas: tx.maxPriorityFeePerGas,
      nonce: tx.nonce,
      chainId: tx.chainId
    });

    await client.transactions.submitSigned({
      operationId: operation.operationId,
      transactionId: tx.id,
      signedTransaction: signedTx
    });

    console.log(`Submitted: ${tx.description}`);
  }

  // Wait for confirmation
  const start = Date.now();
  while (Date.now() - start < 120_000) {
    const op = await client.operations.get(operation.operationId);
    if (op.status === 'CONFIRMED') {
      console.log('Supply confirmed!');
      return op;
    }
    if (op.status === 'FAILED') {
      throw new Error(op.transactions[0]?.error || 'Operation failed');
    }
    await new Promise(r => setTimeout(r, 3000));
  }
  throw new Error('Timeout waiting for confirmation');
}
```

## Next Steps

<CardGroup cols={2}>
  <Card title="Wallet Profiles" icon="layer-group" href="/guides/wallet-profiles">
    Configure EVM chains in your wallet profile
  </Card>

  <Card title="Fireblocks Integration" icon="vault" href="/sdk/custody-providers/fireblocks">
    Sign EVM transactions with Fireblocks custody
  </Card>

  <Card title="Integration Tutorial" icon="book" href="/sdk/integration-tutorial">
    Complete E2E walkthrough
  </Card>
</CardGroup>
