Using the CLI
clarity-abitype ships a small CLI that keeps ABI declarations in your repository in sync with deployed contracts. It reads a config file listing the contracts you care about, fetches their ABIs from the Stacks API, and writes a TypeScript file containing the ABIs with as const assertions so TypeScript can infer types from them.
Installation
The CLI is included in the clarity-abitype package:
npm install clarity-abitypepnpm add clarity-abitypeyarn add clarity-abitypeInitialize
Create a clarity.config.ts file at the root of your project:
npx clarity-abitype initThis scaffolds a config with an empty contract list:
import { defineConfig } from "clarity-abitype/config";
export default defineConfig({
out: "src/generated.ts",
contracts: [],
});| Option | Description |
|---|---|
-c, --config <path> | Path to config file |
-r, --root <path> | Directory to create the config in |
Configure contracts
Add every contract you want an ABI for. The contract field is the full contract identifier (<address>.<contract-name>):
import { defineConfig } from "clarity-abitype/config";
export default defineConfig({
out: "src/abis/generated.ts",
contracts: [
{
name: "sbtcToken",
contract: "SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token",
},
{
name: "myToken",
contract: "SP2C2YFP12AJZB4MABJBAJ55XECVS7E4PMMZ89YZR.my-token",
},
],
});Contract options
| Option | Required | Description |
|---|---|---|
name | Yes | Name used to derive the generated export. sbtcToken generates sbtcTokenAbi. |
contract | Yes | Contract identifier in the form <address>.<contract-name>. |
abi | No | Pre-resolved ABI. When provided, the ABI is not fetched from the API. Useful for offline generation. |
Config options
| Option | Default | Description |
|---|---|---|
out | src/generated.ts | Output file path, relative to the current working directory. |
contracts | [] | Contracts to generate ABIs for. |
apiUrl | https://api.mainnet.hiro.so | Stacks API base URL. Use https://api.testnet.hiro.so for testnet contracts. |
The config can also export a function, which is useful for computing contracts dynamically:
import { defineConfig } from "clarity-abitype/config";
export default defineConfig(async () => ({
out: "src/abis/generated.ts",
contracts: await getContracts(),
}));Generate
Fetch the ABIs and write the output file:
npx clarity-abitype generateUsing config clarity.config.ts
Fetched SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token
Generated 1 ABI at src/abis/generated.ts| Option | Description |
|---|---|
-c, --config <path> | Path to config file |
-r, --root <path> | Directory to resolve the config from |
Contracts are sorted by name, so the generated file is stable between runs. A header and a banner per contract are added to make it clear the file is generated:
// Generated by clarity-abitype. Do not edit.
////////////////////////////////////////////////////////////////////////////////////////////////////
// sbtcToken
// SM3VDXK3WZZSA84XXFKAFAF15NNZX32CTSG82JFQ4.sbtc-token
////////////////////////////////////////////////////////////////////////////////////////////////////
export const sbtcTokenAbi = {
functions: [
// ...
],
variables: [
// ...
],
maps: [],
fungible_tokens: [{ name: "sbtc-token" }],
non_fungible_tokens: [],
epoch: "Epoch30",
clarity_version: "Clarity3",
} as const;Then import the ABI and use it as usual:
import type { ExtractAbiFunctionNames } from "clarity-abitype";
import { sbtcTokenAbi } from "./abis/generated";
type ReadOnlyFunctions = ExtractAbiFunctionNames<
typeof sbtcTokenAbi,
"read_only"
>;
// ^? "get-name" | "get-symbol" | ...Config resolution
The CLI looks for clarity.config.ts, clarity.config.mts, clarity.config.js, or clarity.config.mjs, searching upwards from the current working directory. Use --config to point to a different file or --root to search from a different directory.
TypeScript configs are loaded natively and require Node.js 22.18 or later. On older Node.js versions, use a .js or .mjs config.
Local contracts
The CLI fetches ABIs from a Stacks API, so it targets deployed contracts. For local Clarinet contracts, see the Clarinet SDK guide for how to read interfaces from the simnet.