public async Task <TxDetails> LoadTxDetails(string txid, NeblioAccount account)
    {
        var tinfo = await NeblioTransactionHelpers.GetTransactionInfo(txid);

        string sender = await NeblioTransactionHelpers.GetTransactionSender(txid, tinfo);

        bool fromAnotherAccount = true;
        bool fromSubAccount     = true;

        if (sender == account.Address)
        {
            sender             = "Main Account";
            fromAnotherAccount = false;
            fromSubAccount     = false;
        }
        else if (account.SubAccounts.TryGetValue(sender, out var sacc))
        {
            if (!string.IsNullOrEmpty(sacc.Name))
            {
                sender = sacc.Name;
            }
            else
            {
                sender = sacc.BookmarkFromAccount.Name;
            }
            fromAnotherAccount = false;
            fromSubAccount     = true;
        }

        string rec = await NeblioTransactionHelpers.GetTransactionReceiver(txid, tinfo);

        string receiver = string.Empty;
        var    recbkm   = account.IsInTheBookmarks(rec);

        if (rec == account.Address)
        {
            receiver = "Main Account";
        }
        else if (recbkm.Item1)
        {
            receiver = recbkm.Item2.Name;
        }

        if (string.IsNullOrEmpty(receiver))
        {
            receiver = NeblioTransactionHelpers.ShortenAddress(rec);
        }

        var time = TimeHelpers.UnixTimestampToDateTime((double)tinfo.Blocktime);

        return(new TxDetails()
        {
            FromAnotherAccount = fromAnotherAccount,
            FromSubAccount = fromSubAccount,
            Info = tinfo,
            Receiver = receiver,
            Sender = sender,
            Time = time,
        });
    }
        /// <summary>
        /// Load info about the Utxo
        /// </summary>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public async Task LoadInfo()
        {
            if (string.IsNullOrEmpty(Utxo.Txid))
            {
                throw new Exception("Cannot load Info. Utxo txid is empty.");
            }

            TokenInfo.Clear();
            TotalTokens = 0;
            if (Utxo.Tokens.Count > 0)
            {
                foreach (var tok in Utxo.Tokens)
                {
                    var ti = await NeblioTransactionHelpers.GetTokenMetadata(tok.TokenId);

                    if (ti != null)
                    {
                        TokenInfo.Add(ti);
                        TotalTokens += (int)tok.Amount;
                    }
                }
            }

            TxInfo = await NeblioTransactionHelpers.GetTransactionInfo(Utxo.Txid);
        }
Ejemplo n.º 3
0
        private static async Task GetTxDetails()
        {
            Console.WriteLine("Input Tx Id Hash");
            var txid   = Console.ReadLine();
            var txinfo = await NeblioTransactionHelpers.GetTransactionInfo(txid);

            // sign it with loaded account
            Console.WriteLine("Timestamp");
            Console.WriteLine(TimeHelpers.UnixTimestampToDateTime((double)txinfo.Blocktime));
            Console.WriteLine("Number of confirmations: ");
            Console.WriteLine(txinfo.Confirmations);
            Console.WriteLine("--------------");
            Console.WriteLine("Vins:");
            txinfo.Vin.ToList().ForEach(v => {
                Console.WriteLine($"Vin of value: {v.ValueSat} Nebl sat. from txid: {v.Txid} and vout index {v.Vout}");
            });
            Console.WriteLine("-------------");
            Console.WriteLine("--------------");
            Console.WriteLine("Vouts:");
            txinfo.Vout.ToList().ForEach(v => {
                Console.WriteLine($"Vout index {v.N} of value: {v.Value} Nebl sat. to receiver scrupt pub key {v.ScriptPubKey?.Addresses?.FirstOrDefault()}");
            });
            Console.WriteLine("-------------");
        }
        public static async Task <VerifyNFTTicketDto> LoadNFTTicketToVerify(OwnershipVerificationCodeDto dto, string eventId, List <string> allowedMintingAddresses)
        {
            if (string.IsNullOrEmpty(dto.TxId))
            {
                throw new Exception("Utxo id must be provided.");
            }
            if (string.IsNullOrEmpty(dto.Signature))
            {
                throw new Exception("Signature id must be provided.");
            }
            if (string.IsNullOrEmpty(eventId))
            {
                throw new Exception("Event Id must be provided.");
            }
            if (allowedMintingAddresses == null || allowedMintingAddresses.Count == 0)
            {
                throw new Exception("You must provide list of allowed minting addresses.");
            }

            var msg = CreateMessage(dto.TxId); // create verification message ASAP because of time relation

            var txi = await NeblioTransactionHelpers.GetTransactionInfo(dto.TxId);

            var  Time = TimeHelpers.UnixTimestampToDateTime((double)txi.Blocktime);
            bool isYesterdayOrOlder = DateTime.Today - Time.Date >= TimeSpan.FromDays(1);

            if (isYesterdayOrOlder)
            {
                throw new Exception("This ticket was used earlier than today. Or it is not used at all.");
            }

            var metadata = await NeblioTransactionHelpers.GetTransactionMetadata(NFTHelpers.TokenId, dto.TxId);

            if (metadata.TryGetValue("NFT", out var isnft))
            {
                if (isnft != "true")
                {
                    throw new Exception("This is not NFT");
                }
            }
            if (metadata.TryGetValue("Type", out var type))
            {
                if (type != "NFT Ticket")
                {
                    throw new Exception("This is not NFT Ticket");
                }
            }
            if (metadata.TryGetValue("EventId", out var nfteventId))
            {
                if (nfteventId != eventId)
                {
                    throw new Exception("Event Id on the ticket does not match the requested.");
                }
            }
            if (metadata.TryGetValue("Used", out var used))
            {
                if (used != "true")
                {
                    throw new Exception("This NFT Ticket is not used.");
                }
            }
            else
            {
                throw new Exception("This NFT Ticket is not used.");
            }

            var tx = Transaction.Parse(txi.Hex, NeblioTransactionHelpers.Network);

            var outDto = new VerifyNFTTicketDto();

            if (tx != null && tx.Outputs.Count > 0 && tx.Inputs.Count > 0)
            {
                var outp = tx.Outputs[0];
                var inpt = tx.Inputs[0];
                if (outp != null && inpt != null)
                {
                    var scr  = outp.ScriptPubKey;
                    var add  = scr.GetDestinationAddress(NeblioTransactionHelpers.Network);
                    var addi = inpt.ScriptSig.GetSignerAddress(NeblioTransactionHelpers.Network);
                    if (add != addi)
                    {
                        throw new Exception("This ticket was not used on this address.");
                    }
                    var pubkey = inpt.ScriptSig.GetAllPubKeys().FirstOrDefault();
                    if (pubkey == null)
                    {
                        throw new Exception("Cannot Load the owner Public Key.");
                    }

                    // verify of the signature of the NFT
                    var verres = await ECDSAProvider.VerifyMessage(msg, dto.Signature, pubkey);

                    //var vmsg = await ECDSAProvider.VerifyMessage(msg, dto.Signature, pubkey);
                    if (!verres.Item1)
                    {
                        throw new Exception("Signature of the NFT is not valid.");
                    }

                    // check if the NFT is still as utxo on the address
                    var utxos = await NeblioTransactionHelpers.GetAddressUtxosObjects(add.ToString());

                    if (utxos.FirstOrDefault(u => (u.Txid == dto.TxId && u.Value == 10000 && u.Tokens.Count > 0 && u.Tokens.FirstOrDefault()?.Amount == 1)) == null)
                    {
                        throw new Exception("This ticket is not available on the address as spendable.");
                    }

                    // check if in previous transaction the ticket was unused
                    var prevmeta = await NeblioTransactionHelpers.GetTransactionMetadata(NFTHelpers.TokenId, inpt.PrevOut.Hash.ToString());

                    if (prevmeta.TryGetValue("NFT", out var isprevnft))
                    {
                        if (isprevnft != "true")
                        {
                            throw new Exception("This is not NFT");
                        }
                    }
                    if (prevmeta.TryGetValue("Type", out var prevtype))
                    {
                        if (prevtype != "NFT Ticket")
                        {
                            throw new Exception("This is not NFT Ticket");
                        }
                    }
                    if (prevmeta.TryGetValue("EventId", out var prevnfteventId))
                    {
                        if (prevnfteventId != eventId)
                        {
                            throw new Exception("Event Id on the ticket does not match the requested.");
                        }
                    }
                    if (prevmeta.TryGetValue("Used", out var prevused))
                    {
                        if (prevused == "true")
                        {
                            throw new Exception("This NFT Ticket was already used in previous transaction.");
                        }
                    }

                    // todo track origin for check minting address
                    var res = await VerifyNFTTicketOrigin(inpt.PrevOut.Hash.ToString(), eventId, allowedMintingAddresses);

                    if (!res.Item1)
                    {
                        throw new Exception($"Ticket was not minted on allowed address. The origin is from: {res.Item2.Item2}");
                    }
                    outDto.IsMintedByAllowedAddress = true;
                    outDto.MintAddress = res.Item2.Item2;

                    var nft = new TicketNFT("");
                    await nft.LoadLastData(metadata); // fill with already loaded the newest NFT metadata

                    nft.Time = Time;
                    outDto.IsSignatureValid = true;
                    outDto.NFT                 = nft;
                    outDto.OwnerAddress        = add.ToString();
                    outDto.IsUsedOnSameAddress = true;
                    outDto.OwnerPubKey         = pubkey;
                    outDto.TxId                = dto.TxId;
                }
            }

            return(outDto);
        }
        public static async Task <(bool, (string, string))> VerifyNFTTicketOrigin(string txid, string eventId, List <string> allowedMintingAddresses)
        {
            var found          = false;
            var intxid         = txid;
            var mintingAddress = string.Empty;

            while (!found)
            {
                var info = await NeblioTransactionHelpers.GetTransactionInfo(intxid);

                if (info != null && info.Vin != null && info.Vin.Count > 0)
                {
                    var vin = info.Vin.ToArray()?[0];
                    if (vin.Tokens != null && vin.Tokens.Count > 0)
                    {
                        var vintok = vin.Tokens.ToArray()?[0];
                        if (vintok != null)
                        {
                            var meta = await NeblioTransactionHelpers.GetTransactionMetadata(NFTHelpers.TokenId, intxid);

                            if (meta.TryGetValue("NFT", out var isnft))
                            {
                                if (isnft != "true")
                                {
                                    throw new Exception("This is not NFT");
                                }
                            }
                            if (meta.TryGetValue("Type", out var type))
                            {
                                if (type != "NFT Ticket")
                                {
                                    throw new Exception("This is not NFT Ticket");
                                }
                            }
                            if (meta.TryGetValue("EventId", out var nfteventId))
                            {
                                if (nfteventId != eventId)
                                {
                                    throw new Exception($"Event Id on the ticket does not match the requested. Found during search for origin. Explored TxId {intxid}.");
                                }
                            }
                            if (meta.TryGetValue("Used", out var used))
                            {
                                if (used == "true")
                                {
                                    throw new Exception($"This NFT Ticket is already used. Found during search for origin. Used TxId {intxid}.");
                                }
                            }

                            if (vintok.Amount > 1)
                            {
                                mintingAddress = vin.PreviousOutput.Addresses.ToArray()?[0];
                                if (!string.IsNullOrEmpty(mintingAddress))
                                {
                                    if (allowedMintingAddresses.Contains(mintingAddress))
                                    {
                                        return(true, (intxid, mintingAddress));
                                    }
                                }
                                found = true;
                            }
                            else if (vintok.Amount == 1)
                            {
                                intxid = vin.Txid;
                            }
                        }
                    }
                }
            }

            return(false, (intxid, mintingAddress));
        }
        private async Task CheckNeblioPayments()
        {
            if (VEDLDataContext.Accounts.TryGetValue(ConnectedNeblioAccountAddress, out var account))
            {
                var utxos = new NeblioAPI.Utxos[account.Utxos.Count];
                lock (_lock)
                {
                    account.Utxos.CopyTo(utxos);
                }

                var completedOrdersUtxos = new List <NeblioAPI.Utxos>();

                foreach (var u in utxos)
                {
                    if (u != null)
                    {
                        var info = await NeblioTransactionHelpers.GetTransactionInfo(u.Txid);

                        if (info != null && info.Confirmations > 1)
                        {
                            var msg = NeblioTransactionHelpers.ParseNeblioMessage(info);
                            if (msg.Item1)
                            {
                                //var split = msg.Item2.Split('-');
                                var ordkey = msg.Item2;
                                if (!string.IsNullOrEmpty(ordkey))
                                {
                                    if (Orders.TryGetValue(ordkey, out var ord))
                                    {
                                        if (ord.statusclass == OrderStatus.pending && ord.currency == "NBL")
                                        {
                                            Console.WriteLine($"Order {ord.id}, {ord.order_key} received Neblio payment in value {u.Value}.");
                                            try
                                            {
                                                if (((double)u.Value / NeblioTransactionHelpers.FromSatToMainRatio) >= Convert.ToDouble(ord.total, CultureInfo.InvariantCulture))
                                                {
                                                    Console.WriteLine($"Order {ord.id}, {ord.order_key} payment has correct amount and it is moved to processing state.");
                                                    if (AllowDispatchNFTOrders)
                                                    {
                                                        var add = await GetNeblioAddressFromOrderMetadata(ord);

                                                        if (add.Item1)
                                                        {
                                                            Console.WriteLine($"Order {ord.id}, {ord.order_key} Neblio Address in the order is correct.");
                                                            ord.statusclass    = OrderStatus.processing;
                                                            ord.transaction_id = $"{u.Txid}:{u.Index}";
                                                            ord.date_paid      = TimeHelpers.UnixTimestampToDateTime((double)u.Blocktime);
                                                            var o = await UpdateOrder(ord);
                                                        }
                                                    }
                                                    else
                                                    {
                                                        ord.statusclass    = OrderStatus.processing;
                                                        ord.transaction_id = $"{u.Txid}:{u.Index}";
                                                        ord.date_paid      = TimeHelpers.UnixTimestampToDateTime((double)u.Blocktime);
                                                        var o = await UpdateOrder(ord);
                                                    }
                                                }
                                                else
                                                {
                                                    if (((double)u.Value / NeblioTransactionHelpers.FromSatToMainRatio) > 0.009)
                                                    {
                                                        Console.WriteLine($"Order {ord.id}, {ord.order_key} payment is not correct amount. It is sent back to the sender.");
                                                        var done     = false;
                                                        var attempts = 50;
                                                        while (!done)
                                                        {
                                                            try
                                                            {
                                                                var nres = await account.SendNeblioPayment(account.Address,
                                                                                                           ((double)u.Value / NeblioTransactionHelpers.FromSatToMainRatio) - 0.0002,
                                                                                                           $"Order {ord.order_key} cannot be processed. Wrong sent amount.");

                                                                done = nres.Item1;
                                                                if (done)
                                                                {
                                                                    Console.WriteLine($"Order {ord.id}, {ord.order_key} incorrect received payment sent back with txid: {nres.Item2}");
                                                                    ord.meta_data.Add(new ProductMetadata()
                                                                    {
                                                                        key = "Incorrect Received Payment", value = $"Neblio-{nres.Item2}"
                                                                    });
                                                                    var o = await UpdateOrder(ord);
                                                                }
                                                                if (!nres.Item1)
                                                                {
                                                                    await Task.Delay(5000);
                                                                }
                                                            }
                                                            catch
                                                            {
                                                                await Task.Delay(5000);
                                                            }
                                                            attempts--;
                                                            if (attempts < 0)
                                                            {
                                                                break;
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                            catch (Exception ex)
                                            {
                                                Console.WriteLine("Cannot send update of the order." + ex.Message);
                                            }
                                        }
                                        else if (ord.statusclass == OrderStatus.completed &&
                                                 completedOrdersUtxos.Count <= 10 &&
                                                 !string.IsNullOrEmpty(ConnectedDepositNeblioAccountAddress))
                                        {
                                            completedOrdersUtxos.Add(u);
                                        }
                                    }
                                }
                            }
                        }
                    }

                    await Task.Delay(50);//wait at least 50ms before next request to the api.
                }

                if (completedOrdersUtxos.Count > 5 && !string.IsNullOrEmpty(ConnectedDepositNeblioAccountAddress))
                {
                    var totalAmount = 0.0;
                    foreach (var cu in completedOrdersUtxos)
                    {
                        totalAmount += Convert.ToDouble(cu.Value, CultureInfo.InvariantCulture);
                    }
                    if (totalAmount >= 3)
                    {
                        Console.WriteLine($"Sending completed orders payments Utxos to deposit address.");
                        Console.WriteLine($"Total amount is {totalAmount} - 0.0002 Neblio for the fee.");
                        var done     = false;
                        var attempts = 50;
                        while (!done)
                        {
                            try
                            {
                                var dres = await account.SendMultipleInputNeblioPayment(ConnectedDepositNeblioAccountAddress,
                                                                                        totalAmount - 0.0002,
                                                                                        completedOrdersUtxos,
                                                                                        $"Transfer of completed orders payment.");

                                done = dres.Item1;
                                if (done)
                                {
                                    completedOrdersUtxos.Clear();
                                    Console.WriteLine($"Paymenents for completed orders transfered with txid: {dres.Item2}");
                                }
                                if (!dres.Item1)
                                {
                                    await Task.Delay(5000);
                                }
                            }
                            catch
                            {
                                await Task.Delay(5000);
                            }
                            attempts--;
                            if (attempts < 0)
                            {
                                break;
                            }
                        }
                    }
                }
            }
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Load the NFT based on the data from the cache
        /// </summary>
        /// <param name="metadata">Metadata from cache of NFTs</param>
        /// <param name="utxo">Utxo of the NFT</param>
        /// <param name="utxoindex">Utxo Index of the NFT</param>
        /// <param name="txinfo">preloaded txinfo</param>
        /// <param name="asType">Force the output type</param>
        /// <param name="type">Specify the output type - you must set asType flag</param>
        /// <returns>INFT compatible object</returns>
        public static async Task <INFT> GetNFTFromCacheMetadata(IDictionary <string, string> metadata, string utxo, int utxoindex, NeblioAPI.GetTransactionInfoResponse txinfo = null, bool asType = false, NFTTypes type = NFTTypes.Image)
        {
            if (!asType)
            {
                try
                {
                    type = ParseNFTType(metadata);
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"Cannot load Type of NFT from cache. " + ex.Message);
                    return(null);
                }
            }

            if (type == NFTTypes.IoTDevice)
            {
                return(null);
            }

            if (utxoindex == 1 && metadata.TryGetValue("ReceiptFromPaymentUtxo", out var rfp))
            {
                if (!string.IsNullOrEmpty(rfp))
                {
                    type = NFTTypes.Receipt;
                }
            }

            if (txinfo == null)
            {
                txinfo = await NeblioTransactionHelpers.GetTransactionInfo(utxo);

                if (txinfo == null)
                {
                    return(null);
                }
                if (txinfo.Vout == null)
                {
                    return(null);
                }
            }
            var tokid = string.Empty;

            try
            {
                var tid = txinfo.Vout.ToList()[utxoindex]?.Tokens.ToList()[0]?.TokenId;
                tokid = tid;
                if (string.IsNullOrEmpty(tokid))
                {
                    tokid = NFTHelpers.TokenId;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Cannot parse token Id from NFT. " + ex.Message);
                return(null);
            }

            INFT nft = null;

            switch (type)
            {
            case NFTTypes.Image:
                nft = new ImageNFT(utxo);
                break;

            case NFTTypes.Profile:
                nft = new ProfileNFT(utxo);
                break;

            case NFTTypes.Post:
                nft = new PostNFT(utxo);
                break;

            case NFTTypes.Music:
                nft = new MusicNFT(utxo);
                break;

            case NFTTypes.Payment:
                nft = new PaymentNFT(utxo);
                break;

            case NFTTypes.Receipt:
                nft = new ReceiptNFT(utxo);
                break;

            case NFTTypes.Invoice:
                nft = new InvoiceNFT(utxo);
                break;

            case NFTTypes.Order:
                nft = new OrderNFT(utxo);
                break;

            case NFTTypes.Product:
                nft = new ProductNFT(utxo);
                break;

            case NFTTypes.Message:
                nft = new MessageNFT(utxo);
                break;

            case NFTTypes.Ticket:
                nft = new TicketNFT(utxo);
                break;

            case NFTTypes.Event:
                nft = new EventNFT(utxo);
                break;

            case NFTTypes.CoruzantArticle:
                nft = new CoruzantArticleNFT(utxo);
                break;

            case NFTTypes.CoruzantProfile:
                nft = new CoruzantProfileNFT(utxo);
                break;

            case NFTTypes.Device:
                nft = new DeviceNFT(utxo);
                break;

            case NFTTypes.IoTDevice:
                nft = new IoTDeviceNFT(utxo);
                break;

            case NFTTypes.Protocol:
                nft = new ProtocolNFT(utxo);
                break;

            case NFTTypes.HWSrc:
                nft = new HWSrcNFT(utxo);
                break;

            case NFTTypes.FWSrc:
                nft = new FWSrcNFT(utxo);
                break;

            case NFTTypes.SWSrc:
                nft = new SWSrcNFT(utxo);
                break;

            case NFTTypes.MechSrc:
                nft = new MechSrcNFT(utxo);
                break;

            case NFTTypes.IoTMessage:
                nft = new IoTMessageNFT(utxo);
                break;

            case NFTTypes.Xray:
                nft = new XrayNFT(utxo);
                break;

            case NFTTypes.XrayImage:
                nft = new XrayImageNFT(utxo);
                break;
            }

            if (nft != null)
            {
                nft.Time      = TimeHelpers.UnixTimestampToDateTime((double)txinfo.Blocktime);
                nft.Utxo      = utxo;
                nft.UtxoIndex = utxoindex;
                nft.TxDetails = txinfo;
                nft.TokenId   = tokid;
                nft.IsLoaded  = true;
                await nft.LoadLastData(metadata);

                if (nft.Type == NFTTypes.Message)
                {
                    (nft as MessageNFT).Decrypted = false;
                }
                if (nft.Type == NFTTypes.IoTMessage)
                {
                    (nft as IoTMessageNFT).Decrypted = false;
                }
                if (nft.Type == NFTTypes.IoTDevice)
                {
                    (nft as IoTDeviceNFT).DecryptedSetting = false;
                }

                return(nft);
            }
            else
            {
                return(null);
            }
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Create and load the NFT from the transaction hash
        /// </summary>
        /// <param name="tokenId">Optional. If you know please provide to speed up the loading.</param>
        /// <param name="utxo">NFT transaction hash</param>
        /// <param name="utxoindex">Index of the NFT output. This is important for NFTs from multimint.</param>
        /// <param name="time">already parsed time</param>
        /// <param name="wait">await load - obsolete</param>
        /// <param name="loadJustType">load just specific type of NFT</param>
        /// <param name="justType">specify the type of the NFT which can be load - you must turn on justType flag</param>
        /// <param name="skipTheType">skip some type of NFT</param>
        /// <param name="skipType">specify the type of NFT which should be skipped - you must turn on skipTheType flag</param>
        /// <param name="address">Specify address of owner</param>
        /// <param name="txinfo">if you have loaded txinfo provide it to speed up the loading</param>
        /// <returns>INFT compatible object</returns>
        public static async Task <INFT> GetNFT(string tokenId,
                                               string utxo,
                                               int utxoindex     = 0,
                                               double time       = 0,
                                               bool wait         = false,
                                               bool loadJustType = false,
                                               NFTTypes justType = NFTTypes.Image,
                                               bool skipTheType  = false,
                                               NFTTypes skipType = NFTTypes.Image,
                                               string address    = "",
                                               NeblioAPI.GetTransactionInfoResponse txinfo = null)
        {
            NFTTypes type = NFTTypes.Image;
            INFT     nft  = null;

            if (txinfo == null)
            {
                txinfo = await NeblioTransactionHelpers.GetTransactionInfo(utxo);
            }
            if (txinfo == null)
            {
                return(null);
            }
            if (txinfo.Vout == null)
            {
                return(null);
            }
            var tokid = tokenId;

            try
            {
                var tid = txinfo.Vout.ToList()[utxoindex]?.Tokens.ToList()[0];
                if (tid == null)
                {
                    return(null);
                }
                if (tid.Amount > 1)
                {
                    return(null);
                }

                tokid = tid.TokenId;
                if (string.IsNullOrEmpty(tokid))
                {
                    tokid = NFTHelpers.TokenId;
                }
            }
            catch
            {
                return(null);
            }

            if (VEDLDataContext.AllowCache && tokid == NFTHelpers.TokenId)
            {
                // try to load it from cache
                try
                {
                    if (VEDLDataContext.NFTCache.TryGetValue($"{utxo}:{utxoindex}", out var cachedMetadata))
                    {
                        cachedMetadata.LastAccess = DateTime.UtcNow;
                        cachedMetadata.NumberOfReads++;
                        Console.WriteLine($"Loading {utxo}:{utxoindex} NFT from cache.");
                        if (cachedMetadata.NFTType == NFTTypes.Receipt)
                        {
                            Console.WriteLine($"NFT Receipt");
                        }
                        nft = await GetNFTFromCacheMetadata(cachedMetadata.Metadata, utxo, utxoindex, txinfo, true, cachedMetadata.NFTType);

                        if (nft != null)
                        {
                            Console.WriteLine($"Loading {utxo}:{utxoindex} NFT from cache done.");
                        }
                        if (nft != null)
                        {
                            return(nft);
                        }
                        else
                        {
                            Console.WriteLine($"Loading {utxo}:{utxoindex} NFT from cache was not possible!");
                        }
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Cannot load NFT from cache. " + ex.Message);
                    return(null);
                }
            }

            var meta = await NeblioTransactionHelpers.GetTransactionMetadata(tokid, utxo);

            if (meta == null)
            {
                return(null);
            }
            else if (meta.Count == 0 || meta.Count == 1)
            {
                return(null);
            }


            try
            {
                if (!meta.TryGetValue("NFT", out var nftt))
                {
                    return(null);
                }
                else
                if (nftt != "true")
                {
                    return(null);
                }

                type = ParseNFTType(meta);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Cannot load Type of NFT {utxo}. " + ex.Message);
                if (meta.TryGetValue("SourceUtxo", out var sourceutxo))
                {
                    type = NFTTypes.Image;
                }
                else
                {
                    return(null);
                }
            }

            if (utxoindex == 1 && meta.TryGetValue("ReceiptFromPaymentUtxo", out var rfp))
            {
                if (!string.IsNullOrEmpty(rfp))
                {
                    type = NFTTypes.Receipt;
                }
            }

            if (loadJustType)
            {
                if (justType != type)
                {
                    return(null);
                }
            }
            if (skipTheType)
            {
                if (skipType == type || (skipType == NFTTypes.Message && type == NFTTypes.IoTMessage))
                {
                    return(null);
                }
            }

            var Time = TimeHelpers.UnixTimestampToDateTime(time);

            switch (type)
            {
            case NFTTypes.Image:
                nft           = new ImageNFT(utxo);
                nft.TokenId   = tokid;
                nft.Time      = Time;
                nft.TxDetails = txinfo;
                nft.UtxoIndex = utxoindex;
                //if (wait)
                await nft.ParseOriginData(meta);

                //else
                //nft.ParseOriginData(meta);
                nft.ParsePrice(meta);
                break;

            case NFTTypes.Profile:
                nft           = new ProfileNFT(utxo);
                nft.TokenId   = tokid;
                nft.Time      = Time;
                nft.TxDetails = txinfo;
                nft.UtxoIndex = utxoindex;
                await(nft as ProfileNFT).LoadLastData(meta);
                return(nft);

            case NFTTypes.Post:
                nft           = new PostNFT(utxo);
                nft.TokenId   = tokid;
                nft.Time      = Time;
                nft.TxDetails = txinfo;
                nft.UtxoIndex = utxoindex;
                await(nft as PostNFT).LoadLastData(meta);
                break;

            case NFTTypes.Music:
                nft           = new MusicNFT(utxo);
                nft.TokenId   = tokid;
                nft.Time      = Time;
                nft.TxDetails = txinfo;
                nft.UtxoIndex = utxoindex;
                //await ponft.ParseOriginData();
                if (wait)
                {
                    await nft.ParseOriginData(meta);
                }
                else
                {
                    nft.ParseOriginData(meta);
                }
                nft.ParsePrice(meta);
                break;

            case NFTTypes.Payment:
                nft           = new PaymentNFT(utxo);
                nft.TokenId   = tokid;
                nft.Time      = Time;
                nft.TxDetails = txinfo;
                nft.UtxoIndex = utxoindex;
                await(nft as PaymentNFT).LoadLastData(meta);
                break;

            case NFTTypes.Receipt:
                nft           = new ReceiptNFT(utxo);
                nft.TokenId   = tokid;
                nft.Time      = Time;
                nft.TxDetails = txinfo;
                nft.UtxoIndex = utxoindex;
                await(nft as ReceiptNFT).LoadLastData(meta);
                break;

            case NFTTypes.Invoice:
                nft           = new InvoiceNFT(utxo);
                nft.TokenId   = tokid;
                nft.Time      = Time;
                nft.TxDetails = txinfo;
                nft.UtxoIndex = utxoindex;
                await(nft as InvoiceNFT).LoadLastData(meta);
                break;

            case NFTTypes.Order:
                nft           = new OrderNFT(utxo);
                nft.TokenId   = tokid;
                nft.Time      = Time;
                nft.TxDetails = txinfo;
                nft.UtxoIndex = utxoindex;
                await(nft as OrderNFT).LoadLastData(meta);
                break;

            case NFTTypes.Product:
                nft           = new ProductNFT(utxo);
                nft.TokenId   = tokid;
                nft.Time      = Time;
                nft.TxDetails = txinfo;
                nft.UtxoIndex = utxoindex;
                await(nft as ProductNFT).LoadLastData(meta);
                break;

            case NFTTypes.Message:
                nft           = new MessageNFT(utxo);
                nft.TokenId   = tokid;
                nft.Time      = Time;
                nft.TxDetails = txinfo;
                nft.UtxoIndex = utxoindex;
                await(nft as MessageNFT).LoadLastData(meta);
                break;

            case NFTTypes.Ticket:
                nft           = new TicketNFT(utxo);
                nft.TokenId   = tokid;
                nft.Time      = Time;
                nft.TxDetails = txinfo;
                nft.UtxoIndex = utxoindex;
                if (wait)
                {
                    await nft.ParseOriginData(meta);
                }
                else
                {
                    nft.ParseOriginData(meta);
                }
                nft.ParsePrice(meta);
                break;

            case NFTTypes.Event:
                nft           = new EventNFT(utxo);
                nft.TokenId   = tokid;
                nft.Time      = Time;
                nft.TxDetails = txinfo;
                nft.UtxoIndex = utxoindex;
                if (wait)
                {
                    await nft.ParseOriginData(meta);
                }
                else
                {
                    nft.ParseOriginData(meta);
                }
                nft.ParsePrice(meta);
                break;

            case NFTTypes.CoruzantArticle:
                nft           = new CoruzantArticleNFT(utxo);
                nft.TokenId   = tokid;
                nft.Time      = Time;
                nft.TxDetails = txinfo;
                nft.UtxoIndex = utxoindex;
                if (wait)
                {
                    await(nft as CoruzantArticleNFT).LoadLastData(meta);
                }
                else
                {
                    (nft as CoruzantArticleNFT).LoadLastData(meta);
                }
                nft.ParsePrice(meta);
                break;

            case NFTTypes.CoruzantProfile:
                nft           = new CoruzantProfileNFT(utxo);
                nft.TokenId   = tokid;
                nft.Time      = Time;
                nft.TxDetails = txinfo;
                nft.UtxoIndex = utxoindex;
                if (wait)
                {
                    await(nft as CoruzantProfileNFT).LoadLastData(meta);
                }
                else
                {
                    (nft as CoruzantProfileNFT).LoadLastData(meta);
                }
                break;

            case NFTTypes.Device:
                nft           = new DeviceNFT(utxo);
                nft.TokenId   = tokid;
                nft.Time      = Time;
                nft.TxDetails = txinfo;
                nft.UtxoIndex = utxoindex;
                if (wait)
                {
                    await(nft as DeviceNFT).LoadLastData(meta);
                }
                else
                {
                    (nft as DeviceNFT).LoadLastData(meta);
                }
                break;

            case NFTTypes.IoTDevice:
                nft           = new IoTDeviceNFT(utxo);
                nft.TokenId   = tokid;
                nft.Time      = Time;
                nft.TxDetails = txinfo;
                nft.UtxoIndex = utxoindex;
                if (wait)
                {
                    await(nft as IoTDeviceNFT).LoadLastData(meta);
                }
                else
                {
                    (nft as IoTDeviceNFT).LoadLastData(meta);
                }
                break;

            case NFTTypes.Protocol:
                nft           = new ProtocolNFT(utxo);
                nft.TokenId   = tokid;
                nft.Time      = Time;
                nft.TxDetails = txinfo;
                nft.UtxoIndex = utxoindex;
                if (wait)
                {
                    await(nft as ProtocolNFT).LoadLastData(meta);
                }
                else
                {
                    (nft as ProtocolNFT).LoadLastData(meta);
                }
                break;

            case NFTTypes.HWSrc:
                nft           = new HWSrcNFT(utxo);
                nft.TokenId   = tokid;
                nft.Time      = Time;
                nft.TxDetails = txinfo;
                nft.UtxoIndex = utxoindex;
                if (wait)
                {
                    await(nft as HWSrcNFT).LoadLastData(meta);
                }
                else
                {
                    (nft as HWSrcNFT).LoadLastData(meta);
                }
                break;

            case NFTTypes.FWSrc:
                nft           = new FWSrcNFT(utxo);
                nft.TokenId   = tokid;
                nft.Time      = Time;
                nft.TxDetails = txinfo;
                nft.UtxoIndex = utxoindex;
                if (wait)
                {
                    await(nft as FWSrcNFT).LoadLastData(meta);
                }
                else
                {
                    (nft as FWSrcNFT).LoadLastData(meta);
                }
                break;

            case NFTTypes.SWSrc:
                nft           = new SWSrcNFT(utxo);
                nft.TokenId   = tokid;
                nft.Time      = Time;
                nft.TxDetails = txinfo;
                nft.UtxoIndex = utxoindex;
                if (wait)
                {
                    await(nft as SWSrcNFT).LoadLastData(meta);
                }
                else
                {
                    (nft as SWSrcNFT).LoadLastData(meta);
                }
                break;

            case NFTTypes.MechSrc:
                nft           = new MechSrcNFT(utxo);
                nft.TokenId   = tokid;
                nft.Time      = Time;
                nft.TxDetails = txinfo;
                nft.UtxoIndex = utxoindex;
                if (wait)
                {
                    await(nft as MechSrcNFT).LoadLastData(meta);
                }
                else
                {
                    (nft as MechSrcNFT).LoadLastData(meta);
                }
                break;

            case NFTTypes.IoTMessage:
                nft           = new IoTMessageNFT(utxo);
                nft.TokenId   = tokid;
                nft.Time      = Time;
                nft.TxDetails = txinfo;
                nft.UtxoIndex = utxoindex;
                await(nft as IoTMessageNFT).LoadLastData(meta);
                break;

            case NFTTypes.Xray:
                nft           = new XrayNFT(utxo);
                nft.TokenId   = tokid;
                nft.Time      = Time;
                nft.TxDetails = txinfo;
                nft.UtxoIndex = utxoindex;
                await(nft as XrayNFT).LoadLastData(meta);
                break;

            case NFTTypes.XrayImage:
                nft           = new XrayImageNFT(utxo);
                nft.TokenId   = tokid;
                nft.Time      = Time;
                nft.TxDetails = txinfo;
                nft.UtxoIndex = utxoindex;
                await(nft as XrayImageNFT).LoadLastData(meta);
                break;
            }

            if (VEDLDataContext.AllowCache && tokid == NFTHelpers.TokenId && VEDLDataContext.NFTCache.Count < VEDLDataContext.MaxCachedItems)
            {
                if (nft.Type != NFTTypes.IoTDevice)
                {
                    try
                    {
                        var mtd = await nft.GetMetadata();

                        if (!VEDLDataContext.NFTCache.TryGetValue($"{nft.Utxo}:{nft.UtxoIndex}", out var m))
                        {
                            VEDLDataContext.NFTCache.TryAdd($"{nft.Utxo}:{nft.UtxoIndex}", new Dto.NFTCacheDto()
                            {
                                Address       = address,
                                NFTType       = nft.Type,
                                Metadata      = mtd,
                                Utxo          = nft.Utxo,
                                UtxoIndex     = nft.UtxoIndex,
                                NumberOfReads = 0,
                                LastAccess    = DateTime.UtcNow,
                                FirstSave     = DateTime.UtcNow
                            });
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"Cannot load NFT {utxo} of type {nft.TypeText} to NFTCache dictionary. " + ex.Message);
                    }
                }
            }

            return(nft);
        }