From d55456f3ac2065aac707ba2ce64c3e18cdcfe5f7 Mon Sep 17 00:00:00 2001
From: Evgenii Stratonikov <evgeniy@nspcc.ru>
Date: Tue, 12 Oct 2021 13:33:57 +0300
Subject: [PATCH] [#905] morph/client: handle latest NNS version

Signed-off-by: Evgenii Stratonikov <evgeniy@nspcc.ru>
---
 pkg/morph/client/nns.go | 51 +++++++++++++++++++++++++++++++++++------
 1 file changed, 44 insertions(+), 7 deletions(-)

diff --git a/pkg/morph/client/nns.go b/pkg/morph/client/nns.go
index 6b0a59be7..ede5bec17 100644
--- a/pkg/morph/client/nns.go
+++ b/pkg/morph/client/nns.go
@@ -1,11 +1,16 @@
 package client
 
 import (
+	"errors"
 	"fmt"
 	"strconv"
 
 	nns "github.com/nspcc-dev/neo-go/examples/nft-nd-nns"
+	"github.com/nspcc-dev/neo-go/pkg/rpc/client"
+	"github.com/nspcc-dev/neo-go/pkg/smartcontract"
 	"github.com/nspcc-dev/neo-go/pkg/util"
+	"github.com/nspcc-dev/neo-go/pkg/vm"
+	"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
 )
 
 const (
@@ -48,15 +53,47 @@ func (c *Client) NNSContractAddress(name string) (sh util.Uint160, err error) {
 		return sh, fmt.Errorf("NNS contract state: %w", err)
 	}
 
-	s, err := c.client.NNSResolve(cs.Hash, name, nns.TXT)
+	sh, err = nnsResolve(c.client, cs.Hash, name)
 	if err != nil {
 		return sh, fmt.Errorf("NNS.resolve: %w", err)
 	}
-
-	sh, err = util.Uint160DecodeStringLE(s)
-	if err != nil {
-		return sh, fmt.Errorf("NNS u160 decode: %w", err)
-	}
-
 	return sh, nil
 }
+
+func nnsResolve(c *client.Client, nnsHash util.Uint160, domain string) (util.Uint160, error) {
+	result, err := c.InvokeFunction(nnsHash, "resolve", []smartcontract.Parameter{
+		{
+			Type:  smartcontract.StringType,
+			Value: domain,
+		},
+		{
+			Type:  smartcontract.IntegerType,
+			Value: int64(nns.TXT),
+		},
+	}, nil)
+	if err != nil {
+		return util.Uint160{}, err
+	}
+	if result.State != vm.HaltState.String() {
+		return util.Uint160{}, fmt.Errorf("invocation failed: %s", result.FaultException)
+	}
+	if len(result.Stack) == 0 {
+		return util.Uint160{}, errors.New("result stack is empty")
+	}
+
+	// Parse the result of resolving NNS record.
+	// It works with multiple formats (corresponding to multiple NNS versions).
+	// If array of hashes is provided, it returns only the first one.
+	res := result.Stack[0]
+	if arr, ok := res.Value().([]stackitem.Item); ok {
+		if len(arr) == 0 {
+			return util.Uint160{}, errors.New("NNS record is missing")
+		}
+		res = arr[0]
+	}
+	bs, err := res.TryBytes()
+	if err != nil {
+		return util.Uint160{}, fmt.Errorf("malformed response: %w", err)
+	}
+	return util.Uint160DecodeStringLE(string(bs))
+}