Task <AuthorizationAPIResult> INodeAPI.Trade(TradeBlock block) { throw new NotImplementedException(); }
public void SetBlock(TradeBlock block) { TradeBlockData = JsonConvert.SerializeObject(block); }
public async Task <AuthorizationAPIResult> TradeAsync(TradeBlock block) { return(await PostBlockAsync("Trade", block)); }
public override APIResultCodes Authorize <T>(ref T tblock) { if (!(tblock is TradeOrderBlock)) { return(APIResultCodes.InvalidBlockType); } var block = tblock as TradeOrderBlock; if (block.MaxQuantity != 1) { return(APIResultCodes.FeatureIsNotSupported); } // 1. check if the account already exists if (!_accountCollection.AccountExists(block.AccountID)) { return(APIResultCodes.AccountDoesNotExist); } TransactionBlock lastBlock = _accountCollection.FindLatestBlock(block.AccountID); if (lastBlock == null) { return(APIResultCodes.CouldNotFindLatestBlock); } var result = VerifyBlock(block, lastBlock); if (result != APIResultCodes.Success) { return(result); } //if (lastBlock.Balances[LyraGlobal.LYRA_TICKER_CODE] <= block.Balances[LyraGlobal.LYRA_TICKER_CODE] + block.Fee) // return AuthorizationResultCodes.NegativeTransactionAmount; // Validate the destination account id (should be empty) if (!string.IsNullOrWhiteSpace(block.DestinationAccountId)) { return(APIResultCodes.InvalidDestinationAccountId); } result = VerifyTransactionBlock(block); if (result != APIResultCodes.Success) { return(result); } if (!block.ValidateTransaction(lastBlock)) { return(APIResultCodes.TradeOrderValidationFailed); } var transaction = block.GetTransaction(lastBlock); if (block.MinTradeAmount < 0 || block.MinTradeAmount > block.TradeAmount) { return(APIResultCodes.TradeOrderValidationFailed); } if (block.SellTokenCode != transaction.TokenCode) { return(APIResultCodes.TradeOrderValidationFailed); } var token = _accountCollection.FindTokenGenesisBlock(null, block.BuyTokenCode); if (token == null) { return(APIResultCodes.TradeOrderValidationFailed); } bool res = (block.OrderType == TradeOrderTypes.Sell) ? ValidateSellOrder(block, transaction) : ValidateBuyOrder(block, transaction); if (!res) { return(APIResultCodes.TradeOrderValidationFailed); } MatchTradeBlock = _TradeMatchEngine.Match(block); if (MatchTradeBlock != null) { return(APIResultCodes.TradeOrderMatchFound); } Sign(ref block); _accountCollection.AddBlock(block); _TradeMatchEngine.AddOrder(block); return(base.Authorize(ref tblock)); }
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); }