public JObject GetNep17Balances(JArray _params)
        {
            UInt160 userScriptHash = GetScriptHashFromParam(_params[0].AsString());

            JObject json     = new JObject();
            JArray  balances = new JArray();

            json["balance"] = balances;
            json["address"] = userScriptHash.ToAddress(System.Settings.AddressVersion);

            using (Iterator it = _db.NewIterator(ReadOptions.Default))
            {
                byte[] prefix = Key(Nep17BalancePrefix, userScriptHash);
                for (it.Seek(prefix); it.Valid(); it.Next())
                {
                    ReadOnlySpan <byte> key_bytes = it.Key();
                    if (!key_bytes.StartsWith(prefix))
                    {
                        break;
                    }
                    Nep17BalanceKey key = key_bytes[1..].AsSerializable <Nep17BalanceKey>();
        private void HandleNotification(DataCache snapshot, IVerifiable scriptContainer, UInt160 scriptHash, string eventName,
                                        VM.Types.Array stateItems,
                                        Dictionary <Nep17BalanceKey, Nep17Balance> nep17BalancesChanged, ref ushort transferIndex)
        {
            if (stateItems.Count == 0)
            {
                return;
            }
            if (eventName != "Transfer")
            {
                return;
            }
            if (stateItems.Count < 3)
            {
                return;
            }

            if (!(stateItems[0].IsNull) && !(stateItems[0] is VM.Types.ByteString))
            {
                return;
            }
            if (!(stateItems[1].IsNull) && !(stateItems[1] is VM.Types.ByteString))
            {
                return;
            }
            var amountItem = stateItems[2];

            if (!(amountItem is VM.Types.ByteString || amountItem is VM.Types.Integer))
            {
                return;
            }
            byte[] fromBytes = stateItems[0].IsNull ? null : stateItems[0].GetSpan().ToArray();
            if (fromBytes != null && fromBytes.Length != UInt160.Length)
            {
                return;
            }
            byte[] toBytes = stateItems[1].IsNull ? null : stateItems[1].GetSpan().ToArray();
            if (toBytes != null && toBytes.Length != UInt160.Length)
            {
                return;
            }
            if (fromBytes == null && toBytes == null)
            {
                return;
            }

            var from = UInt160.Zero;
            var to   = UInt160.Zero;

            if (fromBytes != null)
            {
                from = new UInt160(fromBytes);
                var fromKey = new Nep17BalanceKey(from, scriptHash);
                if (!nep17BalancesChanged.ContainsKey(fromKey))
                {
                    nep17BalancesChanged.Add(fromKey, new Nep17Balance());
                }
            }

            if (toBytes != null)
            {
                to = new UInt160(toBytes);
                var toKey = new Nep17BalanceKey(to, scriptHash);
                if (!nep17BalancesChanged.ContainsKey(toKey))
                {
                    nep17BalancesChanged.Add(toKey, new Nep17Balance());
                }
            }
            if (scriptContainer is Transaction transaction)
            {
                RecordTransferHistory(snapshot, scriptHash, from, to, amountItem.GetInteger(), transaction.Hash, ref transferIndex);
            }
        }