From c5dbecb754cf9f130377c5194d4b92ed13130716 Mon Sep 17 00:00:00 2001 From: Ekaterina Pavlova Date: Tue, 9 Apr 2024 01:02:05 +0300 Subject: [PATCH] smartcontract: support dynamic contract hash for bindings Allow dynamic contract hash for contract bindings. Close #3007 Signed-off-by: Ekaterina Pavlova --- cli/smartcontract/contract_test.go | 104 ++++-- cli/smartcontract/generate.go | 27 +- cli/smartcontract/generate_test.go | 97 +++++- .../testdata/verify.bindings.yml | 297 ++++++++++++++++++ pkg/smartcontract/binding/generate.go | 37 ++- 5 files changed, 523 insertions(+), 39 deletions(-) create mode 100755 cli/smartcontract/testdata/verify.bindings.yml diff --git a/cli/smartcontract/contract_test.go b/cli/smartcontract/contract_test.go index 4051952e0..481c1a21b 100644 --- a/cli/smartcontract/contract_test.go +++ b/cli/smartcontract/contract_test.go @@ -25,6 +25,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/neorpc/result" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/nef" + "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" "github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/nspcc-dev/neo-go/pkg/vm/vmstate" @@ -145,18 +146,7 @@ func Blocks() []*alias.Block { cmd = append(cmd, "--in", ctrPath, "--bindings", bindingsPath) // Replace `pkg/interop` in go.mod to avoid getting an actual module version. - goMod := filepath.Join(ctrPath, "go.mod") - data, err := os.ReadFile(goMod) - require.NoError(t, err) - - i := bytes.IndexByte(data, '\n') - data = append([]byte("module myimport.com/testcontract"), data[i:]...) - - wd, err := os.Getwd() - require.NoError(t, err) - data = append(data, "\nreplace github.com/nspcc-dev/neo-go/pkg/interop => "...) - data = append(data, filepath.Join(wd, "../../pkg/interop")...) - require.NoError(t, os.WriteFile(goMod, data, os.ModePerm)) + require.NoError(t, updateGoMod(ctrPath, "myimport.com/testcontract", "../../pkg/interop")) cmd = append(cmd, "--config", cfgPath, "--out", filepath.Join(tmpDir, "out.nef"), @@ -176,7 +166,7 @@ func Blocks() []*alias.Block { bs, err := os.ReadFile(outPath) require.NoError(t, err) - require.Equal(t, `// Code generated by neo-go contract generate-wrapper --manifest --out --hash [--config ]; DO NOT EDIT. + require.Equal(t, `// Code generated by neo-go contract generate-wrapper --manifest --out [--hash ] [--config ]; DO NOT EDIT. // Package testcontract contains wrappers for testcontract contract. package testcontract @@ -213,6 +203,84 @@ func ToMap(a []testcontract.MyPair) map[int]string { `, string(bs)) } +// updateGoMod updates the go.mod file located in the specified directory. +// It sets the module name and replaces the neo-go interop package path with +// the provided one to avoid getting an actual module version. +func updateGoMod(dir, moduleName, neoGoPath string) error { + goModPath := filepath.Join(dir, "go.mod") + data, err := os.ReadFile(goModPath) + if err != nil { + return fmt.Errorf("failed to read go.mod: %w", err) + } + + i := bytes.IndexByte(data, '\n') + if i == -1 { + return fmt.Errorf("unexpected go.mod format") + } + + updatedData := append([]byte("module "+moduleName), data[i:]...) + wd, err := os.Getwd() + if err != nil { + return fmt.Errorf("failed to get working directory: %w", err) + } + + replacementPath := filepath.Join(wd, neoGoPath) + updatedData = append(updatedData, "\nreplace github.com/nspcc-dev/neo-go/pkg/interop => "+replacementPath+" \n"...) + + if err := os.WriteFile(goModPath, updatedData, os.ModePerm); err != nil { + return fmt.Errorf("failed to write updated go.mod: %w", err) + } + + return nil +} + +func TestDynamicWrapper(t *testing.T) { + // For proper contract init. The actual version as it will be replaced. + smartcontract.ModVersion = "v0.0.0" + + tmpDir := t.TempDir() + e := testcli.NewExecutor(t, true) + + ctrPath := "../smartcontract/testdata" + + verifyHash := testcli.DeployContract(t, e, filepath.Join(ctrPath, "verify.go"), filepath.Join(ctrPath, "verify.yml"), testcli.ValidatorWallet, testcli.ValidatorAddr, testcli.ValidatorPass) + + helperContract := `package testcontract + +import ( + "github.com/nspcc-dev/neo-go/pkg/interop" + verify "myimport.com/testcontract/bindings" +) + +func CallVerifyContract(h interop.Hash160) bool{ + contractInstance := verify.NewContract(h) + return contractInstance.Verify() +}` + + helperDir := filepath.Join(tmpDir, "helper") + e.Run(t, "neo-go", "contract", "init", "--name", helperDir) + + require.NoError(t, updateGoMod(helperDir, "myimport.com/testcontract", "../../pkg/interop")) + require.NoError(t, os.WriteFile(filepath.Join(helperDir, "main.go"), []byte(helperContract), os.ModePerm)) + require.NoError(t, os.Mkdir(filepath.Join(helperDir, "bindings"), os.ModePerm)) + + e.Run(t, "neo-go", "contract", "generate-wrapper", + "--config", filepath.Join(ctrPath, "verify.bindings.yml"), "--manifest", filepath.Join(ctrPath, "verify.manifest.json"), + "--out", filepath.Join(helperDir, "bindings", "testdata.go")) + e.Run(t, "neo-go", "contract", "compile", "--in", filepath.Join(helperDir, "main.go"), "--config", filepath.Join(helperDir, "neo-go.yml")) + helperHash := testcli.DeployContract(t, e, filepath.Join(helperDir, "main.go"), filepath.Join(helperDir, "neo-go.yml"), testcli.ValidatorWallet, testcli.ValidatorAddr, testcli.ValidatorPass) + + e.In.WriteString("one\r") + e.Run(t, "neo-go", "contract", "invokefunction", + "--rpc-endpoint", "http://"+e.RPC.Addresses()[0], + "--wallet", testcli.ValidatorWallet, "--address", testcli.ValidatorAddr, "--force", "--await", helperHash.StringLE(), "callVerifyContract", verifyHash.StringLE()) + + tx, _ := e.CheckTxPersisted(t, "Sent invocation transaction ") + aer, err := e.Chain.GetAppExecResults(tx.Hash(), trigger.Application) + require.NoError(t, err) + require.Equal(t, aer[0].Stack[0].Value().(bool), true) +} + func TestContractInitAndCompile(t *testing.T) { // For proper contract init. The actual version as it will be replaced. smartcontract.ModVersion = "v0.0.0" @@ -265,15 +333,7 @@ func TestContractInitAndCompile(t *testing.T) { }) // Replace `pkg/interop` in go.mod to avoid getting an actual module version. - goMod := filepath.Join(ctrPath, "go.mod") - data, err := os.ReadFile(goMod) - require.NoError(t, err) - - wd, err := os.Getwd() - require.NoError(t, err) - data = append(data, "\nreplace github.com/nspcc-dev/neo-go/pkg/interop => "...) - data = append(data, filepath.Join(wd, "../../pkg/interop")...) - require.NoError(t, os.WriteFile(goMod, data, os.ModePerm)) + require.NoError(t, updateGoMod(ctrPath, "myimport.com/testcontract", "../../pkg/interop")) cmd = append(cmd, "--config", cfgPath) diff --git a/cli/smartcontract/generate.go b/cli/smartcontract/generate.go index 7c0ffa8ae..28f9f18ce 100644 --- a/cli/smartcontract/generate.go +++ b/cli/smartcontract/generate.go @@ -30,17 +30,22 @@ var generatorFlags = []cli.Flag{ }, cli.StringFlag{ Name: "hash", - Usage: "Smart-contract hash", + Usage: "Smart-contract hash. If not passed, the wrapper will be designed for dynamic hash usage", }, } var generateWrapperCmd = cli.Command{ - Name: "generate-wrapper", - Usage: "generate wrapper to use in other contracts", - UsageText: "neo-go contract generate-wrapper --manifest --out --hash [--config ]", - Description: ``, - Action: contractGenerateWrapper, - Flags: generatorFlags, + Name: "generate-wrapper", + Usage: "generate wrapper to use in other contracts", + UsageText: "neo-go contract generate-wrapper --manifest --out [--hash ] [--config ]", + Description: `Generates a Go wrapper to use it in other smart contracts. If the + --hash flag is provided, CALLT instruction is used for the target contract + invocation as an optimization of the wrapper contract code. If omitted, the + generated wrapper will be designed for dynamic hash usage, allowing + the hash to be specified at runtime. +`, + Action: contractGenerateWrapper, + Flags: generatorFlags, } var generateRPCWrapperCmd = cli.Command{ @@ -52,15 +57,15 @@ var generateRPCWrapperCmd = cli.Command{ } func contractGenerateWrapper(ctx *cli.Context) error { - return contractGenerateSomething(ctx, binding.Generate, false) + return contractGenerateSomething(ctx, binding.Generate) } func contractGenerateRPCWrapper(ctx *cli.Context) error { - return contractGenerateSomething(ctx, rpcbinding.Generate, true) + return contractGenerateSomething(ctx, rpcbinding.Generate) } // contractGenerateSomething reads generator parameters and calls the given callback. -func contractGenerateSomething(ctx *cli.Context, cb func(binding.Config) error, allowEmptyHash bool) error { +func contractGenerateSomething(ctx *cli.Context, cb func(binding.Config) error) error { if err := cmdargs.EnsureNone(ctx); err != nil { return err } @@ -73,8 +78,6 @@ func contractGenerateSomething(ctx *cli.Context, cb func(binding.Config) error, if err != nil { return cli.NewExitError(fmt.Errorf("invalid contract hash: %w", err), 1) } - } else if !allowEmptyHash { - return cli.NewExitError("contract hash must be provided via --hash flag", 1) } m, _, err := readManifest(ctx.String("manifest"), h) if err != nil { diff --git a/cli/smartcontract/generate_test.go b/cli/smartcontract/generate_test.go index b54fc8fab..195be3d08 100644 --- a/cli/smartcontract/generate_test.go +++ b/cli/smartcontract/generate_test.go @@ -151,7 +151,7 @@ callflags: "--hash", h.StringLE(), })) - const expected = `// Code generated by neo-go contract generate-wrapper --manifest --out --hash [--config ]; DO NOT EDIT. + const expected = `// Code generated by neo-go contract generate-wrapper --manifest --out [--hash ] [--config ]; DO NOT EDIT. // Package wrapper contains wrappers for MyContract contract. package wrapper @@ -233,6 +233,99 @@ func MyFunc(in map[int]mycontract.Input) []mycontract.Output { data, err := os.ReadFile(outFile) require.NoError(t, err) require.Equal(t, expected, string(data)) + + require.NoError(t, app.Run([]string{"", "generate-wrapper", + "--manifest", manifestFile, + "--config", cfgPath, + "--out", outFile, + })) + expectedWithDynamicHash := `// Code generated by neo-go contract generate-wrapper --manifest --out [--hash ] [--config ]; DO NOT EDIT. + +// Package wrapper contains wrappers for MyContract contract. +package wrapper + +import ( + "github.com/heyitsme/mycontract" + "github.com/nspcc-dev/neo-go/pkg/interop" + "github.com/nspcc-dev/neo-go/pkg/interop/contract" + "github.com/nspcc-dev/neo-go/pkg/interop/iterator" + "github.com/nspcc-dev/neo-go/pkg/interop/native/ledger" + "github.com/nspcc-dev/neo-go/pkg/interop/storage" +) + +// Contract represents the MyContract smart contract. +type Contract struct { + Hash interop.Hash160 +} + +// NewContract returns a new Contract instance with the specified hash. +func NewContract(hash interop.Hash160) Contract { + return Contract{Hash: hash} +} + +// Sum invokes ` + "`sum`" + ` method of contract. +func (c Contract) Sum(first int, second int) int { + return contract.Call(c.Hash, "sum", contract.All, first, second).(int) +} + +// Sum2 invokes ` + "`sum`" + ` method of contract. +func (c Contract) Sum2(first int, second int, third int) int { + return contract.Call(c.Hash, "sum", contract.All, first, second, third).(int) +} + +// Sum3 invokes ` + "`sum3`" + ` method of contract. +func (c Contract) Sum3() int { + return contract.Call(c.Hash, "sum3", contract.ReadOnly).(int) +} + +// Zum invokes ` + "`zum`" + ` method of contract. +func (c Contract) Zum(typev int, typev_ int, funcv int) int { + return contract.Call(c.Hash, "zum", contract.All, typev, typev_, funcv).(int) +} + +// JustExecute invokes ` + "`justExecute`" + ` method of contract. +func (c Contract) JustExecute(arr []any) { + contract.Call(c.Hash, "justExecute", contract.All, arr) +} + +// GetPublicKey invokes ` + "`getPublicKey`" + ` method of contract. +func (c Contract) GetPublicKey() interop.PublicKey { + return contract.Call(c.Hash, "getPublicKey", contract.All).(interop.PublicKey) +} + +// OtherTypes invokes ` + "`otherTypes`" + ` method of contract. +func (c Contract) OtherTypes(ctr interop.Hash160, tx interop.Hash256, sig interop.Signature, data any) bool { + return contract.Call(c.Hash, "otherTypes", contract.All, ctr, tx, sig, data).(bool) +} + +// SearchStorage invokes ` + "`searchStorage`" + ` method of contract. +func (c Contract) SearchStorage(ctx storage.Context) iterator.Iterator { + return contract.Call(c.Hash, "searchStorage", contract.All, ctx).(iterator.Iterator) +} + +// GetFromMap invokes ` + "`getFromMap`" + ` method of contract. +func (c Contract) GetFromMap(intMap map[string]int, indices []string) []int { + return contract.Call(c.Hash, "getFromMap", contract.All, intMap, indices).([]int) +} + +// DoSomething invokes ` + "`doSomething`" + ` method of contract. +func (c Contract) DoSomething(bytes []byte, str string) any { + return contract.Call(c.Hash, "doSomething", contract.ReadStates, bytes, str).(any) +} + +// GetBlockWrapper invokes ` + "`getBlockWrapper`" + ` method of contract. +func (c Contract) GetBlockWrapper() ledger.Block { + return contract.Call(c.Hash, "getBlockWrapper", contract.All).(ledger.Block) +} + +// MyFunc invokes ` + "`myFunc`" + ` method of contract. +func (c Contract) MyFunc(in map[int]mycontract.Input) []mycontract.Output { + return contract.Call(c.Hash, "myFunc", contract.All, in).([]mycontract.Output) +} +` + data, err = os.ReadFile(outFile) + require.NoError(t, err) + require.Equal(t, expectedWithDynamicHash, string(data)) } func TestGenerateValidPackageName(t *testing.T) { @@ -267,7 +360,7 @@ func TestGenerateValidPackageName(t *testing.T) { data, err := os.ReadFile(outFile) require.NoError(t, err) - require.Equal(t, `// Code generated by neo-go contract generate-wrapper --manifest --out --hash [--config ]; DO NOT EDIT. + require.Equal(t, `// Code generated by neo-go contract generate-wrapper --manifest --out [--hash ] [--config ]; DO NOT EDIT. // Package myspacecontract contains wrappers for My space contract contract. package myspacecontract diff --git a/cli/smartcontract/testdata/verify.bindings.yml b/cli/smartcontract/testdata/verify.bindings.yml new file mode 100755 index 000000000..927064b60 --- /dev/null +++ b/cli/smartcontract/testdata/verify.bindings.yml @@ -0,0 +1,297 @@ +package: testdata +hash: "0x0000000000000000000000000000000000000000" +overrides: + burnGas.gas: int + call: any + call.args: '[]any' + call.f: any + call.method: string + call.scriptHash: github.com/nspcc-dev/neo-go/pkg/interop.Hash160 + callWithToken: any + callWithToken.args: '[]any' + callWithToken.flags: int + callWithToken.method: string + callWithToken.scriptHash: string + callWithTokenNoRet.args: '[]any' + callWithTokenNoRet.flags: int + callWithTokenNoRet.method: string + callWithTokenNoRet.scriptHash: string + checkWitness: bool + checkWitness.hashOrKey: '[]byte' + createMultisigAccount: '[]byte' + createMultisigAccount.m: int + createMultisigAccount.pubs: '[]github.com/nspcc-dev/neo-go/pkg/interop.PublicKey' + createStandardAccount: '[]byte' + createStandardAccount.pub: github.com/nspcc-dev/neo-go/pkg/interop.PublicKey + currentHash: github.com/nspcc-dev/neo-go/pkg/interop.Hash256 + currentIndex: int + currentSigners: '[]github.com/nspcc-dev/neo-go/pkg/interop/native/ledger.TransactionSigner' + equals: bool + equals.b: any + gasLeft: int + getAddressVersion: int + getBlock: '*github.com/nspcc-dev/neo-go/pkg/interop/native/ledger.Block' + getBlock.indexOrHash: any + getCallFlags: any + getCallingScriptHash: github.com/nspcc-dev/neo-go/pkg/interop.Hash160 + getEntryScriptHash: github.com/nspcc-dev/neo-go/pkg/interop.Hash160 + getExecutingScriptHash: github.com/nspcc-dev/neo-go/pkg/interop.Hash160 + getInvocationCounter: int + getNetwork: int + getNotifications: '[][]any' + getNotifications.h: github.com/nspcc-dev/neo-go/pkg/interop.Hash160 + getRandom: int + getScriptContainer: '*github.com/nspcc-dev/neo-go/pkg/interop/native/ledger.Transaction' + getTime: int + getTransaction: '*github.com/nspcc-dev/neo-go/pkg/interop/native/ledger.Transaction' + getTransaction.hash: github.com/nspcc-dev/neo-go/pkg/interop.Hash256 + getTransactionFromBlock: '*github.com/nspcc-dev/neo-go/pkg/interop/native/ledger.Transaction' + getTransactionFromBlock.indexOrHash: any + getTransactionFromBlock.txIndex: int + getTransactionHeight: int + getTransactionHeight.hash: github.com/nspcc-dev/neo-go/pkg/interop.Hash256 + getTransactionSigners: '[]github.com/nspcc-dev/neo-go/pkg/interop/native/ledger.TransactionSigner' + getTransactionSigners.hash: github.com/nspcc-dev/neo-go/pkg/interop.Hash256 + getTransactionVMState: int + getTransactionVMState.hash: github.com/nspcc-dev/neo-go/pkg/interop.Hash256 + getTrigger: int + loadScript: any + loadScript.args: '[]any' + loadScript.f: any + loadScript.script: '[]byte' + log.message: string + notify.args: '[]any' + notify.name: string + onNEP11Payment.amount: int + onNEP11Payment.data: any + onNEP11Payment.from: github.com/nspcc-dev/neo-go/pkg/interop.Hash160 + onNEP11Payment.token: '[]byte' + onNEP17Payment.amount: int + onNEP17Payment.data: any + onNEP17Payment.from: github.com/nspcc-dev/neo-go/pkg/interop.Hash160 + opcode0NoReturn.op: string + opcode1: any + opcode1NoReturn.arg: any + opcode1NoReturn.op: string + opcode1.arg: any + opcode1.op: string + opcode2: any + opcode2NoReturn.arg1: any + opcode2NoReturn.arg2: any + opcode2NoReturn.op: string + opcode2.arg1: any + opcode2.arg2: any + opcode2.op: string + opcode3: any + opcode3.arg1: any + opcode3.arg2: any + opcode3.arg3: any + opcode3.op: string + platform: '[]byte' + syscall0: any + syscall0NoReturn.name: string + syscall0.name: string + syscall1: any + syscall1NoReturn.arg: any + syscall1NoReturn.name: string + syscall1.arg: any + syscall1.name: string + syscall2: any + syscall2NoReturn.arg1: any + syscall2NoReturn.arg2: any + syscall2NoReturn.name: string + syscall2.arg1: any + syscall2.arg2: any + syscall2.name: string + syscall3: any + syscall3NoReturn.arg1: any + syscall3NoReturn.arg2: any + syscall3NoReturn.arg3: any + syscall3NoReturn.name: string + syscall3.arg1: any + syscall3.arg2: any + syscall3.arg3: any + syscall3.name: string + syscall4: any + syscall4NoReturn.arg1: any + syscall4NoReturn.arg2: any + syscall4NoReturn.arg3: any + syscall4NoReturn.arg4: any + syscall4NoReturn.name: string + syscall4.arg1: any + syscall4.arg2: any + syscall4.arg3: any + syscall4.arg4: any + syscall4.name: string + toBlockSR: '*github.com/nspcc-dev/neo-go/pkg/interop/native/ledger.BlockSR' + verify: bool +namedtypes: + ledger.Block: + base: Array + name: ledger.Block + fields: + - field: Hash + base: Hash256 + - field: Version + base: Integer + - field: PrevHash + base: Hash256 + - field: MerkleRoot + base: Hash256 + - field: Timestamp + base: Integer + - field: Nonce + base: Integer + - field: Index + base: Integer + - field: NextConsensus + base: Hash160 + - field: TransactionsLength + base: Integer + ledger.BlockSR: + base: Array + name: ledger.BlockSR + fields: + - field: Hash + base: Hash256 + - field: Version + base: Integer + - field: PrevHash + base: Hash256 + - field: MerkleRoot + base: Hash256 + - field: Timestamp + base: Integer + - field: Nonce + base: Integer + - field: Index + base: Integer + - field: NextConsensus + base: Hash160 + - field: TransactionsLength + base: Integer + - field: PrevStateRoot + base: Hash256 + ledger.Transaction: + base: Array + name: ledger.Transaction + fields: + - field: Hash + base: Hash256 + - field: Version + base: Integer + - field: Nonce + base: Integer + - field: Sender + base: Hash160 + - field: SysFee + base: Integer + - field: NetFee + base: Integer + - field: ValidUntilBlock + base: Integer + - field: Script + base: ByteArray + ledger.TransactionSigner: + base: Array + name: ledger.TransactionSigner + fields: + - field: Account + base: Hash160 + - field: Scopes + base: Integer + - field: AllowedContracts + base: Array + value: + base: Hash160 + - field: AllowedGroups + base: Array + value: + base: PublicKey + - field: Rules + base: Array + value: + base: Array + name: ledger.WitnessRule + ledger.WitnessCondition: + base: Array + name: ledger.WitnessCondition + fields: + - field: Type + base: Integer + - field: Value + base: Any + ledger.WitnessRule: + base: Array + name: ledger.WitnessRule + fields: + - field: Action + base: Integer + - field: Condition + base: Array + name: ledger.WitnessCondition +types: + call.args: + base: Array + value: + base: Any + call.f: + base: InteropInterface + interface: iterator + callWithToken.args: + base: Array + value: + base: Any + callWithTokenNoRet.args: + base: Array + value: + base: Any + createMultisigAccount.pubs: + base: Array + value: + base: PublicKey + currentSigners: + base: Array + value: + base: Array + name: ledger.TransactionSigner + getBlock: + base: Array + name: ledger.Block + getCallFlags: + base: InteropInterface + interface: iterator + getNotifications: + base: Array + value: + base: Array + value: + base: Any + getScriptContainer: + base: Array + name: ledger.Transaction + getTransaction: + base: Array + name: ledger.Transaction + getTransactionFromBlock: + base: Array + name: ledger.Transaction + getTransactionSigners: + base: Array + value: + base: Array + name: ledger.TransactionSigner + loadScript.args: + base: Array + value: + base: Any + loadScript.f: + base: InteropInterface + interface: iterator + notify.args: + base: Array + value: + base: Any + toBlockSR: + base: Array + name: ledger.BlockSR diff --git a/pkg/smartcontract/binding/generate.go b/pkg/smartcontract/binding/generate.go index 3b86f79d0..24939f458 100644 --- a/pkg/smartcontract/binding/generate.go +++ b/pkg/smartcontract/binding/generate.go @@ -19,7 +19,7 @@ import ( ) const srcTmpl = ` -{{- define "METHOD" -}} +{{- define "FUNCTION" -}} // {{.Name}} {{.Comment}} func {{.Name}}({{range $index, $arg := .Arguments -}} {{- if ne $index 0}}, {{end}} @@ -33,7 +33,21 @@ func {{.Name}}({{range $index, $arg := .Arguments -}} {{- end}} } {{- end -}} -// Code generated by neo-go contract generate-wrapper --manifest --out --hash [--config ]; DO NOT EDIT. +{{- define "METHOD" -}} +// {{.Name}} {{.Comment}} +func (c Contract) {{.Name}}({{range $index, $arg := .Arguments -}} + {{- if ne $index 0}}, {{end}} + {{- .Name}} {{.Type}} + {{- end}}) {{if .ReturnType }}{{ .ReturnType}} { + return contract.Call(c.Hash, "{{ .NameABI }}", contract.{{ .CallFlag }} + {{- range $arg := .Arguments -}}, {{.Name}}{{end}}).({{ .ReturnType }}) + {{- else -}} { + contract.Call(c.Hash, "{{ .NameABI }}", contract.{{ .CallFlag }} + {{- range $arg := .Arguments -}}, {{.Name}}{{end}}) + {{- end}} +} +{{- end -}} +// Code generated by neo-go contract generate-wrapper --manifest --out [--hash ] [--config ]; DO NOT EDIT. // Package {{.PackageName}} contains wrappers for {{.ContractName}} contract. package {{.PackageName}} @@ -42,10 +56,25 @@ import ( {{range $m := .Imports}} "{{ $m }}" {{end}}) +{{if .Hash}} // Hash contains contract hash in big-endian form. const Hash = "{{ .Hash }}" {{range $m := .Methods}} +{{template "FUNCTION" $m }} +{{end}} +{{else}} +// Contract represents the {{.ContractName}} smart contract. +type Contract struct { + Hash interop.Hash160 +} + +// NewContract returns a new Contract instance with the specified hash. +func NewContract(hash interop.Hash160) Contract { + return Contract{Hash: hash} +} +{{range $m := .Methods}} {{template "METHOD" $m }} +{{end}} {{end}}` type ( @@ -127,7 +156,9 @@ func NewConfig() Config { func Generate(cfg Config) error { ctr := TemplateFromManifest(cfg, scTypeToGo) ctr.Imports = append(ctr.Imports, "github.com/nspcc-dev/neo-go/pkg/interop/contract") - ctr.Imports = append(ctr.Imports, "github.com/nspcc-dev/neo-go/pkg/interop/neogointernal") + if ctr.Hash != "" { + ctr.Imports = append(ctr.Imports, "github.com/nspcc-dev/neo-go/pkg/interop/neogointernal") + } sort.Strings(ctr.Imports) return FExecute(srcTemplate, cfg.Output, ctr)