// Let's buy 100 USD for 5 LGT per USD CancelTradeOrderBlock CreateCancelOrderBlock(TransactionBlock previousBlock, TradeOrderBlock order, TransactionBlock previous_to_order_block) { var cancelBlock = new CancelTradeOrderBlock { AccountID = order.AccountID, ServiceHash = string.Empty, Balances = new Dictionary <string, decimal>(), TradeOrderId = order.Hash }; var order_transaction = order.GetTransaction(previous_to_order_block); cancelBlock.Balances.Add(order.SellTokenCode, previousBlock.Balances[order.SellTokenCode] + order_transaction.TotalBalanceChange); // transfer unchanged token balances from the previous block foreach (var balance in previousBlock.Balances) { if (!(cancelBlock.Balances.ContainsKey(balance.Key))) { cancelBlock.Balances.Add(balance.Key, balance.Value); } } if (order.AccountID == AccountId1) { cancelBlock.InitializeBlock(previousBlock, PrivateKey1, AccountId1); } else { cancelBlock.InitializeBlock(previousBlock, PrivateKey2, AccountId2); } return(cancelBlock); }
private bool ValidateSellOrder(TradeOrderBlock block, TransactionInfo transaction) { var serviceblock = _serviceAccount.GetLastServiceBlock(); decimal balance_change = block.TradeAmount; decimal reference_fee = serviceblock.TradeFee; if (block.CoverAnotherTradersFee) { reference_fee = serviceblock.TradeFee * 2; } else if (block.AnotherTraderWillCoverFee) { reference_fee = 0; } if (block.SellTokenCode == LyraGlobal.LYRA_TICKER_CODE) { balance_change += reference_fee; } if (transaction.Amount != balance_change) { return(false); } return(true); }
APIResultCodes ProcessCancelSellOrder(TransactionBlock lastBlock, TradeOrderBlock order, TransactionBlock previous_to_order_block) { var authorizer = new CancelTradeOrderAuthorizer(serviceAccount, accountCollection, tradeMatchEngine); var cancel_block = CreateCancelOrderBlock(lastBlock, order, previous_to_order_block); return(authorizer.Authorize <CancelTradeOrderBlock>(ref cancel_block)); }
public void RemoveOrder(TradeOrderBlock order) { if (order.OrderType == TradeOrderTypes.Sell) { ActiveSellOrders.Remove(order.Hash); } else { ActiveBuyOrders.Remove(order.Hash); } }
public void AddOrder(TradeOrderBlock order) { if (order.OrderType == TradeOrderTypes.Sell) { ActiveSellOrders.Add(order.Hash, order); } else { ActiveBuyOrders.Add(order.Hash, order); } }
private bool ValidateBuyOrder(TradeOrderBlock block, TransactionInfoEx transaction) { int sell_token_precision = FindTokenPrecision(block.SellTokenCode); if (sell_token_precision < 0) { return(false); } int buy_token_precision = FindTokenPrecision(block.BuyTokenCode); if (buy_token_precision < 0) { return(false); } if (transaction.Amount != block.TradeAmount * block.Price) { return(false); } var serviceblock = _serviceAccount.GetLastServiceBlock(); //decimal real_price = Math.Round(block.Price / (decimal)Math.Pow(10, sell_token_precision), sell_token_precision); //decimal real_trade_amount = Math.Round(block.TradeAmount / (decimal)Math.Pow(10, buy_token_precision), buy_token_precision); //long sell_amount = (long) (real_price * real_trade_amount * (decimal)Math.Pow(10, sell_token_precision)); decimal balance_change = block.TradeAmount * block.Price; decimal reference_fee = serviceblock.TradeFee; if (block.CoverAnotherTradersFee) { reference_fee = serviceblock.TradeFee * 2; } if (block.AnotherTraderWillCoverFee) { reference_fee = 0; } if (block.SellTokenCode == LyraGlobal.LYRA_TICKER_CODE) { balance_change += reference_fee; } if (transaction.TotalBalanceChange != balance_change) { return(false); } return(true); }
public async Task <TradeOrderAuthorizationAPIResult> TradeOrderAsync(TradeOrderBlock tradeOrderBlock) { //return await PostBlock("TradeOrder", tradeOrderBlock); using var client = CreateClient(); HttpResponseMessage response = await client.PostAsJsonAsync("TradeOrder", tradeOrderBlock).ConfigureAwait(false); response.EnsureSuccessStatusCode(); if (response.IsSuccessStatusCode) { var result = await response.Content.ReadAsAsync <TradeOrderAuthorizationAPIResult>(); return(result); } else { throw new Exception("Web Api Failed."); } }
Task <TradeOrderAuthorizationAPIResult> INodeAPI.TradeOrder(TradeOrderBlock block) { throw new NotImplementedException(); }
public TradeBlock Match(TradeOrderBlock order) { // Currently we only support nonfungible trades, with one trade per order (MaxQuantity = 1). // An order becomes inactive after first trade/execution. if (order.MaxQuantity != 1) { return(null); } if (order.OrderType == TradeOrderTypes.Buy) { if (ActiveSellOrders == null) { return(null); } foreach (TradeOrderBlock sellorder in ActiveSellOrders.Values) { if (order.BuyTokenCode == sellorder.SellTokenCode && order.SellTokenCode == sellorder.BuyTokenCode && order.TradeAmount <= sellorder.TradeAmount && order.TradeAmount >= sellorder.MinTradeAmount && order.Price >= sellorder.Price) { int sell_token_precision = FindTokenPrecision(order.SellTokenCode); if (sell_token_precision < 0) { continue; } int buy_token_precision = FindTokenPrecision(order.BuyTokenCode); if (buy_token_precision < 0) { continue; } var trade = new TradeBlock(); trade.AccountID = order.AccountID; trade.SellTokenCode = order.SellTokenCode; trade.BuyTokenCode = order.BuyTokenCode; trade.BuyAmount = order.TradeAmount; if (sellorder.CoverAnotherTradersFee) { trade.Fee = 0; trade.FeeType = AuthorizationFeeTypes.NoFee; } else if (sellorder.AnotherTraderWillCoverFee) { trade.Fee = _ServiceAccount.GetLastServiceBlock().TradeFee * 2; trade.FeeType = AuthorizationFeeTypes.BothParties; } else { trade.Fee = _ServiceAccount.GetLastServiceBlock().TradeFee; trade.FeeType = AuthorizationFeeTypes.Regular; } // We take the seller's price since it can be lower that the one offered by the buyer. // If it is really lower, the Trade block should take into account the fact that the buyers pays less than expected. // It is achieved by getting a "change" to the balance of SellToken. // The Authorizer should also take this difference into account as the TransactionInfo and SellAmount can be different. // It can be validated by formula: Original Buy Order's MaxAmount * Price = Trade.SellAmount + "Change" //decimal real_price = sellorder.Price / (decimal)Math.Pow(10, sell_token_precision); //decimal real_buy_amount = trade.BuyAmount / (decimal)Math.Pow(10, buy_token_precision); //trade.SellAmount = (long)(real_price * real_buy_amount * (decimal)Math.Pow(10, sell_token_precision)); trade.SellAmount = order.TradeAmount * sellorder.Price; trade.Balances = new Dictionary <string, decimal>(); trade.DestinationAccountId = sellorder.AccountID; trade.TradeOrderId = sellorder.Hash; return(trade); } } } return(null); }
// The cancellation should restore the balance that was locked by the trade order. // Thus, it should take the balance from the latest block and add the balamce (transactin amount) locked by the order block. APIResultCodes ValidateCancellationBalance(CancelTradeOrderBlock block, TransactionBlock lastBlock, TradeOrderBlock original_order) { var order_previous_block = _accountCollection.FindBlockByHash(original_order.PreviousHash); var order_transaction = original_order.GetTransaction(order_previous_block); var cancel_transaction = block.GetTransaction(lastBlock); if (order_transaction.TotalBalanceChange != cancel_transaction.TotalBalanceChange || order_transaction.TokenCode != cancel_transaction.TokenCode) { return(APIResultCodes.CancelTradeOrderValidationFailed); } return(APIResultCodes.Success); }