From cd9b34416e2cf13b9d570f11653d3b3626f7b153 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Fri, 5 Feb 2021 16:18:08 +0300 Subject: [PATCH] native: call onNEP11Transfer for NEP-11 transfers See neo-project/neo#2287. --- pkg/core/interop_system_test.go | 21 +++++++++++++++++++-- pkg/core/native/nonfungible.go | 21 +++++++++++++++++++++ pkg/core/native_name_service_test.go | 10 ++++++++++ pkg/smartcontract/manifest/manifest.go | 3 +++ 4 files changed, 53 insertions(+), 2 deletions(-) diff --git a/pkg/core/interop_system_test.go b/pkg/core/interop_system_test.go index 574a7d3ad..27d8247ba 100644 --- a/pkg/core/interop_system_test.go +++ b/pkg/core/interop_system_test.go @@ -340,13 +340,20 @@ func getTestContractState(bc *Blockchain) (*state.Contract, *state.Contract) { emit.Syscall(w.BinWriter, interopnames.SystemStorageGetContext) emit.Syscall(w.BinWriter, interopnames.SystemStorageGet) emit.Opcodes(w.BinWriter, opcode.RET) - onPaymentOff := w.Len() + onNEP17PaymentOff := w.Len() emit.Syscall(w.BinWriter, interopnames.SystemRuntimeGetCallingScriptHash) emit.Int(w.BinWriter, 4) emit.Opcodes(w.BinWriter, opcode.PACK) emit.String(w.BinWriter, "LastPayment") emit.Syscall(w.BinWriter, interopnames.SystemRuntimeNotify) emit.Opcodes(w.BinWriter, opcode.RET) + onNEP11PaymentOff := w.Len() + emit.Syscall(w.BinWriter, interopnames.SystemRuntimeGetCallingScriptHash) + emit.Int(w.BinWriter, 4) + emit.Opcodes(w.BinWriter, opcode.PACK) + emit.String(w.BinWriter, "LostPayment") + emit.Syscall(w.BinWriter, interopnames.SystemRuntimeNotify) + emit.Opcodes(w.BinWriter, opcode.RET) update3Off := w.Len() emit.Int(w.BinWriter, 3) emit.Opcodes(w.BinWriter, opcode.JMP, 2+1) @@ -455,9 +462,19 @@ func getTestContractState(bc *Blockchain) (*state.Contract, *state.Contract) { }, ReturnType: smartcontract.VoidType, }, + { + Name: manifest.MethodOnNEP11Payment, + Offset: onNEP11PaymentOff, + Parameters: []manifest.Parameter{ + manifest.NewParameter("from", smartcontract.Hash160Type), + manifest.NewParameter("amount", smartcontract.IntegerType), + manifest.NewParameter("tokenid", smartcontract.ByteArrayType), + }, + ReturnType: smartcontract.VoidType, + }, { Name: manifest.MethodOnNEP17Payment, - Offset: onPaymentOff, + Offset: onNEP17PaymentOff, Parameters: []manifest.Parameter{ manifest.NewParameter("from", smartcontract.Hash160Type), manifest.NewParameter("amount", smartcontract.IntegerType), diff --git a/pkg/core/native/nonfungible.go b/pkg/core/native/nonfungible.go index 36826506f..902287d92 100644 --- a/pkg/core/native/nonfungible.go +++ b/pkg/core/native/nonfungible.go @@ -8,6 +8,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/core/dao" "github.com/nspcc-dev/neo-go/pkg/core/interop" + "github.com/nspcc-dev/neo-go/pkg/core/interop/contract" "github.com/nspcc-dev/neo-go/pkg/core/interop/runtime" istorage "github.com/nspcc-dev/neo-go/pkg/core/interop/storage" "github.com/nspcc-dev/neo-go/pkg/core/state" @@ -277,6 +278,26 @@ func (n *nonfungible) postTransfer(ic *interop.Context, from, to *util.Uint160, }), } ic.Notifications = append(ic.Notifications, ne) + if to == nil { + return + } + cs, err := ic.GetContract(*to) + if err != nil { + return + } + + fromArg := stackitem.Item(stackitem.Null{}) + if from != nil { + fromArg = stackitem.NewByteArray((*from).BytesBE()) + } + args := []stackitem.Item{ + fromArg, + stackitem.NewBigInteger(intOne), + stackitem.NewByteArray(tokenID), + } + if err := contract.CallFromNative(ic, n.Hash, cs, manifest.MethodOnNEP11Payment, args, false); err != nil { + panic(err) + } } func (n *nonfungible) burn(ic *interop.Context, tokenID []byte) { diff --git a/pkg/core/native_name_service_test.go b/pkg/core/native_name_service_test.go index 2042ee55a..1ffd822e4 100644 --- a/pkg/core/native_name_service_test.go +++ b/pkg/core/native_name_service_test.go @@ -287,6 +287,16 @@ func TestTransfer(t *testing.T) { testNameServiceInvokeAux(t, bc, defaultNameServiceSysfee, from, "totalSupply", 1) testNameServiceInvokeAux(t, bc, defaultNameServiceSysfee, from, "ownerOf", to.Contract.ScriptHash().BytesBE(), []byte("neo.com")) + cs, cs2 := getTestContractState(bc) // cs2 doesn't have OnNEP11Transfer + 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")) + testNameServiceInvokeAux(t, bc, defaultRegisterSysfee, to, "transfer", + true, cs.Hash.BytesBE(), []byte("neo.com")) + testNameServiceInvokeAux(t, bc, defaultNameServiceSysfee, from, "totalSupply", 1) + testNameServiceInvokeAux(t, bc, defaultNameServiceSysfee, from, "ownerOf", + cs.Hash.BytesBE(), []byte("neo.com")) } func TestTokensOf(t *testing.T) { diff --git a/pkg/smartcontract/manifest/manifest.go b/pkg/smartcontract/manifest/manifest.go index dc9a07640..b622ab33d 100644 --- a/pkg/smartcontract/manifest/manifest.go +++ b/pkg/smartcontract/manifest/manifest.go @@ -24,6 +24,9 @@ const ( // MethodOnNEP17Payment is name of the method which is called when contract receives NEP-17 tokens. MethodOnNEP17Payment = "onNEP17Payment" + // MethodOnNEP11Payment is the name of the method which is called when contract receives NEP-11 tokens. + MethodOnNEP11Payment = "onNEP11Payment" + // NEP10StandardName represents the name of NEP10 smartcontract standard. NEP10StandardName = "NEP-10" // NEP17StandardName represents the name of NEP17 smartcontract standard.