|
| 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