README
¶
operations-gen
Generates type-safe Go operation wrappers for smart contracts from their ABIs.
Usage
From inside this repository:
go run ./tools/operations-gen -config /path/to/operations_gen_config.yaml
From any other repository, install the binary once and invoke it directly:
# Pin to a published subdirectory tag
go install github.com/smartcontractkit/chainlink-deployments-framework/tools/operations-gen@vX.Y.Z
operations-gen -config /path/to/operations_gen_config.yaml
The -config path can be absolute or relative to the current working directory. All paths inside the config (ABI dirs, bytecode dirs, output dir) are resolved relative to the config file's directory, so the binary can be run from anywhere.
Print the CLI release metadata:
operations-gen -version
Library usage
operations-gen can also be used as a Go package from another repository:
import "github.com/smartcontractkit/chainlink-deployments-framework/tools/operations-gen/generate"
Use GenerateFile when the config already exists on disk:
if err := generate.GenerateFile("changeset/operations_gen_config.yaml"); err != nil {
return err
}
GenerateFile resolves relative output paths and gobindings package loading from
the config file's directory.
Use Generate when the caller has already decoded the config:
var cfg generate.Config
if err := yaml.Unmarshal(configBytes, &cfg); err != nil {
return err
}
cfg.ConfigDir = repoRoot // Base for relative output paths and package loading.
if err := generate.Generate(cfg); err != nil {
return err
}
Install a released version
This module is released with Go module subdirectory tags in the form tools/operations-gen/vX.Y.Z.
Install a specific released version:
go install github.com/smartcontractkit/chainlink-deployments-framework/tools/operations-gen@vX.Y.Z
Download prebuilt release binaries and checksums from the GitHub Releases page:
https://github.com/smartcontractkit/chainlink-deployments-framework/releases
Project structure
tools/operations-gen/
main.go # CLI entrypoint
generate/ # Importable generation package + embedded templates
templates/
evm/
operations.tmpl # EVM codegen template
internal/
core/
core.go # Shared config + helpers/interfaces
families/
evm/
evm.go # EVM handler implementation
abi.go, contract.go,
codegen.go # ABI → IR → template-data pipeline
*_test.go # EVM unit tests
evm_golden_test.go # End-to-end golden generation tests
testdata/
evm/ # ABI/bytecode/config/golden fixtures
main.go intentionally stays thin: it parses CLI flags and delegates to the importable generate package. Shared helpers and common config types live in internal/core.
Configuration
Create an operations_gen_config.yaml that points at your abigen-generated gobindings package:
version: "1.0.0"
chain_family: evm # Optional: defaults to "evm"
output:
base_path: "." # Directory where generated operations/ folders are written
input:
gobindings_package: "github.com/smartcontractkit/chainlink-ccip/chains/evm/gobindings/generated"
# Relative paths are also supported, resolved from the config file's directory:
# gobindings_package: "../gobindings/generated"
contracts:
- contract_name: FeeQuoter
version: "1.6.0"
package_name: fee_quoter # Optional: override default package name
omit_deploy: false # Optional: set true to skip Deploy operation generation (default: false)
functions:
- name: updatePrices
access: owner # Write op with MCMS support
- name: getTokenPrice
access: public # Read op (or public write op)
Top-level fields
| Field | Required | Description |
|---|---|---|
version |
Yes | Config schema version |
chain_family |
No | Target chain family. Only "evm" is supported. Defaults to "evm". |
input.gobindings_package |
No | Parent Go import path or relative filesystem path containing versioned abigen packages. Used to derive contract bindings as <input.gobindings_package>/<version_path>/<package_name>. |
input.zksync_bindings_package |
No | Default Go import path or relative filesystem path for zkSync VM deploy bytecode. Used when a contract sets zksync_bytecode to a symbol only. |
output.base_path |
Yes | Root directory where generated files are written. Relative to the config file. |
Contract fields
| Field | Required | Description |
|---|---|---|
contract_name |
Yes | Contract name as it appears in the ABI (e.g. FeeQuoter) |
version |
Yes | Semver version of the contract (e.g. "1.6.0") |
gobindings_package |
No | Optional full Go import path or relative filesystem path override for this contract's abigen-generated bindings package. Required only when input.gobindings_package is not set. |
package_name |
No | Override the generated Go package name. Defaults to snake_case(contract_name). |
version_path |
No | Override the directory path derived from the version. Defaults to v{major}_{minor}_{patch}. |
omit_deploy |
No | Skip generation of the Deploy operation and bytecode constant. Defaults to false. Cannot be combined with zksync_bytecode. |
zksync_bytecode |
No | zkSync VM deploy bytecode symbol, or {package, symbol}. Package defaults to input.zksync_bindings_package, then the contract's gobindings_package. |
Function access control
| Value | Behaviour |
|---|---|
owner |
Generates a write operation gated by OnlyOwner, producing an MCMS-compatible transaction when the deployer key is not the owner. |
role |
Generates a write operation gated by OpenZeppelin-style hasRole. Requires role: <ROLE_NAME> on the function config. |
public |
Generates a read operation (for view/pure functions) or an unrestricted write operation. |
For access: role, DEFAULT_ADMIN_ROLE maps to the all-zero role and any other
human-readable role name is hashed as keccak256("<ROLE_NAME>"). Raw bytes32
role hashes are rejected so configs remain readable.
Gobindings requirements
The generator expects an abigen-generated package that exports the standard metadata symbol:
var FeeQuoterMetaData = &bind.MetaData{
ABI: "...",
Bin: "...",
}
For omit_deploy: true, only the ABI field is required. Otherwise both ABI and Bin must be present.
Output layout
Generated files are written to:
{output.base_path}/
v1_6_0/
operations/
fee_quoter/
fee_quoter.go
Each generated file contains:
- ABI and bytecode constants, plus a
ContractTypeandVersion - A
Deployoperation (unlessomit_deploy: true) - A
NewWrite<Fn>(c gobindings.<Contract>Interface)factory for everyaccess: owner(or writableaccess: public) function, returning*cld_ops.Operation[…] - A
NewRead<Fn>(c gobindings.<Contract>Interface)factory for everyview/purefunction *Argsstructs for functions that take multiple inputs, and*Resultstructs for reads that return multiple outputs
The generator does not emit its own contract wrapper: each factory takes an interface from the abigen-generated gobindings package. The caller is expected to bind the contract via that package (gobindings.New<Contract>(addr, backend)) and hand the result in.
The generated code depends on three imports:
github.com/smartcontractkit/chainlink-deployments-framework/chain/evm/operations/contract— the operations runtimegithub.com/smartcontractkit/chainlink-deployments-framework/chain/evmand.../operations— chain + ops types used in the factory signatures{gobindings_package}— the derived or per-contract override abigen bindings import path
Extending to new chain families
Only
evmis supported today. The steps below describe how to add support for a new family in the future.
The generator dispatches entirely by chain_family. Each family owns its own YAML contract schema, type mappings, template, and generation logic; only common CLI/config plumbing and dispatch utilities are shared.
To add a new chain family (e.g. solana):
-
Create
internal/families/solana/solana.gowith asolana.Handlertype implementingcore.ChainFamilyHandler:type ChainFamilyHandler interface { Generate(config core.Config, tmpl *template.Template) error }The handler receives the full
core.Config.Config.Input,Config.Output, andConfig.Contractsareyaml.Nodevalues so each chain-family handler can decode its own chain-specific schemas. -
Add
generate/templates/solana/operations.tmplwith chain-appropriate imports and method bodies. -
Register the handler in
chainFamiliesingenerate/chain.go:var chainFamilies = map[string]core.ChainFamilyHandler{ "evm": evm.Handler{}, "solana": solana.Handler{}, }
No CLI changes are needed. Set chain_family: solana in your config to use it.
Documentation
¶
There is no documentation for this package.