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); } } }
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); }
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); } } } }
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"); } }
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); } }
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); } } } } }
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; }); }); }
//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"; }); }); }
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 }
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; }); }); }