diff --git a/cli/smartcontract/testdata/nameservice/nns.go b/cli/smartcontract/testdata/nameservice/nns.go index 62c59082b..511acaedf 100644 --- a/cli/smartcontract/testdata/nameservice/nns.go +++ b/cli/smartcontract/testdata/nameservice/nns.go @@ -2,6 +2,7 @@ package nameservice import ( + "github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/neorpc/result" "github.com/nspcc-dev/neo-go/pkg/rpcclient/nep11" "github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap" @@ -19,17 +20,42 @@ type Invoker interface { Call(contract util.Uint160, operation string, params ...interface{}) (*result.Invoke, error) } +// Actor is used by Contract to call state-changing methods. +type Actor interface { + Invoker + nep11.Actor + MakeCall(contract util.Uint160, method string, params ...interface{}) (*transaction.Transaction, error) + MakeRun(script []byte) (*transaction.Transaction, error) + MakeUnsignedCall(contract util.Uint160, method string, attrs []transaction.Attribute, params ...interface{}) (*transaction.Transaction, error) + MakeUnsignedRun(script []byte, attrs []transaction.Attribute) (*transaction.Transaction, error) + SendCall(contract util.Uint160, method string, params ...interface{}) (util.Uint256, uint32, error) + SendRun(script []byte) (util.Uint256, uint32, error) +} + // ContractReader implements safe contract methods. type ContractReader struct { nep11.NonDivisibleReader invoker Invoker } +// Contract implements all contract methods. +type Contract struct { + ContractReader + nep11.BaseWriter + actor Actor +} + // NewReader creates an instance of ContractReader using Hash and the given Invoker. func NewReader(invoker Invoker) *ContractReader { return &ContractReader{*nep11.NewNonDivisibleReader(invoker, Hash), invoker} } +// New creates an instance of Contract using Hash and the given Actor. +func New(actor Actor) *Contract { + var nep11ndt = nep11.NewNonDivisible(actor, Hash) + return &Contract{ContractReader{nep11ndt.NonDivisibleReader, actor},nep11ndt.BaseWriter, actor} +} + // Roots invokes `roots` method of contract. func (c *ContractReader) Roots() (stackitem.Item, error) { @@ -60,3 +86,201 @@ func (c *ContractReader) GetAllRecords(name string) (stackitem.Item, error) { func (c *ContractReader) Resolve(name string, typev *big.Int) (string, error) { return unwrap.UTF8String(c.invoker.Call(Hash, "resolve", name, typev)) } + +// Update creates a transaction invoking `update` method of the contract. +// This transaction is signed and immediately sent to the network. +// The values returned are its hash, ValidUntilBlock value and error if any. +func (c *Contract) Update(nef []byte, manifest string) (util.Uint256, uint32, error) { + return c.actor.SendCall(Hash, "update", nef, manifest) +} + +// UpdateTransaction creates a transaction invoking `update` method of the contract. +// This transaction is signed, but not sent to the network, instead it's +// returned to the caller. +func (c *Contract) UpdateTransaction(nef []byte, manifest string) (*transaction.Transaction, error) { + return c.actor.MakeCall(Hash, "update", nef, manifest) +} + +// UpdateUnsigned creates a transaction invoking `update` method of the contract. +// This transaction is not signed, it's simply returned to the caller. +// Any fields of it that do not affect fees can be changed (ValidUntilBlock, +// Nonce), fee values (NetworkFee, SystemFee) can be increased as well. +func (c *Contract) UpdateUnsigned(nef []byte, manifest string) (*transaction.Transaction, error) { + return c.actor.MakeUnsignedCall(Hash, "update", nil, nef, manifest) +} + +// AddRoot creates a transaction invoking `addRoot` method of the contract. +// This transaction is signed and immediately sent to the network. +// The values returned are its hash, ValidUntilBlock value and error if any. +func (c *Contract) AddRoot(root string) (util.Uint256, uint32, error) { + return c.actor.SendCall(Hash, "addRoot", root) +} + +// AddRootTransaction creates a transaction invoking `addRoot` method of the contract. +// This transaction is signed, but not sent to the network, instead it's +// returned to the caller. +func (c *Contract) AddRootTransaction(root string) (*transaction.Transaction, error) { + return c.actor.MakeCall(Hash, "addRoot", root) +} + +// AddRootUnsigned creates a transaction invoking `addRoot` method of the contract. +// This transaction is not signed, it's simply returned to the caller. +// Any fields of it that do not affect fees can be changed (ValidUntilBlock, +// Nonce), fee values (NetworkFee, SystemFee) can be increased as well. +func (c *Contract) AddRootUnsigned(root string) (*transaction.Transaction, error) { + return c.actor.MakeUnsignedCall(Hash, "addRoot", nil, root) +} + +// SetPrice creates a transaction invoking `setPrice` method of the contract. +// This transaction is signed and immediately sent to the network. +// The values returned are its hash, ValidUntilBlock value and error if any. +func (c *Contract) SetPrice(priceList []interface{}) (util.Uint256, uint32, error) { + return c.actor.SendCall(Hash, "setPrice", priceList) +} + +// SetPriceTransaction creates a transaction invoking `setPrice` method of the contract. +// This transaction is signed, but not sent to the network, instead it's +// returned to the caller. +func (c *Contract) SetPriceTransaction(priceList []interface{}) (*transaction.Transaction, error) { + return c.actor.MakeCall(Hash, "setPrice", priceList) +} + +// SetPriceUnsigned creates a transaction invoking `setPrice` method of the contract. +// This transaction is not signed, it's simply returned to the caller. +// Any fields of it that do not affect fees can be changed (ValidUntilBlock, +// Nonce), fee values (NetworkFee, SystemFee) can be increased as well. +func (c *Contract) SetPriceUnsigned(priceList []interface{}) (*transaction.Transaction, error) { + return c.actor.MakeUnsignedCall(Hash, "setPrice", nil, priceList) +} + +// Register creates a transaction invoking `register` method of the contract. +// This transaction is signed and immediately sent to the network. +// The values returned are its hash, ValidUntilBlock value and error if any. +func (c *Contract) Register(name string, owner util.Uint160) (util.Uint256, uint32, error) { + return c.actor.SendCall(Hash, "register", name, owner) +} + +// RegisterTransaction creates a transaction invoking `register` method of the contract. +// This transaction is signed, but not sent to the network, instead it's +// returned to the caller. +func (c *Contract) RegisterTransaction(name string, owner util.Uint160) (*transaction.Transaction, error) { + return c.actor.MakeCall(Hash, "register", name, owner) +} + +// RegisterUnsigned creates a transaction invoking `register` method of the contract. +// This transaction is not signed, it's simply returned to the caller. +// Any fields of it that do not affect fees can be changed (ValidUntilBlock, +// Nonce), fee values (NetworkFee, SystemFee) can be increased as well. +func (c *Contract) RegisterUnsigned(name string, owner util.Uint160) (*transaction.Transaction, error) { + return c.actor.MakeUnsignedCall(Hash, "register", nil, name, owner) +} + +// Renew creates a transaction invoking `renew` method of the contract. +// This transaction is signed and immediately sent to the network. +// The values returned are its hash, ValidUntilBlock value and error if any. +func (c *Contract) Renew(name string) (util.Uint256, uint32, error) { + return c.actor.SendCall(Hash, "renew", name) +} + +// RenewTransaction creates a transaction invoking `renew` method of the contract. +// This transaction is signed, but not sent to the network, instead it's +// returned to the caller. +func (c *Contract) RenewTransaction(name string) (*transaction.Transaction, error) { + return c.actor.MakeCall(Hash, "renew", name) +} + +// RenewUnsigned creates a transaction invoking `renew` method of the contract. +// This transaction is not signed, it's simply returned to the caller. +// Any fields of it that do not affect fees can be changed (ValidUntilBlock, +// Nonce), fee values (NetworkFee, SystemFee) can be increased as well. +func (c *Contract) RenewUnsigned(name string) (*transaction.Transaction, error) { + return c.actor.MakeUnsignedCall(Hash, "renew", nil, name) +} + +// Renew_2 creates a transaction invoking `renew` method of the contract. +// This transaction is signed and immediately sent to the network. +// The values returned are its hash, ValidUntilBlock value and error if any. +func (c *Contract) Renew_2(name string, years *big.Int) (util.Uint256, uint32, error) { + return c.actor.SendCall(Hash, "renew", name, years) +} + +// Renew_2Transaction creates a transaction invoking `renew` method of the contract. +// This transaction is signed, but not sent to the network, instead it's +// returned to the caller. +func (c *Contract) Renew_2Transaction(name string, years *big.Int) (*transaction.Transaction, error) { + return c.actor.MakeCall(Hash, "renew", name, years) +} + +// Renew_2Unsigned creates a transaction invoking `renew` method of the contract. +// This transaction is not signed, it's simply returned to the caller. +// Any fields of it that do not affect fees can be changed (ValidUntilBlock, +// Nonce), fee values (NetworkFee, SystemFee) can be increased as well. +func (c *Contract) Renew_2Unsigned(name string, years *big.Int) (*transaction.Transaction, error) { + return c.actor.MakeUnsignedCall(Hash, "renew", nil, name, years) +} + +// SetAdmin creates a transaction invoking `setAdmin` method of the contract. +// This transaction is signed and immediately sent to the network. +// The values returned are its hash, ValidUntilBlock value and error if any. +func (c *Contract) SetAdmin(name string, admin util.Uint160) (util.Uint256, uint32, error) { + return c.actor.SendCall(Hash, "setAdmin", name, admin) +} + +// SetAdminTransaction creates a transaction invoking `setAdmin` method of the contract. +// This transaction is signed, but not sent to the network, instead it's +// returned to the caller. +func (c *Contract) SetAdminTransaction(name string, admin util.Uint160) (*transaction.Transaction, error) { + return c.actor.MakeCall(Hash, "setAdmin", name, admin) +} + +// SetAdminUnsigned creates a transaction invoking `setAdmin` method of the contract. +// This transaction is not signed, it's simply returned to the caller. +// Any fields of it that do not affect fees can be changed (ValidUntilBlock, +// Nonce), fee values (NetworkFee, SystemFee) can be increased as well. +func (c *Contract) SetAdminUnsigned(name string, admin util.Uint160) (*transaction.Transaction, error) { + return c.actor.MakeUnsignedCall(Hash, "setAdmin", nil, name, admin) +} + +// SetRecord creates a transaction invoking `setRecord` method of the contract. +// This transaction is signed and immediately sent to the network. +// The values returned are its hash, ValidUntilBlock value and error if any. +func (c *Contract) SetRecord(name string, typev *big.Int, data string) (util.Uint256, uint32, error) { + return c.actor.SendCall(Hash, "setRecord", name, typev, data) +} + +// SetRecordTransaction creates a transaction invoking `setRecord` method of the contract. +// This transaction is signed, but not sent to the network, instead it's +// returned to the caller. +func (c *Contract) SetRecordTransaction(name string, typev *big.Int, data string) (*transaction.Transaction, error) { + return c.actor.MakeCall(Hash, "setRecord", name, typev, data) +} + +// SetRecordUnsigned creates a transaction invoking `setRecord` method of the contract. +// This transaction is not signed, it's simply returned to the caller. +// Any fields of it that do not affect fees can be changed (ValidUntilBlock, +// Nonce), fee values (NetworkFee, SystemFee) can be increased as well. +func (c *Contract) SetRecordUnsigned(name string, typev *big.Int, data string) (*transaction.Transaction, error) { + return c.actor.MakeUnsignedCall(Hash, "setRecord", nil, name, typev, data) +} + +// DeleteRecord creates a transaction invoking `deleteRecord` method of the contract. +// This transaction is signed and immediately sent to the network. +// The values returned are its hash, ValidUntilBlock value and error if any. +func (c *Contract) DeleteRecord(name string, typev *big.Int) (util.Uint256, uint32, error) { + return c.actor.SendCall(Hash, "deleteRecord", name, typev) +} + +// DeleteRecordTransaction creates a transaction invoking `deleteRecord` method of the contract. +// This transaction is signed, but not sent to the network, instead it's +// returned to the caller. +func (c *Contract) DeleteRecordTransaction(name string, typev *big.Int) (*transaction.Transaction, error) { + return c.actor.MakeCall(Hash, "deleteRecord", name, typev) +} + +// DeleteRecordUnsigned creates a transaction invoking `deleteRecord` method of the contract. +// This transaction is not signed, it's simply returned to the caller. +// Any fields of it that do not affect fees can be changed (ValidUntilBlock, +// Nonce), fee values (NetworkFee, SystemFee) can be increased as well. +func (c *Contract) DeleteRecordUnsigned(name string, typev *big.Int) (*transaction.Transaction, error) { + return c.actor.MakeUnsignedCall(Hash, "deleteRecord", nil, name, typev) +} diff --git a/cli/smartcontract/testdata/nex/nex.go b/cli/smartcontract/testdata/nex/nex.go index 90a9b5645..3ca127356 100644 --- a/cli/smartcontract/testdata/nex/nex.go +++ b/cli/smartcontract/testdata/nex/nex.go @@ -2,6 +2,7 @@ package nextoken import ( + "github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/neorpc/result" "github.com/nspcc-dev/neo-go/pkg/rpcclient/nep17" @@ -19,17 +20,42 @@ type Invoker interface { Call(contract util.Uint160, operation string, params ...interface{}) (*result.Invoke, error) } +// Actor is used by Contract to call state-changing methods. +type Actor interface { + Invoker + nep17.Actor + MakeCall(contract util.Uint160, method string, params ...interface{}) (*transaction.Transaction, error) + MakeRun(script []byte) (*transaction.Transaction, error) + MakeUnsignedCall(contract util.Uint160, method string, attrs []transaction.Attribute, params ...interface{}) (*transaction.Transaction, error) + MakeUnsignedRun(script []byte, attrs []transaction.Attribute) (*transaction.Transaction, error) + SendCall(contract util.Uint160, method string, params ...interface{}) (util.Uint256, uint32, error) + SendRun(script []byte) (util.Uint256, uint32, error) +} + // ContractReader implements safe contract methods. type ContractReader struct { nep17.TokenReader invoker Invoker } +// Contract implements all contract methods. +type Contract struct { + ContractReader + nep17.TokenWriter + actor Actor +} + // NewReader creates an instance of ContractReader using Hash and the given Invoker. func NewReader(invoker Invoker) *ContractReader { return &ContractReader{*nep17.NewReader(invoker, Hash), invoker} } +// New creates an instance of Contract using Hash and the given Actor. +func New(actor Actor) *Contract { + var nep17t = nep17.New(actor, Hash) + return &Contract{ContractReader{nep17t.TokenReader, actor},nep17t.TokenWriter, actor} +} + // Cap invokes `cap` method of contract. func (c *ContractReader) Cap() (*big.Int, error) { @@ -50,3 +76,157 @@ func (c *ContractReader) GetOwner() (util.Uint160, error) { func (c *ContractReader) TotalMinted() (*big.Int, error) { return unwrap.BigInt(c.invoker.Call(Hash, "totalMinted")) } + +// ChangeMinter creates a transaction invoking `changeMinter` method of the contract. +// This transaction is signed and immediately sent to the network. +// The values returned are its hash, ValidUntilBlock value and error if any. +func (c *Contract) ChangeMinter(newMinter *keys.PublicKey) (util.Uint256, uint32, error) { + return c.actor.SendCall(Hash, "changeMinter", newMinter) +} + +// ChangeMinterTransaction creates a transaction invoking `changeMinter` method of the contract. +// This transaction is signed, but not sent to the network, instead it's +// returned to the caller. +func (c *Contract) ChangeMinterTransaction(newMinter *keys.PublicKey) (*transaction.Transaction, error) { + return c.actor.MakeCall(Hash, "changeMinter", newMinter) +} + +// ChangeMinterUnsigned creates a transaction invoking `changeMinter` method of the contract. +// This transaction is not signed, it's simply returned to the caller. +// Any fields of it that do not affect fees can be changed (ValidUntilBlock, +// Nonce), fee values (NetworkFee, SystemFee) can be increased as well. +func (c *Contract) ChangeMinterUnsigned(newMinter *keys.PublicKey) (*transaction.Transaction, error) { + return c.actor.MakeUnsignedCall(Hash, "changeMinter", nil, newMinter) +} + +// ChangeOwner creates a transaction invoking `changeOwner` method of the contract. +// This transaction is signed and immediately sent to the network. +// The values returned are its hash, ValidUntilBlock value and error if any. +func (c *Contract) ChangeOwner(newOwner util.Uint160) (util.Uint256, uint32, error) { + return c.actor.SendCall(Hash, "changeOwner", newOwner) +} + +// ChangeOwnerTransaction creates a transaction invoking `changeOwner` method of the contract. +// This transaction is signed, but not sent to the network, instead it's +// returned to the caller. +func (c *Contract) ChangeOwnerTransaction(newOwner util.Uint160) (*transaction.Transaction, error) { + return c.actor.MakeCall(Hash, "changeOwner", newOwner) +} + +// ChangeOwnerUnsigned creates a transaction invoking `changeOwner` method of the contract. +// This transaction is not signed, it's simply returned to the caller. +// Any fields of it that do not affect fees can be changed (ValidUntilBlock, +// Nonce), fee values (NetworkFee, SystemFee) can be increased as well. +func (c *Contract) ChangeOwnerUnsigned(newOwner util.Uint160) (*transaction.Transaction, error) { + return c.actor.MakeUnsignedCall(Hash, "changeOwner", nil, newOwner) +} + +// Destroy creates a transaction invoking `destroy` method of the contract. +// This transaction is signed and immediately sent to the network. +// The values returned are its hash, ValidUntilBlock value and error if any. +func (c *Contract) Destroy() (util.Uint256, uint32, error) { + return c.actor.SendCall(Hash, "destroy") +} + +// DestroyTransaction creates a transaction invoking `destroy` method of the contract. +// This transaction is signed, but not sent to the network, instead it's +// returned to the caller. +func (c *Contract) DestroyTransaction() (*transaction.Transaction, error) { + return c.actor.MakeCall(Hash, "destroy") +} + +// DestroyUnsigned creates a transaction invoking `destroy` method of the contract. +// This transaction is not signed, it's simply returned to the caller. +// Any fields of it that do not affect fees can be changed (ValidUntilBlock, +// Nonce), fee values (NetworkFee, SystemFee) can be increased as well. +func (c *Contract) DestroyUnsigned() (*transaction.Transaction, error) { + return c.actor.MakeUnsignedCall(Hash, "destroy", nil) +} + +// MaxSupply creates a transaction invoking `maxSupply` method of the contract. +// This transaction is signed and immediately sent to the network. +// The values returned are its hash, ValidUntilBlock value and error if any. +func (c *Contract) MaxSupply() (util.Uint256, uint32, error) { + return c.actor.SendCall(Hash, "maxSupply") +} + +// MaxSupplyTransaction creates a transaction invoking `maxSupply` method of the contract. +// This transaction is signed, but not sent to the network, instead it's +// returned to the caller. +func (c *Contract) MaxSupplyTransaction() (*transaction.Transaction, error) { + return c.actor.MakeCall(Hash, "maxSupply") +} + +// MaxSupplyUnsigned creates a transaction invoking `maxSupply` method of the contract. +// This transaction is not signed, it's simply returned to the caller. +// Any fields of it that do not affect fees can be changed (ValidUntilBlock, +// Nonce), fee values (NetworkFee, SystemFee) can be increased as well. +func (c *Contract) MaxSupplyUnsigned() (*transaction.Transaction, error) { + return c.actor.MakeUnsignedCall(Hash, "maxSupply", nil) +} + +// Mint creates a transaction invoking `mint` method of the contract. +// This transaction is signed and immediately sent to the network. +// The values returned are its hash, ValidUntilBlock value and error if any. +func (c *Contract) Mint(from util.Uint160, to util.Uint160, amount *big.Int, swapId *big.Int, signature []byte, data interface{}) (util.Uint256, uint32, error) { + return c.actor.SendCall(Hash, "mint", from, to, amount, swapId, signature, data) +} + +// MintTransaction creates a transaction invoking `mint` method of the contract. +// This transaction is signed, but not sent to the network, instead it's +// returned to the caller. +func (c *Contract) MintTransaction(from util.Uint160, to util.Uint160, amount *big.Int, swapId *big.Int, signature []byte, data interface{}) (*transaction.Transaction, error) { + return c.actor.MakeCall(Hash, "mint", from, to, amount, swapId, signature, data) +} + +// MintUnsigned creates a transaction invoking `mint` method of the contract. +// This transaction is not signed, it's simply returned to the caller. +// Any fields of it that do not affect fees can be changed (ValidUntilBlock, +// Nonce), fee values (NetworkFee, SystemFee) can be increased as well. +func (c *Contract) MintUnsigned(from util.Uint160, to util.Uint160, amount *big.Int, swapId *big.Int, signature []byte, data interface{}) (*transaction.Transaction, error) { + return c.actor.MakeUnsignedCall(Hash, "mint", nil, from, to, amount, swapId, signature, data) +} + +// Update creates a transaction invoking `update` method of the contract. +// This transaction is signed and immediately sent to the network. +// The values returned are its hash, ValidUntilBlock value and error if any. +func (c *Contract) Update(nef []byte, manifest []byte) (util.Uint256, uint32, error) { + return c.actor.SendCall(Hash, "update", nef, manifest) +} + +// UpdateTransaction creates a transaction invoking `update` method of the contract. +// This transaction is signed, but not sent to the network, instead it's +// returned to the caller. +func (c *Contract) UpdateTransaction(nef []byte, manifest []byte) (*transaction.Transaction, error) { + return c.actor.MakeCall(Hash, "update", nef, manifest) +} + +// UpdateUnsigned creates a transaction invoking `update` method of the contract. +// This transaction is not signed, it's simply returned to the caller. +// Any fields of it that do not affect fees can be changed (ValidUntilBlock, +// Nonce), fee values (NetworkFee, SystemFee) can be increased as well. +func (c *Contract) UpdateUnsigned(nef []byte, manifest []byte) (*transaction.Transaction, error) { + return c.actor.MakeUnsignedCall(Hash, "update", nil, nef, manifest) +} + +// UpdateCap creates a transaction invoking `updateCap` method of the contract. +// This transaction is signed and immediately sent to the network. +// The values returned are its hash, ValidUntilBlock value and error if any. +func (c *Contract) UpdateCap(newCap *big.Int) (util.Uint256, uint32, error) { + return c.actor.SendCall(Hash, "updateCap", newCap) +} + +// UpdateCapTransaction creates a transaction invoking `updateCap` method of the contract. +// This transaction is signed, but not sent to the network, instead it's +// returned to the caller. +func (c *Contract) UpdateCapTransaction(newCap *big.Int) (*transaction.Transaction, error) { + return c.actor.MakeCall(Hash, "updateCap", newCap) +} + +// UpdateCapUnsigned creates a transaction invoking `updateCap` method of the contract. +// This transaction is not signed, it's simply returned to the caller. +// Any fields of it that do not affect fees can be changed (ValidUntilBlock, +// Nonce), fee values (NetworkFee, SystemFee) can be increased as well. +func (c *Contract) UpdateCapUnsigned(newCap *big.Int) (*transaction.Transaction, error) { + return c.actor.MakeUnsignedCall(Hash, "updateCap", nil, newCap) +} diff --git a/docs/compiler.md b/docs/compiler.md index 1b4f5833d..7b909fc6c 100644 --- a/docs/compiler.md +++ b/docs/compiler.md @@ -436,12 +436,11 @@ $ ./bin/neo-go contract generate-wrapper --manifest manifest.json --config contr ### Generating RPC contract bindings To simplify interacting with the contract via RPC you can generate -contract-specific RPC bindings with the "generate-rpcwrapper" command. At the -moment it only works for safe (read-only) methods. If your contract is NEP-11 -or NEP-17 that's autodetected and an appropriate package is included as -well. Notice that the type data available in the manifest is limited, so in -some cases the interface generated may use generic stackitem types. Iterators -are not supported yet. +contract-specific RPC bindings with the "generate-rpcwrapper" command. If your +contract is NEP-11 or NEP-17 that's autodetected and an appropriate package is +included as well. Notice that the type data available in the manifest is +limited, so in some cases the interface generated may use generic stackitem +types. Iterators are not supported yet. ``` $ ./bin/neo-go contract generate-rpcwrapper --manifest manifest.json --out rpcwrapper.go --hash 0x1b4357bff5a01bdf2a6581247cf9ed1e24629176 diff --git a/pkg/smartcontract/rpcbinding/binding.go b/pkg/smartcontract/rpcbinding/binding.go index 0c8b86c30..578e0e048 100644 --- a/pkg/smartcontract/rpcbinding/binding.go +++ b/pkg/smartcontract/rpcbinding/binding.go @@ -12,7 +12,7 @@ import ( ) const srcTmpl = ` -{{- define "METHOD" -}} +{{- define "SAFEMETHOD" -}} // {{.Name}} {{.Comment}} func (c *ContractReader) {{.Name}}({{range $index, $arg := .Arguments -}} {{- if ne $index 0}}, {{end}} @@ -26,6 +26,41 @@ func (c *ContractReader) {{.Name}}({{range $index, $arg := .Arguments -}} {{- end}} } {{- end -}} +{{- define "METHOD" -}} +// {{.Name}} {{.Comment}} +// This transaction is signed and immediately sent to the network. +// The values returned are its hash, ValidUntilBlock value and error if any. +func (c *Contract) {{.Name}}({{range $index, $arg := .Arguments -}} + {{- if ne $index 0}}, {{end}} + {{- .Name}} {{.Type}} + {{- end}}) (util.Uint256, uint32, error) { + return c.actor.SendCall(Hash, "{{ .NameABI }}" + {{- range $index, $arg := .Arguments -}}, {{.Name}}{{end}}) +} + +// {{.Name}}Transaction {{.Comment}} +// This transaction is signed, but not sent to the network, instead it's +// returned to the caller. +func (c *Contract) {{.Name}}Transaction({{range $index, $arg := .Arguments -}} + {{- if ne $index 0}}, {{end}} + {{- .Name}} {{.Type}} + {{- end}}) (*transaction.Transaction, error) { + return c.actor.MakeCall(Hash, "{{ .NameABI }}" + {{- range $index, $arg := .Arguments -}}, {{.Name}}{{end}}) +} + +// {{.Name}}Unsigned {{.Comment}} +// This transaction is not signed, it's simply returned to the caller. +// Any fields of it that do not affect fees can be changed (ValidUntilBlock, +// Nonce), fee values (NetworkFee, SystemFee) can be increased as well. +func (c *Contract) {{.Name}}Unsigned({{range $index, $arg := .Arguments -}} + {{- if ne $index 0}}, {{end}} + {{- .Name}} {{.Type}} + {{- end}}) (*transaction.Transaction, error) { + return c.actor.MakeUnsignedCall(Hash, "{{ .NameABI }}", nil + {{- range $index, $arg := .Arguments -}}, {{.Name}}{{end}}) +} +{{- end -}} // Package {{.PackageName}} contains RPC wrappers for {{.ContractName}} contract. package {{.PackageName}} @@ -45,6 +80,22 @@ type Invoker interface { Call(contract util.Uint160, operation string, params ...interface{}) (*result.Invoke, error) } +{{if .HasWriter}}// Actor is used by Contract to call state-changing methods. +type Actor interface { + Invoker + {{if or .IsNep11D .IsNep11ND}}nep11.Actor{{end -}} + {{if .IsNep17}}nep17.Actor{{end -}} +{{if len .Methods}} + MakeCall(contract util.Uint160, method string, params ...interface{}) (*transaction.Transaction, error) + MakeRun(script []byte) (*transaction.Transaction, error) + MakeUnsignedCall(contract util.Uint160, method string, attrs []transaction.Attribute, params ...interface{}) (*transaction.Transaction, error) + MakeUnsignedRun(script []byte, attrs []transaction.Attribute) (*transaction.Transaction, error) + SendCall(contract util.Uint160, method string, params ...interface{}) (util.Uint256, uint32, error) + SendRun(script []byte) (util.Uint256, uint32, error) +{{end -}} +} + +{{end -}} // ContractReader implements safe contract methods. type ContractReader struct { {{if .IsNep11D}}nep11.DivisibleReader @@ -56,6 +107,19 @@ type ContractReader struct { invoker Invoker } +{{if .HasWriter}}// Contract implements all contract methods. +type Contract struct { + ContractReader + {{if .IsNep11D}}nep11.DivisibleWriter + {{end -}} + {{if .IsNep11ND}}nep11.BaseWriter + {{end -}} + {{if .IsNep17}}nep17.TokenWriter + {{end -}} + actor Actor +} + +{{end -}} // NewReader creates an instance of ContractReader using Hash and the given Invoker. func NewReader(invoker Invoker) *ContractReader { return &ContractReader{ @@ -65,7 +129,30 @@ func NewReader(invoker Invoker) *ContractReader { invoker} } -{{range $m := .Methods}} +{{if .HasWriter}}// New creates an instance of Contract using Hash and the given Actor. +func New(actor Actor) *Contract { + {{if .IsNep11D}}var nep11dt = nep11.NewDivisible(actor, Hash) + {{end -}} + {{if .IsNep11ND}}var nep11ndt = nep11.NewNonDivisible(actor, Hash) + {{end -}} + {{if .IsNep17}}var nep17t = nep17.New(actor, Hash) + {{end -}} + return &Contract{ContractReader{ + {{- if .IsNep11D}}nep11dt.DivisibleReader, {{end -}} + {{- if .IsNep11ND}}nep11ndt.NonDivisibleReader, {{end -}} + {{- if .IsNep17}}nep17t.TokenReader, {{end -}} + actor}, + {{- if .IsNep11D}}nep11dt.DivisibleWriter, {{end -}} + {{- if .IsNep11ND}}nep11ndt.BaseWriter, {{end -}} + {{- if .IsNep17}}nep17t.TokenWriter, {{end -}} + actor} +} + +{{end -}} +{{range $m := .SafeMethods}} +{{template "SAFEMETHOD" $m }} +{{end}} +{{- range $m := .Methods}} {{template "METHOD" $m }} {{end}}` @@ -74,9 +161,14 @@ var srcTemplate = template.Must(template.New("generate").Parse(srcTmpl)) type ( ContractTmpl struct { binding.ContractTmpl + + SafeMethods []binding.MethodTmpl + IsNep11D bool IsNep11ND bool IsNep17 bool + + HasWriter bool } ) @@ -180,43 +272,54 @@ func scTemplateToRPC(cfg binding.Config, bctr binding.ContractTmpl) ContractTmpl } for i := 0; i < len(ctr.Methods); i++ { abim := cfg.Manifest.ABI.GetMethod(ctr.Methods[i].NameABI, len(ctr.Methods[i].Arguments)) - if !abim.Safe { + if abim.Safe { + ctr.SafeMethods = append(ctr.SafeMethods, ctr.Methods[i]) ctr.Methods = append(ctr.Methods[:i], ctr.Methods[i+1:]...) i-- + } else { + ctr.Methods[i].Comment = fmt.Sprintf("creates a transaction invoking `%s` method of the contract.", ctr.Methods[i].NameABI) } } // We're misusing CallFlag field for function name here. - for i := range ctr.Methods { - switch ctr.Methods[i].ReturnType { + for i := range ctr.SafeMethods { + switch ctr.SafeMethods[i].ReturnType { case "interface{}": imports["github.com/nspcc-dev/neo-go/pkg/vm/stackitem"] = struct{}{} - ctr.Methods[i].ReturnType = "stackitem.Item" - ctr.Methods[i].CallFlag = "Item" + ctr.SafeMethods[i].ReturnType = "stackitem.Item" + ctr.SafeMethods[i].CallFlag = "Item" case "bool": - ctr.Methods[i].CallFlag = "Bool" + ctr.SafeMethods[i].CallFlag = "Bool" case "*big.Int": - ctr.Methods[i].CallFlag = "BigInt" + ctr.SafeMethods[i].CallFlag = "BigInt" case "string": - ctr.Methods[i].CallFlag = "UTF8String" + ctr.SafeMethods[i].CallFlag = "UTF8String" case "util.Uint160": - ctr.Methods[i].CallFlag = "Uint160" + ctr.SafeMethods[i].CallFlag = "Uint160" case "util.Uint256": - ctr.Methods[i].CallFlag = "Uint256" + ctr.SafeMethods[i].CallFlag = "Uint256" case "*keys.PublicKey": - ctr.Methods[i].CallFlag = "PublicKey" + ctr.SafeMethods[i].CallFlag = "PublicKey" case "[]byte": - ctr.Methods[i].CallFlag = "Bytes" + ctr.SafeMethods[i].CallFlag = "Bytes" case "[]interface{}": imports["github.com/nspcc-dev/neo-go/pkg/vm/stackitem"] = struct{}{} - ctr.Methods[i].ReturnType = "[]stackitem.Item" - ctr.Methods[i].CallFlag = "Array" + ctr.SafeMethods[i].ReturnType = "[]stackitem.Item" + ctr.SafeMethods[i].CallFlag = "Array" case "*stackitem.Map": - ctr.Methods[i].CallFlag = "Map" + ctr.SafeMethods[i].CallFlag = "Map" } } - imports["github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"] = struct{}{} imports["github.com/nspcc-dev/neo-go/pkg/neorpc/result"] = struct{}{} + if len(ctr.SafeMethods) > 0 { + imports["github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"] = struct{}{} + } + if len(ctr.Methods) > 0 { + imports["github.com/nspcc-dev/neo-go/pkg/core/transaction"] = struct{}{} + } + if len(ctr.Methods) > 0 || ctr.IsNep17 || ctr.IsNep11D || ctr.IsNep11ND { + ctr.HasWriter = true + } ctr.Imports = ctr.Imports[:0] for imp := range imports { ctr.Imports = append(ctr.Imports, imp)