diff --git a/.changeset/clear-beans-deny.md b/.changeset/clear-beans-deny.md new file mode 100644 index 000000000..376856bc7 --- /dev/null +++ b/.changeset/clear-beans-deny.md @@ -0,0 +1,5 @@ +--- +"operations-gen": minor +--- + +feat: Add zkSync VM bytecode support to operations-gen. Generated Deploy operations can now include `ZkSyncVM` bytecode via `zksync_bytecode` and `zksync_bindings_package` config fields. diff --git a/tools/operations-gen/README.md b/tools/operations-gen/README.md index eee63cac9..35629a4f4 100644 --- a/tools/operations-gen/README.md +++ b/tools/operations-gen/README.md @@ -136,6 +136,7 @@ contracts: | `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.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 @@ -147,7 +148,8 @@ contracts: | `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`. | +| `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 diff --git a/tools/operations-gen/generate/templates/evm/operations.tmpl b/tools/operations-gen/generate/templates/evm/operations.tmpl index 595f5667a..170a69261 100644 --- a/tools/operations-gen/generate/templates/evm/operations.tmpl +++ b/tools/operations-gen/generate/templates/evm/operations.tmpl @@ -23,6 +23,9 @@ import ( cld_ops "github.com/smartcontractkit/chainlink-deployments-framework/operations" {{- end}} gobindings "{{.GobindingsImport}}" +{{- if and .ZkSyncBytecodeSymbol (not .ZkSyncBytecodeUseGobindings)}} + zkbindings "{{.ZkSyncBytecodeImport}}" +{{- end}} ) var ContractType cldf_deployment.ContractType = "{{.ContractType}}" @@ -61,6 +64,9 @@ var Deploy = contract.NewDeploy(contract.DeployParams[ConstructorArgs]{ BytecodeByTypeAndVersion: map[string]contract.Bytecode{ cldf_deployment.NewTypeAndVersion(ContractType, *Version).String(): { EVM: common.FromHex(gobindings.{{.ContractType}}MetaData.Bin), +{{- if .ZkSyncBytecodeSymbol}} + ZkSyncVM: {{if .ZkSyncBytecodeUseGobindings}}gobindings{{else}}zkbindings{{end}}.{{.ZkSyncBytecodeSymbol}}, +{{- end}} }, }, }) diff --git a/tools/operations-gen/internal/families/evm/codegen.go b/tools/operations-gen/internal/families/evm/codegen.go index d1bc3b3f2..54b4d690f 100644 --- a/tools/operations-gen/internal/families/evm/codegen.go +++ b/tools/operations-gen/internal/families/evm/codegen.go @@ -13,19 +13,22 @@ import ( // ---- Template data (EVM-specific) ---- type templateData struct { - PackageName string - PackageNameHyphen string - ContractType string - Version string - GobindingsImport string - NeedsBigInt bool - HasWriteOps bool - OmitDeploy bool - Constructor *constructorData - StructDefs []structDefData - ArgStructs []argStructData - Operations []OperationData - ContractMethods []contractMethodData + PackageName string + PackageNameHyphen string + ContractType string + Version string + GobindingsImport string + ZkSyncBytecodeSymbol string + ZkSyncBytecodeImport string + ZkSyncBytecodeUseGobindings bool + NeedsBigInt bool + HasWriteOps bool + OmitDeploy bool + Constructor *constructorData + StructDefs []structDefData + ArgStructs []argStructData + Operations []OperationData + ContractMethods []contractMethodData } type constructorData struct { @@ -92,6 +95,11 @@ func prepareTemplateData(info *ContractInfo) templateData { NeedsBigInt: ChecksNeedsBigInt(info), OmitDeploy: info.OmitDeploy, } + if info.ZkSync != nil { + data.ZkSyncBytecodeSymbol = info.ZkSync.BytecodeSymbol + data.ZkSyncBytecodeImport = info.ZkSync.BytecodePackage + data.ZkSyncBytecodeUseGobindings = info.ZkSync.BytecodePackage == info.GobindingsPackage + } if info.Constructor != nil { data.Constructor = &constructorData{ diff --git a/tools/operations-gen/internal/families/evm/config.go b/tools/operations-gen/internal/families/evm/config.go index a00c58022..0c79443bc 100644 --- a/tools/operations-gen/internal/families/evm/config.go +++ b/tools/operations-gen/internal/families/evm/config.go @@ -8,6 +8,7 @@ type EvmContractConfig struct { PackageName string `yaml:"package_name,omitempty"` // Optional: override package name OmitDeploy bool `yaml:"omit_deploy,omitempty"` // Optional: skip Deploy operation GobindingsPackage string `yaml:"gobindings_package"` // Optional: override the derived gobindings import path or relative filesystem path for this contract. + ZkSyncBytecode ZkSyncBytecodeRef `yaml:"zksync_bytecode,omitempty"` Functions []EvmFunctionConfig `yaml:"functions"` ConfigDir string `yaml:"-"` } @@ -18,6 +19,9 @@ type EvmInputConfig struct { // Contract packages default to: // // GobindingsPackage string `yaml:"gobindings_package"` + // ZkSyncBindingsPackage is the default Go import path for zkSync VM deploy bytecode. + // Used when a contract sets zksync_bytecode to a symbol only. + ZkSyncBindingsPackage string `yaml:"zksync_bindings_package,omitempty"` } // EvmFunctionConfig selects a contract function and assigns its access control. diff --git a/tools/operations-gen/internal/families/evm/contract.go b/tools/operations-gen/internal/families/evm/contract.go index 08f8997dd..93b955787 100644 --- a/tools/operations-gen/internal/families/evm/contract.go +++ b/tools/operations-gen/internal/families/evm/contract.go @@ -29,6 +29,7 @@ type ContractInfo struct { Version string PackageName string GobindingsPackage string + ZkSync *ZkSyncContractInfo OutputPath string OmitDeploy bool Constructor *FunctionInfo @@ -37,6 +38,12 @@ type ContractInfo struct { StructDefs map[string]*structDef } +// ZkSyncContractInfo holds resolved zkSync VM deploy bytecode for code generation. +type ZkSyncContractInfo struct { + BytecodePackage string + BytecodeSymbol string +} + type structDef struct { Name string Fields []ParameterInfo @@ -98,6 +105,15 @@ func extractContractInfo(cfg EvmContractConfig, input EvmInputConfig, output Evm } cfg.GobindingsPackage = resolvedGobindingsPackage + if cfg.OmitDeploy && !cfg.ZkSyncBytecode.IsZero() { + return nil, fmt.Errorf("contract %q: zksync_bytecode cannot be set when omit_deploy is true", cfg.Name) + } + + zkSyncPackage, zkSyncSymbol, err := resolveZkSyncBytecode(cfg, input, cfg.GobindingsPackage) + if err != nil { + return nil, err + } + parsedAbi, err := ReadABI(cfg) if err != nil { return nil, err @@ -113,6 +129,12 @@ func extractContractInfo(cfg EvmContractConfig, input EvmInputConfig, output Evm Functions: make(map[string]*FunctionInfo), StructDefs: make(map[string]*structDef), } + if zkSyncSymbol != "" { + info.ZkSync = &ZkSyncContractInfo{ + BytecodePackage: zkSyncPackage, + BytecodeSymbol: zkSyncSymbol, + } + } extractConstructor(info, parsedAbi) diff --git a/tools/operations-gen/internal/families/evm/evm_golden_test.go b/tools/operations-gen/internal/families/evm/evm_golden_test.go index 6292a187c..008560d7f 100644 --- a/tools/operations-gen/internal/families/evm/evm_golden_test.go +++ b/tools/operations-gen/internal/families/evm/evm_golden_test.go @@ -39,6 +39,13 @@ func TestGenerateFeeQuoter(t *testing.T) { runGoldenGenerationTest(t, "operations_gen_fee_quoter.yaml", "fee_quoter.golden.go") } +// TestGenerateLinkTokenWithZkSyncBindingsPackage verifies generation when +// input.zksync_bindings_package and contract zksync_bytecode are both set. +func TestGenerateLinkTokenWithZkSyncBindingsPackage(t *testing.T) { + t.Parallel() + runGoldenGenerationTest(t, "operations_gen_link_token_zksync_config.yaml", "link_token_zksync.golden.go") +} + func runGoldenGenerationTest(t *testing.T, configFileName string, goldenFileName string) { t.Helper() diff --git a/tools/operations-gen/internal/families/evm/evm_test.go b/tools/operations-gen/internal/families/evm/evm_test.go index 99d8f7abb..55394a40c 100644 --- a/tools/operations-gen/internal/families/evm/evm_test.go +++ b/tools/operations-gen/internal/families/evm/evm_test.go @@ -98,3 +98,51 @@ contracts: require.Contains(t, string(got), `gobindings "`+wantGobindingsPackage+`"`) require.NotContains(t, string(got), `gobindings "./testdata/evm/gobindings`) } + +func TestGenerateResolvesRelativeZkSyncBindingsPackage(t *testing.T) { + t.Parallel() + + const wantZkSyncPackage = "github.com/smartcontractkit/chainlink-deployments-framework/tools/operations-gen/testdata/evm/zksync_bindings" + config := `version: "1.0.0" +chain_family: evm + +input: + gobindings_package: "github.com/smartcontractkit/chainlink-deployments-framework/tools/operations-gen/testdata/evm/gobindings" + zksync_bindings_package: "./testdata/evm/zksync_bindings" + +output: + base_path: "." + +contracts: + - contract_name: ManyChainMultiSig + version: "1.0.0" + package_name: many_chain_multi_sig + zksync_bytecode: ManyChainMultiSigZkBytecode + functions: + - name: owner + access: public +` + + var cfg core.Config + require.NoError(t, yaml.Unmarshal([]byte(config), &cfg), "parsing config") + + moduleDir, err := filepath.Abs(filepath.Join("..", "..", "..")) + require.NoError(t, err) + tmpDir := t.TempDir() + outputBasePath, err := filepath.Rel(moduleDir, tmpDir) + require.NoError(t, err) + cfg.ConfigDir = moduleDir + cfg.Output = mustYAMLNode(t, evm.EvmOutputConfig{BasePath: outputBasePath}) + + tmpl, err := generate.LoadTemplate("evm") + require.NoError(t, err, "loadTemplate") + + require.NoError(t, evm.Handler{}.Generate(cfg, tmpl), "Generate") + + outputPath := core.ContractOutputPath(tmpDir, core.VersionToPath("1.0.0"), "many_chain_multi_sig") + got, err := os.ReadFile(outputPath) + require.NoError(t, err, "reading generated file %s", outputPath) + + require.Contains(t, string(got), `zkbindings "`+wantZkSyncPackage+`"`) + require.Contains(t, string(got), "ZkSyncVM: zkbindings.ManyChainMultiSigZkBytecode") +} diff --git a/tools/operations-gen/internal/families/evm/zksync_bytecode.go b/tools/operations-gen/internal/families/evm/zksync_bytecode.go new file mode 100644 index 000000000..a72c573c8 --- /dev/null +++ b/tools/operations-gen/internal/families/evm/zksync_bytecode.go @@ -0,0 +1,85 @@ +package evm + +import ( + "errors" + "fmt" + + "gopkg.in/yaml.v3" +) + +// ZkSyncBytecodeRef identifies zkSync VM deploy bytecode for a contract. +// YAML accepts a shorthand symbol string or {package, symbol}. +type ZkSyncBytecodeRef struct { + Package string + Symbol string +} + +func (z *ZkSyncBytecodeRef) UnmarshalYAML(value *yaml.Node) error { + *z = ZkSyncBytecodeRef{} + if value == nil { + return nil + } + + switch value.Kind { + case yaml.ScalarNode: + if isYAMLNullScalar(value) { + return nil + } + z.Symbol = value.Value + + return nil + case yaml.MappingNode: + var raw struct { + Package string `yaml:"package"` + Symbol string `yaml:"symbol"` + } + if err := value.Decode(&raw); err != nil { + return err + } + z.Package = raw.Package + z.Symbol = raw.Symbol + if z.Symbol == "" { + return errors.New("zksync_bytecode mapping requires symbol") + } + + return nil + case yaml.DocumentNode, yaml.SequenceNode, yaml.AliasNode: + return fmt.Errorf("zksync_bytecode must be a string or mapping, got %v", value.ShortTag()) + } + + return fmt.Errorf("zksync_bytecode must be a string or mapping, got %v", value.ShortTag()) +} + +func isYAMLNullScalar(value *yaml.Node) bool { + return value.Tag == "!!null" || value.Value == "" || value.Value == "~" +} + +func (z ZkSyncBytecodeRef) IsZero() bool { + return z.Symbol == "" +} + +func resolveZkSyncBytecode( + cfg EvmContractConfig, + input EvmInputConfig, + gobindingsPackage string, +) (packagePath string, symbol string, err error) { + if cfg.ZkSyncBytecode.IsZero() { + return "", "", nil + } + + symbol = cfg.ZkSyncBytecode.Symbol + pkgPath := cfg.ZkSyncBytecode.Package + if pkgPath == "" { + pkgPath = input.ZkSyncBindingsPackage + } + if pkgPath == "" { + return gobindingsPackage, symbol, nil + } + + resolved, err := resolveGobindingsImportPath(pkgPath, cfg.ConfigDir) + if err != nil { + return "", "", fmt.Errorf("resolve zksync_bytecode package for contract %q: %w", cfg.Name, err) + } + + return resolved, symbol, nil +} diff --git a/tools/operations-gen/internal/families/evm/zksync_bytecode_test.go b/tools/operations-gen/internal/families/evm/zksync_bytecode_test.go new file mode 100644 index 000000000..9c5d32667 --- /dev/null +++ b/tools/operations-gen/internal/families/evm/zksync_bytecode_test.go @@ -0,0 +1,146 @@ +package evm + +import ( + "testing" + + "github.com/stretchr/testify/require" + "gopkg.in/yaml.v3" +) + +func TestZkSyncBytecodeRefUnmarshalYAML(t *testing.T) { + t.Parallel() + + t.Run("shorthand symbol", func(t *testing.T) { + t.Parallel() + var ref ZkSyncBytecodeRef + require.NoError(t, yaml.Unmarshal([]byte(`CallProxyZkBytecode`), &ref)) + require.Equal(t, "CallProxyZkBytecode", ref.Symbol) + require.Empty(t, ref.Package) + }) + + t.Run("mapping", func(t *testing.T) { + t.Parallel() + var ref ZkSyncBytecodeRef + require.NoError(t, yaml.Unmarshal([]byte(` +package: github.com/example/zk +symbol: FooZkBytecode +`), &ref)) + require.Equal(t, "github.com/example/zk", ref.Package) + require.Equal(t, "FooZkBytecode", ref.Symbol) + }) + + t.Run("mapping symbol only", func(t *testing.T) { + t.Parallel() + var ref ZkSyncBytecodeRef + require.NoError(t, yaml.Unmarshal([]byte(` +symbol: FooZkBytecode +`), &ref)) + require.Empty(t, ref.Package) + require.Equal(t, "FooZkBytecode", ref.Symbol) + }) + + t.Run("mapping without symbol", func(t *testing.T) { + t.Parallel() + var ref ZkSyncBytecodeRef + err := yaml.Unmarshal([]byte(` +package: github.com/example/zk +`), &ref) + require.ErrorContains(t, err, "zksync_bytecode mapping requires symbol") + }) + + t.Run("scalar overwrites previous mapping", func(t *testing.T) { + t.Parallel() + var ref ZkSyncBytecodeRef + require.NoError(t, yaml.Unmarshal([]byte(` +package: github.com/example/zk +symbol: FooZkBytecode +`), &ref)) + require.NoError(t, yaml.Unmarshal([]byte(`BarZkBytecode`), &ref)) + require.Equal(t, "BarZkBytecode", ref.Symbol) + require.Empty(t, ref.Package) + }) + + t.Run("null is unset", func(t *testing.T) { + t.Parallel() + var cfg struct { + ZkSyncBytecode ZkSyncBytecodeRef `yaml:"zksync_bytecode"` + } + require.NoError(t, yaml.Unmarshal([]byte(`zksync_bytecode: null`), &cfg)) + require.True(t, cfg.ZkSyncBytecode.IsZero()) + }) + + t.Run("tilde is unset", func(t *testing.T) { + t.Parallel() + var cfg struct { + ZkSyncBytecode ZkSyncBytecodeRef `yaml:"zksync_bytecode"` + } + require.NoError(t, yaml.Unmarshal([]byte(`zksync_bytecode: ~`), &cfg)) + require.True(t, cfg.ZkSyncBytecode.IsZero()) + }) + + t.Run("empty string is unset", func(t *testing.T) { + t.Parallel() + var cfg struct { + ZkSyncBytecode ZkSyncBytecodeRef `yaml:"zksync_bytecode"` + } + require.NoError(t, yaml.Unmarshal([]byte(`zksync_bytecode: ""`), &cfg)) + require.True(t, cfg.ZkSyncBytecode.IsZero()) + }) +} + +func TestResolveZkSyncBytecodeUsesInputDefaultPackage(t *testing.T) { + t.Parallel() + + const zkPackage = "github.com/smartcontractkit/chainlink-deployments-framework/tools/operations-gen/testdata/evm/zksync_bindings" + cfg := EvmContractConfig{ + Name: "ManyChainMultiSig", + ZkSyncBytecode: mustZkSyncBytecodeRef(t, "ManyChainMultiSigZkBytecode"), + } + input := EvmInputConfig{ZkSyncBindingsPackage: zkPackage} + + pkg, symbol, err := resolveZkSyncBytecode(cfg, input, "github.com/example/evm") + require.NoError(t, err) + require.Equal(t, zkPackage, pkg) + require.Equal(t, "ManyChainMultiSigZkBytecode", symbol) +} + +func TestResolveZkSyncBytecodeFallsBackToGobindingsPackage(t *testing.T) { + t.Parallel() + + const gobindingsPackage = "github.com/example/gobindings/link_token" + cfg := EvmContractConfig{ + Name: "LinkToken", + ZkSyncBytecode: mustZkSyncBytecodeRef(t, "ZkBytecode"), + } + + pkg, symbol, err := resolveZkSyncBytecode(cfg, EvmInputConfig{}, gobindingsPackage) + require.NoError(t, err) + require.Equal(t, gobindingsPackage, pkg) + require.Equal(t, "ZkBytecode", symbol) +} + +func TestExtractContractInfoRejectsZkSyncBytecodeWithOmitDeploy(t *testing.T) { + t.Parallel() + + cfg := EvmContractConfig{ + Name: "LinkToken", + Version: "1.0.0", + OmitDeploy: true, + GobindingsPackage: "github.com/smartcontractkit/chainlink-deployments-framework/tools/operations-gen/testdata/evm/gobindings/v1_0_0/link_token", + ZkSyncBytecode: mustZkSyncBytecodeRef(t, "ZkBytecode"), + Functions: []EvmFunctionConfig{ + {Name: "transfer", Access: "public"}, + }, + } + + _, err := extractContractInfo(cfg, EvmInputConfig{}, EvmOutputConfig{BasePath: t.TempDir()}) + require.ErrorContains(t, err, "zksync_bytecode cannot be set when omit_deploy is true") +} + +func mustZkSyncBytecodeRef(t *testing.T, symbol string) ZkSyncBytecodeRef { + t.Helper() + var ref ZkSyncBytecodeRef + require.NoError(t, yaml.Unmarshal([]byte(symbol), &ref)) + + return ref +} diff --git a/tools/operations-gen/testdata/evm/gobindings/v1_0_0/link_token/link_token.go b/tools/operations-gen/testdata/evm/gobindings/v1_0_0/link_token/link_token.go index 95ef74617..ed3f583d8 100644 --- a/tools/operations-gen/testdata/evm/gobindings/v1_0_0/link_token/link_token.go +++ b/tools/operations-gen/testdata/evm/gobindings/v1_0_0/link_token/link_token.go @@ -37,6 +37,9 @@ var LinkTokenABI = LinkTokenMetaData.ABI var LinkTokenBin = LinkTokenMetaData.Bin +// ZkBytecode is zkSync VM deploy bytecode for operations-gen tests. +var ZkBytecode = []byte{0xca, 0xfe} + func DeployLinkToken(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *LinkToken, error) { parsed, err := LinkTokenMetaData.GetAbi() if err != nil { diff --git a/tools/operations-gen/testdata/evm/link_token_zksync.golden.go b/tools/operations-gen/testdata/evm/link_token_zksync.golden.go new file mode 100644 index 000000000..5b91cbb46 --- /dev/null +++ b/tools/operations-gen/testdata/evm/link_token_zksync.golden.go @@ -0,0 +1,99 @@ +// Code generated by operations-gen. DO NOT EDIT. + +package link_token + +import ( + "math/big" + + "github.com/Masterminds/semver/v3" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + + cldf_evm "github.com/smartcontractkit/chainlink-deployments-framework/chain/evm" + "github.com/smartcontractkit/chainlink-deployments-framework/chain/evm/operations2/contract" + cldf_deployment "github.com/smartcontractkit/chainlink-deployments-framework/deployment" + cld_ops "github.com/smartcontractkit/chainlink-deployments-framework/operations" + gobindings "github.com/smartcontractkit/chainlink-deployments-framework/tools/operations-gen/testdata/evm/gobindings/v1_0_0/link_token" + zkbindings "github.com/smartcontractkit/chainlink-deployments-framework/tools/operations-gen/testdata/evm/zksync_bindings" +) + +var ContractType cldf_deployment.ContractType = "LinkToken" +var Version = semver.MustParse("1.0.0") +var TypeAndVersion = cldf_deployment.NewTypeAndVersion(ContractType, *Version) + +type TransferArgs struct { + To common.Address `json:"to"` + Amount *big.Int `json:"amount"` +} + +type ApproveArgs struct { + Spender common.Address `json:"spender"` + Amount *big.Int `json:"amount"` +} + +type ConstructorArgs = struct{} + +var Deploy = contract.NewDeploy(contract.DeployParams[ConstructorArgs]{ + Name: "link-token:deploy", + Version: Version, + Description: "Deploys the LinkToken contract", + ContractMetadata: gobindings.LinkTokenMetaData, + BytecodeByTypeAndVersion: map[string]contract.Bytecode{ + cldf_deployment.NewTypeAndVersion(ContractType, *Version).String(): { + EVM: common.FromHex(gobindings.LinkTokenMetaData.Bin), + ZkSyncVM: zkbindings.LinkTokenZkBytecode, + }, + }, +}) + +func NewWriteTransfer(c gobindings.LinkTokenInterface) *cld_ops.Operation[contract.FunctionInput[TransferArgs], contract.WriteOutput, cldf_evm.Chain] { + return contract.NewWrite(contract.WriteParams[TransferArgs, gobindings.LinkTokenInterface]{ + Name: "link-token:transfer", + Version: Version, + Description: "Calls transfer on the contract", + ContractType: ContractType, + ContractABI: gobindings.LinkTokenMetaData.ABI, + Contract: c, + IsAllowedCaller: contract.AllCallersAllowed[gobindings.LinkTokenInterface, TransferArgs], + CallContract: func( + c gobindings.LinkTokenInterface, + opts *bind.TransactOpts, + args TransferArgs, + ) (*types.Transaction, error) { + return c.Transfer(opts, args.To, args.Amount) + }, + }) +} + +func NewReadBalanceOf(c gobindings.LinkTokenInterface) *cld_ops.Operation[contract.FunctionInput[common.Address], *big.Int, cldf_evm.Chain] { + return contract.NewRead(contract.ReadParams[common.Address, *big.Int, gobindings.LinkTokenInterface]{ + Name: "link-token:balance-of", + Version: Version, + Description: "Calls balanceOf on the contract", + ContractType: ContractType, + Contract: c, + CallContract: func(c gobindings.LinkTokenInterface, opts *bind.CallOpts, args common.Address) (*big.Int, error) { + return c.BalanceOf(opts, args) + }, + }) +} + +func NewWriteApprove(c gobindings.LinkTokenInterface) *cld_ops.Operation[contract.FunctionInput[ApproveArgs], contract.WriteOutput, cldf_evm.Chain] { + return contract.NewWrite(contract.WriteParams[ApproveArgs, gobindings.LinkTokenInterface]{ + Name: "link-token:approve", + Version: Version, + Description: "Calls approve on the contract", + ContractType: ContractType, + ContractABI: gobindings.LinkTokenMetaData.ABI, + Contract: c, + IsAllowedCaller: contract.AllCallersAllowed[gobindings.LinkTokenInterface, ApproveArgs], + CallContract: func( + c gobindings.LinkTokenInterface, + opts *bind.TransactOpts, + args ApproveArgs, + ) (*types.Transaction, error) { + return c.Approve(opts, args.Spender, args.Amount) + }, + }) +} diff --git a/tools/operations-gen/testdata/evm/many_chain_multi_sig.golden.go b/tools/operations-gen/testdata/evm/many_chain_multi_sig.golden.go index 08ff53cf4..c35e87f43 100644 --- a/tools/operations-gen/testdata/evm/many_chain_multi_sig.golden.go +++ b/tools/operations-gen/testdata/evm/many_chain_multi_sig.golden.go @@ -13,6 +13,7 @@ import ( cldf_deployment "github.com/smartcontractkit/chainlink-deployments-framework/deployment" cld_ops "github.com/smartcontractkit/chainlink-deployments-framework/operations" gobindings "github.com/smartcontractkit/chainlink-deployments-framework/tools/operations-gen/testdata/evm/gobindings/v1_0_0/many_chain_multi_sig" + zkbindings "github.com/smartcontractkit/chainlink-deployments-framework/tools/operations-gen/testdata/evm/zksync_bindings" ) var ContractType cldf_deployment.ContractType = "ManyChainMultiSig" @@ -44,7 +45,8 @@ var Deploy = contract.NewDeploy(contract.DeployParams[ConstructorArgs]{ ContractMetadata: gobindings.ManyChainMultiSigMetaData, BytecodeByTypeAndVersion: map[string]contract.Bytecode{ cldf_deployment.NewTypeAndVersion(ContractType, *Version).String(): { - EVM: common.FromHex(gobindings.ManyChainMultiSigMetaData.Bin), + EVM: common.FromHex(gobindings.ManyChainMultiSigMetaData.Bin), + ZkSyncVM: zkbindings.ManyChainMultiSigZkBytecode, }, }, }) diff --git a/tools/operations-gen/testdata/evm/operations_gen_link_token_zksync_config.yaml b/tools/operations-gen/testdata/evm/operations_gen_link_token_zksync_config.yaml new file mode 100644 index 000000000..6d4c79aa8 --- /dev/null +++ b/tools/operations-gen/testdata/evm/operations_gen_link_token_zksync_config.yaml @@ -0,0 +1,21 @@ +version: "1.0.0" +chain_family: evm + +input: + gobindings_package: "github.com/smartcontractkit/chainlink-deployments-framework/tools/operations-gen/testdata/evm/gobindings" + zksync_bindings_package: "github.com/smartcontractkit/chainlink-deployments-framework/tools/operations-gen/testdata/evm/zksync_bindings" + +output: + base_path: "." + +contracts: + - contract_name: LinkToken + version: "1.0.0" + zksync_bytecode: LinkTokenZkBytecode + functions: + - name: transfer + access: public + - name: balanceOf + access: public + - name: approve + access: public diff --git a/tools/operations-gen/testdata/evm/operations_gen_mcms_config.yaml b/tools/operations-gen/testdata/evm/operations_gen_mcms_config.yaml index 65c7e40de..3efcbc35f 100644 --- a/tools/operations-gen/testdata/evm/operations_gen_mcms_config.yaml +++ b/tools/operations-gen/testdata/evm/operations_gen_mcms_config.yaml @@ -3,6 +3,7 @@ chain_family: evm input: gobindings_package: "github.com/smartcontractkit/chainlink-deployments-framework/tools/operations-gen/testdata/evm/gobindings" + zksync_bindings_package: "github.com/smartcontractkit/chainlink-deployments-framework/tools/operations-gen/testdata/evm/zksync_bindings" output: base_path: "." @@ -11,6 +12,7 @@ contracts: - contract_name: ManyChainMultiSig version: "1.0.0" package_name: many_chain_multi_sig + zksync_bytecode: ManyChainMultiSigZkBytecode functions: - name: owner access: public diff --git a/tools/operations-gen/testdata/evm/zksync_bindings/bytecode.go b/tools/operations-gen/testdata/evm/zksync_bindings/bytecode.go new file mode 100644 index 000000000..f0e9f6f2c --- /dev/null +++ b/tools/operations-gen/testdata/evm/zksync_bindings/bytecode.go @@ -0,0 +1,6 @@ +// Package zksync_bindings holds zkSync VM bytecode fixtures for operations-gen tests. +package zksync_bindings + +var LinkTokenZkBytecode = []byte{0xca, 0xfe} + +var ManyChainMultiSigZkBytecode = []byte{0xde, 0xad, 0xbe, 0xef}