Merge pull request #2778 from nspcc-dev/rpc-wrapper-writer

State-changing methods in RPC wrappers
This commit is contained in:
Roman Khimov 2022-11-08 21:35:18 +07:00 committed by GitHub
commit 695f00cfeb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 891 additions and 95 deletions

View file

@ -294,6 +294,7 @@ package myspacecontract
import (
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
"github.com/nspcc-dev/neo-go/pkg/util"
"math/big"
)
@ -328,34 +329,37 @@ func TestGenerateRPCBindings(t *testing.T) {
app := cli.NewApp()
app.Commands = []cli.Command{generateWrapperCmd, generateRPCWrapperCmd}
outFile := filepath.Join(tmpDir, "out.go")
require.NoError(t, app.Run([]string{"", "generate-rpcwrapper",
"--manifest", filepath.Join("testdata", "nex", "nex.manifest.json"),
"--out", outFile,
"--hash", "0xa2a67f09e8cf22c6bfd5cea24adc0f4bf0a11aa8",
}))
var checkBinding = func(manifest string, hash string, good string) {
t.Run(manifest, func(t *testing.T) {
outFile := filepath.Join(tmpDir, "out.go")
require.NoError(t, app.Run([]string{"", "generate-rpcwrapper",
"--manifest", manifest,
"--out", outFile,
"--hash", hash,
}))
data, err := os.ReadFile(outFile)
require.NoError(t, err)
data = bytes.ReplaceAll(data, []byte("\r"), []byte{}) // Windows.
expected, err := os.ReadFile(filepath.Join("testdata", "nex", "nex.go"))
require.NoError(t, err)
expected = bytes.ReplaceAll(expected, []byte("\r"), []byte{}) // Windows.
require.Equal(t, string(expected), string(data))
data, err := os.ReadFile(outFile)
require.NoError(t, err)
data = bytes.ReplaceAll(data, []byte("\r"), []byte{}) // Windows.
expected, err := os.ReadFile(good)
require.NoError(t, err)
expected = bytes.ReplaceAll(expected, []byte("\r"), []byte{}) // Windows.
require.Equal(t, string(expected), string(data))
})
}
require.NoError(t, app.Run([]string{"", "generate-rpcwrapper",
"--manifest", filepath.Join("testdata", "nameservice", "nns.manifest.json"),
"--out", outFile,
"--hash", "0x50ac1c37690cc2cfc594472833cf57505d5f46de",
}))
data, err = os.ReadFile(outFile)
require.NoError(t, err)
data = bytes.ReplaceAll(data, []byte("\r"), []byte{}) // Windows.
expected, err = os.ReadFile(filepath.Join("testdata", "nameservice", "nns.go"))
require.NoError(t, err)
expected = bytes.ReplaceAll(expected, []byte("\r"), []byte{}) // Windows.
require.Equal(t, string(expected), string(data))
checkBinding(filepath.Join("testdata", "nex", "nex.manifest.json"),
"0xa2a67f09e8cf22c6bfd5cea24adc0f4bf0a11aa8",
filepath.Join("testdata", "nex", "nex.go"))
checkBinding(filepath.Join("testdata", "nameservice", "nns.manifest.json"),
"0x50ac1c37690cc2cfc594472833cf57505d5f46de",
filepath.Join("testdata", "nameservice", "nns.go"))
checkBinding(filepath.Join("testdata", "gas", "gas.manifest.json"),
"0xd2a4cff31913016155e38e474a2c06d08be276cf",
filepath.Join("testdata", "gas", "gas.go"))
checkBinding(filepath.Join("testdata", "verifyrpc", "verify.manifest.json"),
"0x00112233445566778899aabbccddeeff00112233",
filepath.Join("testdata", "verifyrpc", "verify.go"))
}
func TestGenerate_Errors(t *testing.T) {

47
cli/smartcontract/testdata/gas/gas.go vendored Normal file
View file

@ -0,0 +1,47 @@
// Package gastoken contains RPC wrappers for GasToken contract.
package gastoken
import (
"github.com/nspcc-dev/neo-go/pkg/rpcclient/nep17"
"github.com/nspcc-dev/neo-go/pkg/util"
)
// Hash contains contract hash.
var Hash = util.Uint160{0xcf, 0x76, 0xe2, 0x8b, 0xd0, 0x6, 0x2c, 0x4a, 0x47, 0x8e, 0xe3, 0x55, 0x61, 0x1, 0x13, 0x19, 0xf3, 0xcf, 0xa4, 0xd2}
// Invoker is used by ContractReader to call various safe methods.
type Invoker interface {
nep17.Invoker
}
// Actor is used by Contract to call state-changing methods.
type Actor interface {
Invoker
nep17.Actor
}
// 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}
}

View file

@ -0,0 +1 @@
{"name":"GasToken","groups":[],"features":{},"supportedstandards":["NEP-17"],"abi":{"methods":[{"name":"balanceOf","parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer","offset":0,"safe":true},{"name":"decimals","parameters":[],"returntype":"Integer","offset":7,"safe":true},{"name":"symbol","parameters":[],"returntype":"String","offset":14,"safe":true},{"name":"totalSupply","parameters":[],"returntype":"Integer","offset":21,"safe":true},{"name":"transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Boolean","offset":28,"safe":false}],"events":[{"name":"Transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"}]}]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null}

View file

@ -2,9 +2,10 @@
package nameservice
import (
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/nep11"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"math/big"
@ -16,7 +17,20 @@ var Hash = util.Uint160{0xde, 0x46, 0x5f, 0x5d, 0x50, 0x57, 0xcf, 0x33, 0x28, 0x
// Invoker is used by ContractReader to call various safe methods.
type Invoker interface {
nep11.Invoker
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.
@ -25,11 +39,24 @@ type ContractReader struct {
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 +87,217 @@ 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)
}
func scriptForRegister(name string, owner util.Uint160) ([]byte, error) {
return smartcontract.CreateCallWithAssertScript(Hash, "register", name, owner)
}
// 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) {
script, err := scriptForRegister(name, owner)
if err != nil {
return util.Uint256{}, 0, err
}
return c.actor.SendRun(script)
}
// 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) {
script, err := scriptForRegister(name, owner)
if err != nil {
return nil, err
}
return c.actor.MakeRun(script)
}
// 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) {
script, err := scriptForRegister(name, owner)
if err != nil {
return nil, err
}
return c.actor.MakeUnsignedRun(script, nil)
}
// 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)
}

View file

@ -2,8 +2,8 @@
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"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"
"github.com/nspcc-dev/neo-go/pkg/util"
@ -16,7 +16,20 @@ var Hash = util.Uint160{0xa8, 0x1a, 0xa1, 0xf0, 0x4b, 0xf, 0xdc, 0x4a, 0xa2, 0xc
// Invoker is used by ContractReader to call various safe methods.
type Invoker interface {
nep17.Invoker
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.
@ -25,11 +38,24 @@ type ContractReader struct {
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)
}

View file

@ -0,0 +1,70 @@
// Package verify contains RPC wrappers for verify contract.
package verify
import (
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/util"
)
// Hash contains contract hash.
var Hash = util.Uint160{0x33, 0x22, 0x11, 0x0, 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x0}
// Actor is used by Contract to call state-changing methods.
type Actor interface {
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)
}
// Contract implements all contract methods.
type Contract struct {
actor Actor
}
// New creates an instance of Contract using Hash and the given Actor.
func New(actor Actor) *Contract {
return &Contract{actor}
}
func scriptForVerify() ([]byte, error) {
return smartcontract.CreateCallWithAssertScript(Hash, "verify")
}
// Verify creates a transaction invoking `verify` 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) Verify() (util.Uint256, uint32, error) {
script, err := scriptForVerify()
if err != nil {
return util.Uint256{}, 0, err
}
return c.actor.SendRun(script)
}
// VerifyTransaction creates a transaction invoking `verify` method of the contract.
// This transaction is signed, but not sent to the network, instead it's
// returned to the caller.
func (c *Contract) VerifyTransaction() (*transaction.Transaction, error) {
script, err := scriptForVerify()
if err != nil {
return nil, err
}
return c.actor.MakeRun(script)
}
// VerifyUnsigned creates a transaction invoking `verify` 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) VerifyUnsigned() (*transaction.Transaction, error) {
script, err := scriptForVerify()
if err != nil {
return nil, err
}
return c.actor.MakeUnsignedRun(script, nil)
}

View file

@ -0,0 +1,79 @@
{
"groups" : [],
"extra" : null,
"supportedstandards" : [],
"name" : "verify",
"trusts" : [],
"permissions" : [
{
"methods" : "*",
"contract" : "*"
}
],
"abi" : {
"methods" : [
{
"safe" : false,
"offset" : 0,
"parameters" : [],
"name" : "verify",
"returntype" : "Boolean"
},
{
"returntype" : "Void",
"safe" : false,
"offset" : 5,
"parameters" : [
{
"type" : "Hash160",
"name" : "from"
},
{
"type" : "Integer",
"name" : "amount"
},
{
"type" : "Any",
"name" : "data"
}
],
"name" : "onNEP17Payment"
},
{
"returntype" : "Void",
"safe" : false,
"offset" : 5,
"parameters" : [
{
"type" : "Hash160",
"name" : "from"
},
{
"type" : "Integer",
"name" : "amount"
},
{
"type" : "ByteArray",
"name" : "tokenid"
},
{
"type" : "Any",
"name" : "data"
}
],
"name" : "onNEP11Payment"
}
],
"events" : [
{
"parameters" : [
{
"type" : "Array",
"name" : "args"
}
],
"name" : "Hello world!"
}
]
}
}

View file

@ -436,12 +436,20 @@ $ ./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. It
generates ContractReader structure for safe methods that accept appropriate
data for input and return things returned by the contract. State-changing
methods are contained in Contract structure with each contract method
represented by three wrapper methods that create/send transaction with a
script performing appropriate action. This script invokes contract method and
does not do anything else unless the method's returned value is of a boolean
type, in this case an ASSERT is added to script making it fail when the method
returns false.
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

View file

@ -16,10 +16,17 @@ type DivisibleReader struct {
BaseReader
}
// Divisible is a state-changing interface for divisible NEP-11 contract.
// DivisibleWriter is a state-changing interface for divisible NEP-11 contract.
// It's mostly useful not directly, but as a reusable layer for higher-level
// structures.
type DivisibleWriter struct {
BaseWriter
}
// Divisible is a full reader interface for divisible NEP-11 contract.
type Divisible struct {
DivisibleReader
BaseWriter
DivisibleWriter
}
// OwnerIterator is used for iterating over OwnerOf (for divisible NFTs) results.
@ -38,7 +45,7 @@ func NewDivisibleReader(invoker Invoker, hash util.Uint160) *DivisibleReader {
// NewDivisible creates an instance of Divisible for a contract
// with the given hash using the given actor.
func NewDivisible(actor Actor, hash util.Uint160) *Divisible {
return &Divisible{*NewDivisibleReader(actor, hash), BaseWriter{hash, actor}}
return &Divisible{*NewDivisibleReader(actor, hash), DivisibleWriter{BaseWriter{hash, actor}}}
}
// OwnerOf returns returns an iterator that allows to walk through all owners of
@ -72,7 +79,7 @@ func (t *DivisibleReader) BalanceOfD(owner util.Uint160, token []byte) (*big.Int
// method call using the given parameters and checks for this call result,
// failing the transaction if it's not true. The returned values are transaction
// hash, its ValidUntilBlock value and an error if any.
func (t *Divisible) TransferD(from util.Uint160, to util.Uint160, amount *big.Int, id []byte, data interface{}) (util.Uint256, uint32, error) {
func (t *DivisibleWriter) TransferD(from util.Uint160, to util.Uint160, amount *big.Int, id []byte, data interface{}) (util.Uint256, uint32, error) {
script, err := t.transferScript(from, to, amount, id, data)
if err != nil {
return util.Uint256{}, 0, err
@ -85,7 +92,7 @@ func (t *Divisible) TransferD(from util.Uint160, to util.Uint160, amount *big.In
// `transfer` method call using the given parameters and checks for this call
// result, failing the transaction if it's not true. This transaction is signed,
// but not sent to the network, instead it's returned to the caller.
func (t *Divisible) TransferDTransaction(from util.Uint160, to util.Uint160, amount *big.Int, id []byte, data interface{}) (*transaction.Transaction, error) {
func (t *DivisibleWriter) TransferDTransaction(from util.Uint160, to util.Uint160, amount *big.Int, id []byte, data interface{}) (*transaction.Transaction, error) {
script, err := t.transferScript(from, to, amount, id, data)
if err != nil {
return nil, err
@ -98,7 +105,7 @@ func (t *Divisible) TransferDTransaction(from util.Uint160, to util.Uint160, amo
// `transfer` method call using the given parameters and checks for this call
// result, failing the transaction if it's not true. This transaction is not
// signed and just returned to the caller.
func (t *Divisible) TransferDUnsigned(from util.Uint160, to util.Uint160, amount *big.Int, id []byte, data interface{}) (*transaction.Transaction, error) {
func (t *DivisibleWriter) TransferDUnsigned(from util.Uint160, to util.Uint160, amount *big.Int, id []byte, data interface{}) (*transaction.Transaction, error) {
script, err := t.transferScript(from, to, amount, id, data)
if err != nil {
return nil, err

View file

@ -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,60 @@ func (c *ContractReader) {{.Name}}({{range $index, $arg := .Arguments -}}
{{- end}}
}
{{- end -}}
{{- define "METHOD" -}}
{{- if eq .ReturnType "bool"}}func scriptFor{{.Name}}({{range $index, $arg := .Arguments -}}
{{- if ne $index 0}}, {{end}}
{{- .Name}} {{.Type}}
{{- end}}) ([]byte, error) {
return smartcontract.CreateCallWithAssertScript(Hash, "{{ .NameABI }}"{{- range $index, $arg := .Arguments -}}, {{.Name}}{{end}})
}
{{end}}// {{.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) {
{{if ne .ReturnType "bool"}}return c.actor.SendCall(Hash, "{{ .NameABI }}"
{{- range $index, $arg := .Arguments -}}, {{.Name}}{{end}}){{else}}script, err := scriptFor{{.Name}}({{- range $index, $arg := .Arguments -}}{{- if ne $index 0}}, {{end}}{{.Name}}{{end}})
if err != nil {
return util.Uint256{}, 0, err
}
return c.actor.SendRun(script){{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) {
{{if ne .ReturnType "bool"}}return c.actor.MakeCall(Hash, "{{ .NameABI }}"
{{- range $index, $arg := .Arguments -}}, {{.Name}}{{end}}){{else}}script, err := scriptFor{{.Name}}({{- range $index, $arg := .Arguments -}}{{- if ne $index 0}}, {{end}}{{.Name}}{{end}})
if err != nil {
return nil, err
}
return c.actor.MakeRun(script){{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) {
{{if ne .ReturnType "bool"}}return c.actor.MakeUnsignedCall(Hash, "{{ .NameABI }}", nil
{{- range $index, $arg := .Arguments -}}, {{.Name}}{{end}}){{else}}script, err := scriptFor{{.Name}}({{- range $index, $arg := .Arguments -}}{{- if ne $index 0}}, {{end}}{{.Name}}{{end}})
if err != nil {
return nil, err
}
return c.actor.MakeUnsignedRun(script, nil){{end}}
}
{{- end -}}
// Package {{.PackageName}} contains RPC wrappers for {{.ContractName}} contract.
package {{.PackageName}}
@ -36,16 +90,37 @@ import (
// Hash contains contract hash.
var Hash = {{ .Hash }}
// Invoker is used by ContractReader to call various safe methods.
{{if .HasReader}}// Invoker is used by ContractReader to call various safe methods.
type Invoker interface {
{{if or .IsNep11D .IsNep11ND}}nep11.Invoker
{{end -}}
{{if .IsNep17}}nep17.Invoker
{{end -}}
Call(contract util.Uint160, operation string, params ...interface{}) (*result.Invoke, error)
{{if or .IsNep11D .IsNep11ND}} nep11.Invoker
{{else if .IsNep17}} nep17.Invoker
{{else if len .SafeMethods}} Call(contract util.Uint160, operation string, params ...interface{}) (*result.Invoke, error)
{{end -}}
}
// ContractReader implements safe contract methods.
{{end -}}
{{if .HasWriter}}// Actor is used by Contract to call state-changing methods.
type Actor interface {
{{- if .HasReader}}
Invoker
{{end}}
{{- if or .IsNep11D .IsNep11ND}}
nep11.Actor
{{else 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 -}}
{{if .HasReader}}// ContractReader implements safe contract methods.
type ContractReader struct {
{{if .IsNep11D}}nep11.DivisibleReader
{{end -}}
@ -56,7 +131,22 @@ type ContractReader struct {
invoker Invoker
}
// NewReader creates an instance of ContractReader using Hash and the given Invoker.
{{end -}}
{{if .HasWriter}}// Contract implements all contract methods.
type Contract struct {
{{if .HasReader}}ContractReader
{{end -}}
{{if .IsNep11D}}nep11.DivisibleWriter
{{end -}}
{{if .IsNep11ND}}nep11.BaseWriter
{{end -}}
{{if .IsNep17}}nep17.TokenWriter
{{end -}}
actor Actor
}
{{end -}}
{{if .HasReader}}// NewReader creates an instance of ContractReader using Hash and the given Invoker.
func NewReader(invoker Invoker) *ContractReader {
return &ContractReader{
{{- if .IsNep11D}}*nep11.NewDivisibleReader(invoker, Hash), {{end}}
@ -65,7 +155,32 @@ func NewReader(invoker Invoker) *ContractReader {
invoker}
}
{{range $m := .Methods}}
{{end -}}
{{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{
{{- if .HasReader}}ContractReader{
{{- if .IsNep11D}}nep11dt.DivisibleReader, {{end -}}
{{- if .IsNep11ND}}nep11ndt.NonDivisibleReader, {{end -}}
{{- if .IsNep17}}nep17t.TokenReader, {{end -}}
actor}, {{end -}}
{{- 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 +189,15 @@ var srcTemplate = template.Must(template.New("generate").Parse(srcTmpl))
type (
ContractTmpl struct {
binding.ContractTmpl
SafeMethods []binding.MethodTmpl
IsNep11D bool
IsNep11ND bool
IsNep17 bool
HasReader bool
HasWriter bool
}
)
@ -87,19 +208,58 @@ func NewConfig() binding.Config {
// Generate writes Go file containing smartcontract bindings to the `cfg.Output`.
func Generate(cfg binding.Config) error {
// Avoid changing *cfg.Manifest.
mfst := *cfg.Manifest
mfst.ABI.Methods = make([]manifest.Method, len(mfst.ABI.Methods))
copy(mfst.ABI.Methods, cfg.Manifest.ABI.Methods)
cfg.Manifest = &mfst
var imports = make(map[string]struct{})
var ctr ContractTmpl
// Strip standard methods from NEP-XX packages.
for _, std := range cfg.Manifest.SupportedStandards {
if std == manifest.NEP11StandardName {
imports["github.com/nspcc-dev/neo-go/pkg/rpcclient/nep11"] = struct{}{}
if standard.ComplyABI(cfg.Manifest, standard.Nep11Divisible) == nil {
mfst.ABI.Methods = dropStdMethods(mfst.ABI.Methods, standard.Nep11Divisible)
ctr.IsNep11D = true
} else if standard.ComplyABI(cfg.Manifest, standard.Nep11NonDivisible) == nil {
mfst.ABI.Methods = dropStdMethods(mfst.ABI.Methods, standard.Nep11NonDivisible)
ctr.IsNep11ND = true
}
break // Can't be NEP-17 at the same time.
}
if std == manifest.NEP17StandardName && standard.ComplyABI(cfg.Manifest, standard.Nep17) == nil {
mfst.ABI.Methods = dropStdMethods(mfst.ABI.Methods, standard.Nep17)
imports["github.com/nspcc-dev/neo-go/pkg/rpcclient/nep17"] = struct{}{}
ctr.IsNep17 = true
break // Can't be NEP-11 at the same time.
}
}
// OnNepXXPayment handlers normally can't be called directly.
if standard.ComplyABI(cfg.Manifest, standard.Nep11Payable) == nil {
mfst.ABI.Methods = dropStdMethods(mfst.ABI.Methods, standard.Nep11Payable)
}
if standard.ComplyABI(cfg.Manifest, standard.Nep17Payable) == nil {
mfst.ABI.Methods = dropStdMethods(mfst.ABI.Methods, standard.Nep17Payable)
}
bctr, err := binding.TemplateFromManifest(cfg, scTypeToGo)
if err != nil {
return err
}
ctr := scTemplateToRPC(cfg, bctr)
ctr.ContractTmpl = bctr
ctr = scTemplateToRPC(cfg, ctr, imports)
return srcTemplate.Execute(cfg.Output, ctr)
}
func dropManifestMethods(meths []binding.MethodTmpl, manifested []manifest.Method) []binding.MethodTmpl {
func dropManifestMethods(meths []manifest.Method, manifested []manifest.Method) []manifest.Method {
for _, m := range manifested {
for i := 0; i < len(meths); i++ {
if meths[i].NameABI == m.Name && len(meths[i].Arguments) == len(m.Parameters) {
if meths[i].Name == m.Name && len(meths[i].Parameters) == len(m.Parameters) {
meths = append(meths[:i], meths[i+1:]...)
i--
}
@ -108,7 +268,7 @@ func dropManifestMethods(meths []binding.MethodTmpl, manifested []manifest.Metho
return meths
}
func dropStdMethods(meths []binding.MethodTmpl, std *standard.Standard) []binding.MethodTmpl {
func dropStdMethods(meths []manifest.Method, std *standard.Standard) []manifest.Method {
meths = dropManifestMethods(meths, std.Manifest.ABI.Methods)
if std.Optional != nil {
meths = dropManifestMethods(meths, std.Optional)
@ -152,71 +312,70 @@ func scTypeToGo(name string, typ smartcontract.ParamType, overrides map[string]b
}
}
func scTemplateToRPC(cfg binding.Config, bctr binding.ContractTmpl) ContractTmpl {
var imports = make(map[string]struct{})
var ctr = ContractTmpl{ContractTmpl: bctr}
func scTemplateToRPC(cfg binding.Config, ctr ContractTmpl, imports map[string]struct{}) ContractTmpl {
for i := range ctr.Imports {
imports[ctr.Imports[i]] = struct{}{}
}
ctr.Hash = fmt.Sprintf("%#v", cfg.Hash)
for _, std := range cfg.Manifest.SupportedStandards {
if std == manifest.NEP11StandardName {
imports["github.com/nspcc-dev/neo-go/pkg/rpcclient/nep11"] = struct{}{}
if standard.ComplyABI(cfg.Manifest, standard.Nep11Divisible) == nil {
ctr.Methods = dropStdMethods(ctr.Methods, standard.Nep11Divisible)
ctr.IsNep11D = true
} else if standard.ComplyABI(cfg.Manifest, standard.Nep11NonDivisible) == nil {
ctr.Methods = dropStdMethods(ctr.Methods, standard.Nep11NonDivisible)
ctr.IsNep11ND = true
}
break // Can't be NEP-17 at the same time.
}
if std == manifest.NEP17StandardName && standard.ComplyABI(cfg.Manifest, standard.Nep17) == nil {
ctr.Methods = dropStdMethods(ctr.Methods, standard.Nep17)
imports["github.com/nspcc-dev/neo-go/pkg/rpcclient/nep17"] = struct{}{}
ctr.IsNep17 = true
break // Can't be NEP-11 at the same time.
}
}
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)
if ctr.Methods[i].ReturnType == "bool" {
imports["github.com/nspcc-dev/neo-go/pkg/smartcontract"] = struct{}{}
}
}
}
// 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{}{}
imports["github.com/nspcc-dev/neo-go/pkg/util"] = struct{}{}
if len(ctr.SafeMethods) > 0 {
imports["github.com/nspcc-dev/neo-go/pkg/rpcclient/unwrap"] = struct{}{}
if !(ctr.IsNep17 || ctr.IsNep11D || ctr.IsNep11ND) {
imports["github.com/nspcc-dev/neo-go/pkg/neorpc/result"] = 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
}
if len(ctr.SafeMethods) > 0 || ctr.IsNep17 || ctr.IsNep11D || ctr.IsNep11ND {
ctr.HasReader = true
}
ctr.Imports = ctr.Imports[:0]
for imp := range imports {
ctr.Imports = append(ctr.Imports, imp)