Exemplo n.º 1
0
        public void AddOrderToView(MainService.OpenOrder ord)
        {
            //This function adds an order the view
            if (ord.market != MainService.exchange_market)
            {
                return;
            }                                                          //Not on this market, do not add to view
            if (!(MainPage is MarketPage))
            {
                return;
            }
            MarketPage page = (MarketPage)MainPage;

            if (ord.type == 0)
            {
                //Buying view
                lock (page.Buying_View_List)
                {
                    page.AddSortedOrderToViewList(page.Buying_View_List, ord, true);
                }
            }
            else if (ord.type == 1)
            {
                lock (page.Selling_View_List)
                {
                    page.AddSortedOrderToViewList(page.Selling_View_List, ord, false);
                }
            }
        }
Exemplo n.º 2
0
 public void AddSortedOrderToViewList(ObservableCollection <MainService.OpenOrder> nodelist, MainService.OpenOrder ord, bool highlow)
 {
     //Sort the collection by price
     for (int it = 0; it < nodelist.Count; it++)
     {
         MainService.OpenOrder old_ord = nodelist[it];
         if (old_ord == ord)
         {
             return;
         }                              //Order already in list
         if (old_ord.order_nonce == ord.order_nonce)
         {
             return;
         }                                                      //Order already in list
         if (highlow == true)
         {
             if (old_ord.price <= ord.price)
             {
                 nodelist.Insert(it, ord);
                 return;
             }
         }
         else
         {
             if (old_ord.price >= ord.price)
             {
                 nodelist.Insert(it, ord);
                 return;
             }
         }
     }
     nodelist.Add(ord);
 }
Exemplo n.º 3
0
        public static void UpdateOpenOrderList(int market, string order_nonce)
        {
            //This is not ran on UI thread

            //This function will remove 0 sized orders
            //First find the open order from our list
            MainService.OpenOrder ord = null;
            lock (MainService.OpenOrderList[market])
            {
                for (int i = MainService.OpenOrderList[market].Count - 1; i >= 0; i--)
                {
                    if (MainService.OpenOrderList[market][i].order_nonce == order_nonce && MainService.OpenOrderList[market][i].is_request == false)
                    {
                        ord = MainService.OpenOrderList[market][i];
                        if (MainService.OpenOrderList[market][i].amount <= 0)
                        { //Take off the order if its empty now
                            MainService.OpenOrderList[market].RemoveAt(i); break;
                        }
                    }
                }
            }

            if (ord == null)
            {
                return;
            }

            //Now remove the order from the Market List if present
            if (MainService.NebliDex_UI == null)
            {
                return;
            }                                               //No Forms app present

            if (MainService.NebliDex_UI.MainPage is MarketPage)
            {
                MarketPage page = (MarketPage)MainService.NebliDex_UI.MainPage;
                //Market Page is open, modify its lists
                if (market != MainService.exchange_market)
                {
                    return;
                }
                if (ord.type == 0)
                {
                    //Buying view
                    if (ord.amount <= 0)
                    {
                        page.Buying_View_List.Remove(ord);
                    }
                }
                else if (ord.type == 1)
                {
                    if (ord.amount <= 0)
                    {
                        page.Selling_View_List.Remove(ord);
                    }
                }
            }
        }
Exemplo n.º 4
0
        bool input_updating = false; //Prevents events from firing from another event

        public MatchOrder(MainService.OpenOrder ord)
        {
            InitializeComponent();

            window_order = ord;

            string trade_symbol = MainService.MarketList[MainService.exchange_market].trade_symbol;
            string base_symbol  = MainService.MarketList[MainService.exchange_market].base_symbol;

            min_ord = ord.minimum_amount;
            if (min_ord > ord.amount)
            {
                min_ord = ord.amount;
            }

            if (ord.type == 0)
            {
                //Buy Order
                Header.Text           = "Buy Order Details";
                Order_Type.Text       = "Requesting:";
                Order_Amount.Text     = String.Format(CultureInfo.InvariantCulture, "{0:0.########}", ord.amount);
                Order_Min_Amount.Text = String.Format(CultureInfo.InvariantCulture, "{0:0.########}", min_ord);
                Price.Text            = String.Format(CultureInfo.InvariantCulture, "{0:0.########}", ord.price);
                decimal my_balance = MainService.GetMarketBalance(MainService.exchange_market, 1); //If they are buying, we are selling

                Order_Amount.Text           += " " + trade_symbol;
                Order_Min_Amount.Text       += " " + trade_symbol;
                Price.Text                  += " " + base_symbol;
                My_Amount_Header.Text        = "Amount (" + trade_symbol + "):";
                Total_Cost_Header.Text       = "Total Receive (" + base_symbol + "):";
                My_Balance.Text              = String.Format(CultureInfo.InvariantCulture, "{0:0.########}", my_balance) + " " + trade_symbol;
                Match_Button.BackgroundColor = Xamarin.Forms.Color.FromHex("#63AB1D");
            }
            else
            {
                //Sell Order
                Header.Text           = "Sell Order Details";
                Order_Type.Text       = "Available:";
                Order_Amount.Text     = String.Format(CultureInfo.InvariantCulture, "{0:0.########}", ord.amount);
                Order_Min_Amount.Text = String.Format(CultureInfo.InvariantCulture, "{0:0.########}", min_ord);
                Price.Text            = String.Format(CultureInfo.InvariantCulture, "{0:0.########}", ord.price);
                decimal my_balance = MainService.GetMarketBalance(MainService.exchange_market, 0); //If they are selling, we are buying

                Order_Amount.Text           += " " + trade_symbol;
                Order_Min_Amount.Text       += " " + trade_symbol;
                Price.Text                  += " " + base_symbol;
                My_Amount_Header.Text        = "Amount (" + trade_symbol + "):";
                Total_Cost_Header.Text       = "Total Cost (" + base_symbol + "):";
                My_Balance.Text              = String.Format(CultureInfo.InvariantCulture, "{0:0.########}", my_balance) + " " + base_symbol;
                Match_Button.BackgroundColor = Xamarin.Forms.Color.FromHex("#EA0070");
            }
        }
Exemplo n.º 5
0
        private async void DoubleTapped_Order(object sender, ItemTappedEventArgs e)
        {
            if (market_loading == true)
            {
                return;
            }

            ListView view = sender as ListView;

            if (view == null)
            {
                return;
            }
            if (view.SelectedItem == null)
            {
                return;
            }
            tapped_amount++;
            if (tapped_amount < 2)
            {
                return;
            }                                 //Must tap this order at least twice before trying to trade
            tapped_amount = 0;

            MainService.OpenOrder ord = (MainService.OpenOrder)view.SelectedItem; //This is order

            //Verify that order is not our own order
            bool notmine = true;

            lock (MainService.MyOpenOrderList)
            {
                for (int i = 0; i < MainService.MyOpenOrderList.Count; i++)
                {
                    if (MainService.MyOpenOrderList[i].order_nonce == ord.order_nonce)
                    {
                        notmine = false; break;
                    }
                }
            }

            if (notmine == true)
            {
                await Navigation.PushModalAsync(new MatchOrder(ord));
            }
            else
            {
                MainService.MessageBox("Alert", "Cannot match with your own order!", "OK", false);
            }
        }
Exemplo n.º 6
0
        public void RemoveOrderFromView(MainService.OpenOrder ord)
        {
            //This function adds an order the view
            if (ord.market != MainService.exchange_market)
            {
                return;
            }                                                          //Not on this market, do not need to remove to view
            if (!(MainPage is MarketPage))
            {
                return;
            }
            MarketPage page = (MarketPage)MainPage;

            if (ord.type == 0)
            {
                //Buying view
                lock (page.Buying_View_List)
                {
                    for (int i = page.Buying_View_List.Count - 1; i >= 0; i--)
                    {
                        MainService.OpenOrder ord2 = page.Buying_View_List[i];
                        if (ord2.order_nonce.Equals(ord.order_nonce) == true)
                        { //Remove matching nonce
                            page.Buying_View_List.RemoveAt(i);
                        }
                    }
                }
            }
            else if (ord.type == 1)
            {
                lock (page.Selling_View_List)
                {
                    for (int i = page.Selling_View_List.Count - 1; i >= 0; i--)
                    {
                        MainService.OpenOrder ord2 = page.Selling_View_List[i];
                        if (ord2.order_nonce.Equals(ord.order_nonce) == true)
                        {
                            page.Selling_View_List.RemoveAt(i);
                        }
                    }
                }
            }
        }
Exemplo n.º 7
0
        private void Request_Cancel_Order(object sender, EventArgs e)
        {
            //This will cancel an order, however it will not stop a pending payment after my transaction has broadcasted
            //Also for market orders, will attempt to cancel the order requests
            Label selected_label = sender as Label;

            MainService.OpenOrder ord = (MainService.OpenOrder)selected_label.BindingContext;
            if (ord.order_stage >= 3)
            {
                //The maker has an order in which it is waiting for the taker to redeem balance
                MainService.MessageBox("Notice!", "Your order is currently involved in a trade. Please try again later.", "OK", false);
                return;
            }

            selected_label.IsEnabled = false;
            Task.Run(() =>
            {
                MainService.CancelMyOrder(ord);
                MainService.NebliDex_Activity.RunOnUiThread(() => {
                    selected_label.IsEnabled = true;
                });
            });
        }
Exemplo n.º 8
0
        //Match Order
        private void Make_Order(object sender, EventArgs e)
        {
            //Create our order!
            //Get the price

            if (MainService.IsNumber(Price_Input.Text) == false)
            {
                return;
            }
            if (Price_Input.Text.IndexOf(",", StringComparison.InvariantCulture) >= 0)
            {
                MainService.MessageBox("Notice", "NebliDex does not recognize commas for decimals at this time.", "OK", false);
                return;
            }
            decimal price = decimal.Parse(Price_Input.Text, CultureInfo.InvariantCulture);

            if (price <= 0)
            {
                return;
            }
            if (price > MainService.max_order_price)
            {
                //Price cannot exceed the max
                MainService.MessageBox("Notice", "This price is higher than the maximum price of 10 000 000", "OK", false);
                return;
            }

            //Get the amount
            if (MainService.IsNumber(Amount_Input.Text) == false)
            {
                return;
            }
            if (Amount_Input.Text.IndexOf(",", StringComparison.InvariantCulture) >= 0)
            {
                MainService.MessageBox("Notice", "NebliDex does not recognize commas for decimals at this time.", "OK", false);
                return;
            }
            decimal amount = decimal.Parse(Amount_Input.Text, CultureInfo.InvariantCulture);

            if (amount <= 0)
            {
                return;
            }

            if (MainService.IsNumber(Min_Amount_Input.Text) == false)
            {
                return;
            }
            if (Min_Amount_Input.Text.IndexOf(",", StringComparison.InvariantCulture) >= 0)
            {
                MainService.MessageBox("Notice", "NebliDex does not recognize commas for decimals at this time.", "OK", false);
                return;
            }
            decimal min_amount = decimal.Parse(Min_Amount_Input.Text, CultureInfo.InvariantCulture);

            if (min_amount <= 0)
            {
                MainService.MessageBox("Notice", "The minimum amount is too small.", "OK", false);
                return;
            }
            if (min_amount > amount)
            {
                MainService.MessageBox("Notice", "The minimum amount cannot be greater than the amount.", "OK", false);
                return;
            }

            decimal total = Math.Round(price * amount, 8);

            if (Total_Input.Text.IndexOf(",", StringComparison.InvariantCulture) >= 0)
            {
                MainService.MessageBox("Notice", "NebliDex does not recognize commas for decimals at this time.", "OK", false);
                return;
            }

            if (MainService.MarketList[MainService.exchange_market].base_wallet == 3 || MainService.MarketList[MainService.exchange_market].trade_wallet == 3)
            {
                //Make sure amount is greater than ndexfee x 2
                if (amount < MainService.ndex_fee * 2)
                {
                    MainService.MessageBox("Notice", "This order amount is too small. Must be at least twice the CN fee (" + String.Format(CultureInfo.InvariantCulture, "{0:0.########}", MainService.ndex_fee * 2) + " NDEX)", "OK", false);
                    return;
                }
            }

            int    wallet = 0;
            string msg    = "";
            bool   good   = false;

            if (order_type == 0)
            {
                //This is a buy order we are making, so we need base market balance
                wallet = MainService.MarketList[MainService.exchange_market].base_wallet;
                good   = MainService.CheckWalletBalance(wallet, total, ref msg);
                if (good == true)
                {
                    //Now check the fees
                    good = MainService.CheckMarketFees(MainService.exchange_market, order_type, total, ref msg, false);
                }
            }
            else
            {
                //Selling the trade wallet amount
                wallet = MainService.MarketList[MainService.exchange_market].trade_wallet;
                good   = MainService.CheckWalletBalance(wallet, amount, ref msg);
                if (good == true)
                {
                    good = MainService.CheckMarketFees(MainService.exchange_market, order_type, amount, ref msg, false);
                }
            }

            //Show error messsage if balance not available
            if (good == false)
            {
                //Not enough funds or wallet unavailable
                MainService.MessageBox("Notice", msg, "OK", false);
                return;
            }

            //Make sure that total is greater than blockrate for the base market and the amount is greater than blockrate for trade market
            decimal block_fee1 = 0;
            decimal block_fee2 = 0;
            int     trade_wallet_blockchaintype = MainService.GetWalletBlockchainType(MainService.MarketList[MainService.exchange_market].trade_wallet);
            int     base_wallet_blockchaintype  = MainService.GetWalletBlockchainType(MainService.MarketList[MainService.exchange_market].base_wallet);

            block_fee1 = MainService.blockchain_fee[trade_wallet_blockchaintype];
            block_fee2 = MainService.blockchain_fee[base_wallet_blockchaintype];

            //Now calculate the totals for ethereum blockchain
            if (trade_wallet_blockchaintype == 6)
            {
                block_fee1 = MainService.GetEtherContractTradeFee(MainService.Wallet.CoinERC20(MainService.MarketList[MainService.exchange_market].trade_wallet));
                if (MainService.Wallet.CoinERC20(MainService.MarketList[MainService.exchange_market].trade_wallet) == true)
                {
                    block_fee1 = Convert.ToDecimal(MainService.double_epsilon); // The minimum trade size for ERC20 tokens
                }
            }
            if (base_wallet_blockchaintype == 6)
            {
                block_fee2 = MainService.GetEtherContractTradeFee(MainService.Wallet.CoinERC20(MainService.MarketList[MainService.exchange_market].base_wallet));
                if (MainService.Wallet.CoinERC20(MainService.MarketList[MainService.exchange_market].base_wallet) == true)
                {
                    block_fee2 = Convert.ToDecimal(MainService.double_epsilon); // The minimum trade size for ERC20 tokens
                }
            }

            if (total < block_fee2 || amount < block_fee1)
            {
                //The trade amount is too small
                MainService.MessageBox("Notice", "This trade amount is too small to create because it is lower than the blockchain fee.", "OK", false);
                return;
            }

            //ERC20 only check
            //We need to check if the ERC20 token contract allows us to pull tokens to the atomic swap contract
            bool    sending_erc20 = false;
            decimal erc20_amount  = 0;
            int     erc20_wallet  = 0;

            if (order_type == 0 && MainService.Wallet.CoinERC20(MainService.MarketList[MainService.exchange_market].base_wallet) == true)
            {
                //Buying trade with ERC20
                sending_erc20 = true;
                erc20_amount  = total;
                erc20_wallet  = MainService.MarketList[MainService.exchange_market].base_wallet;
            }
            else if (order_type == 1 && MainService.Wallet.CoinERC20(MainService.MarketList[MainService.exchange_market].trade_wallet) == true)
            {
                //Selling trade that is also an ERC20
                sending_erc20 = true;
                erc20_amount  = amount;
                erc20_wallet  = MainService.MarketList[MainService.exchange_market].trade_wallet;
            }

            //Run the rest as a separate thread
            Task.Run(() => {
                if (sending_erc20 == true)
                {
                    //Make sure the allowance is there already
                    decimal allowance = MainService.GetERC20AtomicSwapAllowance(MainService.GetWalletAddress(erc20_wallet), MainService.ERC20_ATOMICSWAP_ADDRESS, erc20_wallet);
                    if (allowance < 0)
                    {
                        MainService.MessageBox("Notice", "Error determining ERC20 token contract allowance, please try again.", "OK", false);
                        return;
                    }
                    else if (allowance < erc20_amount)
                    {
                        //We need to increase the allowance to send to the atomic swap contract eventually
                        bool result = MainService.PromptUser("Confirmation", "Permission is required from this token's contract to send this amount to the NebliDex atomic swap contract.", "OK", "Cancel");
                        if (result == true)
                        {
                            //Create a transaction with this permission to send up to this amount
                            allowance = 1000000; //1 million tokens by default
                            if (erc20_amount > allowance)
                            {
                                allowance = erc20_amount;
                            }
                            MainService.CreateAndBroadcastERC20Approval(erc20_wallet, allowance, MainService.ERC20_ATOMICSWAP_ADDRESS);
                            MainService.MessageBox("Notice", "Now please wait for your approval to be confirmed by the Ethereum network then try again.", "OK", false);
                        }
                        return;
                    }
                }

                //Because tokens are indivisible at the moment, amounts can only be in whole numbers
                bool ntp1_wallet = MainService.IsWalletNTP1(MainService.MarketList[MainService.exchange_market].trade_wallet);
                if (ntp1_wallet == true)
                {
                    if (Math.Abs(Math.Round(amount) - amount) > 0)
                    {
                        MainService.MessageBox("Notice", "All NTP1 tokens are indivisible at this time. Must be whole amounts.", "OK", false);
                        return;
                    }
                    amount = Math.Round(amount);

                    if (Math.Abs(Math.Round(min_amount) - min_amount) > 0)
                    {
                        MainService.MessageBox("Notice", "All NTP1 tokens are indivisible at this time. Must be whole minimum amounts.", "OK", false);
                        return;
                    }
                    min_amount = Math.Round(min_amount);
                }

                //Check to see if any other open orders of mine
                if (MainService.MyOpenOrderList.Count >= MainService.total_markets)
                {
                    MainService.MessageBox("Notice", "You have exceed the maximum amount (" + MainService.total_markets + ") of open orders.", "OK", false);
                    return;
                }

                MainService.OpenOrder ord = new MainService.OpenOrder();
                ord.order_nonce           = MainService.GenerateHexNonce(32);
                ord.market          = MainService.exchange_market;
                ord.type            = order_type;
                ord.price           = Math.Round(price, 8);
                ord.amount          = Math.Round(amount, 8);
                ord.minimum_amount  = Math.Round(min_amount, 8);
                ord.original_amount = amount;
                ord.order_stage     = 0;
                ord.my_order        = true; //Very important, it defines how much the program can sign automatically

                //Run this on UI thread
                MainService.NebliDex_Activity.RunOnUiThread(() => {
                    //Disable the order button
                    Order_Button.IsEnabled = false;
                    Order_Button.Text      = "Contacting CN...";
                });

                //Try to submit order to CN
                bool worked = MainService.SubmitMyOrder(ord, null);
                if (worked == true)
                {
                    //Add to lists and close order
                    lock (MainService.MyOpenOrderList)
                    {
                        MainService.MyOpenOrderList.Add(ord); //Add to our own personal list
                    }
                    lock (MainService.OpenOrderList[MainService.exchange_market])
                    {
                        MainService.OpenOrderList[MainService.exchange_market].Add(ord);
                    }
                    MainService.NebliDex_UI.AddOrderToView(ord);
                    MainService.AddSavedOrder(ord);
                    MainService.NebliDex_Activity.RunOnUiThread(() => {
                        //Close the Model and go back to Market Page on UI thread
                        Navigation.PopModalAsync();
                    });
                    return;
                }
                //Otherwise re-enable the button
                MainService.NebliDex_Activity.RunOnUiThread(() => {
                    //Reset the button
                    Order_Button.IsEnabled = true;
                    Order_Button.Text      = "Create Order";
                });
            });
        }
Exemplo n.º 9
0
        public static void AddRecentTradeToView(int market, int type, decimal price, decimal amount, string order_nonce, int time)
        {
            if (amount <= 0)
            {
                return;
            }                            //Someone is trying to hack the system

            //First check if our open orders matches this recent trade
            MainService.OpenOrder myord = null;
            lock (MainService.MyOpenOrderList)
            {
                for (int i = MainService.MyOpenOrderList.Count - 1; i >= 0; i--)
                {
                    if (MainService.MyOpenOrderList[i].order_nonce == order_nonce)
                    {
                        if (MainService.MyOpenOrderList[i].is_request == false)
                        {
                            myord = MainService.MyOpenOrderList[i];
                            break;
                        }
                        else
                        {
                            //I am requesting this order, should only occur during simultaneous order request
                            //when only one of the orders match. Clear this request and tell user someone else took order
                            MainService.MyOpenOrderList.RemoveAt(i);
                            MainService.ShowTradeMessage("Trade Failed:\nSomeone else matched this order before you!");
                        }
                    }
                }
            }

            if (market != MainService.exchange_market)
            {
                return;
            }                                                      //We don't care about recent trades from other markets if not critical node

            //Also modify the open order that is not our order
            lock (MainService.OpenOrderList[market])
            {
                for (int i = MainService.OpenOrderList[market].Count - 1; i >= 0; i--)
                {
                    if (MainService.OpenOrderList[market][i].order_nonce == order_nonce && MainService.OpenOrderList[market][i].is_request == false)
                    {
                        if (MainService.OpenOrderList[market][i] != myord)
                        {
                            //Maker will decrease its own balance separately
                            MainService.OpenOrderList[market][i].amount -= amount; //We already subtracted the amount if my order
                            MainService.OpenOrderList[market][i].amount  = Math.Round(MainService.OpenOrderList[market][i].amount, 8);
                        }
                    }
                }
            }

            //This will also calculate the chartlastprice and modify the candle

            MainService.RecentTrade rt = new MainService.RecentTrade();
            rt.amount  = amount;
            rt.market  = market;
            rt.price   = price;
            rt.type    = type;
            rt.utctime = time;

            MainService.InsertRecentTradeByTime(rt); //Insert the trade by time

            //First check to see if this time has already passed the current candle
            bool[] updatedcandle = new bool[2];
            if (time < MainService.ChartLastPrice15StartTime)
            {
                //This time is prior to the start of the candle
                updatedcandle[0] = MainService.TryUpdateOldCandle(market, Convert.ToDouble(price), time, 0);
                if (updatedcandle[0] == true)
                {
                    MainService.NebliDexNetLog("Updated a previous 15 minute candle");
                }
                updatedcandle[1] = MainService.TryUpdateOldCandle(market, Convert.ToDouble(price), time, 1);
                if (updatedcandle[1] == true)
                {
                    MainService.NebliDexNetLog("Updated a previous 90 minute candle");
                }
            }

            MainService.LastPriceObject pr = new MainService.LastPriceObject();
            pr.price  = price;
            pr.market = market;
            pr.atime  = time;
            lock (MainService.ChartLastPrice)
            { //Adding prices is not thread safe
                if (updatedcandle[0] == false)
                {
                    MainService.InsertChartLastPriceByTime(MainService.ChartLastPrice[0], pr);
                }

                if (updatedcandle[1] == false)
                {
                    MainService.InsertChartLastPriceByTime(MainService.ChartLastPrice[1], pr);
                }
            }

            //Update the current candle
            if (MainService.NebliDex_UI == null)
            {
                return;
            }                                                //No Forms app present

            if (market != MainService.exchange_market)
            {
                return;
            }

            if (MainService.NebliDex_UI.MainPage is MarketPage)
            {
                MarketPage page = (MarketPage)MainService.NebliDex_UI.MainPage;

                if (updatedcandle[page.chart_timeline] == false)
                {
                    //This most recent candle hasn't been updated yet
                    //Otherwise run the following code from the UI thread
                    MainService.NebliDex_Activity.RunOnUiThread(() =>
                    {
                        page.UpdateLastCandle(Convert.ToDouble(price));
                    });
                }
                else
                {
                    //Just refresh the view
                    Task.Run(() => page.UpdateCandles());
                }
            }
            UpdateOpenOrderList(market, order_nonce); //This will update the views if necessary and remove the order
        }
Exemplo n.º 10
0
        private void Match_Order(object sender, EventArgs e)
        {
            if (My_Amount.Text.Length == 0 || Total_Amount.Text.Length == 0)
            {
                return;
            }
            if (My_Amount.Text.IndexOf(",") >= 0)
            {
                MainService.MessageBox("Notice!", "NebliDex does not recognize commas for decimals at this time.", "OK", false);
                return;
            }
            if (Total_Amount.Text.IndexOf(",") >= 0)
            {
                MainService.MessageBox("Notice!", "NebliDex does not recognize commas for decimals at this time.", "OK", false);
                return;
            }
            decimal amount = decimal.Parse(My_Amount.Text, CultureInfo.InvariantCulture);
            decimal total  = decimal.Parse(Total_Amount.Text, CultureInfo.InvariantCulture);

            if (amount < min_ord)
            {
                //Cannot be less than the minimum order
                MainService.MessageBox("Notice!", "Amount cannot be less than the minimum match.", "OK", false);
                return;
            }
            if (amount > window_order.amount)
            {
                //Cannot be greater than request
                MainService.MessageBox("Notice!", "Amount cannot be greater than the order.", "OK", false);
                return;
            }

            if (MainService.MarketList[MainService.exchange_market].base_wallet == 3 || MainService.MarketList[MainService.exchange_market].trade_wallet == 3)
            {
                //Make sure amount is greater than ndexfee x 2
                if (amount < MainService.ndex_fee * 2)
                {
                    MainService.MessageBox("Notice!", "This order amount is too small. Must be at least twice the CN fee (" + String.Format(CultureInfo.InvariantCulture, "{0:0.########}", MainService.ndex_fee * 2) + " NDEX)", "OK", false);
                    return;
                }
            }

            string  msg       = "";
            decimal mybalance = 0;
            int     mywallet  = 0;

            //Now check the balances
            if (window_order.type == 1)
            {                                                                        //They are selling, so we are buying
                mybalance = total;                                                   //Base pair balance
                mywallet  = MainService.MarketList[window_order.market].base_wallet; //This is the base pair wallet
            }
            else
            {                                                                         //They are buying so we are selling
                mybalance = amount;                                                   //Base pair balance
                mywallet  = MainService.MarketList[window_order.market].trade_wallet; //This is the trade pair wallet
            }
            bool good = MainService.CheckWalletBalance(mywallet, mybalance, ref msg);

            if (good == true)
            {
                //Now check the fees
                good = MainService.CheckMarketFees(MainService.exchange_market, 1 - window_order.type, mybalance, ref msg, true);
            }

            if (good == false)
            {
                //Not enough funds or wallet unavailable
                MainService.MessageBox("Notice!", msg, "OK", false);
                return;
            }

            //Make sure that total is greater than blockrate for the base market and the amount is greater than blockrate for trade market
            decimal block_fee1 = 0;
            decimal block_fee2 = 0;
            int     trade_wallet_blockchaintype = MainService.GetWalletBlockchainType(MainService.MarketList[MainService.exchange_market].trade_wallet);
            int     base_wallet_blockchaintype  = MainService.GetWalletBlockchainType(MainService.MarketList[MainService.exchange_market].base_wallet);

            block_fee1 = MainService.blockchain_fee[trade_wallet_blockchaintype];
            block_fee2 = MainService.blockchain_fee[base_wallet_blockchaintype];

            //Now calculate the totals for ethereum blockchain
            if (trade_wallet_blockchaintype == 6)
            {
                block_fee1 = MainService.GetEtherContractTradeFee(MainService.Wallet.CoinERC20(MainService.MarketList[MainService.exchange_market].trade_wallet));
                if (MainService.Wallet.CoinERC20(MainService.MarketList[MainService.exchange_market].trade_wallet) == true)
                {
                    block_fee1 = Convert.ToDecimal(MainService.double_epsilon); // The minimum trade size for ERC20 tokens
                }
            }
            if (base_wallet_blockchaintype == 6)
            {
                block_fee2 = MainService.GetEtherContractTradeFee(MainService.Wallet.CoinERC20(MainService.MarketList[MainService.exchange_market].base_wallet));
                if (MainService.Wallet.CoinERC20(MainService.MarketList[MainService.exchange_market].base_wallet) == true)
                {
                    block_fee2 = Convert.ToDecimal(MainService.double_epsilon); // The minimum trade size for ERC20 tokens
                }
            }

            if (total < block_fee2 || amount < block_fee1)
            {
                //The trade amount is too small
                MainService.MessageBox("Notice!", "This trade amount is too small to match because it is lower than the blockchain fee.", "OK", false);
                return;
            }

            //ERC20 only check
            bool    sending_erc20 = false;
            decimal erc20_amount  = 0;
            int     erc20_wallet  = 0;

            if (window_order.type == 1 && MainService.Wallet.CoinERC20(MainService.MarketList[MainService.exchange_market].base_wallet) == true)
            {
                //Maker is selling so we are buying trade with ERC20
                sending_erc20 = true;
                erc20_amount  = total;
                erc20_wallet  = MainService.MarketList[MainService.exchange_market].base_wallet;
            }
            else if (window_order.type == 0 && MainService.Wallet.CoinERC20(MainService.MarketList[MainService.exchange_market].trade_wallet) == true)
            {
                //Maker is buying so we are selling trade that is also an ERC20
                sending_erc20 = true;
                erc20_amount  = amount;
                erc20_wallet  = MainService.MarketList[MainService.exchange_market].trade_wallet;
            }

            //Start running on background thread
            Task.Run(() =>
            {
                if (sending_erc20 == true)
                {
                    //Make sure the allowance is there already
                    decimal allowance = MainService.GetERC20AtomicSwapAllowance(MainService.GetWalletAddress(erc20_wallet), MainService.ERC20_ATOMICSWAP_ADDRESS, erc20_wallet);
                    if (allowance < 0)
                    {
                        MainService.MessageBox("Notice!", "Error determining ERC20 token contract allowance, please try again.", "OK", false);
                        return;
                    }
                    else if (allowance < erc20_amount)
                    {
                        //We need to increase the allowance to send to the atomic swap contract eventually
                        bool result = MainService.PromptUser("Confirmation", "Permission is required from this token's contract to send this amount to the NebliDex atomic swap contract.", "OK", "Cancel");
                        if (result == true)
                        {
                            //Create a transaction with this permission to send up to this amount
                            allowance = 1000000; //1 million tokens by default
                            if (erc20_amount > allowance)
                            {
                                allowance = erc20_amount;
                            }
                            MainService.CreateAndBroadcastERC20Approval(erc20_wallet, allowance, MainService.ERC20_ATOMICSWAP_ADDRESS);
                            MainService.MessageBox("Notice!", "Now please wait for your approval to be confirmed by the Ethereum network then try again.", "OK", false);
                        }
                        return;
                    }
                }

                //Because tokens are indivisible at the moment, amounts can only be in whole numbers
                bool ntp1_wallet = MainService.IsWalletNTP1(MainService.MarketList[MainService.exchange_market].trade_wallet);
                if (ntp1_wallet == true)
                {
                    if (Math.Abs(Math.Round(amount) - amount) > 0)
                    {
                        MainService.MessageBox("Notice!", "All NTP1 tokens are indivisible at this time. Must be whole amounts.", "OK", false);
                        return;
                    }
                    amount = Math.Round(amount);
                }

                //Cannot match order when another order is involved deeply in trade
                bool too_soon = false;
                lock (MainService.MyOpenOrderList)
                {
                    for (int i = 0; i < MainService.MyOpenOrderList.Count; i++)
                    {
                        if (MainService.MyOpenOrderList[i].order_stage > 0)
                        {
                            too_soon = true; break;
                        }                                                                               //Your maker order is matching something
                        if (MainService.MyOpenOrderList[i].is_request == true)
                        {
                            too_soon = true; break;
                        }                                                                                  //Already have another taker order
                    }
                }

                if (too_soon == true)
                {
                    MainService.MessageBox("Notice!", "Another order is currently involved in trade. Please wait and try again.", "OK", false);
                    return;
                }

                //Check to see if any other open orders of mine
                if (MainService.MyOpenOrderList.Count >= MainService.total_markets)
                {
                    MainService.MessageBox("Notice!", "You have exceed the maximum amount (" + MainService.total_markets + ") of open orders.", "OK", false);
                    return;
                }

                //Everything is good, create the request now
                //This will be a match open order (different than a general order)
                MainService.OpenOrder ord = new MainService.OpenOrder();
                ord.is_request            = true; //Match order
                ord.order_nonce           = window_order.order_nonce;
                ord.market          = window_order.market;
                ord.type            = 1 - window_order.type; //Opposite of the original order type
                ord.price           = window_order.price;
                ord.amount          = amount;
                ord.original_amount = amount;
                ord.order_stage     = 0;
                ord.my_order        = true; //Very important, it defines how much the program can sign automatically

                //Try to submit order request to CN
                //Run on UI Thread
                MainService.NebliDex_Activity.RunOnUiThread(() => {
                    Match_Button.IsEnabled = false;
                    Match_Button.Text      = "Contacting CN..."; //This will allow us to wait longer as user is notified
                });

                bool worked = MainService.SubmitMyOrderRequest(ord);
                if (worked == true)
                {
                    //Add to lists and close form
                    if (MainService.MyOpenOrderList.Count > 0)
                    {
                        //Close all the other open orders until this one is finished
                        MainService.QueueAllOpenOrders();
                    }

                    lock (MainService.MyOpenOrderList)
                    {
                        MainService.MyOpenOrderList.Add(ord); //Add to our own personal list
                    }
                    MainService.PendOrder(ord.order_nonce);

                    //Run closing window on UI thread
                    MainService.NebliDex_Activity.RunOnUiThread(() => {
                        //Close the Model and go back to Market Page on UI thread
                        Navigation.PopModalAsync();
                    });
                    return;
                }

                //Run reseting button on UI thread
                MainService.NebliDex_Activity.RunOnUiThread(() => {
                    //Reset the button
                    Match_Button.Text      = "Match";
                    Match_Button.IsEnabled = true;
                });
            });
        }