# abi-typegen
<p align="center">
<img src="docs/abi-typegen.png" alt="abi-typegen" width="360" />
</p>
<p align="center"><strong>Fast typed bindings from Solidity ABI artifacts.</strong></p>
<p align="center">Foundry or Hardhat in, production-ready client bindings out.</p>
<p align="center">
<a href="https://github.com/doublesharp/abi-typegen/actions/workflows/ci.yml"><img alt="CI" src="https://img.shields.io/github/actions/workflow/status/doublesharp/abi-typegen/ci.yml?branch=main&label=ci"></a>
<a href="https://github.com/doublesharp/abi-typegen/actions/workflows/coverage.yml"><img alt="Coverage workflow" src="https://img.shields.io/github/actions/workflow/status/doublesharp/abi-typegen/coverage.yml?branch=main&label=coverage"></a>
<a href="https://doublesharp.github.io/abi-typegen/coverage/"><img alt="Coverage report" src="https://img.shields.io/badge/coverage-report-2ea043"></a>
<a href="https://crates.io/crates/abi-typegen"><img alt="crates.io" src="https://img.shields.io/crates/v/abi-typegen"></a>
<a href="https://www.npmjs.com/package/@0xdoublesharp/abi-typegen"><img alt="npm" src="https://img.shields.io/npm/v/@0xdoublesharp/abi-typegen?label=npm"></a>
</p>
`abi-typegen` is a native Rust CLI that reads compiled Solidity artifacts and generates typed bindings for 14 targets across 8 languages. It works with Foundry and Hardhat, supports single-target and multi-target workflows, and includes the command surface you need for local iteration and CI: `generate`, `watch`, `diff`, `json`, `fetch`, `--check`, and `--clean`.
It is designed to be easy to drop into an existing project: point it at your artifacts, pick a target, and generate code that matches the ecosystem you actually use.
## Why abi-typegen
- Native Rust CLI with very low overhead
- Works with Foundry `out/` and Hardhat `artifacts/contracts/`
- Generates bindings for TypeScript, Python, Go, Rust, Swift, C#, Kotlin, and Solidity
- Supports comma-separated multi-target generation into isolated output directories
- CI-friendly stale-output detection with `generate --check`
- Dry-run inspection with `diff` and parsed ABI inspection with `json`
- Fetch verified contract ABIs from any Etherscan-compatible explorer with `fetch`
- Hardhat plugin for automatic generation on compile
- Forge shell integration for `forge typegen`
## Install
### Rust CLI
```sh
cargo install abi-typegen
```
Pre-built binaries are available on [GitHub Releases](https://github.com/doublesharp/abi-typegen/releases).
### Hardhat plugin
```sh
pnpm add -D @0xdoublesharp/hardhat-abi-typegen
```
If you only want the packaged binary in a Node project, you can install:
```sh
pnpm add -D @0xdoublesharp/abi-typegen
```
## Quick Start
### Foundry
Build your contracts, then generate bindings:
```sh
forge build
abi-typegen generate
```
Minimal `foundry.toml` configuration:
```toml
[abi-typegen]
out = "src/generated"
target = "viem" # or "viem,python" or ["viem", "python"]
```
Watch mode is useful while iterating:
```sh
abi-typegen watch
```
For Zod output, install the latest `zod` package in the consuming project.
### Hardhat
```ts
import { defineConfig } from "hardhat/config";
import abiTypegen from "@0xdoublesharp/hardhat-abi-typegen";
export default defineConfig({
plugins: [abiTypegen],
solidity: "0.8.34",
typegen: {
out: "src/generated",
target: "viem",
contracts: ["Token"],
exclude: ["*Test"],
},
});
```
Bindings are generated automatically on every compile:
```sh
npx hardhat compile
```
Hardhat 2 is still supported through the CommonJS fallback used by `import "@0xdoublesharp/hardhat-abi-typegen"` in Hardhat 2 configs. The explicit fallback subpath is `@0xdoublesharp/hardhat-abi-typegen/hardhat2`.
### Multi-target generation
Multiple targets can be specified in the config file or on the command line:
```toml
# foundry.toml
[abi-typegen]
target = ["viem", "python", "rust"] # also accepts "viem,python,rust"
```
```sh
# CLI
abi-typegen generate --target viem,python,rust
```
Multi-target output is written to one subdirectory per target under the configured output path:
```text
src/generated/
viem/
python/
rust/
```
## Fetch and generate from a block explorer
`fetch` pulls a verified ABI, saves it as a local artifact, and immediately generates typed bindings — all in one command:
```sh
abi-typegen fetch --name WETH --network mainnet \
0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
```
Output (using configured target, defaults to `viem`):
```text
out/WETH.sol/WETH.json ← saved artifact
src/generated/WETH.abi.ts
src/generated/WETH.viem.ts
src/generated/index.ts
```
### From a local ABI file
If you already have a raw ABI JSON file (either a bare array `[...]` or a Foundry/Hardhat artifact `{"abi": [...]}`), use `--file` to skip the network request entirely:
```sh
abi-typegen fetch --name WETH --file ./WETH.abi.json
```
### API key
Most explorers require an API key. Set it once in `.env` in the working directory or in the environment:
```sh
# .env
ETHERSCAN_API_KEY=your_key_here
```
Or pass it directly:
```sh
abi-typegen fetch --name WETH --network mainnet --api-key $KEY 0xc02aaa...
```
### Supported networks
Built-in shortcuts for 80+ networks via the `--network` flag:
| Ethereum | `mainnet`, `sepolia`, `holesky`, `hoodi` |
| OP Stack | `optimism`, `base`, `blast`, `fraxtal`, `worldchain`, `unichain` |
| Arbitrum | `arbitrum`, `arbitrum-nova`, `arbitrum-sepolia` |
| Polygon | `polygon`, `polygon-amoy` |
| BNB Chain | `bsc`, `opbnb` |
| Avalanche | `avalanche`, `fuji` |
| Other L2s | `linea`, `scroll`, `zksync`, `mantle`, `sonic`, `taiko` |
| Alt L1s | `gnosis`, `moonbeam`, `moonriver`, `celo`, `fantom`, `cronos`, `berachain`, `sei` |
| Newer chains | `hyperevm`, `abstract`, `monad`, `megaeth`, `apechain`, `katana` |
Pass `--url` to use any explorer not in the list:
```sh
abi-typegen fetch --name MyToken --url https://api.sonicscan.org/api 0xabc...
```
All networks listed at [docs.etherscan.io/supported-chains](https://docs.etherscan.io/supported-chains) are supported via the Etherscan V2 unified endpoint.
## Targets
| viem | `--target viem` | TypeScript | [viem](https://viem.sh/) contract helpers |
| zod | `--target zod` | TypeScript | [Zod](https://zod.dev/) 4 validation schemas |
| wagmi | `--target wagmi` | TypeScript | [wagmi](https://wagmi.sh/) v2 React hooks |
| ethers v6 | `--target ethers` | TypeScript | [ethers](https://docs.ethers.org/v6/) v6 |
| ethers v5 | `--target ethers5` | TypeScript | ethers v5 |
| web3.js | `--target web3js` | TypeScript | [web3.js](https://docs.web3js.org/) v4 |
| Python | `--target python` | Python | [web3.py](https://web3py.readthedocs.io/) |
| Go | `--target go` | Go | [go-ethereum](https://geth.ethereum.org/) |
| Rust | `--target rust` | Rust | [alloy](https://alloy.rs/) |
| Swift | `--target swift` | Swift | [web3swift](https://github.com/web3swift-team/web3swift) |
| C# | `--target csharp` | C# | [Nethereum](https://nethereum.com/) |
| Kotlin | `--target kotlin` | Kotlin | [web3j](https://docs.web3j.io/) |
| Solidity interfaces | `--target solidity` | Solidity | External contract interfaces |
| YAML | `--target yaml` | YAML | Human-readable ABI descriptions |
## Configuration
### Foundry (`foundry.toml`)
```toml
[abi-typegen]
out = "src/generated" # output directory
target = "viem" # string, "a,b,c", or ["a", "b", "c"]
wrappers = true # emit typed wrapper files when supported
contracts = [] # [] = all; or ["MyToken", "Vault"]
exclude = [] # glob patterns: ["*Test", "*Mock", "I*"]
```
### Hardhat (`hardhat.config.ts`)
```ts
typegen: {
out: "src/generated",
target: "viem", // string, "a,b,c", or ["a", "b", "c"]
wrappers: true,
contracts: [],
exclude: [],
}
```
### CLI overrides
```sh
abi-typegen generate \
--artifacts ./out \
--out ./types \
--target viem \
--contracts Token,Vault \
--exclude "*Test,*Mock" \
--no-wrappers \
--clean
```
## Commands
```sh
abi-typegen generate # write generated bindings
abi-typegen generate --hardhat # use Hardhat artifact layout
abi-typegen generate --check # fail if output is stale
abi-typegen generate --clean # remove stale generated files
abi-typegen diff # show what would change without writing
abi-typegen json --pretty # dump parsed ABI summary as JSON
abi-typegen watch # watch artifacts and regenerate on change
abi-typegen fetch --name <NAME> --network <NETWORK> <ADDRESS>
# fetch ABI from a block explorer and generate bindings
abi-typegen fetch --name <NAME> --file <ABI.json>
# import a local ABI file and generate bindings
abi-typegen init # scaffold [abi-typegen] in foundry.toml
abi-typegen forge-install # install Forge shell integration
```
## What Gets Generated
For each contract, `abi-typegen` generates files based on the selected target.
- TypeScript wrapper targets emit `<Name>.abi.ts` plus a target-specific wrapper file such as `<Name>.viem.ts` or `<Name>.ethers.ts`
- `zod` emits `<Name>.abi.ts` plus `<Name>.zod.ts` with schemas targeting the current Zod 4 API (`import * as z from 'zod'`)
- `solidity` emits `I<Name>.sol` with interface declarations, events, custom errors, and reconstructed structs from ABI tuples
- Non-TypeScript targets emit one primary file per contract such as `.py`, `.go`, `.rs`, `.swift`, `.cs`, or `.kt`
- Multi-target runs keep each target isolated in its own output directory
Overloaded functions get signature-based names so the output stays unambiguous:
- `deposit(uint256)` -> `depositUint`
- `deposit(uint256,address)` -> `depositUintAddress`
### Example output
**viem**
```ts
export function getTokenContract(address: Address, client: Client) {
return getContract({ address, abi: TokenAbi, client });
}
export type TokenTransferParams = {
to: `0x${string}`;
amount: bigint;
};
```
**Rust**
```rust
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TokenTransferParams {
pub to: Address,
pub amount: U256,
}
```
For deeper output examples across all targets, see [docs/generated-output.md](docs/generated-output.md).
## Performance
On the sample benchmark in this repo:
```text
abi-typegen: 25 ms
TypeChain: 763 ms
Speedup: ~30x
```
See [full comparison](docs/comparison.md) with TypeChain, wagmi CLI, abigen, and others.
## CI
### Foundry
```yaml
- run: forge build
- run: abi-typegen generate --check
```
### Hardhat
```yaml
- run: npx hardhat compile
- run: git diff --exit-code src/generated/
```
## Docs
- [docs/configuration.md](docs/configuration.md) for configuration details and target selection
- [docs/generated-output.md](docs/generated-output.md) for target-by-target generated output details
- [docs/forge-integration.md](docs/forge-integration.md) for `forge typegen` shell integration
## Contributing
Issues and PRs are welcome. If you change behavior, include a regression test with the change.