public static async Task <List <(string, int)> > MintNFTTicketsFromTemplate(NeblioAccount account, string templateFileName) { if (!FileHelpers.IsFileExists(templateFileName)) { throw new Exception("Input file does not exists."); } var templateData = FileHelpers.ReadTextFromFile(templateFileName); var ticketTemplate = new PlaneTicketsTemplate(); try { ticketTemplate = JsonConvert.DeserializeObject <PlaneTicketsTemplate>(templateData); } catch (Exception ex) { throw new Exception("Cannot deserialize the template data." + ex.Message); } var output = new List <(string, int)>(); foreach (var section in ticketTemplate.Sections) { foreach (var coulmn in section.ColumnsMarks) { for (var i = 0; i < section.NumberOfRows; i++) { var nft = new TicketNFT(""); nft.Author = ticketTemplate.AerolinesName; nft.Name = "Flight:" + ticketTemplate.FlightNumber; nft.Description = $"Flight: {ticketTemplate.FlightNumber} to {ticketTemplate.Location}"; nft.Tags = "planeticket"; nft.Link = ticketTemplate.AerolinesWebsite; nft.AuthorLink = ticketTemplate.AerolinesWebsite; nft.EventId = ticketTemplate.FlightNumber; nft.EventDate = ticketTemplate.StartOfFlight; nft.Location = ticketTemplate.Location; nft.LocationCoordinates = ticketTemplate.StartLocationCoordinates; nft.Seat = $"Column: {coulmn}, Row: {i}"; nft.Price = section.PriceInNeblio; nft.DogePrice = section.PriceInDoge; nft.TicketClass = section.SectionClass; nft.VideoLink = ticketTemplate.SafetyVideoLink; nft.ImageLink = ticketTemplate.AerolinesLogo; var done = false; while (!done) { var res = await account.MintNFT(nft); done = res.Item1; if (!done) { Console.WriteLine("Waiting for spendable utxo..."); await Task.Delay(5000); } else { output.Add((res.Item2, 0)); } } } } } return(output); }
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); }