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)); }
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); }
/// <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 })); } }
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); }
public ActionResult Statistics() { using (CoinpanicContext db = new CoinpanicContext()) { ViewBag.Errors = db.LnTransactions.AsNoTracking().Where(t => t.IsError).ToList(); } return(View()); }
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")); }
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; } }
// 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)); } }
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")); }
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)); }
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)); }
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)); }
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")); }
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); }
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 })); }
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")); }
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)); }
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")); }
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)); } }
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()); } } }
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); }
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); }
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)); }
/// <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); } } }
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" })); }
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)); } }
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)); }
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 })); }
/// <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." }); }