mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-11-22 19:29:39 +00:00
Merge pull request #1950 from nspcc-dev/nep11/data
*: add `data` to NEP11 Transfer
This commit is contained in:
commit
ba5273999f
18 changed files with 163 additions and 100 deletions
|
@ -4,11 +4,13 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"os"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
||||
|
@ -267,16 +269,51 @@ func TestNEP11_OwnerOf_BalanceOf_Transfer(t *testing.T) {
|
|||
// transfer: no id specified
|
||||
e.In.WriteString(nftOwnerPass + "\r")
|
||||
e.RunWithError(t, cmdTransfer...)
|
||||
cmdTransfer = append(cmdTransfer, "--id", string(tokenID))
|
||||
|
||||
// transfer: good
|
||||
e.In.WriteString(nftOwnerPass + "\r")
|
||||
e.Run(t, cmdTransfer...)
|
||||
e.Run(t, append(cmdTransfer, "--id", string(tokenID))...)
|
||||
e.checkTxPersisted(t)
|
||||
|
||||
// check balance after transfer
|
||||
e.Run(t, append(cmdCheckBalance, "--token", h.StringLE())...)
|
||||
checkBalanceResult(t, nftOwnerAddr, "1") // tokenID1
|
||||
|
||||
// transfer: good, to NEP11-Payable contract, with data
|
||||
verifyH := deployVerifyContract(t, e)
|
||||
cmdTransfer = []string{
|
||||
"neo-go", "wallet", "nep11", "transfer",
|
||||
"--rpc-endpoint", "http://" + e.RPC.Addr,
|
||||
"--wallet", wall,
|
||||
"--to", verifyH.StringLE(),
|
||||
"--from", nftOwnerAddr,
|
||||
"--token", h.StringLE(),
|
||||
"--id", string(tokenID1),
|
||||
"string:some_data",
|
||||
}
|
||||
e.In.WriteString(nftOwnerPass + "\r")
|
||||
e.Run(t, cmdTransfer...)
|
||||
tx, _ := e.checkTxPersisted(t)
|
||||
// check OnNEP11Payment event
|
||||
aer, err := e.Chain.GetAppExecResults(tx.Hash(), trigger.Application)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 2, len(aer[0].Events))
|
||||
nftOwnerHash, err := address.StringToUint160(nftOwnerAddr)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, state.NotificationEvent{
|
||||
ScriptHash: verifyH,
|
||||
Name: "OnNEP11Payment",
|
||||
Item: stackitem.NewArray([]stackitem.Item{
|
||||
stackitem.NewByteArray(nftOwnerHash.BytesBE()),
|
||||
stackitem.NewBigInteger(big.NewInt(1)),
|
||||
stackitem.NewByteArray(tokenID1),
|
||||
stackitem.NewByteArray([]byte("some_data")),
|
||||
}),
|
||||
}, aer[0].Events[1])
|
||||
|
||||
// check balance after transfer
|
||||
e.Run(t, append(cmdCheckBalance, "--token", h.StringLE())...)
|
||||
checkBalanceResult(t, nftOwnerAddr, "0")
|
||||
}
|
||||
|
||||
func deployNFTContract(t *testing.T, e *executor) util.Uint160 {
|
||||
|
|
|
@ -86,7 +86,7 @@ func TestNEP17Balance(t *testing.T) {
|
|||
}
|
||||
|
||||
e.checkNextLine(t, "^\\s*$")
|
||||
addr4, err := address.StringToUint160("NTe3yHH5zsaEGvEHTsFRpCjTef6Aod4yb6") // deployed verify.go contract
|
||||
addr4, err := address.StringToUint160("NaZjSxmRZ4ErG2QEXCQMjjJfvAxMPiutmi") // deployed verify.go contract
|
||||
require.NoError(t, err)
|
||||
e.checkNextLine(t, "^Account "+address.Uint160ToString(addr4))
|
||||
e.checkEOF(t)
|
||||
|
|
12
cli/testdata/verify.go
vendored
12
cli/testdata/verify.go
vendored
|
@ -1,6 +1,9 @@
|
|||
package testdata
|
||||
|
||||
import "github.com/nspcc-dev/neo-go/pkg/interop"
|
||||
import (
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop"
|
||||
"github.com/nspcc-dev/neo-go/pkg/interop/runtime"
|
||||
)
|
||||
|
||||
func Verify() bool {
|
||||
return true
|
||||
|
@ -8,3 +11,10 @@ func Verify() bool {
|
|||
|
||||
func OnNEP17Payment(from interop.Hash160, amount int, data interface{}) {
|
||||
}
|
||||
|
||||
// OnNEP11Payment notifies about NEP11 payment. You don't call this method directly,
|
||||
// instead it's called by NEP11 contract when you transfer funds from your address
|
||||
// to the address of this NFT contract.
|
||||
func OnNEP11Payment(from interop.Hash160, amount int, token []byte, data interface{}) {
|
||||
runtime.Notify("OnNEP11Payment", from, amount, token, data)
|
||||
}
|
||||
|
|
11
cli/testdata/verify.yml
vendored
11
cli/testdata/verify.yml
vendored
|
@ -1 +1,12 @@
|
|||
name: Test verify
|
||||
Events:
|
||||
- name: OnNEP11Payment
|
||||
parameters:
|
||||
- name: from
|
||||
type: Hash160
|
||||
- name: amount
|
||||
type: Integer
|
||||
- name: tokenId
|
||||
type: ByteArray
|
||||
- name: data
|
||||
type: Any
|
||||
|
|
116
cli/testdata/wallet1_solo.json
vendored
116
cli/testdata/wallet1_solo.json
vendored
|
@ -1,84 +1,84 @@
|
|||
{
|
||||
"version": "3.0",
|
||||
"accounts": [
|
||||
"scrypt" : {
|
||||
"r" : 8,
|
||||
"p" : 8,
|
||||
"n" : 16384
|
||||
},
|
||||
"version" : "3.0",
|
||||
"accounts" : [
|
||||
{
|
||||
"address": "NTh9TnZTstvAePEYWDGLLxidBikJE24uTo",
|
||||
"key": "6PYL8Gnjsz4RBKX18jx5ZAQTDH7PKkZwEVjPKEkjNzCDNFE6TKZwaFLibL",
|
||||
"label": "",
|
||||
"contract": {
|
||||
"script": "DCECs2Ir9AF73+MXxYrtX0x1PyBrfbiWBG+n13S7xL9/jcJBdHR2qg==",
|
||||
"parameters": [
|
||||
"address" : "NTh9TnZTstvAePEYWDGLLxidBikJE24uTo",
|
||||
"label" : "",
|
||||
"lock" : false,
|
||||
"contract" : {
|
||||
"parameters" : [
|
||||
{
|
||||
"name": "parameter0",
|
||||
"type": "Signature"
|
||||
"type" : "Signature",
|
||||
"name" : "parameter0"
|
||||
}
|
||||
],
|
||||
"deployed": false
|
||||
"script" : "DCECs2Ir9AF73+MXxYrtX0x1PyBrfbiWBG+n13S7xL9/jcJBdHR2qg==",
|
||||
"deployed" : false
|
||||
},
|
||||
"lock": false,
|
||||
"isdefault": true
|
||||
"isdefault" : true,
|
||||
"key" : "6PYL8Gnjsz4RBKX18jx5ZAQTDH7PKkZwEVjPKEkjNzCDNFE6TKZwaFLibL"
|
||||
},
|
||||
{
|
||||
"address": "NgEisvCqr2h8wpRxQb7bVPWUZdbVCY8Uo6",
|
||||
"key": "6PYL8Gnjsz4RBKX18jx5ZAQTDH7PKkZwEVjPKEkjNzCDNFE6TKZwaFLibL",
|
||||
"label": "",
|
||||
"contract": {
|
||||
"script": "EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFEF7zmyl",
|
||||
"parameters": [
|
||||
"label" : "",
|
||||
"address" : "NgEisvCqr2h8wpRxQb7bVPWUZdbVCY8Uo6",
|
||||
"isdefault" : false,
|
||||
"key" : "6PYL8Gnjsz4RBKX18jx5ZAQTDH7PKkZwEVjPKEkjNzCDNFE6TKZwaFLibL",
|
||||
"contract" : {
|
||||
"parameters" : [
|
||||
{
|
||||
"name": "parameter0",
|
||||
"type": "Signature"
|
||||
"name" : "parameter0",
|
||||
"type" : "Signature"
|
||||
},
|
||||
{
|
||||
"name": "parameter1",
|
||||
"type": "Signature"
|
||||
"type" : "Signature",
|
||||
"name" : "parameter1"
|
||||
},
|
||||
{
|
||||
"name": "parameter2",
|
||||
"type": "Signature"
|
||||
"type" : "Signature",
|
||||
"name" : "parameter2"
|
||||
}
|
||||
],
|
||||
"deployed": false
|
||||
"deployed" : false,
|
||||
"script" : "EwwhAhA6f33QFlWFl/eWDSfFFqQ5T9loueZRVetLAT5AQEBuDCECp7xV/oaE4BGXaNEEujB5W9zIZhnoZK3SYVZyPtGFzWIMIQKzYiv0AXvf4xfFiu1fTHU/IGt9uJYEb6fXdLvEv3+NwgwhA9kMB99j5pDOd5EuEKtRrMlEtmhgI3tgjE+PgwnnHuaZFEF7zmyl"
|
||||
},
|
||||
"lock": false,
|
||||
"isdefault": false
|
||||
"lock" : false
|
||||
},
|
||||
{
|
||||
"address": "NNudMSGzEoktFzdYGYoNb3bzHzbmM1genF",
|
||||
"key": "6PYL8Gnjsz4RBKX18jx5ZAQTDH7PKkZwEVjPKEkjNzCDNFE6TKZwaFLibL",
|
||||
"label": "",
|
||||
"contract": {
|
||||
"script": "EQwhArNiK/QBe9/jF8WK7V9MdT8ga324lgRvp9d0u8S/f43CEUF7zmyl",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "parameter0",
|
||||
"type": "Signature"
|
||||
}
|
||||
],
|
||||
"deployed": false
|
||||
},
|
||||
"lock": false,
|
||||
"isdefault": false
|
||||
},
|
||||
{
|
||||
"address" : "NTe3yHH5zsaEGvEHTsFRpCjTef6Aod4yb6",
|
||||
"key" : "6PYSgdjUPVjo3ZJLg2CsheXnEZzyvUuSm4jCtXP6X7FT82sAQHWt2wpu5A",
|
||||
"address" : "NNudMSGzEoktFzdYGYoNb3bzHzbmM1genF",
|
||||
"label" : "",
|
||||
"contract" : {
|
||||
"script" : "VwEAEdsgQFcAA0A=",
|
||||
"deployed" : true,
|
||||
"parameters" : []
|
||||
"parameters" : [
|
||||
{
|
||||
"name" : "parameter0",
|
||||
"type" : "Signature"
|
||||
}
|
||||
],
|
||||
"deployed" : false,
|
||||
"script" : "EQwhArNiK/QBe9/jF8WK7V9MdT8ga324lgRvp9d0u8S/f43CEUF7zmyl"
|
||||
},
|
||||
"lock" : false,
|
||||
"isdefault" : false
|
||||
"isdefault" : false,
|
||||
"key" : "6PYL8Gnjsz4RBKX18jx5ZAQTDH7PKkZwEVjPKEkjNzCDNFE6TKZwaFLibL"
|
||||
},
|
||||
{
|
||||
"contract" : {
|
||||
"parameters" : [],
|
||||
"script" : "VwEAEdsgQFcAA0BXAQR4eXp7VBTAcAwOT25ORVAxMVBheW1lbnRoUEGVAW9hIUA=",
|
||||
"deployed" : true
|
||||
},
|
||||
"lock" : false,
|
||||
"isdefault" : false,
|
||||
"key" : "6PYVxVpeNjxGDFTTG61ARGy6mCz6fQsGm9qW2tsFW3ox1zM6KpCoWSE4PB",
|
||||
"address" : "NaZjSxmRZ4ErG2QEXCQMjjJfvAxMPiutmi",
|
||||
"label" : "acc"
|
||||
}
|
||||
],
|
||||
"scrypt": {
|
||||
"n": 16384,
|
||||
"r": 8,
|
||||
"p": 8
|
||||
},
|
||||
"extra": {
|
||||
"Tokens": null
|
||||
"extra" : {
|
||||
"Tokens" : null
|
||||
}
|
||||
}
|
|
@ -80,7 +80,7 @@ func newNEP11Commands() []cli.Command {
|
|||
{
|
||||
Name: "transfer",
|
||||
Usage: "transfer NEP11 tokens",
|
||||
UsageText: "transfer --wallet <path> --rpc-endpoint <node> --timeout <time> --from <addr> --to <addr> --token <hash-or-name> --id <token-id> [--amount string] [-- <cosigner1:Scope> [<cosigner2> [...]]]",
|
||||
UsageText: "transfer --wallet <path> --rpc-endpoint <node> --timeout <time> --from <addr> --to <addr> --token <hash-or-name> --id <token-id> [--amount string] [data] [-- <cosigner1:Scope> [<cosigner2> [...]]]",
|
||||
Action: transferNEP11,
|
||||
Flags: transferFlags,
|
||||
Description: `Transfers specified NEP11 token with optional cosigners list attached to
|
||||
|
@ -235,7 +235,7 @@ func transferNEP11(ctx *cli.Context) error {
|
|||
return transferNEP(ctx, manifest.NEP11StandardName)
|
||||
}
|
||||
|
||||
func signAndSendNEP11Transfer(ctx *cli.Context, c *client.Client, acc *wallet.Account, token, to util.Uint160, tokenID string, amount *big.Int, cosigners []client.SignerAccount) error {
|
||||
func signAndSendNEP11Transfer(ctx *cli.Context, c *client.Client, acc *wallet.Account, token, to util.Uint160, tokenID string, amount *big.Int, data interface{}, cosigners []client.SignerAccount) error {
|
||||
gas := flags.Fixed8FromContext(ctx, "gas")
|
||||
|
||||
var (
|
||||
|
@ -247,9 +247,9 @@ func signAndSendNEP11Transfer(ctx *cli.Context, c *client.Client, acc *wallet.Ac
|
|||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("bad account address: %w", err), 1)
|
||||
}
|
||||
tx, err = c.CreateNEP11TransferTx(acc, token, int64(gas), cosigners, from, to, amount, tokenID)
|
||||
tx, err = c.CreateNEP11TransferTx(acc, token, int64(gas), cosigners, from, to, amount, tokenID, data)
|
||||
} else {
|
||||
tx, err = c.CreateNEP11TransferTx(acc, token, int64(gas), cosigners, to, tokenID)
|
||||
tx, err = c.CreateNEP11TransferTx(acc, token, int64(gas), cosigners, to, tokenID, data)
|
||||
}
|
||||
if err != nil {
|
||||
return cli.NewExitError(err, 1)
|
||||
|
|
|
@ -549,13 +549,13 @@ func transferNEP(ctx *cli.Context, standard string) error {
|
|||
return cli.NewExitError(errors.New("token ID should be specified"), 1)
|
||||
}
|
||||
if amountArg == "" {
|
||||
return signAndSendNEP11Transfer(ctx, c, acc, token.Hash, to, tokenID, nil, cosignersAccounts)
|
||||
return signAndSendNEP11Transfer(ctx, c, acc, token.Hash, to, tokenID, nil, data, cosignersAccounts)
|
||||
}
|
||||
amount, err := fixedn.FromString(amountArg, int(token.Decimals))
|
||||
if err != nil {
|
||||
return cli.NewExitError(fmt.Errorf("invalid amount: %w", err), 1)
|
||||
}
|
||||
return signAndSendNEP11Transfer(ctx, c, acc, token.Hash, to, tokenID, amount, cosignersAccounts)
|
||||
return signAndSendNEP11Transfer(ctx, c, acc, token.Hash, to, tokenID, amount, data, cosignersAccounts)
|
||||
default:
|
||||
return cli.NewExitError(fmt.Errorf("unsupported token standard %s", standard), 1)
|
||||
}
|
||||
|
|
|
@ -181,10 +181,9 @@ func OwnerOf(token []byte) interop.Hash160 {
|
|||
return getOwnerOf(ctx, token)
|
||||
}
|
||||
|
||||
// Transfer token from its owner to another user, notice that it only has two
|
||||
// parameters because token owner can be deduced from token ID itself and RC1
|
||||
// implementation doesn't yet have 'data' parameter as in NEP-17 Transfer.
|
||||
func Transfer(to interop.Hash160, token []byte) bool {
|
||||
// Transfer token from its owner to another user, notice that it only has three
|
||||
// parameters because token owner can be deduced from token ID itself.
|
||||
func Transfer(to interop.Hash160, token []byte, data interface{}) bool {
|
||||
if len(to) != 20 {
|
||||
panic("invalid 'to' address")
|
||||
}
|
||||
|
@ -212,15 +211,15 @@ func Transfer(to interop.Hash160, token []byte) bool {
|
|||
setTokensOf(ctx, to, toksTo)
|
||||
setOwnerOf(ctx, token, to)
|
||||
}
|
||||
postTransfer(owner, to, token)
|
||||
postTransfer(owner, to, token, data)
|
||||
return true
|
||||
}
|
||||
|
||||
// postTransfer emits Transfer event and calls onNEP11Payment if needed.
|
||||
func postTransfer(from interop.Hash160, to interop.Hash160, token []byte) {
|
||||
func postTransfer(from interop.Hash160, to interop.Hash160, token []byte, data interface{}) {
|
||||
runtime.Notify("Transfer", from, to, 1, token)
|
||||
if management.GetContract(to) != nil {
|
||||
contract.Call(to, "onNEP11Payment", contract.All, from, 1, token)
|
||||
contract.Call(to, "onNEP11Payment", contract.All, from, 1, token, data)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -259,7 +258,7 @@ func OnNEP17Payment(from interop.Hash160, amount int, data interface{}) {
|
|||
total++
|
||||
storage.Put(ctx, []byte(totalSupplyPrefix), total)
|
||||
|
||||
postTransfer(nil, from, []byte(token))
|
||||
postTransfer(nil, from, []byte(token), nil) // no `data` during minting
|
||||
}
|
||||
|
||||
// Verify allows owner to manage contract's address, including earned GAS
|
||||
|
|
|
@ -108,13 +108,13 @@ func TestOnPayableChecks(t *testing.T) {
|
|||
t.Run("NEP-11, good", func(t *testing.T) {
|
||||
src := `package payable
|
||||
import "github.com/nspcc-dev/neo-go/pkg/interop"
|
||||
func OnNEP11Payment(from interop.Hash160, amount int, tokenID []byte) {}`
|
||||
func OnNEP11Payment(from interop.Hash160, amount int, tokenID []byte, data interface{}) {}`
|
||||
require.NoError(t, compileAndCheck(t, src))
|
||||
})
|
||||
t.Run("NEP-11, bad", func(t *testing.T) {
|
||||
src := `package payable
|
||||
import "github.com/nspcc-dev/neo-go/pkg/interop"
|
||||
func OnNEP11Payment(from interop.Hash160, amount int, oldParam string, tokenID []byte) {}`
|
||||
func OnNEP11Payment(from interop.Hash160, amount int, oldParam string, tokenID []byte, data interface{}) {}`
|
||||
require.Error(t, compileAndCheck(t, src))
|
||||
})
|
||||
t.Run("NEP-17, good", func(t *testing.T) {
|
||||
|
|
|
@ -169,7 +169,7 @@ func TestNativeHelpersCompile(t *testing.T) {
|
|||
{"properties", []string{`"neo.com"`}},
|
||||
{"tokens", nil},
|
||||
{"tokensOf", []string{u160}},
|
||||
{"transfer", []string{u160, `"neo.com"`}},
|
||||
{"transfer", []string{u160, `"neo.com"`, "nil"}},
|
||||
|
||||
// name service
|
||||
{"addRoot", []string{`"com"`}},
|
||||
|
|
|
@ -319,7 +319,7 @@ func getTestContractState(bc *Blockchain) (*state.Contract, *state.Contract) {
|
|||
emit.Opcodes(w.BinWriter, opcode.RET)
|
||||
onNEP11PaymentOff := w.Len()
|
||||
emit.Syscall(w.BinWriter, interopnames.SystemRuntimeGetCallingScriptHash)
|
||||
emit.Int(w.BinWriter, 4)
|
||||
emit.Int(w.BinWriter, 5)
|
||||
emit.Opcodes(w.BinWriter, opcode.PACK)
|
||||
emit.String(w.BinWriter, "LostPayment")
|
||||
emit.Syscall(w.BinWriter, interopnames.SystemRuntimeNotify)
|
||||
|
@ -454,6 +454,7 @@ func getTestContractState(bc *Blockchain) (*state.Contract, *state.Contract) {
|
|||
manifest.NewParameter("from", smartcontract.Hash160Type),
|
||||
manifest.NewParameter("amount", smartcontract.IntegerType),
|
||||
manifest.NewParameter("tokenid", smartcontract.ByteArrayType),
|
||||
manifest.NewParameter("data", smartcontract.AnyType),
|
||||
},
|
||||
ReturnType: smartcontract.VoidType,
|
||||
},
|
||||
|
|
|
@ -107,7 +107,8 @@ func newNonFungible(name string, id int32, symbol string, decimals byte) *nonfun
|
|||
|
||||
desc = newDescriptor("transfer", smartcontract.BoolType,
|
||||
manifest.NewParameter("to", smartcontract.Hash160Type),
|
||||
manifest.NewParameter("tokenId", smartcontract.ByteArrayType))
|
||||
manifest.NewParameter("tokenId", smartcontract.ByteArrayType),
|
||||
manifest.NewParameter("data", smartcontract.AnyType))
|
||||
md = newMethodAndPrice(n.transfer, 1<<17, callflag.States|callflag.AllowNotify)
|
||||
md.StorageFee = 50
|
||||
n.AddMethod(md, desc)
|
||||
|
@ -267,10 +268,10 @@ func (n *nonfungible) mint(ic *interop.Context, s nftTokenState) {
|
|||
ts := n.TotalSupply(ic.DAO)
|
||||
ts.Add(ts, intOne)
|
||||
n.setTotalSupply(ic.DAO, ts)
|
||||
n.postTransfer(ic, nil, &owner, s.ID())
|
||||
n.postTransfer(ic, nil, &owner, s.ID(), stackitem.Null{})
|
||||
}
|
||||
|
||||
func (n *nonfungible) postTransfer(ic *interop.Context, from, to *util.Uint160, tokenID []byte) {
|
||||
func (n *nonfungible) postTransfer(ic *interop.Context, from, to *util.Uint160, tokenID []byte, data stackitem.Item) {
|
||||
ne := state.NotificationEvent{
|
||||
ScriptHash: n.Hash,
|
||||
Name: "Transfer",
|
||||
|
@ -298,6 +299,7 @@ func (n *nonfungible) postTransfer(ic *interop.Context, from, to *util.Uint160,
|
|||
fromArg,
|
||||
stackitem.NewBigInteger(intOne),
|
||||
stackitem.NewByteArray(tokenID),
|
||||
data,
|
||||
}
|
||||
if err := contract.CallFromNative(ic, n.Hash, cs, manifest.MethodOnNEP11Payment, args, false); err != nil {
|
||||
panic(err)
|
||||
|
@ -332,7 +334,7 @@ func (n *nonfungible) burnByKey(ic *interop.Context, key []byte) {
|
|||
ts := n.TotalSupply(ic.DAO)
|
||||
ts.Sub(ts, intOne)
|
||||
n.setTotalSupply(ic.DAO, ts)
|
||||
n.postTransfer(ic, &owner, nil, id)
|
||||
n.postTransfer(ic, &owner, nil, id, stackitem.Null{})
|
||||
}
|
||||
|
||||
func (n *nonfungible) transfer(ic *interop.Context, args []stackitem.Item) stackitem.Item {
|
||||
|
@ -373,7 +375,7 @@ func (n *nonfungible) transfer(ic *interop.Context, args []stackitem.Item) stack
|
|||
acc.Add(tokenID)
|
||||
n.putAccountState(ic.DAO, key, acc)
|
||||
}
|
||||
n.postTransfer(ic, &from, &to, tokenID)
|
||||
n.postTransfer(ic, &from, &to, tokenID, args[2])
|
||||
return stackitem.NewBool(true)
|
||||
}
|
||||
|
||||
|
|
|
@ -270,11 +270,11 @@ func TestTransfer(t *testing.T) {
|
|||
testNameServiceInvokeAux(t, bc, defaultNameServiceSysfee, from, "setRecord", stackitem.Null{},
|
||||
"neo.com", int64(nnsrecords.A), "1.2.3.4")
|
||||
testNameServiceInvokeAux(t, bc, defaultRegisterSysfee, from, "transfer",
|
||||
nil, to.Contract.ScriptHash().BytesBE(), []byte("not.exists"))
|
||||
nil, to.Contract.ScriptHash().BytesBE(), []byte("not.exists"), nil)
|
||||
testNameServiceInvokeAux(t, bc, defaultRegisterSysfee, true, "transfer",
|
||||
false, to.Contract.ScriptHash().BytesBE(), []byte("neo.com"))
|
||||
false, to.Contract.ScriptHash().BytesBE(), []byte("neo.com"), nil)
|
||||
testNameServiceInvokeAux(t, bc, defaultRegisterSysfee, from, "transfer",
|
||||
true, to.Contract.ScriptHash().BytesBE(), []byte("neo.com"))
|
||||
true, to.Contract.ScriptHash().BytesBE(), []byte("neo.com"), nil)
|
||||
testNameServiceInvokeAux(t, bc, defaultNameServiceSysfee, from, "totalSupply", 1)
|
||||
testNameServiceInvokeAux(t, bc, defaultNameServiceSysfee, from, "ownerOf",
|
||||
to.Contract.ScriptHash().BytesBE(), []byte("neo.com"))
|
||||
|
@ -282,9 +282,9 @@ func TestTransfer(t *testing.T) {
|
|||
require.NoError(t, bc.contracts.Management.PutContractState(bc.dao, cs))
|
||||
require.NoError(t, bc.contracts.Management.PutContractState(bc.dao, cs2))
|
||||
testNameServiceInvokeAux(t, bc, defaultRegisterSysfee, to, "transfer",
|
||||
nil, cs2.Hash.BytesBE(), []byte("neo.com"))
|
||||
nil, cs2.Hash.BytesBE(), []byte("neo.com"), nil)
|
||||
testNameServiceInvokeAux(t, bc, defaultRegisterSysfee, to, "transfer",
|
||||
true, cs.Hash.BytesBE(), []byte("neo.com"))
|
||||
true, cs.Hash.BytesBE(), []byte("neo.com"), nil)
|
||||
testNameServiceInvokeAux(t, bc, defaultNameServiceSysfee, from, "totalSupply", 1)
|
||||
testNameServiceInvokeAux(t, bc, defaultNameServiceSysfee, from, "ownerOf",
|
||||
cs.Hash.BytesBE(), []byte("neo.com"))
|
||||
|
|
|
@ -67,9 +67,9 @@ func TokensOf(addr interop.Hash160) iterator.Iterator {
|
|||
}
|
||||
|
||||
// Transfer represents `transfer` method of NameService native contract.
|
||||
func Transfer(to interop.Hash160, tokenID string) bool {
|
||||
func Transfer(to interop.Hash160, tokenID string, data interface{}) bool {
|
||||
return contract.Call(interop.Hash160(Hash), "transfer",
|
||||
contract.ReadStates|contract.States|contract.AllowNotify, to, tokenID).(bool)
|
||||
contract.ReadStates|contract.States|contract.AllowNotify, to, tokenID, data).(bool)
|
||||
}
|
||||
|
||||
// AddRoot represents `addRoot` method of NameService native contract.
|
||||
|
|
|
@ -45,11 +45,11 @@ func (c *Client) NEP11TokenInfo(tokenHash util.Uint160) (*wallet.Token, error) {
|
|||
// on a given token to move the whole NEP11 token with the specified token ID to
|
||||
// given account and sends it to the network returning just a hash of it.
|
||||
func (c *Client) TransferNEP11(acc *wallet.Account, to util.Uint160,
|
||||
tokenHash util.Uint160, tokenID string, gas int64, cosigners []SignerAccount) (util.Uint256, error) {
|
||||
tokenHash util.Uint160, tokenID string, data interface{}, gas int64, cosigners []SignerAccount) (util.Uint256, error) {
|
||||
if !c.initDone {
|
||||
return util.Uint256{}, errNetworkNotInitialized
|
||||
}
|
||||
tx, err := c.CreateNEP11TransferTx(acc, tokenHash, gas, cosigners, to, tokenID)
|
||||
tx, err := c.CreateNEP11TransferTx(acc, tokenHash, gas, cosigners, to, tokenID, data)
|
||||
if err != nil {
|
||||
return util.Uint256{}, err
|
||||
}
|
||||
|
@ -62,8 +62,8 @@ func (c *Client) TransferNEP11(acc *wallet.Account, to util.Uint160,
|
|||
// of) NEP11 token with the specified token ID to given account and returns it.
|
||||
// The returned transaction is not signed. CreateNEP11TransferTx is also a
|
||||
// helper for TransferNEP11 and TransferNEP11D.
|
||||
// `args` for TransferNEP11: to util.Uint160, tokenID string;
|
||||
// `args` for TransferNEP11D: from, to util.Uint160, amount int64, tokenID string.
|
||||
// `args` for TransferNEP11: to util.Uint160, tokenID string, data interface{};
|
||||
// `args` for TransferNEP11D: from, to util.Uint160, amount int64, tokenID string, data interface{}.
|
||||
func (c *Client) CreateNEP11TransferTx(acc *wallet.Account, tokenHash util.Uint160,
|
||||
gas int64, cosigners []SignerAccount, args ...interface{}) (*transaction.Transaction, error) {
|
||||
w := io.NewBufBinWriter()
|
||||
|
@ -143,7 +143,7 @@ func (c *Client) NEP11NDOwnerOf(tokenHash util.Uint160, tokenID string) (util.Ui
|
|||
// (in FixedN format using contract's number of decimals) to given account and
|
||||
// sends it to the network returning just a hash of it.
|
||||
func (c *Client) TransferNEP11D(acc *wallet.Account, to util.Uint160,
|
||||
tokenHash util.Uint160, amount int64, tokenID string, gas int64, cosigners []SignerAccount) (util.Uint256, error) {
|
||||
tokenHash util.Uint160, amount int64, tokenID string, data interface{}, gas int64, cosigners []SignerAccount) (util.Uint256, error) {
|
||||
if !c.initDone {
|
||||
return util.Uint256{}, errNetworkNotInitialized
|
||||
}
|
||||
|
@ -151,7 +151,7 @@ func (c *Client) TransferNEP11D(acc *wallet.Account, to util.Uint160,
|
|||
if err != nil {
|
||||
return util.Uint256{}, fmt.Errorf("bad account address: %w", err)
|
||||
}
|
||||
tx, err := c.CreateNEP11TransferTx(acc, tokenHash, gas, cosigners, from, to, amount, tokenID)
|
||||
tx, err := c.CreateNEP11TransferTx(acc, tokenHash, gas, cosigners, from, to, amount, tokenID, data)
|
||||
if err != nil {
|
||||
return util.Uint256{}, err
|
||||
}
|
||||
|
|
|
@ -834,7 +834,7 @@ func TestClient_NEP11(t *testing.T) {
|
|||
require.EqualValues(t, expected, p)
|
||||
})
|
||||
t.Run("Transfer", func(t *testing.T) {
|
||||
_, err := c.TransferNEP11(wallet.NewAccountFromPrivateKey(testchain.PrivateKeyByID(0)), testchain.PrivateKeyByID(1).GetScriptHash(), h, "neo.com", 0, nil)
|
||||
_, err := c.TransferNEP11(wallet.NewAccountFromPrivateKey(testchain.PrivateKeyByID(0)), testchain.PrivateKeyByID(1).GetScriptHash(), h, "neo.com", nil, 0, nil)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ var nep11Base = &Standard{
|
|||
Parameters: []manifest.Parameter{
|
||||
{Name: "to", Type: smartcontract.Hash160Type},
|
||||
{Name: "tokenId", Type: smartcontract.ByteArrayType},
|
||||
{Name: "data", Type: smartcontract.AnyType},
|
||||
},
|
||||
ReturnType: smartcontract.BoolType,
|
||||
},
|
||||
|
@ -112,6 +113,7 @@ var nep11Divisible = &Standard{
|
|||
{Name: "to", Type: smartcontract.Hash160Type},
|
||||
{Name: "amount", Type: smartcontract.IntegerType},
|
||||
{Name: "tokenId", Type: smartcontract.ByteArrayType},
|
||||
{Name: "data", Type: smartcontract.AnyType},
|
||||
},
|
||||
ReturnType: smartcontract.BoolType,
|
||||
},
|
||||
|
|
|
@ -14,6 +14,7 @@ var nep11payable = &Standard{
|
|||
{Name: "from", Type: smartcontract.Hash160Type},
|
||||
{Name: "amount", Type: smartcontract.IntegerType},
|
||||
{Name: "tokenid", Type: smartcontract.ByteArrayType},
|
||||
{Name: "data", Type: smartcontract.AnyType},
|
||||
},
|
||||
ReturnType: smartcontract.VoidType,
|
||||
}},
|
||||
|
|
Loading…
Reference in a new issue