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

# Ethers-style Interface

> Reference implementation of ethers v6 Interface patterns using Voltaire primitives

<Info>
  **Skill** — Copyable reference implementation. Use as-is or customize. See [Skills Philosophy](/concepts/skills).
</Info>

# Ethers-style Interface

A copyable reference implementation that follows [ethers v6](https://docs.ethers.org/v6/) Interface patterns, built on Voltaire primitives.

## Overview

This Skill provides:

* **Interface**: Main ABI abstraction with ethers v6 API
* **Fragment classes**: FunctionFragment, EventFragment, ErrorFragment
* **Encoding/Decoding**: Function data, event logs, error results
* **Parsing**: Parse transactions, logs, and errors from raw data

## Quick Start

```typescript theme={null}
import { Interface } from './examples/ethers-interface/index.js';

const abi = [
  {
    type: 'function',
    name: 'transfer',
    inputs: [
      { type: 'address', name: 'to' },
      { type: 'uint256', name: 'amount' },
    ],
    outputs: [{ type: 'bool', name: '' }],
    stateMutability: 'nonpayable',
  },
  {
    type: 'event',
    name: 'Transfer',
    inputs: [
      { type: 'address', name: 'from', indexed: true },
      { type: 'address', name: 'to', indexed: true },
      { type: 'uint256', name: 'value', indexed: false },
    ],
  },
  {
    type: 'error',
    name: 'InsufficientBalance',
    inputs: [
      { type: 'uint256', name: 'available' },
      { type: 'uint256', name: 'required' },
    ],
  },
];

const iface = new Interface(abi);
```

## Encoding Function Calls

Encode function call data for transaction `data` field:

```typescript theme={null}
// Encode transfer(address,uint256)
const data = iface.encodeFunctionData('transfer', [
  '0x742d35Cc6634C0532925a3b844Bc9e7595f251e3',
  1000000n,
]);
// 0xa9059cbb000000000000000000000000742d35cc6634c0532925a3b844bc9e7595f251e3...

// Get function by selector
const fn = iface.getFunction('0xa9059cbb');
console.log(fn?.name); // "transfer"
```

## Decoding Function Data

Decode function call data back to arguments:

```typescript theme={null}
// Decode transaction data
const decoded = iface.decodeFunctionData('transfer', data);
console.log(decoded[0]); // "0x742d35cc6634c0532925a3b844bc9e7595f251e3"
console.log(decoded[1]); // 1000000n

// Decode function result (return values)
const result = iface.decodeFunctionResult('transfer', returnData);
console.log(result[0]); // true
```

## Event Encoding/Decoding

Encode event logs for testing or mocking:

```typescript theme={null}
// Encode event log
const { data, topics } = iface.encodeEventLog('Transfer', [
  '0x742d35Cc6634C0532925a3b844Bc9e7595f251e3',
  '0x1234567890123456789012345678901234567890',
  1000n,
]);

// Decode event log from raw data
const decoded = iface.decodeEventLog('Transfer', data, topics);
console.log(decoded[0]); // from address
console.log(decoded[1]); // to address
console.log(decoded[2]); // 1000n
```

## Error Encoding/Decoding

Handle custom error reverts:

```typescript theme={null}
// Encode error for testing
const errorData = iface.encodeErrorResult('InsufficientBalance', [100n, 200n]);

// Decode error from revert data
const decoded = iface.decodeErrorResult('InsufficientBalance', errorData);
console.log(decoded[0]); // 100n (available)
console.log(decoded[1]); // 200n (required)

// Built-in Error and Panic
const standardError = iface.encodeErrorResult('Error', ['Something went wrong']);
const panicError = iface.encodeErrorResult('Panic', [0x11n]); // Arithmetic overflow
```

## Parsing Raw Data

Parse unknown data to discover its type:

```typescript theme={null}
// Parse transaction
const txDescription = iface.parseTransaction({ data, value: 0n });
if (txDescription) {
  console.log(txDescription.name);      // "transfer"
  console.log(txDescription.args);      // [address, amount]
  console.log(txDescription.selector);  // "0xa9059cbb"
}

// Parse log
const logDescription = iface.parseLog({ topics, data });
if (logDescription) {
  console.log(logDescription.name);     // "Transfer"
  console.log(logDescription.args);     // [from, to, value]
  console.log(logDescription.topic);    // topic hash
}

// Parse error
const errorDescription = iface.parseError(revertData);
if (errorDescription) {
  console.log(errorDescription.name);   // "InsufficientBalance"
  console.log(errorDescription.args);   // [available, required]
}
```

## Fragment Inspection

Inspect ABI fragments:

```typescript theme={null}
// Get all functions
iface.forEachFunction((fn, index) => {
  console.log(fn.name, fn.selector, fn.stateMutability);
});

// Get all events
iface.forEachEvent((ev, index) => {
  console.log(ev.name, ev.topicHash, ev.anonymous);
});

// Check existence
console.log(iface.hasFunction('transfer')); // true
console.log(iface.hasEvent('Transfer'));    // true

// Get by name or selector
const fn = iface.getFunction('transfer');
const ev = iface.getEvent('Transfer');
const err = iface.getError('InsufficientBalance');
```

## Human-Readable Format

Convert ABI to human-readable format:

```typescript theme={null}
// Full format with names
const full = iface.format(false);
// ["function transfer(address to, uint256 amount) returns (bool)", ...]

// Minimal format without names
const minimal = iface.format(true);
// ["function transfer(address,uint256) returns (bool)", ...]

// JSON format
const json = iface.formatJson();
// '[{"type":"function","name":"transfer",...}]'
```

## Constructor Encoding

Encode constructor arguments for deployment:

```typescript theme={null}
const constructorAbi = [
  {
    type: 'constructor',
    inputs: [
      { type: 'string', name: 'name' },
      { type: 'string', name: 'symbol' },
    ],
  },
];

const iface = new Interface(constructorAbi);
const deployData = iface.encodeDeploy(['My Token', 'MTK']);
// Append to bytecode for deployment
```

## Filter Topics

Create filter topics for `eth_getLogs`:

```typescript theme={null}
// Filter for specific sender
const topics = iface.encodeFilterTopics('Transfer', [
  '0x742d35Cc6634C0532925a3b844Bc9e7595f251e3',
  null, // any recipient
]);

// Filter for multiple possible values
const multiTopics = iface.encodeFilterTopics('Transfer', [
  ['0xaddr1', '0xaddr2'], // from either address
  null,
]);
```

## Fragment Classes

Work with fragments directly:

```typescript theme={null}
import {
  FunctionFragment,
  EventFragment,
  ErrorFragment,
  ParamType
} from './examples/ethers-interface/index.js';

// Create fragments from ABI items
const fn = FunctionFragment.from({
  type: 'function',
  name: 'test',
  inputs: [{ type: 'uint256', name: 'x' }],
  outputs: [{ type: 'bool' }],
  stateMutability: 'view',
});

console.log(fn.selector);       // "0x29e99f07"
console.log(fn.format());       // "test(uint256)"
console.log(fn.constant);       // true (view function)

// Compute selectors directly
const selector = FunctionFragment.getSelector('transfer', ['address', 'uint256']);
const topicHash = EventFragment.getTopicHash('Transfer', ['address', 'address', 'uint256']);
```

## ParamType

Inspect parameter types:

```typescript theme={null}
const param = ParamType.from({
  type: 'tuple',
  name: 'data',
  components: [
    { type: 'uint256', name: 'id' },
    { type: 'string', name: 'name' },
  ],
});

console.log(param.type);        // "tuple"
console.log(param.isTuple());   // true
console.log(param.isArray());   // false
console.log(param.components);  // [ParamType, ParamType]

// Format in different modes
console.log(param.format('sighash')); // "(uint256,string)"
console.log(param.format('full'));    // "(uint256 id, string name) data"
```

## Source Code

Full implementation available at:

* `examples/ethers-interface/Interface.js` - Main Interface class
* `examples/ethers-interface/Fragment.js` - Fragment classes
* `examples/ethers-interface/errors.ts` - Error classes
* `examples/ethers-interface/EthersInterfaceTypes.ts` - TypeScript types
* `examples/ethers-interface/EthersInterface.test.ts` - Comprehensive tests

## API Reference

### Interface

| Method                                | Description                 |
| ------------------------------------- | --------------------------- |
| `encodeFunctionData(name, values?)`   | Encode function call data   |
| `decodeFunctionData(name, data)`      | Decode function call params |
| `decodeFunctionResult(name, data)`    | Decode function return data |
| `encodeFunctionResult(name, values?)` | Encode function return data |
| `encodeEventLog(name, values)`        | Encode event log            |
| `decodeEventLog(name, data, topics?)` | Decode event log            |
| `encodeFilterTopics(name, values)`    | Encode filter topics        |
| `encodeErrorResult(name, values?)`    | Encode error data           |
| `decodeErrorResult(name, data)`       | Decode error data           |
| `encodeDeploy(values?)`               | Encode constructor args     |
| `parseTransaction(tx)`                | Parse transaction data      |
| `parseLog(log)`                       | Parse event log             |
| `parseError(data)`                    | Parse error data            |
| `getFunction(key, values?)`           | Get function fragment       |
| `getEvent(key, values?)`              | Get event fragment          |
| `getError(key, values?)`              | Get error fragment          |
| `forEachFunction(cb)`                 | Iterate functions           |
| `forEachEvent(cb)`                    | Iterate events              |
| `forEachError(cb)`                    | Iterate errors              |
| `format(minimal?)`                    | Human-readable ABI          |
| `formatJson()`                        | JSON ABI string             |

### FunctionFragment

| Property          | Description                  |
| ----------------- | ---------------------------- |
| `name`            | Function name                |
| `selector`        | 4-byte selector (hex)        |
| `inputs`          | Input parameters             |
| `outputs`         | Output parameters            |
| `stateMutability` | pure/view/nonpayable/payable |
| `constant`        | Is view/pure                 |
| `payable`         | Can receive ether            |

### EventFragment

| Property    | Description        |
| ----------- | ------------------ |
| `name`      | Event name         |
| `topicHash` | 32-byte topic hash |
| `inputs`    | Event parameters   |
| `anonymous` | Is anonymous event |

### ErrorFragment

| Property   | Description      |
| ---------- | ---------------- |
| `name`     | Error name       |
| `selector` | 4-byte selector  |
| `inputs`   | Error parameters |
