Skip to content

Commit 8a090ef

Browse files
feat(operations-gen): add evm support
Add evm support for the operations-gen cli, basically ported the code from https://github.com/smartcontractkit/chainlink-ccip/blob/main/chains/evm/cmd/operations-gen/main.go and adapted it to the new design JIRA: https://smartcontract-it.atlassian.net/browse/CLD-1777
1 parent 6da1e79 commit 8a090ef

File tree

5 files changed

+1198
-25
lines changed

5 files changed

+1198
-25
lines changed

taskfiles/generate/Taskfile.yml

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -9,27 +9,3 @@ tasks:
99
desc: Generate mocks for interfaces
1010
cmds:
1111
- mockery
12-
13-
operations:
14-
desc: Generate contract operation wrappers from a config file
15-
summary: |
16-
Generates type-safe Go operation wrappers for EVM (or other chain family) contracts.
17-
18-
Pass CONFIG variable with an absolute path, or a path relative to the repo root.
19-
Relative paths are resolved against the repo root before being passed to the generator.
20-
21-
Example:
22-
task generate:operations CONFIG=/path/to/operations_gen_config.yaml
23-
task generate:operations CONFIG=./path/from/repo/root/operations_gen_config.yaml
24-
vars:
25-
CONFIG: '{{.CONFIG}}'
26-
# If CONFIG is absolute use it as-is; otherwise treat it as relative to the repo root.
27-
# This avoids a dependency on `realpath` which is not available on all platforms.
28-
ABS_CONFIG:
29-
sh: |
30-
case "{{.CONFIG}}" in
31-
/*) printf '%s\n' "{{.CONFIG}}" ;;
32-
*) printf '%s\n' "{{.ROOT_DIR}}/{{.CONFIG}}" ;;
33-
esac
34-
cmds:
35-
- cd {{.ROOT_DIR}}/tools/operations-gen && go run . -config {{.ABS_CONFIG}}

tools/operations-gen/README.md

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
# operations-gen
2+
3+
Generates type-safe Go operation wrappers for smart contracts from their ABIs.
4+
5+
## Usage
6+
7+
Via the repo task runner (from the repo root):
8+
9+
```bash
10+
task generate:operations CONFIG=/path/to/operations_gen_config.yaml
11+
```
12+
13+
Or run directly from this directory:
14+
15+
```bash
16+
go run . -config /path/to/operations_gen_config.yaml
17+
```
18+
19+
The `-config` path can be absolute or relative to the current working directory.
20+
21+
## Configuration
22+
23+
Create an `operations_gen_config.yaml` alongside your ABI/bytecode directories:
24+
25+
```yaml
26+
version: "1.0.0"
27+
chain_family: evm # Optional: defaults to "evm"
28+
29+
input:
30+
base_path: "." # Directory containing abi/ and bytecode/ subdirectories
31+
32+
output:
33+
base_path: "." # Directory where generated operations/ folders are written
34+
35+
contracts:
36+
- contract_name: FeeQuoter
37+
version: "1.6.0"
38+
package_name: fee_quoter # Optional: override default package name
39+
abi_file: "fee_quoter.json" # Optional: override default ABI filename
40+
no_deployment: false # Optional: skip bytecode and Deploy operation
41+
functions:
42+
- name: updatePrices
43+
access: owner # Write op with MCMS support
44+
- name: getTokenPrice
45+
access: public # Read op (or public write op)
46+
```
47+
48+
### Top-level fields
49+
50+
| Field | Required | Description |
51+
| ------------------ | -------- | ---------------------------------------------------------------------------------------------- |
52+
| `version` | Yes | Config schema version |
53+
| `chain_family` | No | Target chain family. Only `"evm"` is supported. Defaults to `"evm"`. |
54+
| `input.base_path` | Yes | Root directory containing `abi/` and `bytecode/` subdirectories. Relative to the config file. |
55+
| `output.base_path` | Yes | Root directory where generated files are written. Relative to the config file. |
56+
57+
### Contract fields
58+
59+
| Field | Required | Description |
60+
| --------------- | -------- | ---------------------------------------------------------------------------------------------------------------- |
61+
| `contract_name` | Yes | Contract name as it appears in the ABI (e.g. `FeeQuoter`) |
62+
| `version` | Yes | Semver version of the contract (e.g. `"1.6.0"`) |
63+
| `package_name` | No | Override the generated Go package name. Defaults to `snake_case(contract_name)`. |
64+
| `abi_file` | No | Override the ABI filename. Defaults to `{package_name}.json`. |
65+
| `version_path` | No | Override the directory path derived from the version. Defaults to `v{major}_{minor}_{patch}`. |
66+
| `no_deployment` | No | Skip the bytecode constant and `Deploy` operation. Useful for contracts deployed elsewhere. Defaults to `false`. |
67+
68+
### Function access control
69+
70+
| Value | Behaviour |
71+
| -------- | ---------------------------------------------------------------------------------------------------------------------------------- |
72+
| `owner` | Generates a write operation gated by `OnlyOwner`, producing an MCMS-compatible transaction when the deployer key is not the owner. |
73+
| `public` | Generates a read operation (for `view`/`pure` functions) or an unrestricted write operation. |
74+
75+
## Input layout
76+
77+
The generator expects ABIs and bytecode at fixed paths under `input.base_path`:
78+
79+
```
80+
{input.base_path}/
81+
abi/
82+
v1_6_0/
83+
fee_quoter.json
84+
bytecode/
85+
v1_6_0/
86+
fee_quoter.bin
87+
```
88+
89+
Version `1.6.0` maps to directory `v1_6_0`. Override with `version_path` if your layout differs.
90+
91+
## Output layout
92+
93+
Generated files are written to:
94+
95+
```
96+
{output.base_path}/
97+
v1_6_0/
98+
operations/
99+
fee_quoter/
100+
fee_quoter.go
101+
```
102+
103+
Each generated file contains:
104+
105+
- ABI and bytecode constants
106+
- A bound contract wrapper with typed methods
107+
- A `Deploy` operation (unless `no_deployment: true`)
108+
- A typed write operation for each `access: owner` or writable `access: public` function
109+
- A typed read operation for each `view`/`pure` function
110+
111+
The generated code imports the runtime helpers from:
112+
113+
```
114+
github.com/smartcontractkit/chainlink-deployments-framework/chain/evm/operations/contract
115+
```
116+
117+
## Extending to new chain families
118+
119+
> Only `evm` is supported today. The steps below describe how to add support for a new family in the future.
120+
121+
The generator dispatches entirely by `chain_family`. Each family owns its own YAML contract schema, type mappings, template, and generation logic — nothing is shared between families at the code level.
122+
123+
To add a new chain family (e.g. `solana`):
124+
125+
1. Create `solana.go` with a `solanaHandler` struct implementing `ChainFamilyHandler`:
126+
```go
127+
type ChainFamilyHandler interface {
128+
Generate(config Config, tmpl *template.Template) error
129+
}
130+
```
131+
The handler receives the full `Config` (including raw `[]*yaml.Node` contracts) and decodes its own chain-specific contract schema from those nodes.
132+
133+
2. Add `templates/solana/operations.tmpl` with chain-appropriate imports and method bodies.
134+
135+
3. Register the handler in `chainFamilies` in `main.go`:
136+
```go
137+
var chainFamilies = map[string]ChainFamilyHandler{
138+
"evm": evmHandler{},
139+
"solana": solanaHandler{},
140+
}
141+
```
142+
143+
No other changes to `main.go` are needed. Set `chain_family: solana` in your config to use it.

0 commit comments

Comments
 (0)