mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-10-16 05:43:24 +00:00
manifest: add NEP-24
Close #3451 Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
This commit is contained in:
parent
d9a6a7cd3f
commit
3a9fdda478
5 changed files with 510 additions and 1 deletions
176
pkg/rpcclient/nep11/royalty.go
Normal file
176
pkg/rpcclient/nep11/royalty.go
Normal file
|
@ -0,0 +1,176 @@
|
||||||
|
// Package nep11 provides RPC wrappers for NEP-11 contracts, including support for NEP-24 NFT royalties.
|
||||||
|
package nep11
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"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"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RoyaltyInfoDetail contains information about the recipient and the royalty amount.
|
||||||
|
type RoyaltyInfoDetail struct {
|
||||||
|
RoyaltyRecipient util.Uint160
|
||||||
|
RoyaltyAmount *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 is an interface for contracts implementing NEP-24 royalties.
|
||||||
|
type RoyaltyReader struct {
|
||||||
|
BaseReader
|
||||||
|
}
|
||||||
|
|
||||||
|
// RoyaltyWriter is an interface for state-changing methods related to NEP-24 royalties.
|
||||||
|
type RoyaltyWriter struct {
|
||||||
|
BaseWriter
|
||||||
|
}
|
||||||
|
|
||||||
|
// Royalty is a full reader and writer interface for NEP-24 royalties.
|
||||||
|
type Royalty struct {
|
||||||
|
RoyaltyReader
|
||||||
|
RoyaltyWriter
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRoyaltyReader creates an instance of RoyaltyReader for a contract with the given hash using the given invoker.
|
||||||
|
func NewRoyaltyReader(invoker Invoker, hash util.Uint160) *RoyaltyReader {
|
||||||
|
return &RoyaltyReader{*NewBaseReader(invoker, hash)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRoyalty creates an instance of Royalty for a contract with the given hash using the given actor.
|
||||||
|
func NewRoyalty(actor Actor, hash util.Uint160) *Royalty {
|
||||||
|
return &Royalty{*NewRoyaltyReader(actor, hash), RoyaltyWriter{BaseWriter{hash, actor}}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RoyaltyInfo retrieves the royalty information for a given token ID, including the recipient(s) and amount(s).
|
||||||
|
func (r *RoyaltyReader) RoyaltyInfo(tokenID []byte, royaltyToken util.Uint160, salePrice *big.Int) ([]RoyaltyInfoDetail, error) {
|
||||||
|
items, err := unwrap.Array(r.invoker.Call(r.hash, "RoyaltyInfo", tokenID, royaltyToken, salePrice))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
royaltyDetail, err := itemToRoyaltyInfoDetail(items)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to decode royalty detail: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return []RoyaltyInfoDetail{*royaltyDetail}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// itemToRoyaltyInfoDetail converts an array of stack items into a RoyaltyInfoDetail struct.
|
||||||
|
func itemToRoyaltyInfoDetail(items []stackitem.Item) (*RoyaltyInfoDetail, error) {
|
||||||
|
if len(items) != 2 {
|
||||||
|
return nil, fmt.Errorf("invalid structure: expected 2 items, got %d", len(items))
|
||||||
|
}
|
||||||
|
|
||||||
|
recipientBytes, err := items[0].TryBytes()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to decode RoyaltyRecipient: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate recipient byte size (should be 20 bytes for Uint160)
|
||||||
|
if len(recipientBytes) != 20 {
|
||||||
|
return nil, fmt.Errorf("invalid RoyaltyRecipient: expected byte size of 20, got %d", len(recipientBytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
recipient, err := util.Uint160DecodeBytesBE(recipientBytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid RoyaltyRecipient: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
amountBigInt, err := items[1].TryInteger()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to decode RoyaltyAmount: %w", err)
|
||||||
|
}
|
||||||
|
amount := big.NewInt(0).Set(amountBigInt)
|
||||||
|
|
||||||
|
return &RoyaltyInfoDetail{
|
||||||
|
RoyaltyRecipient: recipient,
|
||||||
|
RoyaltyAmount: amount,
|
||||||
|
}, 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)
|
||||||
|
}
|
||||||
|
if _, ok := arr[4].Value().(*big.Int); !ok {
|
||||||
|
return fmt.Errorf("invalid type for Amount: expected Integer, got %T", arr[4].Value())
|
||||||
|
}
|
||||||
|
e.Amount, err = arr[4].TryInteger()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to decode Amount: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
291
pkg/rpcclient/nep11/royalty_test.go
Normal file
291
pkg/rpcclient/nep11/royalty_test.go
Normal file
|
@ -0,0 +1,291 @@
|
||||||
|
package nep11
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"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"
|
||||||
|
)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
setupFunc func()
|
||||||
|
expectErr bool
|
||||||
|
expectedRI []RoyaltyInfoDetail
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "error case",
|
||||||
|
setupFunc: func() {
|
||||||
|
ta.err = errors.New("some error")
|
||||||
|
},
|
||||||
|
expectErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "valid response",
|
||||||
|
setupFunc: func() {
|
||||||
|
ta.err = nil
|
||||||
|
recipient := util.Uint160{7, 8, 9}
|
||||||
|
amount := big.NewInt(100)
|
||||||
|
ta.res = &result.Invoke{
|
||||||
|
State: "HALT",
|
||||||
|
Stack: []stackitem.Item{stackitem.Make([]stackitem.Item{
|
||||||
|
stackitem.Make(recipient.BytesBE()),
|
||||||
|
stackitem.Make(amount),
|
||||||
|
})},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
expectErr: false,
|
||||||
|
expectedRI: []RoyaltyInfoDetail{
|
||||||
|
{RoyaltyRecipient: util.Uint160{7, 8, 9}, RoyaltyAmount: big.NewInt(100)},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid data response",
|
||||||
|
setupFunc: func() {
|
||||||
|
ta.res = &result.Invoke{
|
||||||
|
State: "HALT",
|
||||||
|
Stack: []stackitem.Item{
|
||||||
|
stackitem.Make([]stackitem.Item{
|
||||||
|
stackitem.Make(util.Uint160{7, 8, 9}.BytesBE()),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
expectErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
tt.setupFunc()
|
||||||
|
ri, err := rr.RoyaltyInfo(tokenID, royaltyToken, salePrice)
|
||||||
|
if tt.expectErr {
|
||||||
|
require.Error(t, err)
|
||||||
|
} else {
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, tt.expectedRI, ri)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestItemToRoyaltyInfoDetail(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
items []stackitem.Item
|
||||||
|
expectErr bool
|
||||||
|
expected *RoyaltyInfoDetail
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "valid input",
|
||||||
|
items: []stackitem.Item{
|
||||||
|
stackitem.Make(util.Uint160{7, 8, 9}.BytesBE()),
|
||||||
|
stackitem.Make(big.NewInt(100)),
|
||||||
|
},
|
||||||
|
expectErr: false,
|
||||||
|
expected: &RoyaltyInfoDetail{
|
||||||
|
RoyaltyRecipient: util.Uint160{7, 8, 9},
|
||||||
|
RoyaltyAmount: big.NewInt(100),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid number of items",
|
||||||
|
items: []stackitem.Item{
|
||||||
|
stackitem.Make(util.Uint160{7, 8, 9}.BytesBE()),
|
||||||
|
},
|
||||||
|
expectErr: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid recipient size",
|
||||||
|
items: []stackitem.Item{
|
||||||
|
stackitem.Make([]byte{1, 2}),
|
||||||
|
stackitem.Make(big.NewInt(100)),
|
||||||
|
},
|
||||||
|
expectErr: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
ri, err := itemToRoyaltyInfoDetail(tt.items)
|
||||||
|
if tt.expectErr {
|
||||||
|
require.Error(t, err)
|
||||||
|
} else {
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, tt.expected, ri)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFromStackItem(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
item *stackitem.Array
|
||||||
|
expectErr bool
|
||||||
|
expected *RoyaltiesTransferredEvent
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "valid stack item",
|
||||||
|
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.NewBool(true)), // 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)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,7 +19,7 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
var checks = map[string][]*Standard{
|
var checks = map[string][]*Standard{
|
||||||
manifest.NEP11StandardName: {Nep11NonDivisible, Nep11Divisible},
|
manifest.NEP11StandardName: {Nep11NonDivisible, Nep11Divisible, Nep11WithRoyalty},
|
||||||
manifest.NEP17StandardName: {Nep17},
|
manifest.NEP17StandardName: {Nep17},
|
||||||
manifest.NEP11Payable: {Nep11Payable},
|
manifest.NEP11Payable: {Nep11Payable},
|
||||||
manifest.NEP17Payable: {Nep17Payable},
|
manifest.NEP17Payable: {Nep17Payable},
|
||||||
|
|
39
pkg/smartcontract/manifest/standard/nep24.go
Normal file
39
pkg/smartcontract/manifest/standard/nep24.go
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
package standard
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Nep11WithRoyalty is a NEP-24 Standard for NFT royalties.
|
||||||
|
var Nep11WithRoyalty = &Standard{
|
||||||
|
Base: Nep11Base,
|
||||||
|
Manifest: manifest.Manifest{
|
||||||
|
ABI: manifest.ABI{
|
||||||
|
Methods: []manifest.Method{
|
||||||
|
{
|
||||||
|
Name: "RoyaltyInfo",
|
||||||
|
Parameters: []manifest.Parameter{
|
||||||
|
{Name: "tokenId", Type: smartcontract.ByteArrayType},
|
||||||
|
{Name: "royaltyToken", Type: smartcontract.Hash160Type},
|
||||||
|
{Name: "salePrice", Type: smartcontract.IntegerType},
|
||||||
|
},
|
||||||
|
ReturnType: smartcontract.ArrayType,
|
||||||
|
Safe: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
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},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
|
@ -407,6 +407,9 @@ func Generate(cfg binding.Config) error {
|
||||||
} else if standard.ComplyABI(cfg.Manifest, standard.Nep11NonDivisible) == nil {
|
} else if standard.ComplyABI(cfg.Manifest, standard.Nep11NonDivisible) == nil {
|
||||||
mfst.ABI.Methods = dropStdMethods(mfst.ABI.Methods, standard.Nep11NonDivisible)
|
mfst.ABI.Methods = dropStdMethods(mfst.ABI.Methods, standard.Nep11NonDivisible)
|
||||||
ctr.IsNep11ND = true
|
ctr.IsNep11ND = true
|
||||||
|
} else if standard.ComplyABI(cfg.Manifest, standard.Nep11WithRoyalty) == nil {
|
||||||
|
mfst.ABI.Methods = dropStdMethods(mfst.ABI.Methods, standard.Nep11WithRoyalty)
|
||||||
|
ctr.IsNep11D = true
|
||||||
}
|
}
|
||||||
mfst.ABI.Events = dropStdEvents(mfst.ABI.Events, standard.Nep11Base)
|
mfst.ABI.Events = dropStdEvents(mfst.ABI.Events, standard.Nep11Base)
|
||||||
break // Can't be NEP-17 at the same time.
|
break // Can't be NEP-17 at the same time.
|
||||||
|
|
Loading…
Reference in a new issue