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

# How to: Display Transaction Fees

> Fetch, calculate, and display transaction fees as USD amounts in your wallet UI.

Arc uses USDC as its native gas token, so fees are inherently denominated in
USD. The `eth_gasPrice` and `eth_feeHistory` RPCs return values in USDC wei (18
decimals). The EWMA fee smoothing model keeps fees predictable—dramatic spikes
are unlikely. Display fees as `$X.XX` (or `~$0.01`), never as "Gwei" or "ETH."

## Prerequisites

Before you begin:

* You have an RPC endpoint for Arc.
* You are using an EIP-1559-compatible library (viem, ethers.js, or equivalent).
* You understand that Arc's native currency is USDC, not ETH.

## Steps

### Step 1. Fetch the current gas price

Use `eth_gasPrice` for a single value or `eth_feeHistory` for historical base
fees and priority fee percentiles.

```typescript theme={null}
import { createPublicClient, http, formatUnits } from "viem";
import { arc } from "viem/chains";

const client = createPublicClient({
  chain: arc,
  transport: http("https://rpc.arc.circle.com"),
});

// Simple: current gas price in USDC wei
const gasPrice = await client.getGasPrice();
console.log("Gas price (wei):", gasPrice);

// Detailed: recent base fee history
const feeHistory = await client.getFeeHistory({
  blockCount: 4,
  rewardPercentiles: [25, 50, 75],
});
console.log("Latest base fee (wei):", feeHistory.baseFeePerGas.at(-1));
```

### Step 2. Estimate gas for the transaction

Use `eth_estimateGas` to determine how much gas your transaction requires.

```typescript theme={null}
// Native USDC transfer: ~21,000 gas
const simpleTransferGas = 21_000n;

// ERC-20 token transfer or contract call: use estimateGas
const contractGas = await client.estimateGas({
  account: "0xYourAddress",
  to: "0xContractAddress",
  data: encodedCalldata,
});
```

Typical gas costs:

| Transaction type     | Approximate gas        |
| -------------------- | ---------------------- |
| Native USDC send     | 21,000                 |
| ERC-20 transfer      | \~65,000               |
| Contract interaction | Varies—always estimate |

### Step 3. Build EIP-1559 fee parameters

Arc supports EIP-1559 transactions. Set `maxFeePerGas` and
`maxPriorityFeePerGas`:

```typescript theme={null}
const latestBlock = await client.getBlock();
const baseFee = latestBlock.baseFeePerGas!;

// 2x base fee is generous—Arc's EWMA smoothing keeps fees stable
const maxFeePerGas = baseFee * 2n;

// Priority fee of 0 is acceptable on Arc (validators don't require tips)
const maxPriorityFeePerGas = 0n;
```

<Info>
  The effective gas price is `baseFeePerGas + priorityFee`. The base fee has a
  minimum of 20 Gwei in USDC terms. Because Arc uses an EWMA (exponentially
  weighted moving average) model to adjust the base fee gradually, fee spikes
  are smoothed out and prices remain predictable.
</Info>

### Step 4. Calculate the maximum fee in USD

Multiply the gas limit by `maxFeePerGas`, then convert from 18-decimal USDC wei
to a dollar amount.

```typescript theme={null}
function calculateMaxFeeUsd(gasLimit: bigint, maxFeePerGas: bigint): string {
  const maxCostWei = gasLimit * maxFeePerGas;
  // USDC has 18 decimals as the native gas token on Arc
  // Since 1 USDC = $1, the numeric value IS the USD cost
  const usdCost = formatUnits(maxCostWei, 18);
  return usdCost;
}

// Example: simple transfer
const maxFee = calculateMaxFeeUsd(21_000n, maxFeePerGas);
console.log(`Max fee: $${Number(maxFee).toFixed(6)}`);
```

### Step 5. Format fees for display

Show fees as a dollar amount. Use `~` to indicate the value is an estimate.

```typescript theme={null}
function formatFeeDisplay(gasLimit: bigint, maxFeePerGas: bigint): string {
  const maxCostWei = gasLimit * maxFeePerGas;
  const usdValue = Number(formatUnits(maxCostWei, 18));

  if (usdValue < 0.01) {
    return "< $0.01";
  }
  return `~$${usdValue.toFixed(2)}`;
}
```

<Warning>
  Standard libraries like ethers.js and viem label the native currency as "ETH"
  by default. You must override this in your UI. Displaying "0.00042 ETH"
  instead of "\~\$0.01" confuses users and misrepresents the cost.
</Warning>

## Worked examples

### Simple USDC transfer

```typescript theme={null}
// Given: base fee = 20 Gwei (minimum), gas limit = 21,000
const baseFee = 20_000_000_000n; // 20 Gwei in wei
const gasLimit = 21_000n;
const maxFeePerGas = baseFee * 2n; // 40 Gwei

const maxCostWei = gasLimit * maxFeePerGas;
// 21,000 * 40,000,000,000 = 840,000,000,000,000 wei
// = 0.00000084 USDC = $0.00000084

const display = formatFeeDisplay(gasLimit, maxFeePerGas);
// Output: "< $0.01"
```

### Contract interaction

```typescript theme={null}
// Given: base fee = 500,000 Gwei (0.0005 USDC), gas limit = 65,000
const baseFee = 500_000_000_000_000n; // 500,000 Gwei in wei
const gasLimit = 65_000n;
const maxFeePerGas = baseFee * 2n; // 1,000,000 Gwei

const maxCostWei = gasLimit * maxFeePerGas;
// 65,000 * 1,000,000,000,000,000 = 65,000,000,000,000,000,000 wei
// = 0.065 USDC = $0.065

const display = formatFeeDisplay(gasLimit, maxFeePerGas);
// Output: "~$0.07"
```

<Tip>
  Users are only charged `gasUsed * effectiveGasPrice`. The difference between
  `maxFeePerGas` and the actual effective gas price is refunded. It's safe to
  show the maximum estimate in your UI with language like "Max fee" or "Up to."
</Tip>

## See also

* [Transaction lifecycle](/integrate/wallets/transaction-lifecycle)
