mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-11-25 03:47:18 +00:00
manifest: support NEP-24
Close #3451 Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
This commit is contained in:
parent
54e3708566
commit
b2bd8e4a0a
21 changed files with 1715 additions and 36 deletions
|
@ -476,7 +476,7 @@ func TestAssistedRPCBindings(t *testing.T) {
|
|||
tmpDir := t.TempDir()
|
||||
e := testcli.NewExecutor(t, false)
|
||||
|
||||
var checkBinding = func(source string, hasDefinedHash bool, guessEventTypes bool, suffix ...string) {
|
||||
var checkBinding = func(source, configFile, expectedFile string, hasDefinedHash, guessEventTypes bool, suffix ...string) {
|
||||
testName := source
|
||||
if len(suffix) != 0 {
|
||||
testName += suffix[0]
|
||||
|
@ -484,14 +484,21 @@ func TestAssistedRPCBindings(t *testing.T) {
|
|||
testName += fmt.Sprintf(", predefined hash: %t", hasDefinedHash)
|
||||
t.Run(testName, func(t *testing.T) {
|
||||
outFile := filepath.Join(tmpDir, "out.go")
|
||||
configFile := filepath.Join(source, "config.yml")
|
||||
expectedFile := filepath.Join(source, "rpcbindings.out")
|
||||
if configFile == "" {
|
||||
if len(suffix) != 0 {
|
||||
configFile = filepath.Join(source, "config"+suffix[0]+".yml")
|
||||
} else {
|
||||
configFile = filepath.Join(source, "config.yml")
|
||||
}
|
||||
}
|
||||
if expectedFile == "" {
|
||||
expectedFile = filepath.Join(source, "rpcbindings.out")
|
||||
if len(suffix) != 0 {
|
||||
expectedFile = filepath.Join(source, "rpcbindings"+suffix[0]+".out")
|
||||
} else if !hasDefinedHash {
|
||||
expectedFile = filepath.Join(source, "rpcbindings_dynamic_hash.out")
|
||||
}
|
||||
}
|
||||
manifestF := filepath.Join(tmpDir, "manifest.json")
|
||||
bindingF := filepath.Join(tmpDir, "binding.yml")
|
||||
nefF := filepath.Join(tmpDir, "out.nef")
|
||||
|
@ -532,12 +539,18 @@ func TestAssistedRPCBindings(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, hasDefinedHash := range []bool{true, false} {
|
||||
checkBinding(filepath.Join("testdata", "rpcbindings", "types"), hasDefinedHash, false)
|
||||
checkBinding(filepath.Join("testdata", "rpcbindings", "structs"), hasDefinedHash, false)
|
||||
checkBinding(filepath.Join("testdata", "rpcbindings", "types"), "", "", hasDefinedHash, false)
|
||||
checkBinding(filepath.Join("testdata", "rpcbindings", "structs"), "", "", hasDefinedHash, false)
|
||||
checkBinding(filepath.Join("testdata", "rpcbindings", "royalty"), "", "", hasDefinedHash, false)
|
||||
}
|
||||
checkBinding(filepath.Join("testdata", "rpcbindings", "notifications"), true, false)
|
||||
checkBinding(filepath.Join("testdata", "rpcbindings", "notifications"), true, false, "_extended")
|
||||
checkBinding(filepath.Join("testdata", "rpcbindings", "notifications"), true, true, "_guessed")
|
||||
checkBinding(filepath.Join("testdata", "rpcbindings", "notifications"), "", "", true, false)
|
||||
checkBinding(filepath.Join("testdata", "rpcbindings", "notifications"), "", "", true, false, "_extended")
|
||||
checkBinding(filepath.Join("testdata", "rpcbindings", "notifications"), "", "", true, true, "_guessed")
|
||||
|
||||
checkBinding(filepath.Join("..", "..", "examples", "nft-d"), filepath.Join("..", "..", "examples", "nft-d", "nft.yml"), filepath.Join("testdata", "rpcbindings", "nft-d", "rpcbindings_dynamic_hash.out"), false, false)
|
||||
checkBinding(filepath.Join("..", "..", "examples", "nft-d"), filepath.Join("..", "..", "examples", "nft-d", "nft.yml"), filepath.Join("testdata", "rpcbindings", "nft-d", "rpcbindings.out"), true, true)
|
||||
checkBinding(filepath.Join("..", "..", "examples", "nft-nd"), filepath.Join("..", "..", "examples", "nft-nd", "nft.yml"), filepath.Join("testdata", "rpcbindings", "nft-nd", "rpcbindings_dynamic_hash.out"), false, false)
|
||||
checkBinding(filepath.Join("..", "..", "examples", "nft-nd"), filepath.Join("..", "..", "examples", "nft-nd", "nft.yml"), filepath.Join("testdata", "rpcbindings", "nft-nd", "rpcbindings.out"), true, true)
|
||||
|
||||
require.False(t, rewriteExpectedOutputs)
|
||||
}
|
||||
|
|
146
cli/smartcontract/testdata/rpcbindings/nft-d/rpcbindings.out
vendored
Normal file
146
cli/smartcontract/testdata/rpcbindings/nft-d/rpcbindings.out
vendored
Normal file
|
@ -0,0 +1,146 @@
|
|||
// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
|
||||
|
||||
// Package nft contains RPC wrappers for NeoFS Object NFT contract.
|
||||
package nft
|
||||
|
||||
import (
|
||||
"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/nep24"
|
||||
"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}
|
||||
|
||||
// Invoker is used by ContractReader to call various safe methods.
|
||||
type Invoker interface {
|
||||
nep11.Invoker
|
||||
}
|
||||
|
||||
// Actor is used by Contract to call state-changing methods.
|
||||
type Actor interface {
|
||||
Invoker
|
||||
|
||||
nep11.Actor
|
||||
|
||||
MakeCall(contract util.Uint160, method string, params ...any) (*transaction.Transaction, error)
|
||||
MakeRun(script []byte) (*transaction.Transaction, error)
|
||||
MakeUnsignedCall(contract util.Uint160, method string, attrs []transaction.Attribute, params ...any) (*transaction.Transaction, error)
|
||||
MakeUnsignedRun(script []byte, attrs []transaction.Attribute) (*transaction.Transaction, error)
|
||||
SendCall(contract util.Uint160, method string, params ...any) (util.Uint256, uint32, error)
|
||||
SendRun(script []byte) (util.Uint256, uint32, error)
|
||||
}
|
||||
|
||||
// ContractReader implements safe contract methods.
|
||||
type ContractReader struct {
|
||||
nep11.DivisibleReader
|
||||
nep24.RoyaltyReader
|
||||
invoker Invoker
|
||||
hash util.Uint160
|
||||
}
|
||||
|
||||
// Contract implements all contract methods.
|
||||
type Contract struct {
|
||||
ContractReader
|
||||
nep11.DivisibleWriter
|
||||
actor Actor
|
||||
hash util.Uint160
|
||||
}
|
||||
|
||||
// NewReader creates an instance of ContractReader using Hash and the given Invoker.
|
||||
func NewReader(invoker Invoker) *ContractReader {
|
||||
var hash = Hash
|
||||
return &ContractReader{*nep11.NewDivisibleReader(invoker, hash), *nep24.NewRoyaltyReader(invoker, hash), invoker, hash}
|
||||
}
|
||||
|
||||
// New creates an instance of Contract using Hash and the given Actor.
|
||||
func New(actor Actor) *Contract {
|
||||
var hash = Hash
|
||||
var nep11dt = nep11.NewDivisible(actor, hash)
|
||||
var nep24t = nep24.NewRoyaltyReader(actor, hash)
|
||||
return &Contract{ContractReader{nep11dt.DivisibleReader, *nep24t, actor, hash}, nep11dt.DivisibleWriter, actor, hash}
|
||||
}
|
||||
|
||||
// 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(c.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(c.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(c.hash, "destroy", nil)
|
||||
}
|
||||
|
||||
// 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(c.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(c.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(c.hash, "update", nil, nef, manifest)
|
||||
}
|
||||
|
||||
func (c *Contract) scriptForVerify() ([]byte, error) {
|
||||
return smartcontract.CreateCallWithAssertScript(c.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 := c.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 := c.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 := c.scriptForVerify()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.actor.MakeUnsignedRun(script, nil)
|
||||
}
|
141
cli/smartcontract/testdata/rpcbindings/nft-d/rpcbindings_dynamic_hash.out
vendored
Normal file
141
cli/smartcontract/testdata/rpcbindings/nft-d/rpcbindings_dynamic_hash.out
vendored
Normal file
|
@ -0,0 +1,141 @@
|
|||
// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
|
||||
|
||||
// Package nft contains RPC wrappers for NeoFS Object NFT contract.
|
||||
package nft
|
||||
|
||||
import (
|
||||
"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/nep24"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
)
|
||||
|
||||
// Invoker is used by ContractReader to call various safe methods.
|
||||
type Invoker interface {
|
||||
nep11.Invoker
|
||||
}
|
||||
|
||||
// Actor is used by Contract to call state-changing methods.
|
||||
type Actor interface {
|
||||
Invoker
|
||||
|
||||
nep11.Actor
|
||||
|
||||
MakeCall(contract util.Uint160, method string, params ...any) (*transaction.Transaction, error)
|
||||
MakeRun(script []byte) (*transaction.Transaction, error)
|
||||
MakeUnsignedCall(contract util.Uint160, method string, attrs []transaction.Attribute, params ...any) (*transaction.Transaction, error)
|
||||
MakeUnsignedRun(script []byte, attrs []transaction.Attribute) (*transaction.Transaction, error)
|
||||
SendCall(contract util.Uint160, method string, params ...any) (util.Uint256, uint32, error)
|
||||
SendRun(script []byte) (util.Uint256, uint32, error)
|
||||
}
|
||||
|
||||
// ContractReader implements safe contract methods.
|
||||
type ContractReader struct {
|
||||
nep11.DivisibleReader
|
||||
nep24.RoyaltyReader
|
||||
invoker Invoker
|
||||
hash util.Uint160
|
||||
}
|
||||
|
||||
// Contract implements all contract methods.
|
||||
type Contract struct {
|
||||
ContractReader
|
||||
nep11.DivisibleWriter
|
||||
actor Actor
|
||||
hash util.Uint160
|
||||
}
|
||||
|
||||
// NewReader creates an instance of ContractReader using provided contract hash and the given Invoker.
|
||||
func NewReader(invoker Invoker, hash util.Uint160) *ContractReader {
|
||||
return &ContractReader{*nep11.NewDivisibleReader(invoker, hash), *nep24.NewRoyaltyReader(invoker, hash), invoker, hash}
|
||||
}
|
||||
|
||||
// New creates an instance of Contract using provided contract hash and the given Actor.
|
||||
func New(actor Actor, hash util.Uint160) *Contract {
|
||||
var nep11dt = nep11.NewDivisible(actor, hash)
|
||||
var nep24t = nep24.NewRoyaltyReader(actor, hash)
|
||||
return &Contract{ContractReader{nep11dt.DivisibleReader, *nep24t, actor, hash}, nep11dt.DivisibleWriter, actor, hash}
|
||||
}
|
||||
|
||||
// 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(c.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(c.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(c.hash, "destroy", nil)
|
||||
}
|
||||
|
||||
// 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(c.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(c.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(c.hash, "update", nil, nef, manifest)
|
||||
}
|
||||
|
||||
func (c *Contract) scriptForVerify() ([]byte, error) {
|
||||
return smartcontract.CreateCallWithAssertScript(c.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 := c.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 := c.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 := c.scriptForVerify()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.actor.MakeUnsignedRun(script, nil)
|
||||
}
|
249
cli/smartcontract/testdata/rpcbindings/nft-nd/rpcbindings.out
vendored
Normal file
249
cli/smartcontract/testdata/rpcbindings/nft-nd/rpcbindings.out
vendored
Normal file
|
@ -0,0 +1,249 @@
|
|||
// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
|
||||
|
||||
// Package nft contains RPC wrappers for HASHY NFT contract.
|
||||
package nft
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"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/nep24"
|
||||
"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"
|
||||
)
|
||||
|
||||
// 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}
|
||||
|
||||
// NftRoyaltyRecipientShare is a contract-specific nft.RoyaltyRecipientShare type used by its methods.
|
||||
type NftRoyaltyRecipientShare struct {
|
||||
Address util.Uint160
|
||||
Share *big.Int
|
||||
}
|
||||
|
||||
// Invoker is used by ContractReader to call various safe methods.
|
||||
type Invoker interface {
|
||||
nep11.Invoker
|
||||
}
|
||||
|
||||
// Actor is used by Contract to call state-changing methods.
|
||||
type Actor interface {
|
||||
Invoker
|
||||
|
||||
nep11.Actor
|
||||
|
||||
MakeCall(contract util.Uint160, method string, params ...any) (*transaction.Transaction, error)
|
||||
MakeRun(script []byte) (*transaction.Transaction, error)
|
||||
MakeUnsignedCall(contract util.Uint160, method string, attrs []transaction.Attribute, params ...any) (*transaction.Transaction, error)
|
||||
MakeUnsignedRun(script []byte, attrs []transaction.Attribute) (*transaction.Transaction, error)
|
||||
SendCall(contract util.Uint160, method string, params ...any) (util.Uint256, uint32, error)
|
||||
SendRun(script []byte) (util.Uint256, uint32, error)
|
||||
}
|
||||
|
||||
// ContractReader implements safe contract methods.
|
||||
type ContractReader struct {
|
||||
nep11.NonDivisibleReader
|
||||
nep24.RoyaltyReader
|
||||
invoker Invoker
|
||||
hash util.Uint160
|
||||
}
|
||||
|
||||
// Contract implements all contract methods.
|
||||
type Contract struct {
|
||||
ContractReader
|
||||
nep11.BaseWriter
|
||||
actor Actor
|
||||
hash util.Uint160
|
||||
}
|
||||
|
||||
// NewReader creates an instance of ContractReader using Hash and the given Invoker.
|
||||
func NewReader(invoker Invoker) *ContractReader {
|
||||
var hash = Hash
|
||||
return &ContractReader{*nep11.NewNonDivisibleReader(invoker, hash), *nep24.NewRoyaltyReader(invoker, hash), invoker, hash}
|
||||
}
|
||||
|
||||
// New creates an instance of Contract using Hash and the given Actor.
|
||||
func New(actor Actor) *Contract {
|
||||
var hash = Hash
|
||||
var nep11ndt = nep11.NewNonDivisible(actor, hash)
|
||||
var nep24t = nep24.NewRoyaltyReader(actor, hash)
|
||||
return &Contract{ContractReader{nep11ndt.NonDivisibleReader, *nep24t, actor, hash}, nep11ndt.BaseWriter, actor, hash}
|
||||
}
|
||||
|
||||
// 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(c.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(c.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(c.hash, "destroy", nil)
|
||||
}
|
||||
|
||||
func (c *Contract) scriptForSetRoyaltyInfo(ctx any, tokenID []byte, recipients []*NftRoyaltyRecipientShare) ([]byte, error) {
|
||||
return smartcontract.CreateCallWithAssertScript(c.hash, "setRoyaltyInfo", ctx, tokenID, recipients)
|
||||
}
|
||||
|
||||
// SetRoyaltyInfo creates a transaction invoking `setRoyaltyInfo` 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) SetRoyaltyInfo(ctx any, tokenID []byte, recipients []*NftRoyaltyRecipientShare) (util.Uint256, uint32, error) {
|
||||
script, err := c.scriptForSetRoyaltyInfo(ctx, tokenID, recipients)
|
||||
if err != nil {
|
||||
return util.Uint256{}, 0, err
|
||||
}
|
||||
return c.actor.SendRun(script)
|
||||
}
|
||||
|
||||
// SetRoyaltyInfoTransaction creates a transaction invoking `setRoyaltyInfo` method of the contract.
|
||||
// This transaction is signed, but not sent to the network, instead it's
|
||||
// returned to the caller.
|
||||
func (c *Contract) SetRoyaltyInfoTransaction(ctx any, tokenID []byte, recipients []*NftRoyaltyRecipientShare) (*transaction.Transaction, error) {
|
||||
script, err := c.scriptForSetRoyaltyInfo(ctx, tokenID, recipients)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.actor.MakeRun(script)
|
||||
}
|
||||
|
||||
// SetRoyaltyInfoUnsigned creates a transaction invoking `setRoyaltyInfo` 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) SetRoyaltyInfoUnsigned(ctx any, tokenID []byte, recipients []*NftRoyaltyRecipientShare) (*transaction.Transaction, error) {
|
||||
script, err := c.scriptForSetRoyaltyInfo(ctx, tokenID, recipients)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.actor.MakeUnsignedRun(script, nil)
|
||||
}
|
||||
|
||||
// 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(c.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(c.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(c.hash, "update", nil, nef, manifest)
|
||||
}
|
||||
|
||||
func (c *Contract) scriptForVerify() ([]byte, error) {
|
||||
return smartcontract.CreateCallWithAssertScript(c.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 := c.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 := c.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 := c.scriptForVerify()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.actor.MakeUnsignedRun(script, nil)
|
||||
}
|
||||
|
||||
// itemToNftRoyaltyRecipientShare converts stack item into *NftRoyaltyRecipientShare.
|
||||
// NULL item is returned as nil pointer without error.
|
||||
func itemToNftRoyaltyRecipientShare(item stackitem.Item, err error) (*NftRoyaltyRecipientShare, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, null := item.(stackitem.Null)
|
||||
if null {
|
||||
return nil, nil
|
||||
}
|
||||
var res = new(NftRoyaltyRecipientShare)
|
||||
err = res.FromStackItem(item)
|
||||
return res, err
|
||||
}
|
||||
|
||||
// FromStackItem retrieves fields of NftRoyaltyRecipientShare from the given
|
||||
// [stackitem.Item] or returns an error if it's not possible to do to so.
|
||||
func (res *NftRoyaltyRecipientShare) FromStackItem(item stackitem.Item) error {
|
||||
arr, ok := item.Value().([]stackitem.Item)
|
||||
if !ok {
|
||||
return errors.New("not an array")
|
||||
}
|
||||
if len(arr) != 2 {
|
||||
return errors.New("wrong number of structure elements")
|
||||
}
|
||||
|
||||
var (
|
||||
index = -1
|
||||
err error
|
||||
)
|
||||
index++
|
||||
res.Address, err = func(item stackitem.Item) (util.Uint160, error) {
|
||||
b, err := item.TryBytes()
|
||||
if err != nil {
|
||||
return util.Uint160{}, err
|
||||
}
|
||||
u, err := util.Uint160DecodeBytesBE(b)
|
||||
if err != nil {
|
||||
return util.Uint160{}, err
|
||||
}
|
||||
return u, nil
|
||||
}(arr[index])
|
||||
if err != nil {
|
||||
return fmt.Errorf("field Address: %w", err)
|
||||
}
|
||||
|
||||
index++
|
||||
res.Share, err = arr[index].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("field Share: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
244
cli/smartcontract/testdata/rpcbindings/nft-nd/rpcbindings_dynamic_hash.out
vendored
Normal file
244
cli/smartcontract/testdata/rpcbindings/nft-nd/rpcbindings_dynamic_hash.out
vendored
Normal file
|
@ -0,0 +1,244 @@
|
|||
// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
|
||||
|
||||
// Package nft contains RPC wrappers for HASHY NFT contract.
|
||||
package nft
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"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/nep24"
|
||||
"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"
|
||||
)
|
||||
|
||||
// NftRoyaltyRecipientShare is a contract-specific nft.RoyaltyRecipientShare type used by its methods.
|
||||
type NftRoyaltyRecipientShare struct {
|
||||
Address util.Uint160
|
||||
Share *big.Int
|
||||
}
|
||||
|
||||
// Invoker is used by ContractReader to call various safe methods.
|
||||
type Invoker interface {
|
||||
nep11.Invoker
|
||||
}
|
||||
|
||||
// Actor is used by Contract to call state-changing methods.
|
||||
type Actor interface {
|
||||
Invoker
|
||||
|
||||
nep11.Actor
|
||||
|
||||
MakeCall(contract util.Uint160, method string, params ...any) (*transaction.Transaction, error)
|
||||
MakeRun(script []byte) (*transaction.Transaction, error)
|
||||
MakeUnsignedCall(contract util.Uint160, method string, attrs []transaction.Attribute, params ...any) (*transaction.Transaction, error)
|
||||
MakeUnsignedRun(script []byte, attrs []transaction.Attribute) (*transaction.Transaction, error)
|
||||
SendCall(contract util.Uint160, method string, params ...any) (util.Uint256, uint32, error)
|
||||
SendRun(script []byte) (util.Uint256, uint32, error)
|
||||
}
|
||||
|
||||
// ContractReader implements safe contract methods.
|
||||
type ContractReader struct {
|
||||
nep11.NonDivisibleReader
|
||||
nep24.RoyaltyReader
|
||||
invoker Invoker
|
||||
hash util.Uint160
|
||||
}
|
||||
|
||||
// Contract implements all contract methods.
|
||||
type Contract struct {
|
||||
ContractReader
|
||||
nep11.BaseWriter
|
||||
actor Actor
|
||||
hash util.Uint160
|
||||
}
|
||||
|
||||
// NewReader creates an instance of ContractReader using provided contract hash and the given Invoker.
|
||||
func NewReader(invoker Invoker, hash util.Uint160) *ContractReader {
|
||||
return &ContractReader{*nep11.NewNonDivisibleReader(invoker, hash), *nep24.NewRoyaltyReader(invoker, hash), invoker, hash}
|
||||
}
|
||||
|
||||
// New creates an instance of Contract using provided contract hash and the given Actor.
|
||||
func New(actor Actor, hash util.Uint160) *Contract {
|
||||
var nep11ndt = nep11.NewNonDivisible(actor, hash)
|
||||
var nep24t = nep24.NewRoyaltyReader(actor, hash)
|
||||
return &Contract{ContractReader{nep11ndt.NonDivisibleReader, *nep24t, actor, hash}, nep11ndt.BaseWriter, actor, hash}
|
||||
}
|
||||
|
||||
// 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(c.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(c.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(c.hash, "destroy", nil)
|
||||
}
|
||||
|
||||
func (c *Contract) scriptForSetRoyaltyInfo(ctx any, tokenID []byte, recipients []*NftRoyaltyRecipientShare) ([]byte, error) {
|
||||
return smartcontract.CreateCallWithAssertScript(c.hash, "setRoyaltyInfo", ctx, tokenID, recipients)
|
||||
}
|
||||
|
||||
// SetRoyaltyInfo creates a transaction invoking `setRoyaltyInfo` 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) SetRoyaltyInfo(ctx any, tokenID []byte, recipients []*NftRoyaltyRecipientShare) (util.Uint256, uint32, error) {
|
||||
script, err := c.scriptForSetRoyaltyInfo(ctx, tokenID, recipients)
|
||||
if err != nil {
|
||||
return util.Uint256{}, 0, err
|
||||
}
|
||||
return c.actor.SendRun(script)
|
||||
}
|
||||
|
||||
// SetRoyaltyInfoTransaction creates a transaction invoking `setRoyaltyInfo` method of the contract.
|
||||
// This transaction is signed, but not sent to the network, instead it's
|
||||
// returned to the caller.
|
||||
func (c *Contract) SetRoyaltyInfoTransaction(ctx any, tokenID []byte, recipients []*NftRoyaltyRecipientShare) (*transaction.Transaction, error) {
|
||||
script, err := c.scriptForSetRoyaltyInfo(ctx, tokenID, recipients)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.actor.MakeRun(script)
|
||||
}
|
||||
|
||||
// SetRoyaltyInfoUnsigned creates a transaction invoking `setRoyaltyInfo` 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) SetRoyaltyInfoUnsigned(ctx any, tokenID []byte, recipients []*NftRoyaltyRecipientShare) (*transaction.Transaction, error) {
|
||||
script, err := c.scriptForSetRoyaltyInfo(ctx, tokenID, recipients)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.actor.MakeUnsignedRun(script, nil)
|
||||
}
|
||||
|
||||
// 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(c.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(c.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(c.hash, "update", nil, nef, manifest)
|
||||
}
|
||||
|
||||
func (c *Contract) scriptForVerify() ([]byte, error) {
|
||||
return smartcontract.CreateCallWithAssertScript(c.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 := c.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 := c.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 := c.scriptForVerify()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.actor.MakeUnsignedRun(script, nil)
|
||||
}
|
||||
|
||||
// itemToNftRoyaltyRecipientShare converts stack item into *NftRoyaltyRecipientShare.
|
||||
// NULL item is returned as nil pointer without error.
|
||||
func itemToNftRoyaltyRecipientShare(item stackitem.Item, err error) (*NftRoyaltyRecipientShare, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, null := item.(stackitem.Null)
|
||||
if null {
|
||||
return nil, nil
|
||||
}
|
||||
var res = new(NftRoyaltyRecipientShare)
|
||||
err = res.FromStackItem(item)
|
||||
return res, err
|
||||
}
|
||||
|
||||
// FromStackItem retrieves fields of NftRoyaltyRecipientShare from the given
|
||||
// [stackitem.Item] or returns an error if it's not possible to do to so.
|
||||
func (res *NftRoyaltyRecipientShare) FromStackItem(item stackitem.Item) error {
|
||||
arr, ok := item.Value().([]stackitem.Item)
|
||||
if !ok {
|
||||
return errors.New("not an array")
|
||||
}
|
||||
if len(arr) != 2 {
|
||||
return errors.New("wrong number of structure elements")
|
||||
}
|
||||
|
||||
var (
|
||||
index = -1
|
||||
err error
|
||||
)
|
||||
index++
|
||||
res.Address, err = func(item stackitem.Item) (util.Uint160, error) {
|
||||
b, err := item.TryBytes()
|
||||
if err != nil {
|
||||
return util.Uint160{}, err
|
||||
}
|
||||
u, err := util.Uint160DecodeBytesBE(b)
|
||||
if err != nil {
|
||||
return util.Uint160{}, err
|
||||
}
|
||||
return u, nil
|
||||
}(arr[index])
|
||||
if err != nil {
|
||||
return fmt.Errorf("field Address: %w", err)
|
||||
}
|
||||
|
||||
index++
|
||||
res.Share, err = arr[index].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("field Share: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
16
cli/smartcontract/testdata/rpcbindings/royalty/config.yml
vendored
Normal file
16
cli/smartcontract/testdata/rpcbindings/royalty/config.yml
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
name: Test royalty
|
||||
sourceurl: https://github.com/nspcc-dev/neo-go/
|
||||
supportedstandards: ["NEP-24-Payable"]
|
||||
events:
|
||||
- name: RoyaltiesTransferred
|
||||
parameters:
|
||||
- name: royaltyToken
|
||||
type: Hash160
|
||||
- name: royaltyRecipient
|
||||
type: Hash160
|
||||
- name: buyer
|
||||
type: Hash160
|
||||
- name: tokenId
|
||||
type: ByteArray
|
||||
- name: amount
|
||||
type: Integer
|
13
cli/smartcontract/testdata/rpcbindings/royalty/royalty.go
vendored
Normal file
13
cli/smartcontract/testdata/rpcbindings/royalty/royalty.go
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
package royalty
|
||||
|
||||
import (
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/native/std"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/runtime"
|
||||
)
|
||||
|
||||
// RoyaltiesTransferred notifies about royalty payment. This method is called by marketplace
|
||||
// contract when royalties are transferred.
|
||||
func RoyaltiesTransferred(royaltyToken, royaltyRecipient, buyer interop.Hash160, tokenId []byte, amount int) {
|
||||
runtime.Notify("RoyaltiesTransferred", royaltyToken, royaltyRecipient, buyer, std.Deserialize(tokenId), amount)
|
||||
}
|
57
cli/smartcontract/testdata/rpcbindings/royalty/rpcbindings.out
vendored
Normal file
57
cli/smartcontract/testdata/rpcbindings/royalty/rpcbindings.out
vendored
Normal file
|
@ -0,0 +1,57 @@
|
|||
// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
|
||||
|
||||
// Package royalty contains RPC wrappers for Test royalty contract.
|
||||
package royalty
|
||||
|
||||
import (
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
// 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 ...any) (*transaction.Transaction, error)
|
||||
MakeRun(script []byte) (*transaction.Transaction, error)
|
||||
MakeUnsignedCall(contract util.Uint160, method string, attrs []transaction.Attribute, params ...any) (*transaction.Transaction, error)
|
||||
MakeUnsignedRun(script []byte, attrs []transaction.Attribute) (*transaction.Transaction, error)
|
||||
SendCall(contract util.Uint160, method string, params ...any) (util.Uint256, uint32, error)
|
||||
SendRun(script []byte) (util.Uint256, uint32, error)
|
||||
}
|
||||
|
||||
// Contract implements all contract methods.
|
||||
type Contract struct {
|
||||
actor Actor
|
||||
hash util.Uint160
|
||||
}
|
||||
|
||||
// New creates an instance of Contract using Hash and the given Actor.
|
||||
func New(actor Actor) *Contract {
|
||||
var hash = Hash
|
||||
return &Contract{actor, hash}
|
||||
}
|
||||
|
||||
// RoyaltiesTransferred creates a transaction invoking `royaltiesTransferred` 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) RoyaltiesTransferred(royaltyToken util.Uint160, royaltyRecipient util.Uint160, buyer util.Uint160, tokenId []byte, amount *big.Int) (util.Uint256, uint32, error) {
|
||||
return c.actor.SendCall(c.hash, "royaltiesTransferred", royaltyToken, royaltyRecipient, buyer, tokenId, amount)
|
||||
}
|
||||
|
||||
// RoyaltiesTransferredTransaction creates a transaction invoking `royaltiesTransferred` method of the contract.
|
||||
// This transaction is signed, but not sent to the network, instead it's
|
||||
// returned to the caller.
|
||||
func (c *Contract) RoyaltiesTransferredTransaction(royaltyToken util.Uint160, royaltyRecipient util.Uint160, buyer util.Uint160, tokenId []byte, amount *big.Int) (*transaction.Transaction, error) {
|
||||
return c.actor.MakeCall(c.hash, "royaltiesTransferred", royaltyToken, royaltyRecipient, buyer, tokenId, amount)
|
||||
}
|
||||
|
||||
// RoyaltiesTransferredUnsigned creates a transaction invoking `royaltiesTransferred` 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) RoyaltiesTransferredUnsigned(royaltyToken util.Uint160, royaltyRecipient util.Uint160, buyer util.Uint160, tokenId []byte, amount *big.Int) (*transaction.Transaction, error) {
|
||||
return c.actor.MakeUnsignedCall(c.hash, "royaltiesTransferred", nil, royaltyToken, royaltyRecipient, buyer, tokenId, amount)
|
||||
}
|
53
cli/smartcontract/testdata/rpcbindings/royalty/rpcbindings_dynamic_hash.out
vendored
Normal file
53
cli/smartcontract/testdata/rpcbindings/royalty/rpcbindings_dynamic_hash.out
vendored
Normal file
|
@ -0,0 +1,53 @@
|
|||
// Code generated by neo-go contract generate-rpcwrapper --manifest <file.json> --out <file.go> [--hash <hash>] [--config <config>]; DO NOT EDIT.
|
||||
|
||||
// Package royalty contains RPC wrappers for Test royalty contract.
|
||||
package royalty
|
||||
|
||||
import (
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
// Actor is used by Contract to call state-changing methods.
|
||||
type Actor interface {
|
||||
MakeCall(contract util.Uint160, method string, params ...any) (*transaction.Transaction, error)
|
||||
MakeRun(script []byte) (*transaction.Transaction, error)
|
||||
MakeUnsignedCall(contract util.Uint160, method string, attrs []transaction.Attribute, params ...any) (*transaction.Transaction, error)
|
||||
MakeUnsignedRun(script []byte, attrs []transaction.Attribute) (*transaction.Transaction, error)
|
||||
SendCall(contract util.Uint160, method string, params ...any) (util.Uint256, uint32, error)
|
||||
SendRun(script []byte) (util.Uint256, uint32, error)
|
||||
}
|
||||
|
||||
// Contract implements all contract methods.
|
||||
type Contract struct {
|
||||
actor Actor
|
||||
hash util.Uint160
|
||||
}
|
||||
|
||||
// New creates an instance of Contract using provided contract hash and the given Actor.
|
||||
func New(actor Actor, hash util.Uint160) *Contract {
|
||||
return &Contract{actor, hash}
|
||||
}
|
||||
|
||||
// RoyaltiesTransferred creates a transaction invoking `royaltiesTransferred` 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) RoyaltiesTransferred(royaltyToken util.Uint160, royaltyRecipient util.Uint160, buyer util.Uint160, tokenId []byte, amount *big.Int) (util.Uint256, uint32, error) {
|
||||
return c.actor.SendCall(c.hash, "royaltiesTransferred", royaltyToken, royaltyRecipient, buyer, tokenId, amount)
|
||||
}
|
||||
|
||||
// RoyaltiesTransferredTransaction creates a transaction invoking `royaltiesTransferred` method of the contract.
|
||||
// This transaction is signed, but not sent to the network, instead it's
|
||||
// returned to the caller.
|
||||
func (c *Contract) RoyaltiesTransferredTransaction(royaltyToken util.Uint160, royaltyRecipient util.Uint160, buyer util.Uint160, tokenId []byte, amount *big.Int) (*transaction.Transaction, error) {
|
||||
return c.actor.MakeCall(c.hash, "royaltiesTransferred", royaltyToken, royaltyRecipient, buyer, tokenId, amount)
|
||||
}
|
||||
|
||||
// RoyaltiesTransferredUnsigned creates a transaction invoking `royaltiesTransferred` 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) RoyaltiesTransferredUnsigned(royaltyToken util.Uint160, royaltyRecipient util.Uint160, buyer util.Uint160, tokenId []byte, amount *big.Int) (*transaction.Transaction, error) {
|
||||
return c.actor.MakeUnsignedCall(c.hash, "royaltiesTransferred", nil, royaltyToken, royaltyRecipient, buyer, tokenId, amount)
|
||||
}
|
|
@ -25,8 +25,8 @@ See the table below for the detailed examples description.
|
|||
| [engine](engine) | This contract demonstrates how to use `runtime` interop package which implements an API for `System.Runtime.*` Neo system calls. Please, refer to the `runtime` [package documentation](../pkg/interop/doc.go) for details. |
|
||||
| [events](events) | The contract shows how execution notifications with the different arguments types can be sent with the help of `runtime.Notify` function of the `runtime` interop package. Please, refer to the `runtime.Notify` [function documentation](../pkg/interop/runtime/runtime.go) for details. |
|
||||
| [iterator](iterator) | This example describes a way to work with Neo iterators. Please, refer to the `iterator` [package documentation](../pkg/interop/iterator/iterator.go) for details. |
|
||||
| [nft-d](nft-d) | NEP-11 divisible NFT. See NEP-11 token standard [specification](https://github.com/neo-project/proposals/blob/master/nep-11.mediawiki) for details. |
|
||||
| [nft-nd](nft-nd) | NEP-11 non-divisible NFT. See NEP-11 token standard [specification](https://github.com/neo-project/proposals/blob/master/nep-11.mediawiki) for details. |
|
||||
| [nft-d](nft-d) | NEP-11 divisible NFT. This contract implements the NEP-11 and the NEP-24 token standards. See NEP-11 token standard [specification](https://github.com/neo-project/proposals/blob/master/nep-11.mediawiki) and NEP-24 [specification](https://github.com/neo-project/proposals/blob/master/nep-24.mediawiki) for details. |
|
||||
| [nft-nd](nft-nd) | NEP-11 non-divisible NFT. This contract implements the NEP-11 and the NEP-24 token standards. See NEP-11 token standard [specification](https://github.com/neo-project/proposals/blob/master/nep-11.mediawiki) and NEP-24 [specification](https://github.com/neo-project/proposals/blob/master/nep-24.mediawiki) for details. |
|
||||
| [nft-nd-nns](nft-nd-nns) | Neo Name Service contract which is NEP-11 non-divisible NFT. The contract implements methods for Neo domain name system managing such as domains registration/transferring, records addition and names resolving. The package also contains tests implemented with [neotest](https://pkg.go.dev/github.com/nspcc-dev/neo-go/pkg/neotest). |
|
||||
| [oracle](oracle) | Oracle demo contract exposing two methods that you can use to process URLs. It uses oracle native contract, see [interop package documentation](../pkg/interop/native/oracle/oracle.go) also. |
|
||||
| [runtime](runtime) | This contract demonstrates how to use special `_initialize` and `_deploy` methods. See the [compiler documentation](../docs/compiler.md#vm-api-interop-layer ) for methods details. It also shows the pattern for checking owner witness inside the contract with the help of `runtime.CheckWitness` interop [function](../pkg/interop/runtime/runtime.go). |
|
||||
|
|
|
@ -425,3 +425,43 @@ func Update(nef, manifest []byte) {
|
|||
}
|
||||
management.Update(nef, manifest)
|
||||
}
|
||||
|
||||
// RoyaltyRecipient contains information about the recipient and the royalty amount.
|
||||
type RoyaltyRecipient struct {
|
||||
Address interop.Hash160
|
||||
Amount int
|
||||
}
|
||||
|
||||
// RoyaltyInfo returns a list of royalty recipients and the corresponding royalty amounts.
|
||||
func RoyaltyInfo(tokenID []byte, royaltyToken interop.Hash160, salePrice int) []RoyaltyRecipient {
|
||||
if salePrice <= 0 {
|
||||
panic("sale price must be positive")
|
||||
}
|
||||
|
||||
executingHash := runtime.GetExecutingScriptHash()
|
||||
if !royaltyToken.Equals(executingHash) {
|
||||
panic("invalid royalty token")
|
||||
}
|
||||
|
||||
ctx := storage.GetReadOnlyContext()
|
||||
if !isTokenValid(ctx, tokenID) {
|
||||
panic("unknown token")
|
||||
}
|
||||
ownerIter := ownersOf(ctx, tokenID)
|
||||
var owners []interop.Hash160
|
||||
for iterator.Next(ownerIter) {
|
||||
owners = append(owners, iterator.Value(ownerIter).(interop.Hash160))
|
||||
}
|
||||
|
||||
var (
|
||||
recipients []RoyaltyRecipient
|
||||
amount = salePrice / 10 / len(owners)
|
||||
)
|
||||
for _, owner := range owners {
|
||||
recipients = append(recipients, RoyaltyRecipient{
|
||||
Address: owner,
|
||||
Amount: amount,
|
||||
})
|
||||
}
|
||||
return recipients
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
name: "NeoFS Object NFT"
|
||||
sourceurl: https://github.com/nspcc-dev/neo-go/
|
||||
supportedstandards: ["NEP-11"]
|
||||
safemethods: ["balanceOf", "decimals", "symbol", "totalSupply", "tokensOf", "ownerOf", "properties", "tokens"]
|
||||
supportedstandards: ["NEP-11", "NEP-24"]
|
||||
safemethods: ["balanceOf", "decimals", "symbol", "totalSupply", "tokensOf", "ownerOf", "properties", "tokens", "royaltyInfo"]
|
||||
events:
|
||||
- name: Transfer
|
||||
parameters:
|
||||
|
|
|
@ -30,6 +30,8 @@ const (
|
|||
accountPrefix = "a"
|
||||
// tokenPrefix contains map from token id to it's owner.
|
||||
tokenPrefix = "t"
|
||||
// royaltyInfoPrefix contains map from token id to its royalty information.
|
||||
royaltyInfoPrefix = "r"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -285,3 +287,68 @@ func Properties(id []byte) map[string]string {
|
|||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// RoyaltyRecipient contains information about the recipient and the royalty amount.
|
||||
type RoyaltyRecipient struct {
|
||||
Address interop.Hash160
|
||||
Amount int
|
||||
}
|
||||
|
||||
// RoyaltyInfo returns a list of royalty recipients and the corresponding royalty amounts.
|
||||
func RoyaltyInfo(tokenID []byte, royaltyToken interop.Hash160, salePrice int) []RoyaltyRecipient {
|
||||
if salePrice <= 0 {
|
||||
panic("sale price must be positive")
|
||||
}
|
||||
|
||||
executingHash := runtime.GetExecutingScriptHash()
|
||||
if !royaltyToken.Equals(executingHash) {
|
||||
panic("invalid royalty token")
|
||||
}
|
||||
|
||||
ctx := storage.GetReadOnlyContext()
|
||||
owner := getOwnerOf(ctx, tokenID)
|
||||
if owner == nil {
|
||||
panic("invalid token ID")
|
||||
}
|
||||
|
||||
royaltyInfoKey := append([]byte(royaltyInfoPrefix), tokenID...)
|
||||
val := storage.Get(ctx, royaltyInfoKey)
|
||||
|
||||
var recipients []RoyaltyRecipient
|
||||
if val == nil {
|
||||
recipients = []RoyaltyRecipient{
|
||||
{
|
||||
Address: owner,
|
||||
Amount: salePrice / 10,
|
||||
},
|
||||
}
|
||||
} else {
|
||||
bval := val.([]byte)
|
||||
storedRecipients := std.Deserialize(bval)
|
||||
st := storedRecipients.([]RoyaltyRecipientShare)
|
||||
for _, r := range st {
|
||||
recipients = append(recipients, RoyaltyRecipient{
|
||||
Address: r.Address,
|
||||
Amount: salePrice * r.Share / 100,
|
||||
})
|
||||
}
|
||||
}
|
||||
return recipients
|
||||
}
|
||||
|
||||
// RoyaltyRecipientShare contains information about the recipient and the royalty share in percents.
|
||||
type RoyaltyRecipientShare struct {
|
||||
Address interop.Hash160
|
||||
Share int
|
||||
}
|
||||
|
||||
// SetRoyaltyInfo sets the royalty share for specified recipients on a given token ID.
|
||||
// Only the token owner can set the royalty information.
|
||||
func SetRoyaltyInfo(ctx storage.Context, tokenID []byte, recipients []RoyaltyRecipientShare) bool {
|
||||
if !runtime.CheckWitness(getOwnerOf(ctx, tokenID)) {
|
||||
return false
|
||||
}
|
||||
putKey := append([]byte(royaltyInfoPrefix), tokenID...)
|
||||
storage.Put(ctx, putKey, std.Serialize(recipients))
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
name: "HASHY NFT"
|
||||
sourceurl: https://github.com/nspcc-dev/neo-go/
|
||||
supportedstandards: ["NEP-11"]
|
||||
safemethods: ["balanceOf", "decimals", "symbol", "totalSupply", "tokensOf", "ownerOf", "tokens", "properties"]
|
||||
supportedstandards: ["NEP-11", "NEP-24"]
|
||||
safemethods: ["balanceOf", "decimals", "symbol", "totalSupply", "tokensOf", "ownerOf", "tokens", "properties", "royaltyInfo"]
|
||||
events:
|
||||
- name: Transfer
|
||||
parameters:
|
||||
|
|
32
pkg/rpcclient/nep24/doc_test.go
Normal file
32
pkg/rpcclient/nep24/doc_test.go
Normal file
|
@ -0,0 +1,32 @@
|
|||
package nep24_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/invoker"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/nep24"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
)
|
||||
|
||||
func ExampleRoyaltyReader() {
|
||||
// No error checking done at all, intentionally.
|
||||
c, _ := rpcclient.New(context.Background(), "url", rpcclient.Options{})
|
||||
|
||||
// Safe methods are reachable with just an invoker, no need for an account there.
|
||||
inv := invoker.New(c, nil)
|
||||
|
||||
// NEP-24 contract hash.
|
||||
nep24Hash := util.Uint160{9, 8, 7}
|
||||
|
||||
// And a reader interface.
|
||||
n24 := nep24.NewRoyaltyReader(inv, nep24Hash)
|
||||
|
||||
// Get the royalty information for a token.
|
||||
tokenID := []byte("someTokenID")
|
||||
royaltyToken := util.Uint160{1, 2, 3}
|
||||
salePrice := big.NewInt(1000)
|
||||
royaltyInfo, _ := n24.RoyaltyInfo(tokenID, royaltyToken, salePrice)
|
||||
_ = royaltyInfo
|
||||
}
|
185
pkg/rpcclient/nep24/royalty.go
Normal file
185
pkg/rpcclient/nep24/royalty.go
Normal file
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
Package nep24 provides RPC wrappers for NEP-24 contracts.
|
||||
|
||||
All methods are safe (read-only) and encapsulated in the RoyaltyReader structure,
|
||||
designed for managing NFT royalties and retrieving royalty information.
|
||||
Refer to the nep11 package for basic NFT functionalities, while nep24 handles
|
||||
royalty-related operations.
|
||||
*/
|
||||
package nep24
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/neptoken"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
)
|
||||
|
||||
// RoyaltyRecipient contains information about the recipient and the royalty amount.
|
||||
type RoyaltyRecipient struct {
|
||||
Address util.Uint160
|
||||
Amount *big.Int
|
||||
}
|
||||
|
||||
// RoyaltiesTransferredEvent represents a RoyaltiesTransferred event as defined in
|
||||
// the NEP-24 standard.
|
||||
type RoyaltiesTransferredEvent struct {
|
||||
RoyaltyToken util.Uint160
|
||||
RoyaltyRecipient util.Uint160
|
||||
Buyer util.Uint160
|
||||
TokenID []byte
|
||||
Amount *big.Int
|
||||
}
|
||||
|
||||
// RoyaltyReader represents safe (read-only) methods of NEP-24 token. It can be
|
||||
// used to query data about royalties.
|
||||
type RoyaltyReader struct {
|
||||
invoker neptoken.Invoker
|
||||
hash util.Uint160
|
||||
}
|
||||
|
||||
// NewRoyaltyReader returns a new RoyaltyReader instance.
|
||||
func NewRoyaltyReader(invoker neptoken.Invoker, hash util.Uint160) *RoyaltyReader {
|
||||
return &RoyaltyReader{
|
||||
invoker: invoker,
|
||||
hash: hash,
|
||||
}
|
||||
}
|
||||
|
||||
// RoyaltyInfo returns the royalty information for the given tokenID, royaltyToken,
|
||||
// and salePrice.
|
||||
func (c *RoyaltyReader) RoyaltyInfo(tokenID []byte, royaltyToken util.Uint160, salePrice *big.Int) ([]RoyaltyRecipient, error) {
|
||||
res, err := c.invoker.Call(c.hash, "royaltyInfo", tokenID, royaltyToken, salePrice)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(res.Stack) != 1 {
|
||||
return nil, errors.New("invalid response: expected a single item on the stack")
|
||||
}
|
||||
rootItem, ok := res.Stack[0].Value().([]stackitem.Item)
|
||||
if !ok {
|
||||
return nil, errors.New("invalid response: expected an array of royalties")
|
||||
}
|
||||
|
||||
var royalties []RoyaltyRecipient
|
||||
for _, item := range rootItem {
|
||||
royalty, ok := item.Value().([]stackitem.Item)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid royalty structure: expected array of 2 items, got %d", len(royalty))
|
||||
}
|
||||
var recipient RoyaltyRecipient
|
||||
err = recipient.FromStackItem(royalty)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode royalty detail: %w", err)
|
||||
}
|
||||
royalties = append(royalties, recipient)
|
||||
}
|
||||
|
||||
return royalties, nil
|
||||
}
|
||||
|
||||
// FromStackItem converts a stack item into a RoyaltyRecipient struct.
|
||||
func (r *RoyaltyRecipient) FromStackItem(item []stackitem.Item) error {
|
||||
if len(item) != 2 {
|
||||
return fmt.Errorf("invalid royalty structure: expected 2 items, got %d", len(item))
|
||||
}
|
||||
|
||||
recipientBytes, err := item[0].TryBytes()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to decode recipient address: %w", err)
|
||||
}
|
||||
|
||||
recipient, err := util.Uint160DecodeBytesBE(recipientBytes)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid recipient address: %w", err)
|
||||
}
|
||||
|
||||
amountBigInt, err := item[1].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to decode royalty amount: %w", err)
|
||||
}
|
||||
if amountBigInt.Sign() < 0 {
|
||||
return errors.New("negative royalty amount")
|
||||
}
|
||||
amount := big.NewInt(0).Set(amountBigInt)
|
||||
r.Amount = amount
|
||||
r.Address = recipient
|
||||
return nil
|
||||
}
|
||||
|
||||
// RoyaltiesTransferredEventsFromApplicationLog retrieves all emitted
|
||||
// RoyaltiesTransferredEvents from the provided [result.ApplicationLog].
|
||||
func RoyaltiesTransferredEventsFromApplicationLog(log *result.ApplicationLog) ([]*RoyaltiesTransferredEvent, error) {
|
||||
if log == nil {
|
||||
return nil, errors.New("nil application log")
|
||||
}
|
||||
var res []*RoyaltiesTransferredEvent
|
||||
for i, ex := range log.Executions {
|
||||
for j, e := range ex.Events {
|
||||
if e.Name != "RoyaltiesTransferred" {
|
||||
continue
|
||||
}
|
||||
event := new(RoyaltiesTransferredEvent)
|
||||
err := event.FromStackItem(e.Item)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode event from stackitem (event #%d, execution #%d): %w", j, i, err)
|
||||
}
|
||||
res = append(res, event)
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// FromStackItem converts a stack item into a RoyaltiesTransferredEvent struct.
|
||||
func (e *RoyaltiesTransferredEvent) FromStackItem(item *stackitem.Array) error {
|
||||
if item == nil {
|
||||
return errors.New("nil item")
|
||||
}
|
||||
arr, ok := item.Value().([]stackitem.Item)
|
||||
if !ok || len(arr) != 5 {
|
||||
return errors.New("invalid event structure: expected array of 5 items")
|
||||
}
|
||||
|
||||
b, err := arr[0].TryBytes()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to decode RoyaltyToken: %w", err)
|
||||
}
|
||||
e.RoyaltyToken, err = util.Uint160DecodeBytesBE(b)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid RoyaltyToken: %w", err)
|
||||
}
|
||||
|
||||
b, err = arr[1].TryBytes()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to decode RoyaltyRecipient: %w", err)
|
||||
}
|
||||
e.RoyaltyRecipient, err = util.Uint160DecodeBytesBE(b)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid RoyaltyRecipient: %w", err)
|
||||
}
|
||||
|
||||
b, err = arr[2].TryBytes()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to decode Buyer: %w", err)
|
||||
}
|
||||
e.Buyer, err = util.Uint160DecodeBytesBE(b)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid Buyer: %w", err)
|
||||
}
|
||||
|
||||
e.TokenID, err = arr[3].TryBytes()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to decode TokenID: %w", err)
|
||||
}
|
||||
|
||||
e.Amount, err = arr[4].TryInteger()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to decode Amount: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
300
pkg/rpcclient/nep24/royalty_test.go
Normal file
300
pkg/rpcclient/nep24/royalty_test.go
Normal file
|
@ -0,0 +1,300 @@
|
|||
package nep24
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||
"github.com/nspcc-dev/neo-go/pkg/neorpc/result"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
type testAct struct {
|
||||
err error
|
||||
res *result.Invoke
|
||||
}
|
||||
|
||||
func (t *testAct) Call(contract util.Uint160, operation string, params ...any) (*result.Invoke, error) {
|
||||
return t.res, t.err
|
||||
}
|
||||
|
||||
func TestRoyaltyReaderRoyaltyInfo(t *testing.T) {
|
||||
ta := new(testAct)
|
||||
rr := NewRoyaltyReader(ta, util.Uint160{1, 2, 3})
|
||||
|
||||
tokenID := []byte{1, 2, 3}
|
||||
royaltyToken := util.Uint160{4, 5, 6}
|
||||
salePrice := big.NewInt(1000)
|
||||
|
||||
ta.res = &result.Invoke{
|
||||
State: "HALT",
|
||||
Stack: []stackitem.Item{
|
||||
stackitem.Make([]stackitem.Item{
|
||||
stackitem.Make([]stackitem.Item{
|
||||
stackitem.Make(util.Uint160{7, 8, 9}.BytesBE()),
|
||||
stackitem.Make(big.NewInt(100)),
|
||||
}),
|
||||
stackitem.Make([]stackitem.Item{
|
||||
stackitem.Make(util.Uint160{7, 8, 9}.BytesBE()),
|
||||
stackitem.Make(big.NewInt(200)),
|
||||
}),
|
||||
}),
|
||||
},
|
||||
}
|
||||
ri, err := rr.RoyaltyInfo(tokenID, royaltyToken, salePrice)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, []RoyaltyRecipient{
|
||||
{
|
||||
Address: util.Uint160{7, 8, 9},
|
||||
Amount: big.NewInt(100),
|
||||
},
|
||||
{
|
||||
Address: util.Uint160{7, 8, 9},
|
||||
Amount: big.NewInt(200),
|
||||
},
|
||||
}, ri)
|
||||
|
||||
ta.err = errors.New("")
|
||||
_, err = rr.RoyaltyInfo(tokenID, royaltyToken, salePrice)
|
||||
require.Error(t, err)
|
||||
|
||||
ta.res = &result.Invoke{
|
||||
State: "HALT",
|
||||
Stack: []stackitem.Item{
|
||||
stackitem.Make([]stackitem.Item{
|
||||
stackitem.Make(util.Uint160{7, 8, 9}.BytesBE()),
|
||||
}),
|
||||
},
|
||||
}
|
||||
_, err = rr.RoyaltyInfo(tokenID, royaltyToken, salePrice)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestRoyaltyRecipient_FromStackItem(t *testing.T) {
|
||||
tests := map[string]struct {
|
||||
items []stackitem.Item
|
||||
err error
|
||||
expected RoyaltyRecipient
|
||||
}{
|
||||
"good": {
|
||||
items: []stackitem.Item{
|
||||
stackitem.Make(util.Uint160{7, 8, 9}.BytesBE()),
|
||||
stackitem.Make(big.NewInt(100)),
|
||||
},
|
||||
err: nil,
|
||||
expected: RoyaltyRecipient{
|
||||
Address: util.Uint160{7, 8, 9},
|
||||
Amount: big.NewInt(100),
|
||||
},
|
||||
},
|
||||
"invalid number of items": {
|
||||
items: []stackitem.Item{
|
||||
stackitem.Make(util.Uint160{7, 8, 9}.BytesBE()),
|
||||
},
|
||||
err: fmt.Errorf("invalid royalty structure: expected 2 items, got 1"),
|
||||
},
|
||||
"invalid recipient size": {
|
||||
items: []stackitem.Item{
|
||||
stackitem.Make([]byte{1, 2}),
|
||||
stackitem.Make(big.NewInt(100)),
|
||||
},
|
||||
err: fmt.Errorf("invalid recipient address: expected byte size of 20 got 2"),
|
||||
},
|
||||
"invalid recipient type": {
|
||||
items: []stackitem.Item{
|
||||
stackitem.Make([]int{7, 8, 9}),
|
||||
stackitem.Make(big.NewInt(100)),
|
||||
},
|
||||
err: fmt.Errorf("failed to decode recipient address: invalid conversion: Array/ByteString"),
|
||||
},
|
||||
"invalid amount type": {
|
||||
items: []stackitem.Item{
|
||||
stackitem.Make(util.Uint160{7, 8, 9}.BytesBE()),
|
||||
stackitem.Make([]int{7, 8, 9}),
|
||||
},
|
||||
err: fmt.Errorf("failed to decode royalty amount: invalid conversion: Array/Integer"),
|
||||
},
|
||||
"negative amount": {
|
||||
items: []stackitem.Item{
|
||||
stackitem.Make(util.Uint160{7, 8, 9}.BytesBE()),
|
||||
stackitem.Make(big.NewInt(-100)),
|
||||
},
|
||||
err: fmt.Errorf("negative royalty amount"),
|
||||
},
|
||||
}
|
||||
for name, tt := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
var ri RoyaltyRecipient
|
||||
err := ri.FromStackItem(tt.items)
|
||||
if tt.err != nil {
|
||||
require.EqualError(t, err, tt.err.Error())
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tt.expected, ri)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRoyaltiesTransferredEventFromStackitem(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
item *stackitem.Array
|
||||
expectErr bool
|
||||
expected *RoyaltiesTransferredEvent
|
||||
}{
|
||||
{
|
||||
name: "good",
|
||||
item: stackitem.NewArray([]stackitem.Item{
|
||||
stackitem.Make(util.Uint160{1, 2, 3}.BytesBE()), // RoyaltyToken
|
||||
stackitem.Make(util.Uint160{4, 5, 6}.BytesBE()), // RoyaltyRecipient
|
||||
stackitem.Make(util.Uint160{7, 8, 9}.BytesBE()), // Buyer
|
||||
stackitem.Make([]byte{1, 2, 3}), // TokenID
|
||||
stackitem.Make(big.NewInt(100)), // Amount
|
||||
}),
|
||||
expectErr: false,
|
||||
expected: &RoyaltiesTransferredEvent{
|
||||
RoyaltyToken: util.Uint160{1, 2, 3},
|
||||
RoyaltyRecipient: util.Uint160{4, 5, 6},
|
||||
Buyer: util.Uint160{7, 8, 9},
|
||||
TokenID: []byte{1, 2, 3},
|
||||
Amount: big.NewInt(100),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid number of items",
|
||||
item: stackitem.NewArray([]stackitem.Item{
|
||||
stackitem.Make(util.Uint160{1, 2, 3}.BytesBE()), // Only one item
|
||||
}),
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "invalid recipient size",
|
||||
item: stackitem.NewArray([]stackitem.Item{
|
||||
stackitem.Make(util.Uint160{1, 2, 3}.BytesBE()), // RoyaltyToken
|
||||
stackitem.Make([]byte{1, 2}), // Invalid RoyaltyRecipient
|
||||
stackitem.Make(util.Uint160{7, 8, 9}.BytesBE()), // Buyer
|
||||
stackitem.Make([]byte{1, 2, 3}), // TokenID
|
||||
stackitem.Make(big.NewInt(100)), // Amount
|
||||
}),
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "invalid integer amount",
|
||||
item: stackitem.NewArray([]stackitem.Item{
|
||||
stackitem.Make(util.Uint160{1, 2, 3}.BytesBE()), // RoyaltyToken
|
||||
stackitem.Make(util.Uint160{4, 5, 6}.BytesBE()), // RoyaltyRecipient
|
||||
stackitem.Make(util.Uint160{7, 8, 9}.BytesBE()), // Buyer
|
||||
stackitem.Make([]byte{1, 2, 3}), // TokenID
|
||||
stackitem.Make(stackitem.NewStruct(nil)), // Invalid integer for Amount
|
||||
}),
|
||||
expectErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
event := new(RoyaltiesTransferredEvent)
|
||||
err := event.FromStackItem(tt.item)
|
||||
if tt.expectErr {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tt.expected, event)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRoyaltiesTransferredEventsFromApplicationLog(t *testing.T) {
|
||||
createEvent := func(token, recipient, buyer util.Uint160, tokenID []byte, amount *big.Int) state.NotificationEvent {
|
||||
return state.NotificationEvent{
|
||||
ScriptHash: util.Uint160{1, 2, 3}, // Any contract address.
|
||||
Name: "RoyaltiesTransferred",
|
||||
Item: stackitem.NewArray([]stackitem.Item{
|
||||
stackitem.Make(token.BytesBE()), // RoyaltyToken
|
||||
stackitem.Make(recipient.BytesBE()), // RoyaltyRecipient
|
||||
stackitem.Make(buyer.BytesBE()), // Buyer
|
||||
stackitem.Make(tokenID), // TokenID
|
||||
stackitem.Make(amount), // Amount
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
log *result.ApplicationLog
|
||||
expectErr bool
|
||||
expected []*RoyaltiesTransferredEvent
|
||||
}{
|
||||
{
|
||||
name: "valid log with one event",
|
||||
log: &result.ApplicationLog{
|
||||
Executions: []state.Execution{
|
||||
{
|
||||
Events: []state.NotificationEvent{
|
||||
createEvent(
|
||||
util.Uint160{1, 2, 3}, // RoyaltyToken
|
||||
util.Uint160{4, 5, 6}, // RoyaltyRecipient
|
||||
util.Uint160{7, 8, 9}, // Buyer
|
||||
[]byte{1, 2, 3}, // TokenID
|
||||
big.NewInt(100), // Amount
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectErr: false,
|
||||
expected: []*RoyaltiesTransferredEvent{
|
||||
{
|
||||
RoyaltyToken: util.Uint160{1, 2, 3},
|
||||
RoyaltyRecipient: util.Uint160{4, 5, 6},
|
||||
Buyer: util.Uint160{7, 8, 9},
|
||||
TokenID: []byte{1, 2, 3},
|
||||
Amount: big.NewInt(100),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid event structure (missing fields)",
|
||||
log: &result.ApplicationLog{
|
||||
Executions: []state.Execution{
|
||||
{
|
||||
Events: []state.NotificationEvent{
|
||||
{
|
||||
Name: "RoyaltiesTransferred",
|
||||
Item: stackitem.NewArray([]stackitem.Item{
|
||||
stackitem.Make(util.Uint160{1, 2, 3}.BytesBE()), // RoyaltyToken
|
||||
// Missing other fields
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expectErr: true,
|
||||
},
|
||||
{
|
||||
name: "empty log",
|
||||
log: &result.ApplicationLog{},
|
||||
expectErr: false,
|
||||
expected: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
events, err := RoyaltiesTransferredEventsFromApplicationLog(tt.log)
|
||||
if tt.expectErr {
|
||||
require.Error(t, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tt.expected, events)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -26,6 +26,11 @@ const (
|
|||
NEP11Payable = "NEP-11-Payable"
|
||||
// NEP17Payable represents the name of contract interface which can receive NEP-17 tokens.
|
||||
NEP17Payable = "NEP-17-Payable"
|
||||
// NEP24StandardName represents the name of the NEP-24 smart contract standard for NFT royalties.
|
||||
NEP24StandardName = "NEP-24"
|
||||
// NEP24Payable represents the name of the contract interface for handling royalty payments in accordance
|
||||
// with the NEP-24 standard.
|
||||
NEP24Payable = "NEP-24-Payable"
|
||||
|
||||
emptyFeatures = "{}"
|
||||
)
|
||||
|
|
|
@ -23,6 +23,8 @@ var checks = map[string][]*Standard{
|
|||
manifest.NEP17StandardName: {Nep17},
|
||||
manifest.NEP11Payable: {Nep11Payable},
|
||||
manifest.NEP17Payable: {Nep17Payable},
|
||||
manifest.NEP24StandardName: {Nep24},
|
||||
manifest.NEP24Payable: {Nep24Payable},
|
||||
}
|
||||
|
||||
// Check checks if the manifest complies with all provided standards.
|
||||
|
|
51
pkg/smartcontract/manifest/standard/nep24.go
Normal file
51
pkg/smartcontract/manifest/standard/nep24.go
Normal file
|
@ -0,0 +1,51 @@
|
|||
package standard
|
||||
|
||||
import (
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
||||
)
|
||||
|
||||
// MethodRoyaltyInfo is the name of the method that returns royalty information.
|
||||
const MethodRoyaltyInfo = "royaltyInfo"
|
||||
|
||||
// Nep24 is a NEP-24 Standard for NFT royalties.
|
||||
var Nep24 = &Standard{
|
||||
Manifest: manifest.Manifest{
|
||||
ABI: manifest.ABI{
|
||||
Methods: []manifest.Method{
|
||||
{
|
||||
Name: MethodRoyaltyInfo,
|
||||
Parameters: []manifest.Parameter{
|
||||
{Name: "tokenId", Type: smartcontract.ByteArrayType},
|
||||
{Name: "royaltyToken", Type: smartcontract.Hash160Type},
|
||||
{Name: "salePrice", Type: smartcontract.IntegerType},
|
||||
},
|
||||
ReturnType: smartcontract.ArrayType,
|
||||
Safe: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{manifest.NEP11StandardName},
|
||||
}
|
||||
|
||||
// Nep24Payable contains an event that MUST be triggered after marketplaces
|
||||
// transferring royalties to the royalty recipient if royaltyInfo method is implemented.
|
||||
var Nep24Payable = &Standard{
|
||||
Manifest: manifest.Manifest{
|
||||
ABI: manifest.ABI{
|
||||
Events: []manifest.Event{
|
||||
{
|
||||
Name: "RoyaltiesTransferred",
|
||||
Parameters: []manifest.Parameter{
|
||||
{Name: "royaltyToken", Type: smartcontract.Hash160Type},
|
||||
{Name: "royaltyRecipient", Type: smartcontract.Hash160Type},
|
||||
{Name: "buyer", Type: smartcontract.Hash160Type},
|
||||
{Name: "tokenId", Type: smartcontract.ByteArrayType},
|
||||
{Name: "amount", Type: smartcontract.IntegerType},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
|
@ -179,6 +179,8 @@ type ContractReader struct {
|
|||
{{end -}}
|
||||
{{if .IsNep17}}nep17.TokenReader
|
||||
{{end -}}
|
||||
{{if .IsNep24}}nep24.RoyaltyReader
|
||||
{{end -}}
|
||||
invoker Invoker
|
||||
hash util.Uint160
|
||||
}
|
||||
|
@ -208,6 +210,7 @@ func NewReader(invoker Invoker{{- if not (len .Hash) -}}, hash util.Uint160{{- e
|
|||
{{- if .IsNep11D}}*nep11.NewDivisibleReader(invoker, hash), {{end}}
|
||||
{{- if .IsNep11ND}}*nep11.NewNonDivisibleReader(invoker, hash), {{end}}
|
||||
{{- if .IsNep17}}*nep17.NewReader(invoker, hash), {{end -}}
|
||||
{{- if .IsNep24}}*nep24.NewRoyaltyReader(invoker, hash), {{end -}}
|
||||
invoker, hash}
|
||||
}
|
||||
{{end -}}
|
||||
|
@ -223,11 +226,14 @@ func New(actor Actor{{- if not (len .Hash) -}}, hash util.Uint160{{- end -}}) *C
|
|||
{{end -}}
|
||||
{{if .IsNep17}}var nep17t = nep17.New(actor, hash)
|
||||
{{end -}}
|
||||
{{if .IsNep24}}var nep24t = nep24.NewRoyaltyReader(actor, hash)
|
||||
{{end -}}
|
||||
return &Contract{
|
||||
{{- if .HasReader}}ContractReader{
|
||||
{{- if .IsNep11D}}nep11dt.DivisibleReader, {{end -}}
|
||||
{{- if .IsNep11ND}}nep11ndt.NonDivisibleReader, {{end -}}
|
||||
{{- if .IsNep17}}nep17t.TokenReader, {{end -}}
|
||||
{{- if .IsNep24}}*nep24t, {{end -}}
|
||||
actor, hash}, {{end -}}
|
||||
{{- if .IsNep11D}}nep11dt.DivisibleWriter, {{end -}}
|
||||
{{- if .IsNep11ND}}nep11ndt.BaseWriter, {{end -}}
|
||||
|
@ -352,6 +358,8 @@ type (
|
|||
IsNep11D bool
|
||||
IsNep11ND bool
|
||||
IsNep17 bool
|
||||
IsNep24 bool
|
||||
IsNep24Payable bool
|
||||
|
||||
HasReader bool
|
||||
HasWriter bool
|
||||
|
@ -404,25 +412,50 @@ func Generate(cfg binding.Config) error {
|
|||
|
||||
// Strip standard methods from NEP-XX packages.
|
||||
for _, std := range cfg.Manifest.SupportedStandards {
|
||||
if std == manifest.NEP11StandardName {
|
||||
switch std {
|
||||
case 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
|
||||
}
|
||||
mfst.ABI.Events = dropStdEvents(mfst.ABI.Events, standard.Nep11Base)
|
||||
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)
|
||||
case manifest.NEP17StandardName:
|
||||
if standard.ComplyABI(cfg.Manifest, standard.Nep17) == nil {
|
||||
imports["github.com/nspcc-dev/neo-go/pkg/rpcclient/nep17"] = struct{}{}
|
||||
ctr.IsNep17 = true
|
||||
mfst.ABI.Events = dropStdEvents(mfst.ABI.Events, standard.Nep17)
|
||||
break // Can't be NEP-11 at the same time.
|
||||
}
|
||||
case manifest.NEP24StandardName:
|
||||
if standard.ComplyABI(cfg.Manifest, standard.Nep24) == nil {
|
||||
imports["github.com/nspcc-dev/neo-go/pkg/rpcclient/nep24"] = struct{}{}
|
||||
ctr.IsNep24 = true
|
||||
}
|
||||
case manifest.NEP24Payable:
|
||||
if standard.ComplyABI(cfg.Manifest, standard.Nep24Payable) == nil {
|
||||
ctr.IsNep24Payable = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ctr.IsNep11D {
|
||||
mfst.ABI.Methods = dropStdMethods(mfst.ABI.Methods, standard.Nep11Divisible)
|
||||
}
|
||||
if ctr.IsNep11ND {
|
||||
mfst.ABI.Methods = dropStdMethods(mfst.ABI.Methods, standard.Nep11NonDivisible)
|
||||
}
|
||||
if ctr.IsNep11D || ctr.IsNep11ND {
|
||||
mfst.ABI.Events = dropStdEvents(mfst.ABI.Events, standard.Nep11Base)
|
||||
}
|
||||
if ctr.IsNep17 {
|
||||
mfst.ABI.Methods = dropStdMethods(mfst.ABI.Methods, standard.Nep17)
|
||||
mfst.ABI.Events = dropStdEvents(mfst.ABI.Events, standard.Nep17)
|
||||
}
|
||||
if ctr.IsNep24 {
|
||||
mfst.ABI.Methods = dropStdMethods(mfst.ABI.Methods, standard.Nep24)
|
||||
cfg = dropNep24Types(cfg)
|
||||
}
|
||||
if ctr.IsNep24Payable {
|
||||
mfst.ABI.Events = dropStdEvents(mfst.ABI.Events, standard.Nep24Payable)
|
||||
}
|
||||
|
||||
// OnNepXXPayment handlers normally can't be called directly.
|
||||
|
@ -519,6 +552,38 @@ func dropStdEvents(events []manifest.Event, std *standard.Standard) []manifest.E
|
|||
return events
|
||||
}
|
||||
|
||||
// dropNep24Types removes NamedTypes of NEP-24 from the config if they are used only from the methods of the standard.
|
||||
func dropNep24Types(cfg binding.Config) binding.Config {
|
||||
var targetTypeName string
|
||||
// Find structure returned by standard.MethodRoyaltyInfo method
|
||||
// and remove it from binding.Config.NamedTypes as it will be imported from nep24 package.
|
||||
if royaltyInfo, ok := cfg.Types[standard.MethodRoyaltyInfo]; ok && royaltyInfo.Value != nil {
|
||||
returnType, exists := cfg.NamedTypes[royaltyInfo.Value.Name]
|
||||
if !exists || returnType.Fields == nil || len(returnType.Fields) != 2 ||
|
||||
returnType.Fields[0].ExtendedType.Base != smartcontract.Hash160Type ||
|
||||
returnType.Fields[1].ExtendedType.Base != smartcontract.IntegerType {
|
||||
return cfg
|
||||
}
|
||||
targetTypeName = royaltyInfo.Value.Name
|
||||
} else {
|
||||
return cfg
|
||||
}
|
||||
found := false
|
||||
for _, typeDef := range cfg.Types {
|
||||
if typeDef.Value != nil && typeDef.Value.Name == targetTypeName {
|
||||
if found {
|
||||
return cfg
|
||||
}
|
||||
found = true
|
||||
}
|
||||
}
|
||||
|
||||
if found {
|
||||
delete(cfg.NamedTypes, targetTypeName)
|
||||
}
|
||||
return cfg
|
||||
}
|
||||
|
||||
func extendedTypeToGo(et binding.ExtendedType, named map[string]binding.ExtendedType) (string, string) {
|
||||
switch et.Base {
|
||||
case smartcontract.AnyType:
|
||||
|
@ -834,7 +899,7 @@ func scTemplateToRPC(cfg binding.Config, ctr ContractTmpl, imports map[string]st
|
|||
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) {
|
||||
if !(ctr.IsNep17 || ctr.IsNep11D || ctr.IsNep11ND || ctr.IsNep24) {
|
||||
imports["github.com/nspcc-dev/neo-go/pkg/neorpc/result"] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
@ -844,7 +909,7 @@ func scTemplateToRPC(cfg binding.Config, ctr ContractTmpl, imports map[string]st
|
|||
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 {
|
||||
if len(ctr.SafeMethods) > 0 || ctr.IsNep17 || ctr.IsNep11D || ctr.IsNep11ND || ctr.IsNep24 {
|
||||
ctr.HasReader = true
|
||||
}
|
||||
ctr.Imports = ctr.Imports[:0]
|
||||
|
|
Loading…
Reference in a new issue