Example #1
0
        public ActionResult Index()
        {
            IndexViewModel vm = new IndexViewModel();

            using (var db = new CoinpanicContext())
            {
                var seednodes = db.SeedNodes.AsNoTracking().Where(n => n.Coin == nodeService.Coin).ToList();

                nodeService.ConnectNodes(seednodes.Select(n => new NodeDetails()
                {
                    coin = nodeService.Coin,
                    ip   = n.IP,
                    port = n.Port,
                    use  = n.Enabled,
                }).ToList());

                vm.Peers = seednodes.AsEnumerable().Select(n => new PeerModel()
                {
                    Id          = n.SeedNodeId,
                    IP          = n.IP,
                    port        = n.Port,
                    Label       = n.Label,
                    IsConnected = n.Enabled && (nodeService.TryGetNode(n.IP, n.Port) != null),
                    uptime      = n.Enabled && (nodeService.TryGetNode(n.IP, n.Port) != null) ? ((nodeService.TryGetNode(n.IP, n.Port).State == NBitcoin.Protocol.NodeState.HandShaked || nodeService.TryGetNode(n.IP, n.Port).State == NBitcoin.Protocol.NodeState.Connected) ? nodeService.TryGetNode(n.IP, n.Port).Peer.Ago.ToString() : "") : "",
                    status      = n.Enabled == false ? "Disabled" : (nodeService.TryGetNode(n.IP, n.Port) != null ? nodeService.TryGetNode(n.IP, n.Port).State.ToString() : ""),
                }).ToList();
            }
            ViewBag.Title             = "Coinpanic Node Interface";
            ViewBag.Coin              = nodeService.Coin;
            ViewBag.NumConnectedPeers = nodeService.NumConnectedPeers;

            return(View(vm));
        }
Example #2
0
        private static LnNode GetOrCreateNode(LndRpcClient lndClient, string pubkey, CoinpanicContext db)
        {
            var    nodeFind = db.LnNodes.Where(n => n.PubKey == pubkey).Include("Channels");
            LnNode theNode;

            if (nodeFind.Count() < 1)
            {
                // no record yet of node!
                var nodeInfo = lndClient.GetNodeInfo(pubkey);
                if (nodeInfo.node == null)
                {
                    return(null);
                }

                theNode = new LnNode()
                {
                    Alias       = nodeInfo.node.alias,
                    Color       = nodeInfo.node.color,
                    last_update = nodeInfo.node.last_update,
                    PubKey      = nodeInfo.node.pub_key,
                };
                theNode.Channels = new HashSet <LnChannel>();
                db.LnNodes.Add(theNode);
                db.SaveChanges();
            }
            else
            {
                theNode = nodeFind.First();
            }

            return(theNode);
        }
Example #3
0
        /// <summary>
        /// Controller for the claim confirmation page, where users will
        /// review the claim and get instructions for signing.
        /// </summary>
        /// <param name="claimId"></param>
        /// <returns></returns>
        public ActionResult ClaimConfirm(string claimId)
        {
            try
            {
                CoinClaim userclaim = new CoinClaim();
                using (CoinpanicContext db = new CoinpanicContext())
                {
                    userclaim = db.Claims.Where(c => c.ClaimId == claimId).Include(c => c.InputAddresses).AsNoTracking().First();
                }
                ViewBag.Multiplier = BitcoinForks.ForkByShortName[userclaim.CoinShortName].Multiplier;

                //if (userclaim.CoinShortName == "BCH")
                //{
                //    // Convert
                //    var depositAddress = SharpCashAddr.Converter.oldAddrToCashAddr(userclaim.DepositAddress, out bool isP2PKH, out _);
                //    userclaim.DepositAddress = depositAddress;
                //}

                return(View(userclaim));
            }
            catch
            {
                return(RedirectToAction("ClaimError", new { message = "claimId not valid", claimId = claimId }));
            }
        }
Example #4
0
        private static string TransmitViaJSONRPC(string ClaimId, CoinpanicContext db, CoinClaim userclaim, string signedTransaction, string coin)
        {
            GetConnectionDetails(coin, out string host, out int port, out string user, out string pass);
            var client = new RestClient("http://" + host + ":" + Convert.ToString(port));

            client.Authenticator = new HttpBasicAuthenticator(user, pass);
            var request = new RestRequest("/", Method.POST);

            request.RequestFormat = DataFormat.Json;
            request.AddBody(new
            {
                jsonrpc = "1.0",
                id      = "1",
                method  = "sendrawtransaction",
                @params = new List <string>()
                {
                    signedTransaction
                },
            });

            var restResponse = client.Execute(request);
            var content      = restResponse.Content; // raw content as string

            userclaim.TransactionHash = content;
            userclaim.WasTransmitted  = true;
            userclaim.SubmitDate      = DateTime.Now;
            db.SaveChanges();
            MonitoringService.SendMessage("New " + userclaim.CoinShortName + " broadcasting via explorer " + Convert.ToString(userclaim.TotalValue),
                                          "Claim broadcast: https://www.coinpanic.com/Claim/ClaimConfirm?claimId=" + ClaimId + " " + " for " + userclaim.CoinShortName + "\r\n " + signedTransaction);
            return(content);
        }
Example #5
0
        public ActionResult Statistics()
        {
            using (CoinpanicContext db = new CoinpanicContext())
            {
                ViewBag.Errors = db.LnTransactions.AsNoTracking().Where(t => t.IsError).ToList();
            }

            return(View());
        }
Example #6
0
 public ActionResult EnableDisable(int?nid)
 {
     using (var db = new CoinpanicContext())
     {
         var sn = db.SeedNodes.FirstOrDefault(n => n.SeedNodeId == nid);
         sn.Enabled = !sn.Enabled;   //toggle.
         db.SaveChanges();
     }
     return(RedirectToAction("Index"));
 }
Example #7
0
 public void TestMethod1()
 {
     using (CoinpanicContext db = new CoinpanicContext())
     {
         // select * from LnTransaction where UserId = '13f8da23-a0d0-42e3-8c99-5f3c00878892'
         // select * from LNCJUser where TotalWithdrawn > TotalDeposited order by NumWithdraws desc
         // select * from LnTransaction as a inner join LnCJUser on a.UserId = LNCJUser.LnCJUserId order by TransactionId desc
         var c      = db.LnTransactions.Count();
         var greedy = db.LnTransactions.ToDictionary(a => a, a => a);
         int z      = 1;
     }
 }
Example #8
0
        // GET: NewClaim
        public async Task <ActionResult> NewClaim(string coin, string coupon, string addresses)
        {
            string claimId = ShortId.Generate(useNumbers: false, useSpecial: false, length: 10);
            string ip      = Request.UserHostAddress;

            List <string> addressList = addresses != null ? new List <string>(
                addresses.Split(new string[] { "," },
                                StringSplitOptions.RemoveEmptyEntries)) : new List <string>();

            using (CoinpanicContext db = new CoinpanicContext())
            {
                // Ensure the ClaimId is unique
                while (db.Claims.Where(c => c.ClaimId == claimId).Count() > 0)
                {
                    claimId = ShortId.Generate(useNumbers: false, useSpecial: false, length: 10);
                }

                db.Claims.Add(new CoinClaim()
                {
                    ClaimId       = claimId,
                    CoinShortName = coin,
                    RequestIP     = ip
                });
                var res = db.SaveChanges();
                var ci  = db.IndexCoinInfo.Where(i => i.Coin == coin).AsNoTracking();
                if (ci.Count() > 0)
                {
                    ViewBag.Exchanges = ci.First().Exchanges.ToList();
                }
                else
                {
                    ViewBag.Exchanges = new List <Models.ExchangeInfo>();
                }
            }



            // Make sure we understand how to sign the requested coin
            if (BitcoinForks.ForkByShortName.Keys.Contains(coin))
            {
                var NewClaim = new CoinClaim {
                    CoinShortName = coin, ClaimId = claimId
                };
                List <InputAddress> inputs;
                inputs = GetInputAddresses(NewClaim, addressList);
                NewClaim.InputAddresses = inputs;
                return(View(NewClaim));
            }
            else
            {
                return(RedirectToAction("InvalidCoin"));
            }
        }
 public string Test()
 {
     using (CoinpanicContext db = new CoinpanicContext())
     {
         var jar = db.LnCommunityJars.AsNoTracking().Where(j => j.IsTestnet == false).FirstOrDefault();
         if (jar == null)
         {
             return("Jar not found");
         }
         return(Convert.ToString(jar.Balance));
     }
 }
Example #10
0
 public ActionResult Disconnect(int?nid)
 {
     using (var db = new CoinpanicContext())
     {
         var sn = db.SeedNodes.AsNoTracking().FirstOrDefault(n => n.SeedNodeId == nid);
         nodeService.DisconnectNode(new NodeDetails()
         {
             ip   = sn.IP,
             port = sn.Port
         });
     }
     return(RedirectToAction("Index"));
 }
Example #11
0
        public ActionResult CommunityJar(int page = 1)
        {
            //return RedirectToAction("Maintenance", "Home");
            //return RedirectToAction(actionName: "Maintenance", controllerName:"Home");
            LndRpcClient lndClient = GetLndClient();

            // TODO: Added this try-catch to avoid errors
            ViewBag.URI = "03a9d79bcfab7feb0f24c3cd61a57f0f00de2225b6d31bce0bc4564efa3b1b5aaf@13.92.254.226:9735";

            string userId = SetOrUpdateUserCookie();

            // This will be the list of transactions shown to the user
            LnCJTransactions latestTx = new LnCJTransactions();

            using (CoinpanicContext db = new CoinpanicContext())
            {
                var jar = db.LnCommunityJars.AsNoTracking().Where(j => j.IsTestnet == usingTestnet).First();
                ViewBag.Balance = jar.Balance;
                int NumTransactions = jar.Transactions.Count();

                // Code for the paging
                ViewBag.NumTransactions = NumTransactions;
                ViewBag.NumPages        = Math.Ceiling(Convert.ToDouble(NumTransactions) / 20.0);
                ViewBag.ActivePage      = page;
                ViewBag.FirstPage       = (page - 3) < 1 ? 1 : (page - 3);
                ViewBag.LastPage        = (page + 3) < 6 ? 6 : (page + 3);

                //Get user
                string ip      = GetClientIpAddress(Request);
                var    user    = GetUserFromDb(userId, db, jar, ip);
                var    userMax = (user.TotalDeposited - user.TotalWithdrawn);
                if (userMax < 150)
                {
                    userMax = 150;
                }
                ViewBag.UserBalance = userMax;

                // Query and filter the transactions.  Cast into view model.
                latestTx.Transactions = jar.Transactions.OrderByDescending(t => t.TimestampSettled).Skip((page - 1) * 20).Take(20).Select(t => new LnCJTransaction()
                {
                    Timestamp = t.TimestampSettled == null ? DateTime.UtcNow : (DateTime)t.TimestampSettled,
                    Amount    = t.Value,
                    Memo      = t.Memo,
                    Type      = t.IsDeposit ? "Deposit" : "Withdrawal",
                    Id        = t.TransactionId,
                    Fee       = t.FeePaid_Satoshi ?? -1,
                }).ToList();
                latestTx.Balance = jar.Balance;
            }
            return(View(latestTx));
        }
Example #12
0
        public ActionResult CoinBalance(string coin, string addresses)
        {
            List <string> addressList = new List <string>(
                addresses.Split(new string[] { "," },
                                StringSplitOptions.RemoveEmptyEntries));

            var invalid = addressList.Where(a => !Bitcoin.IsValidAddress(a)).ToList();

            var addressesToCheck = addressList.Except(invalid).ToList();

            var scanner        = new BlockScanner();
            var claimAddresses = Bitcoin.ParseAddresses(addressesToCheck);

            Tuple <List <ICoin>, Dictionary <string, double> > claimcoins;
            bool   usedExplorer = false;
            double TotalValue   = 0.0;
            bool   searchError  = false;
            Dictionary <string, double> balances;

            try
            {
                claimcoins = scanner.GetUnspentTransactionOutputs(claimAddresses, coin, out usedExplorer);
                TotalValue = Convert.ToDouble(claimcoins.Item1.Sum(o => ((Money)o.Amount).ToDecimal(MoneyUnit.BTC)));
                balances   = claimcoins.Item2;
            }
            catch (Exception e)
            {
                balances    = new Dictionary <string, double>();
                searchError = true;
            }

            using (CoinpanicContext db = new CoinpanicContext())
            {
                db.IndexCoinInfo.Where(i => i.Coin == coin).ToList();
            }

            AddressSummary result = new AddressSummary()
            {
                InvalidAddresses = invalid,
                CoinName         = BitcoinForks.ForkByShortName[coin].LongName,
                Empty            = TotalValue <= 0,
                Coin             = coin,
                Balance          = Convert.ToString(TotalValue),
                UsedExplorer     = usedExplorer,
                Addresses        = addressesToCheck,
                SearchError      = searchError,
            };

            return(PartialView(result));
        }
Example #13
0
        public ActionResult ShowTransaction(int id)
        {
            LnTransaction t = new LnTransaction();

            using (CoinpanicContext db = new CoinpanicContext())
            {
                var tr = db.LnTransactions.AsNoTracking().FirstOrDefault(tid => tid.TransactionId == id);
                if (tr != null)
                {
                    t = tr;
                }
            }
            return(View(t));
        }
Example #14
0
 public ActionResult Delete(int?nid)
 {
     Debug.Write("Delete " + Convert.ToString(nid));
     if (nid == null)
     {
         return(RedirectToAction("Index"));
     }
     using (var db = new CoinpanicContext())
     {
         var sn = db.SeedNodes.Where(n => n.SeedNodeId == nid).FirstOrDefault();
         db.SeedNodes.Remove(sn);
         db.SaveChanges();
     }
     return(RedirectToAction("Index"));
 }
Example #15
0
        private static LnCJUser GetUserFromDb(string userId, CoinpanicContext db, LnCommunityJar jar, string ip)
        {
            LnCJUser user;
            var      users = db.LnCommunityJarUsers.Where(u => u.LnCJUserId == userId).ToList();

            if (users.Count == 0)
            {
                // new user
                user = new LnCJUser()
                {
                    LnCJUserId           = userId,
                    JarId                = jar.JarId,
                    UserIP               = ip,
                    NumDeposits          = 0,
                    NumWithdraws         = 0,
                    TotalDeposited       = 0,
                    TotalWithdrawn       = 0,
                    TimesampLastDeposit  = DateTime.UtcNow - TimeSpan.FromDays(1),
                    TimesampLastWithdraw = DateTime.UtcNow - TimeSpan.FromDays(1),
                };
                db.LnCommunityJarUsers.Add(user);
            }
            else if (users.Count > 1)
            {
                // error
                throw new Exception("User database error: multiple users with same id.");
            }
            else
            {
                user = users.First();
            }

            // Ensure copy in usersDB
            if (db.LnCommunityUsers.Where(u => u.UserId == user.LnCJUserId).Count() < 1)
            {
                // need to add to db
                LnUser newu = new LnUser()
                {
                    UserId  = user.LnCJUserId,
                    Balance = user.TotalDeposited - user.TotalWithdrawn,
                };
                db.LnCommunityUsers.Add(newu);
            }

            db.SaveChanges();

            return(user);
        }
Example #16
0
        public ActionResult GetJarBalances()
        {
            bool   useTestnet = GetUseTestnet();
            string ip         = GetClientIpAddress(Request);;
            string balance;
            string userDeposits  = "0";
            string userWithdraws = "0";

            using (CoinpanicContext db = new CoinpanicContext())
            {
                var jar = db.LnCommunityJars.Where(j => j.IsTestnet == useTestnet).First();
                balance = Convert.ToString(jar.Balance);
                var user = db.LnCommunityJarUsers.Where(u => u.UserIP == ip).ToList();
            }
            return(Json(new { Balance = balance, Deposits = userDeposits, Withdraws = userWithdraws }));
        }
Example #17
0
 public ActionResult Connect(int?nid)
 {
     using (var db = new CoinpanicContext())
     {
         var sn = db.SeedNodes.AsNoTracking().FirstOrDefault(n => n.SeedNodeId == nid);
         nodeService.ConnectNode(
             new NodeDetails()
         {
             coin = nodeService.Coin,
             ip   = sn.IP,
             port = sn.Port,
             use  = sn.Enabled,
         }, force: true);
     }
     return(RedirectToAction("Index"));
 }
Example #18
0
        public ActionResult MultiCoinResults(string addresses)
        {
            List <string> validCoins = new List <string>();

            //List<string> knownCoins = BitcoinForks.ForkByShortName.Keys.ToList();
            using (CoinpanicContext db = new CoinpanicContext())
            {
                validCoins = db.IndexCoinInfo.AsNoTracking().Select(i => i.Coin).ToList();
            }
            AddressSearchViewModel viewModel = new AddressSearchViewModel()
            {
                Addresses = addresses.Replace("\r\n", ","),
                Coins     = validCoins,
            };

            return(View(viewModel));
        }
Example #19
0
 public ActionResult AddNode(string label, string ip, int?port)
 {
     if (port != null)
     {
         SeedNode newNode = new SeedNode()
         {
             Coin    = nodeService.Coin,
             IP      = ip,
             Label   = label,
             Port    = Convert.ToInt32(port),
             Enabled = true,
         };
         using (var db = new CoinpanicContext())
         {
             db.SeedNodes.Add(newNode);
             db.SaveChanges();
         }
     }
     return(RedirectToAction("Index"));
 }
Example #20
0
        public ActionResult DownloadClaimDataFile(string claimId)
        {
            using (CoinpanicContext db = new CoinpanicContext())
            {
                var userclaim = db.Claims.Where(c => c.ClaimId == claimId);

                if (userclaim.Count() < 1)
                {
                    return(RedirectToAction("ClaimError", new { message = "Unable to find data for claim " + claimId }));
                }

                Response.Clear();
                Response.AddHeader("Content-Disposition", "attachment; filename=ClaimData.txt");
                Response.ContentType = "text/json";

                // Write all my data
                string blockdata = userclaim.First().ClaimData;
                Response.Write(blockdata);
                Response.End();

                // Not sure what else to do here
                return(Content(String.Empty));
            }
        }
Example #21
0
        public IHttpActionResult Post([FromBody] BroadcastModel b)
        {
            using (CoinpanicContext db = new CoinpanicContext())
            {
                //MonitoringService.SendMessage("Received tx POST " + b.ClaimId, "Claim broadcast: https://www.coinpanic.com/Claim/ClaimConfirm?claimId=" + b.ClaimId );
                CoinClaim userclaim = db.Claims.Where(c => c.ClaimId == b.ClaimId).FirstOrDefault();

                if (userclaim == null)
                {
                    userclaim = new CoinClaim();
                }

                //Clean up the signed transaction Hex
                string signedTransaction = b.Hex;
                signedTransaction    = signedTransaction.Replace("\n", String.Empty);
                signedTransaction    = signedTransaction.Replace("\r", String.Empty);
                signedTransaction    = signedTransaction.Replace("\t", String.Empty);
                signedTransaction    = signedTransaction.Trim().Replace(" ", "");
                userclaim.SignedTX   = signedTransaction;
                userclaim.SubmitDate = DateTime.Now;
                db.SaveChanges();

                BroadcastResponse response = new BroadcastResponse()
                {
                    Error  = false,
                    Result = "Transaction successfully broadcast.",
                    Txid   = "",
                };
                var tx = signedTransaction;

                if (tx == "")
                {
                    response.Result = "Error: No signed transaction provided.";
                    MonitoringService.SendMessage("Empty tx " + userclaim.CoinShortName + " submitted.", "Claim broadcast: https://www.coinpanic.com/Claim/ClaimConfirm?claimId=" + b.ClaimId);
                    return(Ok(response));
                }

                Transaction t = null;
                try
                {
                    t = Transaction.Parse(tx.Trim().Replace(" ", ""));
                }
                catch (Exception e)
                {
                    response.Error  = true;
                    response.Result = "Error parsing transaction";
                    MonitoringService.SendMessage("Invalid tx " + userclaim.CoinShortName + " submitted " + Convert.ToString(userclaim.TotalValue), "Claim broadcast: https://www.coinpanic.com/Claim/ClaimConfirm?claimId=" + b.ClaimId + " " + " for " + userclaim.CoinShortName + "\r\n " + signedTransaction);
                    return(Ok(response));
                }

                //BCX submit
                if (nodeService.Coin == "BCX")
                {
                }
                // Disable for now so that the full node is used (for segwit claims)
                if (false)//nodeService.Coin == "BTCP")
                {
                    try
                    {
                        var client  = new RestClient("https://explorer.btcprivate.org/api/");
                        var request = new RestRequest("tx/send/", Method.POST);
                        request.AddJsonBody(new { rawtx = signedTransaction });
                        //request.AddParameter("rawtx", signedTransaction);

                        IRestResponse restResponse = client.Execute(request);
                        var           content      = restResponse.Content; // raw content as string
                                                                           //ViewBag.content = content;
                        userclaim.TransactionHash = content;
                        userclaim.WasTransmitted  = true;
                        userclaim.SubmitDate      = DateTime.Now;
                        db.SaveChanges();
                        MonitoringService.SendMessage("New " + userclaim.CoinShortName + " broadcasting via explorer " + Convert.ToString(userclaim.TotalValue), "Claim broadcast: https://www.coinpanic.com/Claim/ClaimConfirm?claimId=" + b.ClaimId + " " + " for " + userclaim.CoinShortName + "\r\n " + signedTransaction);
                        response.Result = content;
                        return(Ok(response));
                    }
                    catch (Exception e)
                    {
                        MonitoringService.SendMessage("B2X explorer send failed", e.Message);
                    }
                }
                if (nodeService.Coin == "BTG")
                {
                    try
                    {
                        var client  = new RestClient("https://explorer.bitcoingold.org/insight-api/");
                        var request = new RestRequest("tx/send/", Method.POST);
                        request.AddJsonBody(new { rawtx = signedTransaction });
                        //request.AddParameter("rawtx", signedTransaction);

                        IRestResponse restResponse = client.Execute(request);
                        var           content      = restResponse.Content; // raw content as string
                                                                           //ViewBag.content = content;
                        userclaim.TransactionHash = content;
                        userclaim.WasTransmitted  = true;
                        userclaim.SubmitDate      = DateTime.Now;
                        db.SaveChanges();
                        MonitoringService.SendMessage("New " + userclaim.CoinShortName + " broadcasting via explorer " + Convert.ToString(userclaim.TotalValue), "Claim broadcast: https://www.coinpanic.com/Claim/ClaimConfirm?claimId=" + b.ClaimId + " " + " for " + userclaim.CoinShortName + "\r\n " + signedTransaction);
                        response.Result = content;
                        return(Ok(response));
                    }
                    catch (Exception e)
                    {
                        MonitoringService.SendMessage(userclaim.CoinShortName + " explorer send failed", e.Message);
                    }
                }
                if (nodeService.Coin == "BTX")
                {
                    try
                    {
                        var client  = new RestClient("http://insight.bitcore.cc/api/");
                        var request = new RestRequest("tx/send", Method.POST);
                        request.AddJsonBody(new { rawtx = signedTransaction });
                        //request.AddParameter("rawtx", signedTransaction);

                        IRestResponse restResponse = client.Execute(request);
                        var           content      = restResponse.Content; // raw content as string
                                                                           //ViewBag.content = content;
                        userclaim.TransactionHash = content;
                        userclaim.WasTransmitted  = true;
                        userclaim.SubmitDate      = DateTime.Now;
                        db.SaveChanges();
                        MonitoringService.SendMessage("New " + userclaim.CoinShortName + " broadcasting via explorer " + Convert.ToString(userclaim.TotalValue), "Claim broadcast: https://www.coinpanic.com/Claim/ClaimConfirm?claimId=" + b.ClaimId + " " + " for " + userclaim.CoinShortName + "\r\n " + signedTransaction);
                        response.Result = content;
                        return(Ok(response));
                    }
                    catch (Exception e)
                    {
                        MonitoringService.SendMessage(userclaim.CoinShortName + " explorer send failed", e.Message);
                    }
                }
                if (nodeService.Coin == "B2X")
                {
                    try
                    {
                        var client  = new RestClient("https://explorer.b2x-segwit.io/b2x-insight-api/");
                        var request = new RestRequest("tx/send/", Method.POST);
                        request.AddJsonBody(new { rawtx = signedTransaction });
                        //request.AddParameter("rawtx", signedTransaction);

                        IRestResponse restResponse = client.Execute(request);
                        var           content      = restResponse.Content; // raw content as string
                                                                           //ViewBag.content = content;
                        userclaim.TransactionHash = content;
                        userclaim.WasTransmitted  = true;
                        userclaim.SubmitDate      = DateTime.Now;
                        db.SaveChanges();
                        MonitoringService.SendMessage("New " + userclaim.CoinShortName + " broadcasting via explorer " + Convert.ToString(userclaim.TotalValue), "Claim broadcast: https://www.coinpanic.com/Claim/ClaimConfirm?claimId=" + b.ClaimId + " " + " for " + userclaim.CoinShortName + "\r\n " + signedTransaction);
                        response.Result = content;
                        return(Ok(response));
                    }
                    catch (Exception e)
                    {
                        MonitoringService.SendMessage("B2X explorer send failed", e.Message);
                    }
                }
                if (nodeService.Coin == "BTV")
                {
                    //https://block.bitvote.one/tx/send   ps://block.bitvote.one/insight-api/
                    try
                    {
                        var client  = new RestClient("https://block.bitvote.one/insight-api/");
                        var request = new RestRequest("tx/send/", Method.POST);
                        request.AddJsonBody(new { rawtx = signedTransaction });
                        //request.AddParameter("rawtx", signedTransaction);

                        IRestResponse restResponse = client.Execute(request);
                        var           content      = restResponse.Content; // raw content as string
                                                                           //ViewBag.content = content;
                        userclaim.TransactionHash = content;
                        userclaim.WasTransmitted  = true;
                        userclaim.SubmitDate      = DateTime.Now;
                        db.SaveChanges();
                        MonitoringService.SendMessage("New " + userclaim.CoinShortName + " broadcasting via explorer " + Convert.ToString(userclaim.TotalValue), "Claim broadcast: https://www.coinpanic.com/Claim/ClaimConfirm?claimId=" + b.ClaimId + " " + " for " + userclaim.CoinShortName + "\r\n " + signedTransaction);
                        response.Result = content;
                        return(Ok(response));
                    }
                    catch (Exception e)
                    {
                        MonitoringService.SendMessage("BTV explorer send failed", e.Message);
                    }
                }
                if (nodeService.Coin == "BTP")
                {
                    try
                    {
                        var client  = new RestClient("http://exp.btceasypay.com/insight-api/");
                        var request = new RestRequest("tx/send/", Method.POST);
                        request.AddJsonBody(new { rawtx = signedTransaction });
                        //request.AddParameter("rawtx", signedTransaction);

                        IRestResponse restResponse = client.Execute(request);
                        var           content      = restResponse.Content; // raw content as string
                                                                           //ViewBag.content = content;
                        userclaim.TransactionHash = content;
                        userclaim.WasTransmitted  = true;
                        userclaim.SubmitDate      = DateTime.Now;
                        db.SaveChanges();
                        MonitoringService.SendMessage("New " + userclaim.CoinShortName + " broadcasting via explorer " + Convert.ToString(userclaim.TotalValue), "Claim broadcast: https://www.coinpanic.com/Claim/ClaimConfirm?claimId=" + b.ClaimId + " " + " for " + userclaim.CoinShortName + "\r\n " + signedTransaction);
                        response.Result = content;
                        return(Ok(response));
                    }
                    catch (Exception e)
                    {
                        MonitoringService.SendMessage("BTV explorer send failed", e.Message);
                    }
                    //MonitoringService.SendMessage("New " + userclaim.CoinShortName + " begin broadcasting via explorer " + Convert.ToString(userclaim.TotalValue), "Claim broadcast: https://www.coinpanic.com/Claim/ClaimConfirm?claimId=" + b.ClaimId + " " + " for " + userclaim.CoinShortName + "\r\n " + signedTransaction);

                    //var bitpieClient = new RestClient
                    //{
                    //    BaseUrl = new Uri("https://bitpie.getcai.com/api/v1/")
                    //};
                    //var txRequest = new RestRequest("/btp/broadcast", Method.POST);

                    //string data = "{\"raw_tx\": \""+ userclaim.SignedTX + "\"}";
                    //txRequest.AddParameter("application/json; charset=utf-8", data, ParameterType.RequestBody);
                    //txRequest.RequestFormat = DataFormat.Json;
                    //try
                    //{
                    //    var txresponse = bitpieClient.Execute(txRequest);
                    //    if (txresponse.IsSuccessful)
                    //    {
                    //        if (txresponse.Content == "{\"result\": 0, \"error\": \"\"}")
                    //        {
                    //            response.Result = "Transaction was broadcast.  Network reported unknown error.  Double check signatures and ensure coins not already claimed.";
                    //        }
                    //        else if (txresponse.Content == "{\"result\": 0, \"error\": \"broadcast error\"}")
                    //        {
                    //            response.Result = "Transaction successfully broadcast.  No known errors identified.";
                    //        }
                    //        else
                    //        {
                    //            response.Result = "Transaction successfully broadcast.  Result code: " + txresponse.Content;
                    //        }
                    //        response.Txid = t.GetHash().ToString();
                    //    }
                    //    else
                    //    {
                    //        response.Result = "Error sending transactoin.  Node service unavailable.";
                    //    }
                    //    Debug.Print(txresponse.StatusDescription);
                    //    MonitoringService.SendMessage("New " + userclaim.CoinShortName + " broadcast via explorer " + Convert.ToString(userclaim.TotalValue), "Claim broadcast: https://www.coinpanic.com/Claim/ClaimConfirm?claimId=" + b.ClaimId + " " + " for " + userclaim.CoinShortName + "\r\n " + signedTransaction);
                    //}
                    //catch (Exception e)
                    //{
                    //    MonitoringService.SendMessage("Tx server error", e.Message);
                    //    response.Result = "Transmission Error";
                    //    return InternalServerError();
                    //}
                    //return Ok(response);
                }

                //Regular nodes
                try
                {
                    // If we don't have any connections, try to open them.
                    if (nodeService.NumConnectedPeers < 1)
                    {
                        var seednodes = db.SeedNodes.Where(n => n.Coin == nodeService.Coin);
                        nodeService.ConnectNodes(seednodes.Select(n => new NodeDetails()
                        {
                            coin = nodeService.Coin,
                            ip   = n.IP,
                            port = n.Port,
                            use  = n.Enabled,
                        }).ToList());
                    }

                    string txid = t.GetHash().ToString();
                    response.Txid             = txid;
                    userclaim.TransactionHash = txid;
                    db.SaveChanges();

                    var res = nodeService.BroadcastTransaction(t, false);
                    if (res.IsError)
                    {
                        userclaim.WasTransmitted = false;
                        userclaim.SignedTX       = signedTransaction;
                        MonitoringService.SendMessage("New " + userclaim.CoinShortName + " error broadcasting " + Convert.ToString(userclaim.TotalValue), "Claim broadcast: https://www.coinpanic.com/Claim/ClaimConfirm?claimId=" + b.ClaimId + " " + " for " + userclaim.CoinShortName + "\r\n txid: " + txid + "\r\nResult: " + res.Result);
                    }
                    else
                    {
                        userclaim.TransactionHash = txid;
                        userclaim.WasTransmitted  = true;
                        userclaim.SignedTX        = signedTransaction;
                        MonitoringService.SendMessage("New " + userclaim.CoinShortName + " broadcasting " + Convert.ToString(userclaim.TotalValue), "Claim broadcast: https://www.coinpanic.com/Claim/ClaimConfirm?claimId=" + b.ClaimId + " " + " for " + userclaim.CoinShortName + "\r\n txid: " + txid + "\r\nResult: " + res.Result);
                    }
                    response.Result = res.Result;
                    db.SaveChanges();
                    return(Ok(response));
                }
                catch (Exception e)
                {
                    MonitoringService.SendMessage("Tx server error", e.Message);
                    return(InternalServerError());
                }
            }
        }
Example #22
0
        private static LnChannel GetOrCreateChannel(LndRpcClient lndClient, CoinpanicContext db, Channel c)
        {
            LnChannel thisChannel;

            string chan_id = "";            // Temporary variable to use as the ChannelId identifier (should be unique) - used for db key

            if (c.chan_id == null)          // This sometimes happens for private channels.
            {
                chan_id = c.channel_point;  // this should always exist
            }
            else
            {
                chan_id = c.chan_id;        // Use value if reported
            }

            var chanFind = db.LnChannels.Where(ch => ch.ChannelId == chan_id);

            if (chanFind.Count() < 1)
            {
                var chan = lndClient.GetChanInfo(chan_id);
                if (chan == null)
                {
                    var Node1 = GetOrCreateNode(lndClient, c.remote_pubkey, db);
                    var Node2 = GetOrCreateNode(lndClient, lndClient.GetInfo().identity_pubkey, db);
                    if (Node1 == null || Node2 == null)
                    {
                        // Bad node, can't find info in lnd database.
                        return(null);
                    }

                    // not in database
                    thisChannel = new LnChannel()
                    {
                        Capacity  = Convert.ToInt64(chan.capacity),
                        ChannelId = chan_id,
                        ChanPoint = chan.chan_point,
                        Node1     = Node1,
                        Node2     = Node2,
                    };
                }
                else
                {
                    var Node1 = GetOrCreateNode(lndClient, chan.node1_pub, db);
                    var Node2 = GetOrCreateNode(lndClient, chan.node2_pub, db);
                    // not in database
                    thisChannel = new LnChannel()
                    {
                        Capacity  = Convert.ToInt64(chan.capacity),
                        ChannelId = chan.channel_id,
                        ChanPoint = chan.chan_point,
                        Node1     = Node1,
                        Node2     = Node2,
                    };
                }

                db.SaveChanges();
            }
            else
            {
                thisChannel = chanFind.First();
            }
            return(thisChannel);
        }
Example #23
0
        private static List <LnChannelConnectionPoints> GetChanHist(LndRpcClient lndClient, CoinpanicContext db, Channel c)
        {
            List <LnChannelConnectionPoints> chanHist;
            Int64 otherchanId = Convert.ToInt64(c.chan_id);
            var   ch          = db.LnChannelHistory.Where(h => h.ChanId == otherchanId);

            if (ch.Count() > 0)
            {
                // already known - check status
                chanHist = ch.OrderByDescending(h => h.Timestamp).AsNoTracking().ToList();
            }
            else
            {
                LnNode remoteNode = GetOrCreateNode(lndClient, c.remote_pubkey, db);
                // new channel history
                LnChannelConnectionPoints newChanHist = new LnChannelConnectionPoints()
                {
                    IsConnected   = c.active,
                    LocalBalance  = Convert.ToInt64(c.local_balance),
                    RemoteBalance = Convert.ToInt64(c.remote_balance),
                    Timestamp     = DateTime.UtcNow,
                    RemoteNode    = remoteNode,
                    ChanId        = Convert.ToInt64(c.chan_id),
                };
                db.LnChannelHistory.Add(newChanHist);
                db.SaveChanges();
                chanHist = new List <LnChannelConnectionPoints>()
                {
                    newChanHist
                };
            }

            return(chanHist);
        }
Example #24
0
        public ActionResult NodeChannels()
        {
            if (DateTime.Now - LastNodeChannelsUpdate > StatusCacheTimeout)
            {
                Guid       taskid     = Guid.NewGuid();
                UpdateTask updateTask = new UpdateTask()
                {
                    id   = taskid,
                    task = new Task(() =>
                    {
                        try
                        {
                            bool useTestnet        = GetUseTestnet();
                            LndRpcClient lndClient = GetLndClient(useTestnet);
                            string pubkey          = nodeURIViewModel.Node_Pubkey;
                            if (pubkey == "") // If not already known
                            {
                                var info                     = lndClient.GetInfo();
                                pubkey                       = info.identity_pubkey;
                                nodeURIViewModel.URI         = info.uris.First();
                                nodeURIViewModel.Alias       = info.alias;
                                nodeURIViewModel.Node_Pubkey = info.identity_pubkey;
                            }

                            var channels = lndClient.GetChannels();

                            nodeChannelViewModel.channels = new List <LnChannelInfoModel>(); // Clear cache

                            using (CoinpanicContext db = new CoinpanicContext())
                            {
                                LnNode myNode = GetOrCreateNode(lndClient, nodeURIViewModel.Node_Pubkey, db);

                                //Check each channel
                                foreach (var c in channels.channels)
                                {
                                    LnChannelInfoModel channelViewModel = new LnChannelInfoModel();

                                    // Check if this is a new channel
                                    if (myNode.Channels.Where(ch => ch.ChannelId == c.chan_id).Count() < 1)
                                    {
                                        try
                                        {
                                            LnChannel thisChannel = GetOrCreateChannel(lndClient, db, c);

                                            if (thisChannel != null && !myNode.Channels.Contains(thisChannel))
                                            {
                                                myNode.Channels.Add(thisChannel);
                                                db.SaveChanges();
                                            }
                                        }
                                        catch (Exception e)
                                        {
                                            // TODO - manage errors reading channels
                                            LnChannel thisChannel = null;
                                        }
                                    }

                                    // Check if there is a history for the channel
                                    //List<LnChannelConnectionPoints> chanHist = GetChanHist(lndClient, db, c);
                                    DateTime cutoff          = DateTime.UtcNow - TimeSpan.FromDays(30);
                                    Int64 otherchanid        = Convert.ToInt64(c.chan_id);
                                    channelViewModel.History = db.LnChannelHistory
                                                               .Where(ch => ch.ChanId == otherchanid)
                                                               .Where(ch => ch.Timestamp > cutoff)
                                                               .OrderByDescending(ch => ch.Timestamp)
                                                               .Include("RemoteNode")
                                                               .Take(30)
                                                               .AsNoTracking()
                                                               .ToList();

                                    LnChannelConnectionPoints prevChanHist;
                                    if (channelViewModel.History.Count() > 0)
                                    {
                                        prevChanHist = channelViewModel.History.First();
                                    }
                                    else
                                    {
                                        prevChanHist = new LnChannelConnectionPoints()
                                        {
                                            Timestamp = DateTime.UtcNow,
                                        };
                                    }

                                    // check for changes
                                    if (prevChanHist.IsConnected != c.active ||
                                        prevChanHist.LocalBalance != Convert.ToInt64(c.local_balance) ||
                                        prevChanHist.RemoteBalance != Convert.ToInt64(c.remote_balance) ||
                                        DateTime.UtcNow - prevChanHist.Timestamp > TimeSpan.FromHours(6))
                                    {
                                        // update
                                        LnNode remoteNode = GetOrCreateNode(lndClient, c.remote_pubkey, db);
                                        LnChannelConnectionPoints newChanHist = new LnChannelConnectionPoints()
                                        {
                                            IsConnected   = c.active,
                                            LocalBalance  = Convert.ToInt64(c.local_balance),
                                            RemoteBalance = Convert.ToInt64(c.remote_balance),
                                            Timestamp     = DateTime.UtcNow,
                                            RemoteNode    = remoteNode,
                                            ChanId        = Convert.ToInt64(c.chan_id),
                                        };
                                        prevChanHist.RemoteNode = remoteNode;
                                        db.LnChannelHistory.Add(newChanHist);
                                        db.SaveChanges();
                                    }
                                    if (c.remote_balance is null)
                                    {
                                        c.remote_balance = "0";
                                    }
                                    if (c.local_balance is null)
                                    {
                                        c.local_balance = "0";
                                    }
                                    channelViewModel.ChanInfo   = c;
                                    channelViewModel.RemoteNode = prevChanHist.RemoteNode;
                                    nodeChannelViewModel.channels.Add(channelViewModel);
                                }
                            }

                            // Updates to channelinfo
                            nodeSummaryViewModel.NumChannels          = channels.channels.Count;
                            nodeSummaryViewModel.Capacity             = Convert.ToDouble(channels.channels.Sum(c => Convert.ToInt64(c.capacity))) / 100000000.0;
                            nodeSummaryViewModel.LocalCapacity        = Convert.ToDouble(channels.channels.Sum(n => Convert.ToInt64(n.local_balance))) / 100000000.0;
                            nodeSummaryViewModel.RemoteCapacity       = Convert.ToDouble(channels.channels.Sum(n => Convert.ToInt64(n.remote_balance))) / 100000000.0;
                            nodeSummaryViewModel.ActiveCapacity       = Convert.ToDouble(channels.channels.Where(c => c.active).Sum(c => Convert.ToInt64(c.capacity))) / 100000000.0;
                            nodeSummaryViewModel.ActiveLocalCapacity  = Convert.ToDouble(channels.channels.Where(c => c.active).Sum(n => Convert.ToInt64(n.local_balance))) / 100000000.0;
                            nodeSummaryViewModel.ActiveRemoteCapacity = Convert.ToDouble(channels.channels.Where(c => c.active).Sum(n => Convert.ToInt64(n.remote_balance))) / 100000000.0;

                            UpdateTaskComplete(taskid);
                        }
                        catch (Exception e)
                        {
                            // Try again on next refresh
                            LastNodeChannelsUpdate = DateTime.Now - StatusCacheTimeout;
                        }
                    }),
                };
                updateTasks.TryAdd(taskid, updateTask);
                updateTask.task.Start();

                LastNodeChannelsUpdate = DateTime.Now;
            }

            return(PartialView("NodeChannels", nodeChannelViewModel));
        }
Example #25
0
        /// <summary>
        /// Notify web clients via Signalr that an invoice has been paid
        /// </summary>
        /// <param name="invoice"></param>
        private static void NotifyClientsInvoicePaid(Invoice invoice)
        {
            var  context  = GlobalHost.ConnectionManager.GetHubContext <NotificationHub>();
            bool isTesnet = GetUseTestnet();

            if (invoice.settle_date == "0" || invoice.settle_date == null)
            {
                // Was not settled
                return;
            }

            //Save in db
            using (CoinpanicContext db = new CoinpanicContext())
            {
                var jar = db.LnCommunityJars.Where(j => j.IsTestnet == isTesnet).First();

                //check if unsettled transaction exists
                var      tx         = db.LnTransactions.Where(tr => tr.PaymentRequest == invoice.payment_request).ToList();
                DateTime settletime = DateTime.UtcNow;

                LnTransaction t;
                if (tx.Count > 0)
                {
                    t = tx.First();
                    t.TimestampSettled = DateTime.SpecifyKind(new DateTime(1970, 1, 1), DateTimeKind.Utc) + TimeSpan.FromSeconds(Convert.ToInt64(invoice.settle_date));
                    t.IsSettled        = invoice.settled;
                }
                else
                {
                    //insert transaction
                    settletime = DateTime.SpecifyKind(new DateTime(1970, 1, 1), DateTimeKind.Utc) + TimeSpan.FromSeconds(Convert.ToInt64(invoice.settle_date));
                    t          = new LnTransaction()
                    {
                        IsSettled        = invoice.settled,
                        Memo             = invoice.memo,
                        Value            = Convert.ToInt64(invoice.value),
                        IsTestnet        = GetUseTestnet(),
                        HashStr          = invoice.r_hash,
                        IsDeposit        = true,
                        TimestampSettled = settletime,
                        TimestampCreated = DateTime.SpecifyKind(new DateTime(1970, 1, 1), DateTimeKind.Utc) + TimeSpan.FromSeconds(Convert.ToInt64(invoice.creation_date)),
                        PaymentRequest   = invoice.payment_request,
                        UserId           = Guid.NewGuid().ToString(),
                    };
                    db.LnTransactions.Add(t);
                }

                var userId = t.UserId;
                var user   = GetUserFromDb(userId, db, jar,
                                           ip: "" // only used when creating a new user, so set blank for this.
                                           );

                user.TotalDeposited     += Convert.ToInt64(invoice.value);
                user.NumDeposits        += 1;
                user.TimesampLastDeposit = DateTime.UtcNow;

                t.IsSettled = invoice.settled;
                if (t.IsDeposit && t.IsSettled)
                {
                    jar.Balance += Convert.ToInt64(invoice.value);
                }
                jar.Transactions.Add(t);
                db.SaveChanges();

                //re-fetch to get the transaction id
                // Ok, this may not be required.
                //var tnew = db.LnTransactions.AsNoTracking().FirstOrDefault(tr => tr.PaymentRequest == invoice.payment_request && (DateTime)tr.TimestampSettled == settletime);

                //if (tnew != null)
                //    t = tnew;

                // Notify Web clients - this is shown to user

                // Client needs to check that the transaction received is theirs before marking successful.
                var newT = new LnCJTransaction()
                {
                    Timestamp = t.TimestampSettled == null ? DateTime.UtcNow : (DateTime)t.TimestampSettled,
                    Amount    = t.Value,
                    Memo      = t.Memo,
                    Type      = t.IsDeposit ? "Deposit" : "Withdrawal",
                    Id        = t.TransactionId,
                    Fee       = t.FeePaid_Satoshi ?? -1,
                };

                context.Clients.All.NotifyNewTransaction(newT);
                if (invoice.settled)
                {
                    context.Clients.All.NotifyInvoicePaid(invoice.payment_request);
                }
            }
        }
Example #26
0
        public ActionResult Broadcast(IndexViewModel model)
        {
            try
            {
                // Verification
                if (ModelState.IsValid)
                {
                    // If we don't have any connections, try to open them.
                    if (nodeService.NumConnectedPeers < 1)
                    {
                        using (var db = new CoinpanicContext())
                        {
                            var seednodes = db.SeedNodes.Where(n => n.Coin == nodeService.Coin);
                            nodeService.ConnectNodes(seednodes.Select(n => new NodeDetails()
                            {
                                coin = nodeService.Coin,
                                ip   = n.IP,
                                port = n.Port,
                                use  = n.Enabled,
                            }).ToList());
                        }
                    }

                    var         tx = model.Broadcast.Hex;
                    Transaction t  = null;
                    try
                    {
                        t = Transaction.Parse(tx.Trim().Replace(" ", ""));
                    }
                    catch (Exception e)
                    {
                        //catch bad transactions
                        return(this.Json(new
                        {
                            EnableSuccess = true,
                            SuccessTitle = "Error",
                            SuccessMsg = e.Message,
                        }));
                        //MonitoringService.SendMessage("Invalid tx " + userclaim.CoinShortName + " submitted " + Convert.ToString(userclaim.TotalValue), "Claim broadcast: https://www.coinpanic.com/Claim/ClaimConfirm?claimId=" + claimId + " " + " for " + userclaim.CoinShortName + "\r\n " + signedTransaction);
                        //return RedirectToAction("ClaimError", new { message = e.Message + ". Unable to parse signed transaction: \r\n" + tx, claimId = claimId });
                    }
                    string txid = t.GetHash().ToString();
                    var    res  = nodeService.BroadcastTransaction(t, false);
                    //Thread.Sleep(5000); //Simulate delay
                    // Info.
                    return(this.Json(new
                    {
                        EnableSuccess = true,
                        SuccessTitle = t.GetHash().ToString(),
                        SuccessMsg = res.Result,
                    }));
                }
            }
            catch (Exception ex)
            {
                // Info
                Console.Write(ex);
            }
            // Info
            return(this.Json(new
            {
                EnableError = true,
                ErrorTitle = "Error",
                ErrorMsg = "Something goes wrong, please try again later"
            }));
        }
Example #27
0
        public ActionResult Broadcast(string ClaimId, string Hex)
        {
            /*
             * Known Errors:
             *
             * Missing a signature on one or more input (private key)
             * {"result":null,"error":{"code":-26,"message":"16: mandatory-script-verify-flag-failed (Operation not valid with the current stack size)"},"id":"1"}
             */
            using (CoinpanicContext db = new CoinpanicContext())
            {
                CoinClaim userclaim = db.Claims.Where(c => c.ClaimId == ClaimId).FirstOrDefault();

                if (userclaim == null)
                {
                    userclaim = new CoinClaim();
                }

                //Clean up the signed transaction Hex
                string signedTransaction = Hex;
                signedTransaction    = signedTransaction.Replace("\n", String.Empty);
                signedTransaction    = signedTransaction.Replace("\r", String.Empty);
                signedTransaction    = signedTransaction.Replace("\t", String.Empty);
                signedTransaction    = signedTransaction.Trim().Replace(" ", "");
                userclaim.SignedTX   = signedTransaction;
                userclaim.SubmitDate = DateTime.Now;
                if (signedTransaction != "")
                {
                    db.SaveChanges();
                }

                // This is what is returned to the client
                BroadcastResponse response = new BroadcastResponse()
                {
                    Error  = false,
                    Result = "Transaction successfully broadcast.",
                    Txid   = "",
                };

                var tx = signedTransaction;

                if (tx == "")
                {
                    response.Error  = true;
                    response.Result = "Error: No signed transaction provided.";
                    MonitoringService.SendMessage("Empty tx " + userclaim.CoinShortName + " submitted.",
                                                  "Claim broadcast: https://www.coinpanic.com/Claim/ClaimConfirm?claimId=" + ClaimId);
                    return(Json(response));
                }

                Transaction t = null;
                try
                {
                    t = Transaction.Parse(tx.Trim().Replace(" ", ""));
                }
                catch (Exception e)
                {
                    response.Error  = true;
                    response.Result = "Error parsing transaction";
                    MonitoringService.SendMessage("Invalid tx " + userclaim.CoinShortName + " submitted " + Convert.ToString(userclaim.TotalValue),
                                                  "Claim broadcast: https://www.coinpanic.com/Claim/ClaimConfirm?claimId=" + ClaimId + " " + " for " + userclaim.CoinShortName + "\r\n "
                                                  + signedTransaction + "\r\n"
                                                  + e.Message);
                    return(Json(response));
                }

                // Transmit via explorers
                if (userclaim.CoinShortName == "BCA")
                {
                    try
                    {
                        var url     = "https://explorer.bitcoinatom.io/";
                        var client  = new RestClient(url);
                        var request = new RestRequest("/rpc-terminal/", Method.POST);
                        request.AddHeader("content-type", "application/x-www-form-urlencoded");
                        request.AddHeader("x-requested-with", "XMLHttpRequest");
                        request.AddObject(new
                        {
                            cmd = "sendrawtransaction " + signedTransaction
                        });

                        IRestResponse restResponse = client.Execute(request);
                        var           content      = restResponse.Content; // raw content as string
                        userclaim.TransactionHash = content;
                        userclaim.WasTransmitted  = true;
                        userclaim.SubmitDate      = DateTime.Now;

                        db.SaveChanges();
                        MonitoringService.SendMessage("New " + userclaim.CoinShortName + " broadcasting via explorer " + Convert.ToString(userclaim.TotalValue),
                                                      "Claim broadcast: https://www.coinpanic.com/Claim/ClaimConfirm?claimId=" + ClaimId + " " + " for " + userclaim.CoinShortName + "\r\n " + signedTransaction
                                                      + "\r\n Result: " + content);
                        response.Result = content;
                        return(Json(response));
                    }
                    catch (Exception e)
                    {
                        MonitoringService.SendMessage(userclaim.CoinShortName + " explorer send failed", e.Message);
                    }
                }
                if (userclaim.CoinShortName == "B2X")
                {
                    try
                    {
                        var client  = new RestClient("https://explorer.b2x-segwit.io/b2x-insight-api/");
                        var request = new RestRequest("tx/send/", Method.POST);
                        request.AddJsonBody(new { rawtx = signedTransaction });

                        IRestResponse restResponse = client.Execute(request);
                        var           content      = restResponse.Content; // raw content as string
                        userclaim.TransactionHash = content;
                        userclaim.WasTransmitted  = true;
                        userclaim.SubmitDate      = DateTime.Now;

                        db.SaveChanges();
                        MonitoringService.SendMessage("New " + userclaim.CoinShortName + " broadcasting via explorer " + Convert.ToString(userclaim.TotalValue),
                                                      "Claim broadcast: https://www.coinpanic.com/Claim/ClaimConfirm?claimId=" + ClaimId + " " + " for " + userclaim.CoinShortName + "\r\n " + signedTransaction
                                                      + "\r\n Result: " + content);
                        response.Result = content;
                        return(Json(response));
                    }
                    catch (Exception e)
                    {
                        MonitoringService.SendMessage(userclaim.CoinShortName + " explorer send failed", e.Message);
                    }
                }
                if (userclaim.CoinShortName == "SBTC")
                {
                    //http://block.superbtc.org/insight-api/tx/send
                    try
                    {
                        var client  = new RestClient("http://block.superbtc.org/insight-api/");
                        var request = new RestRequest("tx/send/", Method.POST);
                        request.AddJsonBody(new { rawtx = signedTransaction });

                        IRestResponse restResponse = client.Execute(request);
                        var           content      = restResponse.Content; // raw content as string
                        userclaim.TransactionHash = content;
                        userclaim.WasTransmitted  = true;
                        userclaim.SubmitDate      = DateTime.Now;

                        db.SaveChanges();
                        MonitoringService.SendMessage("New " + userclaim.CoinShortName + " broadcasting via explorer " + Convert.ToString(userclaim.TotalValue),
                                                      "Claim broadcast: https://www.coinpanic.com/Claim/ClaimConfirm?claimId=" + ClaimId + " " + " for " + userclaim.CoinShortName + "\r\n " + signedTransaction
                                                      + "\r\n Result: " + content);
                        response.Result = content;
                        return(Json(response));
                    }
                    catch (Exception e)
                    {
                        MonitoringService.SendMessage(userclaim.CoinShortName + " explorer send failed", e.Message);
                    }
                }
                if (userclaim.CoinShortName == "BCI")
                {
                    //https://explorer.bitcoininterest.io/api/
                    try
                    {
                        var client  = new RestClient("https://explorer.bitcoininterest.io/api/");
                        var request = new RestRequest("tx/send/", Method.POST);
                        request.AddJsonBody(new { rawtx = signedTransaction });

                        IRestResponse restResponse = client.Execute(request);
                        var           content      = restResponse.Content; // raw content as string
                        userclaim.TransactionHash = content;
                        userclaim.WasTransmitted  = true;
                        userclaim.SubmitDate      = DateTime.Now;

                        db.SaveChanges();
                        MonitoringService.SendMessage("New " + userclaim.CoinShortName + " broadcasting via explorer " + Convert.ToString(userclaim.TotalValue),
                                                      "Claim broadcast: https://www.coinpanic.com/Claim/ClaimConfirm?claimId=" + ClaimId + " " + " for " + userclaim.CoinShortName + "\r\n " + signedTransaction
                                                      + "\r\n Result: " + content);
                        response.Result = content;
                        return(Json(response));
                    }
                    catch (Exception e)
                    {
                        MonitoringService.SendMessage(userclaim.CoinShortName + " explorer send failed", e.Message);
                    }
                }
                if (userclaim.CoinShortName == "BCX")
                {
                    //https://explorer.bitcoininterest.io/api/
                    try
                    {
                        var client  = new RestClient("https://bcx.info/insight-api/");
                        var request = new RestRequest("tx/send/", Method.POST);
                        request.AddJsonBody(new { rawtx = signedTransaction });

                        IRestResponse restResponse = client.Execute(request);
                        var           content      = restResponse.Content; // raw content as string
                        userclaim.TransactionHash = content;
                        userclaim.WasTransmitted  = true;
                        userclaim.SubmitDate      = DateTime.Now;

                        db.SaveChanges();
                        MonitoringService.SendMessage("New " + userclaim.CoinShortName + " broadcasting via explorer " + Convert.ToString(userclaim.TotalValue),
                                                      "Claim broadcast: https://www.coinpanic.com/Claim/ClaimConfirm?claimId=" + ClaimId + " " + " for " + userclaim.CoinShortName + "\r\n " + signedTransaction
                                                      + "\r\n Result: " + content);
                        response.Result = content;
                        return(Json(response));
                    }
                    catch (Exception e)
                    {
                        MonitoringService.SendMessage(userclaim.CoinShortName + " explorer send failed", e.Message);
                    }
                }
                // Broadcast via own nodes over RPC
                if (userclaim.CoinShortName == "BBC" ||
                    userclaim.CoinShortName == "BTF" ||
                    userclaim.CoinShortName == "BCL" ||
                    userclaim.CoinShortName == "BCBC" ||
                    userclaim.CoinShortName == "BTV" ||
                    userclaim.CoinShortName == "BCD" ||
                    userclaim.CoinShortName == "UBTC" ||
                    userclaim.CoinShortName == "BTW" ||
                    userclaim.CoinShortName == "BPA")
                {
                    try
                    {
                        string content = TransmitViaJSONRPC(ClaimId, db, userclaim, signedTransaction, userclaim.CoinShortName);
                        response.Result = content;
                        return(Json(response));
                    }
                    catch (Exception e)
                    {
                        MonitoringService.SendMessage(userclaim.CoinShortName + " RPC send failed", e.Message);
                    }
                }
                if (userclaim.CoinShortName == "BTCP")
                {
                    try
                    {
                        var client  = new RestClient("https://explorer.btcprivate.org/api/");
                        var request = new RestRequest("tx/send/", Method.POST);
                        request.AddJsonBody(new { rawtx = signedTransaction });
                        //request.AddParameter("rawtx", signedTransaction);

                        IRestResponse restResponse = client.Execute(request);
                        var           content      = restResponse.Content; // raw content as string
                                                                           //ViewBag.content = content;
                        userclaim.TransactionHash = content;
                        userclaim.WasTransmitted  = true;
                        userclaim.SubmitDate      = DateTime.Now;
                        db.SaveChanges();
                        MonitoringService.SendMessage("New " + userclaim.CoinShortName + " broadcasting via explorer " + Convert.ToString(userclaim.TotalValue),
                                                      "Claim broadcast: https://www.coinpanic.com/Claim/ClaimConfirm?claimId=" + ClaimId + " " + " for " + userclaim.CoinShortName + "\r\n " + signedTransaction);
                        response.Result = content;
                        return(Json(response));
                    }
                    catch (Exception e)
                    {
                        MonitoringService.SendMessage(userclaim.CoinShortName + " explorer send failed", e.Message);
                    }
                }
                else if (userclaim.CoinShortName == "BTG")
                {
                    try
                    {
                        var client  = new RestClient("https://explorer.bitcoingold.org/insight-api/");
                        var request = new RestRequest("tx/send/", Method.POST);
                        request.AddJsonBody(new { rawtx = signedTransaction });
                        //request.AddParameter("rawtx", signedTransaction);

                        IRestResponse restResponse = client.Execute(request);
                        var           content      = restResponse.Content; // raw content as string
                                                                           //ViewBag.content = content;
                        userclaim.TransactionHash = content;
                        userclaim.WasTransmitted  = true;
                        userclaim.SubmitDate      = DateTime.Now;
                        db.SaveChanges();
                        MonitoringService.SendMessage("New " + userclaim.CoinShortName + " broadcasting via explorer " + Convert.ToString(userclaim.TotalValue),
                                                      "Claim broadcast: https://www.coinpanic.com/Claim/ClaimConfirm?claimId=" + ClaimId + " " + " for " + userclaim.CoinShortName + "\r\n " + signedTransaction);
                        response.Result = content;
                        return(Json(response));
                    }
                    catch (Exception e)
                    {
                        MonitoringService.SendMessage(userclaim.CoinShortName + " explorer send failed", e.Message);
                    }
                }
                if (userclaim.CoinShortName == "BTX")
                {
                    try
                    {
                        var client  = new RestClient("https://insight.bitcore.cc/api/");
                        var request = new RestRequest("tx/send", Method.POST);
                        //request.AddJsonBody(new { rawtx = signedTransaction });
                        request.AddParameter("rawtx", signedTransaction);
                        request.RequestFormat = DataFormat.Json;
                        //request.AddUrlSegment("rawtx", signedTransaction);
                        IRestResponse restResponse = client.Execute(request);
                        var           content      = restResponse.Content; // raw content as string
                                                                           //ViewBag.content = content;
                        userclaim.TransactionHash = content;
                        userclaim.WasTransmitted  = true;
                        userclaim.SubmitDate      = DateTime.Now;
                        db.SaveChanges();
                        MonitoringService.SendMessage("New " + userclaim.CoinShortName + " broadcasting via explorer " + Convert.ToString(userclaim.TotalValue),
                                                      "Claim broadcast: https://www.coinpanic.com/Claim/ClaimConfirm?claimId=" + ClaimId + " " + " for " + userclaim.CoinShortName + "\r\n " + signedTransaction);
                        response.Result = content;
                        return(Json(response));
                    }
                    catch (Exception e)
                    {
                        MonitoringService.SendMessage(userclaim.CoinShortName + " explorer send failed", e.Message);
                    }
                }
                if (userclaim.CoinShortName == "BTV")
                {
                    //https://block.bitvote.one/tx/send   ps://block.bitvote.one/insight-api/
                    try
                    {
                        var client  = new RestClient("https://block.bitvote.one/insight-api/");
                        var request = new RestRequest("tx/send/", Method.POST);
                        request.AddJsonBody(new { rawtx = signedTransaction });
                        //request.AddParameter("rawtx", signedTransaction);

                        IRestResponse restResponse = client.Execute(request);
                        var           content      = restResponse.Content; // raw content as string
                                                                           //ViewBag.content = content;
                        userclaim.TransactionHash = content;
                        userclaim.WasTransmitted  = true;
                        userclaim.SubmitDate      = DateTime.Now;
                        db.SaveChanges();
                        MonitoringService.SendMessage("New " + userclaim.CoinShortName + " broadcasting via explorer " + Convert.ToString(userclaim.TotalValue),
                                                      "Claim broadcast: https://www.coinpanic.com/Claim/ClaimConfirm?claimId=" + ClaimId + " " + " for " + userclaim.CoinShortName + "\r\n " + signedTransaction);
                        response.Result = content;
                        return(Json(response));
                    }
                    catch (Exception e)
                    {
                        MonitoringService.SendMessage(userclaim.CoinShortName + " explorer send failed", e.Message);
                    }
                }
                if (userclaim.CoinShortName == "BTP")
                {
                    try
                    {
                        var client  = new RestClient("http://exp.btceasypay.com/insight-api/");
                        var request = new RestRequest("tx/send/", Method.POST);
                        request.AddJsonBody(new { rawtx = signedTransaction });
                        IRestResponse restResponse = client.Execute(request);
                        var           content      = restResponse.Content; // raw content as string
                        userclaim.TransactionHash = content;
                        userclaim.WasTransmitted  = true;
                        userclaim.SubmitDate      = DateTime.Now;
                        db.SaveChanges();
                        MonitoringService.SendMessage("New " + userclaim.CoinShortName + " broadcasting via explorer " + Convert.ToString(userclaim.TotalValue),
                                                      "Claim broadcast: https://www.coinpanic.com/Claim/ClaimConfirm?claimId=" + ClaimId + " " + " for " + userclaim.CoinShortName + "\r\n " + signedTransaction);
                        response.Result = content;
                        return(Json(response));
                    }
                    catch (Exception e)
                    {
                        MonitoringService.SendMessage(userclaim.CoinShortName + " explorer send failed", e.Message);
                    }
                }

                // Transmit via Full Node
                try
                {
                    string url     = "https://www.metabittrader.com/" + userclaim.CoinShortName + "/";
                    var    client  = new RestClient(url);
                    var    request = new RestRequest("api/tx/", Method.POST);
                    request.AddJsonBody(new { Hex = Hex, ClaimId = ClaimId });
                    IRestResponse <BroadcastResponse> restResponse = client.Execute <BroadcastResponse>(request);
                    var content = restResponse.Data;
                    // Forward result
                    return(Json(content));
                }
                catch (Exception e)
                {
                    MonitoringService.SendMessage(userclaim.CoinShortName + " explorer send failed", e.Message);
                }
                response.Result = "Unknown error broadcasting.";
                response.Error  = true;
                return(Json(response));
            }
        }
Example #28
0
        public ActionResult GetJarDepositInvoice(string amount, string memo)
        {
            string ip = GetClientIpAddress(Request);;

            if (memo == null || memo == "")
            {
                memo = "Coinpanic Community Jar";
            }

            bool useTestnet = GetUseTestnet();
            var  lndClient  = new LndRpcClient(
                host: System.Configuration.ConfigurationManager.AppSettings[useTestnet ? "LnTestnetHost" : "LnMainnetHost"],
                macaroonAdmin: System.Configuration.ConfigurationManager.AppSettings[useTestnet ? "LnTestnetMacaroonAdmin" : "LnMainnetMacaroonAdmin"],
                macaroonRead: System.Configuration.ConfigurationManager.AppSettings[useTestnet ? "LnTestnetMacaroonRead" : "LnMainnetMacaroonRead"],
                macaroonInvoice: System.Configuration.ConfigurationManager.AppSettings[useTestnet ? "LnTestnetMacaroonInvoice" : "LnMainnetMacaroonInvoice"]);

            var inv = lndClient.AddInvoice(Convert.ToInt64(amount), memo: memo, expiry: "432000");

            LnRequestInvoiceResponse resp = new LnRequestInvoiceResponse()
            {
                Invoice = inv.payment_request,
                Result  = "success",
            };

            string userId = "";

            //Check if user is returning
            if (HttpContext.Request.Cookies["CoinpanicCommunityJarUser"] != null)
            {
                var cookie = HttpContext.Request.Cookies.Get("CoinpanicCommunityJarUser");
                cookie.Expires = DateTime.Now.AddDays(7);   //update
                HttpContext.Response.Cookies.Remove("CoinpanicCommunityJarUser");
                HttpContext.Response.SetCookie(cookie);
                userId = cookie.Value;
            }
            else
            {
                HttpCookie cookie = new HttpCookie("CoinpanicCommunityJarUser");
                cookie.Value   = Guid.NewGuid().ToString();
                cookie.Expires = DateTime.Now.AddDays(7);
                HttpContext.Response.Cookies.Remove("CoinpanicCommunityJarUser");
                HttpContext.Response.SetCookie(cookie);
                userId = cookie.Value;
            }

            //Create transaction record (not settled)
            using (CoinpanicContext db = new CoinpanicContext())
            {
                var jar = db.LnCommunityJars.Where(j => j.IsTestnet == useTestnet).First();

                //is this a previous user?
                LnCJUser user;
                user = GetUserFromDb(userId, db, jar, ip);

                //create a new transaction
                LnTransaction t = new LnTransaction()
                {
                    UserId    = user.LnCJUserId,
                    IsSettled = false,
                    Memo      = memo,
                    Value     = Convert.ToInt64(amount),
                    IsTestnet = GetUseTestnet(),
                    HashStr   = inv.r_hash,
                    IsDeposit = true,
                    //TimestampSettled = DateTime.SpecifyKind(new DateTime(1970, 1, 1), DateTimeKind.Utc) + TimeSpan.FromSeconds(Convert.ToInt64(invoice.settle_date)),
                    TimestampCreated  = DateTime.Now,
                    PaymentRequest    = inv.payment_request,
                    DestinationPubKey = System.Configuration.ConfigurationManager.AppSettings["LnPubkey"],
                };
                db.LnTransactions.Add(t);
                db.SaveChanges();
            }

            // If a listener is not already running, this should start

            // Check if there is one already online.
            var numListeners = lndTransactionListeners.Count(kvp => kvp.Value.IsLive);

            // If we don't have one running - start it and subscribe
            if (numListeners < 1)
            {
                var listener = lndClient.GetListener();
                lndTransactionListeners.TryAdd(listener.ListenerId, listener); //keep alive while we wait for payment
                listener.InvoicePaid += NotifyClientsInvoicePaid;              //handle payment message
                listener.StreamLost  += OnListenerLost;                        //stream lost
                var a = new Task(() => listener.Start());                      //listen for payment
                a.Start();
            }
            return(Json(resp));
        }
Example #29
0
        public ActionResult InitializeClaim(string claimId, string PublicKeys, string depositAddress, string emailAddress)
        {
            using (CoinpanicContext db = new CoinpanicContext())
            {
                CoinClaim userclaim = db.Claims.Where(c => c.ClaimId == claimId).Include(c => c.InputAddresses).First();

                // Clean up input
                depositAddress = depositAddress.Replace("\n", String.Empty);
                depositAddress = depositAddress.Replace("\r", String.Empty);
                depositAddress = depositAddress.Replace("\t", String.Empty);
                depositAddress = depositAddress.Trim().Replace(" ", "");

                userclaim.DepositAddress = depositAddress;
                userclaim.Email          = emailAddress;

                List <string> list = new List <string>(
                    PublicKeys.Split(new string[] { "\r\n" },
                                     StringSplitOptions.RemoveEmptyEntries));

                if (list.Count < 1)
                {
                    return(RedirectToAction("ClaimError", new { message = "You must enter at least one address to claim", claimId = claimId }));
                }

                // Convert depositAddress if BCH

                if (userclaim.CoinShortName == "BCH" && depositAddress.StartsWith("bitcoincash:"))
                {
                    // Convert
                    depositAddress = SharpCashAddr.Converter.cashAddrToOldAddr(depositAddress, out bool isP2PKH, out _);
                }

                if (!Bitcoin.IsValidAddress(depositAddress, userclaim.CoinShortName, BitcoinForks.ForkByShortName[userclaim.CoinShortName].Network))
                {
                    return(RedirectToAction("ClaimError", new { message = "Deposit Address not valid", claimId = claimId }));
                }

                var invalid = list.Where(a => !Bitcoin.IsValidAddress(a));
                if (invalid.Count() > 0)
                {
                    return(RedirectToAction("ClaimError", new { message = String.Join(", ", invalid) + (invalid.Count() < 2 ? " is" : " are") + " invalid.", claimId = claimId }));
                }

                var scanner        = new BlockScanner();
                var claimAddresses = Bitcoin.ParseAddresses(list);

                Tuple <List <ICoin>, Dictionary <string, double> > claimcoins;
                try
                {
                    claimcoins = scanner.GetUnspentTransactionOutputs(claimAddresses, userclaim.CoinShortName, out bool usedExplorer);
                }
                catch (Exception e)
                {
                    return(RedirectToAction("ClaimError", new { message = "Error searching for your addresses in the blockchain", claimId = claimId }));
                }

                var amounts  = scanner.CalculateOutputAmounts_Their_My_Fee(claimcoins.Item1, 0.05, 0.0003 * claimcoins.Item1.Count);
                var balances = claimcoins.Item2;

                // Return converted addresses to user
                List <InputAddress> inputs;
                inputs = GetInputAddresses(userclaim, list, balances);

                userclaim.InputAddresses = inputs;
                userclaim.Deposited      = Convert.ToDouble(amounts[0].ToDecimal(MoneyUnit.BTC));
                userclaim.MyFee          = Convert.ToDouble(amounts[1].ToDecimal(MoneyUnit.BTC));
                userclaim.MinerFee       = Convert.ToDouble(amounts[2].ToDecimal(MoneyUnit.BTC));
                userclaim.TotalValue     = userclaim.Deposited + userclaim.MyFee + userclaim.MinerFee;
                userclaim.InitializeDate = DateTime.Now;

                if (userclaim.Deposited < 0)
                {
                    userclaim.Deposited = 0;
                }
                if (userclaim.MyFee < 0)
                {
                    userclaim.MyFee = 0;
                }

                // Generate unsigned tx
                var mydepaddr = ConfigurationManager.AppSettings[userclaim.CoinShortName + "Deposit"];

                if (userclaim.CoinShortName == "BCH" && mydepaddr.StartsWith("bitcoincash:"))
                {
                    // Convert
                    mydepaddr = SharpCashAddr.Converter.cashAddrToOldAddr(mydepaddr, out bool isP2PKH, out _);
                }

                var utx = Bitcoin.GenerateUnsignedTX(
                    UTXOs: claimcoins.Item1,
                    amounts: amounts,
                    clientDepAddr: Bitcoin.ParseAddress(depositAddress, userclaim.CoinShortName, BitcoinForks.ForkByShortName[userclaim.CoinShortName].Network),
                    MyDepositAddr: Bitcoin.ParseAddress(mydepaddr, userclaim.CoinShortName, BitcoinForks.ForkByShortName[userclaim.CoinShortName].Network),
                    forkShortName: userclaim.CoinShortName);

                userclaim.UnsignedTX = utx;

                // Generate witness data
                var w = Bitcoin.GetBlockData(claimcoins.Item1);
                userclaim.BlockData = w;

                // New format of message
                BlockData bd = new BlockData()
                {
                    fork      = userclaim.CoinShortName,
                    coins     = claimcoins.Item1,
                    utx       = utx,
                    addresses = balances.Select(kvp => kvp.Key).ToList(),
                };
                string bdstr = NBitcoin.JsonConverters.Serializer.ToString(bd);
                userclaim.ClaimData = bdstr;

                db.SaveChanges();

                MonitoringService.SendMessage("New " + userclaim.CoinShortName + " claim", "new claim Initialized. https://www.coinpanic.com/Claim/ClaimConfirm?claimId=" + claimId + " " + " for " + userclaim.CoinShortName);
            }
            return(RedirectToAction("ClaimConfirm", new { claimId = claimId }));
        }
Example #30
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="request"></param>
        /// <param name="userId"></param>
        /// <param name="lndClient"></param>
        /// <returns></returns>
        public object TryWithdrawal(string request, string userId, string ip, LndRpcClient lndClient)
        {
            int maxWithdraw           = 150;
            int maxWithdraw_firstuser = 150;

            if (lndClient == null)
            {
                throw new ArgumentNullException(nameof(lndClient));
            }

            // Lock all threading
            lock (withdrawLock)
            {
                LnCJUser user;
                try
                {
                    var decoded = lndClient.DecodePayment(request);

                    // Check if payment request is ok
                    if (decoded.destination == null)
                    {
                        return(new { Result = "Error decoding invoice." });
                    }

                    // Check that there are funds in the Jar
                    Int64          balance;
                    LnCommunityJar jar;
                    using (CoinpanicContext db = new CoinpanicContext())
                    {
                        jar = db.LnCommunityJars
                              .Where(j => j.IsTestnet == false)
                              .AsNoTracking().First();

                        balance = jar.Balance;

                        if (Convert.ToInt64(decoded.num_satoshis) > balance)
                        {
                            return(new { Result = "Requested amount is greater than the available balance." });
                        }

                        //Get user
                        user = GetUserFromDb(userId, db, jar, ip);

                        var userMax = (user.TotalDeposited - user.TotalWithdrawn);
                        if (userMax < maxWithdraw)
                        {
                            userMax = maxWithdraw;
                        }

                        if (Convert.ToInt64(decoded.num_satoshis) > userMax)
                        {
                            return(new { Result = "Requested amount is greater than maximum allowed." });
                        }
                    }

                    // Check for banned nodes
                    if (IsNodeBanned(decoded.destination, out string banmessage))
                    {
                        return(new { Result = "Banned.  Reason: " + banmessage });
                    }

                    if (decoded.destination == "03a9d79bcfab7feb0f24c3cd61a57f0f00de2225b6d31bce0bc4564efa3b1b5aaf")
                    {
                        return(new { Result = "Can not deposit from jar!" });
                    }

                    //Check rate limits

                    if (nodeWithdrawAttemptTimes.TryGetValue(decoded.destination, out DateTime lastWithdraw))
                    {
                        if ((DateTime.UtcNow - lastWithdraw) < withdrawRateLimit)
                        {
                            return(new { Result = "Rate limit exceeded." });
                        }
                    }

                    bool isanon = false;
                    using (CoinpanicContext db = new CoinpanicContext())
                    {
                        //check if new user
                        DateTime?LastWithdraw = user.TimesampLastWithdraw;

                        //LastWithdraw = db.LnTransactions.Where(tx => tx.IsDeposit == false && tx.IsSettled == true && tx.UserId == user.LnCJUserId).OrderBy(tx => tx.TimestampCreated).AsNoTracking().First().TimestampCreated;
                        if (user.NumWithdraws == 0 && user.NumDeposits == 0)
                        {
                            maxWithdraw = maxWithdraw_firstuser;
                            isanon      = true;
                            //check ip (if someone is not using cookies to rob the site)
                            var userIPs = db.LnCommunityJarUsers.Where(u => u.UserIP == ip).ToList();
                            if (userIPs.Count > 1)
                            {
                                //most recent withdraw
                                LastWithdraw = userIPs.Max(u => u.TimesampLastWithdraw);
                            }

                            // Re-check limits
                            if (Convert.ToInt64(decoded.num_satoshis) > maxWithdraw)
                            {
                                return(new { Result = "Requested amount is greater than maximum allowed for first time users (" + Convert.ToString(maxWithdraw) + ").  Make a deposit." });
                            }
                        }

                        if (user.TotalDeposited - user.TotalWithdrawn < maxWithdraw)
                        {
                            //check for time rate limiting
                            if (DateTime.UtcNow - LastWithdraw < TimeSpan.FromHours(1))
                            {
                                return(new { Result = "You must wait another " + ((user.TimesampLastWithdraw + TimeSpan.FromHours(1)) - DateTime.UtcNow).Value.TotalMinutes.ToString("0.0") + " minutes before withdrawing again, or make a deposit first." });
                            }
                        }

                        //Check if already paid
                        if (db.LnTransactions.Where(tx => tx.PaymentRequest == request && tx.IsSettled).Count() > 0)
                        {
                            return(new { Result = "Invoice has already been paid." });
                        }

                        if (isanon && DateTime.Now - timeLastAnonWithdraw < TimeSpan.FromMinutes(60))
                        {
                            return(new { Result = "Too many first-time user withdraws.  You must wait another " + ((timeLastAnonWithdraw + TimeSpan.FromMinutes(60)) - DateTime.Now).TotalMinutes.ToString("0.0") + " minutes before withdrawing again, or make a deposit first." });
                        }
                    }

                    SendPaymentResponse paymentresult;
                    if (WithdrawRequests.TryAdd(request, DateTime.UtcNow))
                    {
                        paymentresult = lndClient.PayInvoice(request);
                    }
                    else
                    {
                        //double request!
                        Thread.Sleep(1000);

                        //Check if paid (in another thread)
                        using (CoinpanicContext db = new CoinpanicContext())
                        {
                            var txs = db.LnTransactions.Where(t => t.PaymentRequest == request && t.IsSettled).OrderByDescending(t => t.TimestampSettled).AsNoTracking();
                            if (txs.Count() > 0)
                            {
                                //var tx = txs.First();
                                WithdrawRequests.TryRemove(request, out DateTime reqInitTimeA);
                                return(new { Result = "success", Fees = "0" });
                            }

                            return(new { Result = "Please click only once.  Payment already in processing." });
                        }
                    }
                    WithdrawRequests.TryRemove(request, out DateTime reqInitTime);

                    if (paymentresult.payment_error != null)
                    {
                        // Save payment error to database
                        using (CoinpanicContext db = new CoinpanicContext())
                        {
                            user = GetUserFromDb(userId, db, jar, ip);
                            LnTransaction t = new LnTransaction()
                            {
                                UserId            = user.LnCJUserId,
                                IsSettled         = false,
                                Memo              = decoded.description ?? "Withdraw",
                                Value             = Convert.ToInt64(decoded.num_satoshis),
                                IsTestnet         = false,
                                HashStr           = decoded.payment_hash,
                                IsDeposit         = false,
                                TimestampCreated  = DateTime.UtcNow, //can't know
                                PaymentRequest    = request,
                                DestinationPubKey = decoded.destination,
                                IsError           = true,
                                ErrorMessage      = paymentresult.payment_error,
                            };
                            db.LnTransactions.Add(t);
                            db.SaveChanges();
                        }
                        return(new { Result = "Payment Error: " + paymentresult.payment_error });
                    }

                    // We have a successful payment

                    // Record time of withdraw to the node
                    nodeWithdrawAttemptTimes.TryAdd(decoded.destination, DateTime.UtcNow);

                    // Notify client(s)
                    var context = GlobalHost.ConnectionManager.GetHubContext <NotificationHub>();

                    using (CoinpanicContext db = new CoinpanicContext())
                    {
                        user = GetUserFromDb(userId, db, jar, ip);
                        user.NumWithdraws        += 1;
                        user.TotalWithdrawn      += Convert.ToInt64(decoded.num_satoshis);
                        user.TimesampLastWithdraw = DateTime.UtcNow;

                        //insert transaction
                        LnTransaction t = new LnTransaction()
                        {
                            UserId            = user.LnCJUserId,
                            IsSettled         = true,
                            Memo              = decoded.description == null ? "Withdraw" : decoded.description,
                            Value             = Convert.ToInt64(decoded.num_satoshis),
                            IsTestnet         = false,
                            HashStr           = decoded.payment_hash,
                            IsDeposit         = false,
                            TimestampSettled  = DateTime.UtcNow,
                            TimestampCreated  = DateTime.UtcNow, //can't know
                            PaymentRequest    = request,
                            FeePaid_Satoshi   = (paymentresult.payment_route.total_fees == null ? 0 : Convert.ToInt64(paymentresult.payment_route.total_fees)),
                            NumberOfHops      = paymentresult.payment_route.hops == null ? 0 : paymentresult.payment_route.hops.Count(),
                            DestinationPubKey = decoded.destination,
                        };
                        db.LnTransactions.Add(t);
                        db.SaveChanges();

                        jar          = db.LnCommunityJars.Where(j => j.IsTestnet == false).First();
                        jar.Balance -= Convert.ToInt64(decoded.num_satoshis);
                        jar.Balance -= paymentresult.payment_route.total_fees != null?Convert.ToInt64(paymentresult.payment_route.total_fees) : 0;

                        jar.Transactions.Add(t);
                        db.SaveChanges();

                        var newT = new LnCJTransaction()
                        {
                            Timestamp = t.TimestampSettled == null ? DateTime.UtcNow : (DateTime)t.TimestampSettled,
                            Amount    = t.Value,
                            Memo      = t.Memo,
                            Type      = t.IsDeposit ? "Deposit" : "Withdrawal",
                            Id        = t.TransactionId,
                        };

                        context.Clients.All.NotifyNewTransaction(newT);
                    }

                    if (isanon)
                    {
                        timeLastAnonWithdraw = DateTime.Now;
                    }

                    return(new { Result = "success", Fees = (paymentresult.payment_route.total_fees == null ? "0" : paymentresult.payment_route.total_fees) });
                }
                catch (Exception e)
                {
                    return(new { Result = "Error decoding request." });
                }
            }
            return(new { Result = "Error decoding request." });
        }