Пример #1
0
 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);
        }