Пример #1
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);
        }
Пример #2
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);
        }
Пример #3
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);
        }
Пример #4
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"));
 }
Пример #5
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"));
            }
        }
Пример #6
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"));
 }
Пример #7
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);
        }
Пример #8
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"));
 }
Пример #9
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);
        }
Пример #10
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));
        }
Пример #11
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);
                }
            }
        }
Пример #12
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));
        }
Пример #13
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." });
        }
Пример #14
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 }));
        }
Пример #15
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));
            }
        }
Пример #16
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());
                }
            }
        }