Ejemplo n.º 1
0
 public ExchangeOrder(Timestamp timestamp, Address creator, BigInteger quantity, BigInteger rate, ExchangeOrderSide side)
 {
     Timestamp = timestamp;
     Creator   = creator;
     Quantity  = quantity;
     Rate      = rate;
     Side      = side;
 }
        public ExchangeOrder(ExchangeOrder order, BigInteger newPrice, BigInteger newOrderSize)
        {
            Uid       = order.Uid;
            Timestamp = order.Timestamp;
            Creator   = order.Creator;

            Amount     = newOrderSize;
            BaseSymbol = order.BaseSymbol;

            Price       = newOrderSize;
            QuoteSymbol = order.QuoteSymbol;

            Side = order.Side;
            Type = order.Type;
        }
        public ExchangeOrder(BigInteger uid, Timestamp timestamp, Address creator, BigInteger amount, string baseSymbol, BigInteger price, string quoteSymbol, ExchangeOrderSide side, ExchangeOrderType type)
        {
            Uid       = uid;
            Timestamp = timestamp;
            Creator   = creator;

            Amount     = amount;
            BaseSymbol = baseSymbol;

            Price       = price;
            QuoteSymbol = quoteSymbol;

            Side = side;
            Type = type;
        }
Ejemplo n.º 4
0
            public decimal OpenMarketOrder(decimal orderSize, ExchangeOrderSide side)
            {
                var nexus = simulator.Nexus;

                var baseSymbol    = baseToken.Symbol;
                var baseDecimals  = baseToken.Decimals;
                var quoteSymbol   = quoteToken.Symbol;
                var quoteDecimals = quoteToken.Decimals;

                var orderToken = side == Buy ? quoteToken : baseToken;

                var orderSizeBigint = UnitConversion.ToBigInteger(orderSize, orderToken.Decimals);

                var OpenerBaseTokensInitial  = simulator.Nexus.RootChain.GetTokenBalance(simulator.Nexus.RootStorage, baseSymbol, user.Address);
                var OpenerQuoteTokensInitial = simulator.Nexus.RootChain.GetTokenBalance(simulator.Nexus.RootStorage, quoteSymbol, user.Address);

                BigInteger OpenerBaseTokensDelta  = 0;
                BigInteger OpenerQuoteTokensDelta = 0;

                //get the starting balance for every address on the opposite side of the orderbook, so we can compare it to the final balance of each of those addresses
                var otherSide = side == Buy ? Sell : Buy;
                var startingOppositeOrderbook   = (ExchangeOrder[])simulator.Nexus.RootChain.InvokeContract(simulator.Nexus.RootStorage, "exchange", "GetOrderBook", baseSymbol, quoteSymbol, otherSide).ToObject();
                var OtherAddressesTokensInitial = new Dictionary <Address, BigInteger>();

                //*******************************************************************************************************************************************************************************
                //*** the following method to check token balance state only works for the scenario of a single new exchange order per block that triggers other pre-existing exchange orders ***
                //*******************************************************************************************************************************************************************************
                foreach (var oppositeOrder in startingOppositeOrderbook)
                {
                    if (OtherAddressesTokensInitial.ContainsKey(oppositeOrder.Creator) == false)
                    {
                        var targetSymbol = otherSide == Buy ? baseSymbol : quoteSymbol;
                        OtherAddressesTokensInitial.Add(oppositeOrder.Creator, simulator.Nexus.RootChain.GetTokenBalance(simulator.Nexus.RootStorage, targetSymbol, oppositeOrder.Creator));
                    }
                }
                //--------------------------


                simulator.BeginBlock();
                var tx = simulator.GenerateCustomTransaction(user, ProofOfWork.None, () =>
                                                             ScriptUtils.BeginScript().AllowGas(user.Address, Address.Null, 1, 9999)
                                                             .CallContract("exchange", "OpenMarketOrder", user.Address, baseSymbol, quoteSymbol, orderSizeBigint, side).
                                                             SpendGas(user.Address).EndScript());

                simulator.EndBlock();

                var txCost = simulator.Nexus.RootChain.GetTransactionFee(tx);

                BigInteger escrowedAmount = orderSizeBigint;

                //take into account the transfer of the owner's wallet to the chain address
                if (side == Buy)
                {
                    OpenerQuoteTokensDelta -= escrowedAmount;
                }
                else if (side == Sell)
                {
                    OpenerBaseTokensDelta -= escrowedAmount;
                }

                //take into account tx cost in case one of the symbols is the FuelToken
                if (baseSymbol == DomainSettings.FuelTokenSymbol)
                {
                    OpenerBaseTokensDelta -= txCost;
                }
                else
                if (quoteSymbol == DomainSettings.FuelTokenSymbol)
                {
                    OpenerQuoteTokensDelta -= txCost;
                }

                var events = nexus.FindBlockByTransaction(tx).GetEventsForTransaction(tx.Hash);

                var ordersCreated      = events.Count(x => x.Kind == EventKind.OrderCreated && x.Address == user.Address);
                var wasNewOrderCreated = ordersCreated >= 1;

                Assert.IsTrue(wasNewOrderCreated, "No orders were created");

                var ordersClosed         = events.Count(x => x.Kind == EventKind.OrderClosed && x.Address == user.Address);
                var wasNewOrderClosed    = ordersClosed == 1;
                var wasNewOrderCancelled = events.Count(x => x.Kind == EventKind.OrderCancelled && x.Address == user.Address) == 1;

                var           createdOrderEvent    = events.First(x => x.Kind == EventKind.OrderCreated);
                var           createdOrderUid      = Serialization.Unserialize <BigInteger>(createdOrderEvent.Data);
                ExchangeOrder createdOrderPostFill = new ExchangeOrder();

                //----------------
                //verify the order does not exist in the orderbook

                //in case the new order was IoC and it wasnt closed, order should have been cancelled
                if (wasNewOrderClosed == false)
                {
                    Assert.IsTrue(wasNewOrderCancelled, "Non closed order did not get cancelled");
                }
                else
                //if the new order was closed
                if (wasNewOrderClosed)
                {
                    Assert.IsTrue(wasNewOrderCancelled == false, "Closed order also got cancelled");
                }

                //check that the order no longer exists on the orderbook
                try
                {
                    simulator.Nexus.RootChain.InvokeContract(simulator.Nexus.RootStorage, "exchange", "GetExchangeOrder", createdOrderUid);
                    Assert.IsTrue(false, "Market order exists on the orderbooks");
                }
                catch (Exception e)
                {
                    //purposefully empty, this is the expected code-path
                }

                //------------------
                //validate that everyone received their tokens appropriately

                BigInteger escrowedUsage = 0;   //this will hold the amount of the escrowed amount that was actually used in the filling of the order
                                                //for IoC orders, we need to make sure that what wasn't used gets returned properly
                                                //for non IoC orders, we need to make sure that what wasn't used stays on the orderbook
                BigInteger baseTokensReceived = 0, quoteTokensReceived = 0;
                var        OtherAddressesTokensDelta = new Dictionary <Address, BigInteger>();

                //*******************************************************************************************************************************************************************************
                //*** the following method to check token balance state only works for the scenario of a single new exchange order per block that triggers other pre-existing exchange orders ***
                //*******************************************************************************************************************************************************************************

                //calculate the expected delta of the balances of all addresses involved
                var tokenExchangeEvents = events.Where(x => x.Kind == EventKind.TokenReceive);

                foreach (var tokenExchangeEvent in tokenExchangeEvents)
                {
                    var eventData = Serialization.Unserialize <TokenEventData>(tokenExchangeEvent.Data);

                    if (tokenExchangeEvent.Address == user.Address)
                    {
                        if (eventData.symbol == baseSymbol)
                        {
                            baseTokensReceived += eventData.value;
                        }
                        else
                        if (eventData.symbol == quoteSymbol)
                        {
                            quoteTokensReceived += eventData.value;
                        }
                    }
                    else
                    {
                        Assert.IsTrue(OtherAddressesTokensInitial.ContainsKey(tokenExchangeEvent.Address), "Address that was not on this orderbook received tokens");

                        if (OtherAddressesTokensDelta.ContainsKey(tokenExchangeEvent.Address))
                        {
                            OtherAddressesTokensDelta[tokenExchangeEvent.Address] += eventData.value;
                        }
                        else
                        {
                            OtherAddressesTokensDelta.Add(tokenExchangeEvent.Address, eventData.value);
                        }

                        escrowedUsage += eventData.value;   //the tokens other addresses receive come from the escrowed amount of the order opener
                    }
                }

                OpenerBaseTokensDelta  += baseTokensReceived;
                OpenerQuoteTokensDelta += quoteTokensReceived;

                var expectedRemainingEscrow = escrowedAmount - escrowedUsage;

                switch (side)
                {
                case Buy:
                    Assert.IsTrue(Abs(OpenerQuoteTokensDelta) == escrowedUsage - (quoteSymbol == DomainSettings.FuelTokenSymbol ? txCost : 0));
                    break;

                case Sell:
                    Assert.IsTrue(Abs(OpenerBaseTokensDelta) == escrowedUsage - (baseSymbol == DomainSettings.FuelTokenSymbol ? txCost : 0));
                    break;
                }

                //get the actual final balance of all addresses involved and make sure it matches the expected deltas
                var OpenerBaseTokensFinal  = simulator.Nexus.RootChain.GetTokenBalance(simulator.Nexus.RootStorage, baseSymbol, user.Address);
                var OpenerQuoteTokensFinal = simulator.Nexus.RootChain.GetTokenBalance(simulator.Nexus.RootStorage, quoteSymbol, user.Address);

                Assert.IsTrue(OpenerBaseTokensFinal == OpenerBaseTokensDelta + OpenerBaseTokensInitial);
                Assert.IsTrue(OpenerQuoteTokensFinal == OpenerQuoteTokensDelta + OpenerQuoteTokensInitial);

                foreach (var entry in OtherAddressesTokensInitial)
                {
                    var        otherAddressInitialTokens = entry.Value;
                    BigInteger delta = 0;

                    if (OtherAddressesTokensDelta.ContainsKey(entry.Key))
                    {
                        delta = OtherAddressesTokensDelta[entry.Key];
                    }

                    var targetSymbol = otherSide == Buy ? baseSymbol : quoteSymbol;

                    var otherAddressFinalTokens = simulator.Nexus.RootChain.GetTokenBalance(simulator.Nexus.RootStorage, targetSymbol, entry.Key);

                    Assert.IsTrue(otherAddressFinalTokens == delta + otherAddressInitialTokens);
                }

                return(side == Buy?UnitConversion.ToDecimal(baseTokensReceived, baseToken.Decimals) : UnitConversion.ToDecimal(quoteTokensReceived, quoteToken.Decimals));
            }
Ejemplo n.º 5
0
 public decimal OpenLimitOrder(BigInteger orderSize, BigInteger orderPrice, ExchangeOrderSide side, bool IoC = false)
 {
     return(OpenLimitOrder(UnitConversion.ToDecimal(orderSize, baseToken.Decimals), UnitConversion.ToDecimal(orderPrice, quoteToken.Decimals), side, IoC));
 }
Ejemplo n.º 6
0
        public void OpenOrder(Address from, string baseSymbol, string quoteSymbol, BigInteger quantity, BigInteger rate, ExchangeOrderSide side)
        {
            Runtime.Expect(IsWitness(from), "invalid witness");

            Runtime.Expect(Runtime.Nexus.TokenExists(baseSymbol), "invalid base token");
            var baseToken = Runtime.Nexus.GetTokenInfo(baseSymbol);

            Runtime.Expect(baseToken.Flags.HasFlag(TokenFlags.Fungible), "token must be fungible");

            Runtime.Expect(Runtime.Nexus.TokenExists(quoteSymbol), "invalid quote token");
            var quoteToken = Runtime.Nexus.GetTokenInfo(quoteSymbol);

            Runtime.Expect(quoteToken.Flags.HasFlag(TokenFlags.Fungible), "token must be fungible");

            //var tokenABI = Chain.FindABI(NativeABI.Token);
            //Runtime.Expect(baseTokenContract.ABI.Implements(tokenABI));

            var pair = baseSymbol + "_" + quoteSymbol;

            switch (side)
            {
            case ExchangeOrderSide.Sell:
            {
                var balances = new BalanceSheet(baseSymbol);
                var balance  = balances.Get(this.Storage, from);
                Runtime.Expect(balance >= quantity, "not enought balance");

                Runtime.Expect(Runtime.Nexus.TransferTokens(baseSymbol, this.Storage, Runtime.Chain, from, Runtime.Chain.Address, quantity), "transfer failed");

                break;
            }

            case ExchangeOrderSide.Buy:
            {
                var balances = new BalanceSheet(quoteSymbol);
                var balance  = balances.Get(this.Storage, from);

                var expectedAmount = quantity / rate;
                Runtime.Expect(balance >= expectedAmount, "not enought balance");

                // TODO check this
                Runtime.Expect(Runtime.Nexus.TransferTokens(quoteSymbol, this.Storage, Runtime.Chain, from, Runtime.Chain.Address, expectedAmount), "transfer failed");
                break;
            }

            default: throw new ContractException("invalid order side");
            }

            var order = new ExchangeOrder(Runtime.Time, from, quantity, rate, side);
            var list  = _orders.Get <string, StorageList>(pair);

            list.Add(order);
        }
Ejemplo n.º 7
0
        private ExchangeOrder[] GetOrderBook(string baseSymbol, string quoteSymbol, bool oneSideFlag, ExchangeOrderSide side = Buy)
        {
            var buyKey  = BuildOrderKey(Buy, quoteSymbol, baseSymbol);
            var sellKey = BuildOrderKey(Sell, quoteSymbol, baseSymbol);

            var buyOrders  = ((oneSideFlag && side == Buy) || !oneSideFlag) ? _orders.Get <string, StorageList>(buyKey) : new StorageList();
            var sellOrders = ((oneSideFlag && side == Sell) || !oneSideFlag) ? _orders.Get <string, StorageList>(sellKey) : new StorageList();

            var buyCount  = buyOrders.Context == null ? 0 : buyOrders.Count();
            var sellCount = sellOrders.Context == null ? 0 : sellOrders.Count();

            ExchangeOrder[] orderbook = new ExchangeOrder[(long)(buyCount + sellCount)];

            for (long i = 0; i < buyCount; i++)
            {
                orderbook[i] = buyOrders.Get <ExchangeOrder>(i);
            }

            for (long i = (long)buyCount; i < orderbook.Length; i++)
            {
                orderbook[i] = sellOrders.Get <ExchangeOrder>(i);
            }

            return(orderbook);
        }
Ejemplo n.º 8
0
 public ExchangeOrder[] GetOrderBook(string baseSymbol, string quoteSymbol, ExchangeOrderSide side)
 {
     return(GetOrderBook(baseSymbol, quoteSymbol, true, side));
 }
Ejemplo n.º 9
0
 public string CalculateEscrowSymbol(IToken baseToken, IToken quoteToken, ExchangeOrderSide side) => side == Sell ? baseToken.Symbol : quoteToken.Symbol;
Ejemplo n.º 10
0
        /*
         * TODO: implement methods that allow cleaning up the order history book.. make sure only the exchange that placed the orders can clear them
         */

        /*
         * TODO: implement code for trail stops and a method to allow a 3rd party to update the trail stop, without revealing user or order info
         */

        public BigInteger CalculateEscrowAmount(BigInteger orderSize, BigInteger orderPrice, IToken baseToken, IToken quoteToken, ExchangeOrderSide side)
        {
            switch (side)
            {
            case Sell:
                return(orderSize);

            case Buy:
                return(Runtime.ConvertBaseToQuote(orderSize, orderPrice, baseToken, quoteToken));

            default: throw new ContractException("invalid order side");
            }
        }
Ejemplo n.º 11
0
 /// <summary>
 /// Creates a limit order on the exchange
 /// </summary>
 /// <param name="from"></param>
 /// <param name="baseSymbol">For SOUL/KCAL pair, SOUL would be the base symbol</param>
 /// <param name="quoteSymbol">For SOUL/KCAL pair, KCAL would be the quote symbol</param>
 /// <param name="orderSize">Amount of base symbol tokens the user wants to buy/sell</param>
 /// <param name="price">Amount of quote symbol tokens the user wants to pay/receive per unit of base symbol tokens</param>
 /// <param name="side">If the order is a buy or sell order</param>
 /// <param name="IoC">"Immediate or Cancel" flag: if true, requires any unfulfilled parts of the order to be cancelled immediately after a single attempt at fulfilling it.</param>
 public void OpenLimitOrder(Address from, Address provider, string baseSymbol, string quoteSymbol, BigInteger orderSize, BigInteger price, ExchangeOrderSide side, bool IoC)
 {
     OpenOrder(from, provider, baseSymbol, quoteSymbol, side, IoC ? ImmediateOrCancel : Limit, orderSize, price);
 }
Ejemplo n.º 12
0
 public void OpenMarketOrder(Address from, Address provider, string baseSymbol, string quoteSymbol, BigInteger orderSize, ExchangeOrderSide side)
 {
     OpenOrder(from, provider, baseSymbol, quoteSymbol, side, Market, orderSize, 0);
 }
Ejemplo n.º 13
0
        private void OpenOrder(Address from, Address provider, string baseSymbol, string quoteSymbol, ExchangeOrderSide side, ExchangeOrderType orderType, BigInteger orderSize, BigInteger price)
        {
            Runtime.Expect(Runtime.IsWitness(from), "invalid witness");

            Runtime.Expect(Runtime.GasTarget == provider, "invalid gas target");

            Runtime.Expect(baseSymbol != quoteSymbol, "invalid base/quote pair");

            Runtime.Expect(Runtime.TokenExists(baseSymbol), "invalid base token");
            var baseToken = Runtime.GetToken(baseSymbol);

            Runtime.Expect(baseToken.Flags.HasFlag(TokenFlags.Fungible), "token must be fungible");

            Runtime.Expect(Runtime.TokenExists(quoteSymbol), "invalid quote token");
            var quoteToken = Runtime.GetToken(quoteSymbol);

            Runtime.Expect(quoteToken.Flags.HasFlag(TokenFlags.Fungible), "token must be fungible");

            if (orderType != Market)
            {
                Runtime.Expect(orderSize >= GetMinimumTokenQuantity(baseToken), "order size is not sufficient");
                Runtime.Expect(price >= GetMinimumTokenQuantity(quoteToken), "order price is not sufficient");
            }

            var uid = Runtime.GenerateUID();

            //--------------
            //perform escrow for non-market orders
            string     orderEscrowSymbol = CalculateEscrowSymbol(baseToken, quoteToken, side);
            IToken     orderEscrowToken  = orderEscrowSymbol == baseSymbol ? baseToken : quoteToken;
            BigInteger orderEscrowAmount;
            BigInteger orderEscrowUsage = 0;

            if (orderType == Market)
            {
                orderEscrowAmount = orderSize;
                Runtime.Expect(orderEscrowAmount >= GetMinimumTokenQuantity(orderEscrowToken), "market order size is not sufficient");
            }
            else
            {
                orderEscrowAmount = CalculateEscrowAmount(orderSize, price, baseToken, quoteToken, side);
            }

            //BigInteger baseTokensUnfilled = orderSize;

            var balance = Runtime.GetBalance(orderEscrowSymbol, from);

            Runtime.Expect(balance >= orderEscrowAmount, "not enough balance");

            Runtime.TransferTokens(orderEscrowSymbol, from, this.Address, orderEscrowAmount);
            //------------

            var         thisOrder = new ExchangeOrder();
            StorageList orderList;
            BigInteger  orderIndex = 0;

            thisOrder = new ExchangeOrder(uid, Runtime.Time, from, provider, orderSize, baseSymbol, price, quoteSymbol, side, orderType);
            Runtime.Notify(EventKind.OrderCreated, from, uid);

            var key = BuildOrderKey(side, quoteSymbol, baseSymbol);

            orderList  = _orders.Get <string, StorageList>(key);
            orderIndex = orderList.Add <ExchangeOrder>(thisOrder);
            _orderMap.Set <BigInteger, string>(uid, key);

            var makerSide   = side == Buy ? Sell : Buy;
            var makerKey    = BuildOrderKey(makerSide, quoteSymbol, baseSymbol);
            var makerOrders = _orders.Get <string, StorageList>(makerKey);

            do
            {
                int        bestIndex          = -1;
                BigInteger bestPrice          = 0;
                Timestamp  bestPriceTimestamp = 0;

                ExchangeOrder takerOrder = thisOrder;

                var makerOrdersCount = makerOrders.Count();
                for (int i = 0; i < makerOrdersCount; i++)
                {
                    var makerOrder = makerOrders.Get <ExchangeOrder>(i);

                    if (side == Buy)
                    {
                        if (makerOrder.Price > takerOrder.Price && orderType != Market) // too expensive, we wont buy at this price
                        {
                            continue;
                        }

                        if (bestIndex == -1 || makerOrder.Price < bestPrice || (makerOrder.Price == bestPrice && makerOrder.Timestamp < bestPriceTimestamp))
                        {
                            bestIndex          = i;
                            bestPrice          = makerOrder.Price;
                            bestPriceTimestamp = makerOrder.Timestamp;
                        }
                    }
                    else
                    {
                        if (makerOrder.Price < takerOrder.Price && orderType != Market) // too cheap, we wont sell at this price
                        {
                            continue;
                        }

                        if (bestIndex == -1 || makerOrder.Price > bestPrice || (makerOrder.Price == bestPrice && makerOrder.Timestamp < bestPriceTimestamp))
                        {
                            bestIndex          = i;
                            bestPrice          = makerOrder.Price;
                            bestPriceTimestamp = makerOrder.Timestamp;
                        }
                    }
                }

                if (bestIndex >= 0)
                {
                    //since order "uid" has found a match, the creator of this order will be a taker as he will remove liquidity from the market
                    //and the creator of the "bestIndex" order is the maker as he is providing liquidity to the taker
                    var takerAvailableEscrow = orderEscrowAmount - orderEscrowUsage;
                    var takerEscrowUsage     = BigInteger.Zero;
                    var takerEscrowSymbol    = orderEscrowSymbol;

                    var makerOrder        = makerOrders.Get <ExchangeOrder>(bestIndex);
                    var makerEscrow       = _escrows.Get <BigInteger, BigInteger>(makerOrder.Uid);
                    var makerEscrowUsage  = BigInteger.Zero;;
                    var makerEscrowSymbol = orderEscrowSymbol == baseSymbol ? quoteSymbol : baseSymbol;

                    //Get fulfilled order size in base tokens
                    //and then calculate the corresponding fulfilled order size in quote tokens
                    if (takerEscrowSymbol == baseSymbol)
                    {
                        var makerEscrowBaseEquivalent = Runtime.ConvertQuoteToBase(makerEscrow, makerOrder.Price, baseToken, quoteToken);
                        takerEscrowUsage = takerAvailableEscrow < makerEscrowBaseEquivalent ? takerAvailableEscrow : makerEscrowBaseEquivalent;

                        makerEscrowUsage = CalculateEscrowAmount(takerEscrowUsage, makerOrder.Price, baseToken, quoteToken, Buy);
                    }
                    else
                    {
                        var takerEscrowBaseEquivalent = Runtime.ConvertQuoteToBase(takerAvailableEscrow, makerOrder.Price, baseToken, quoteToken);
                        makerEscrowUsage = makerEscrow < takerEscrowBaseEquivalent ? makerEscrow : takerEscrowBaseEquivalent;

                        takerEscrowUsage = CalculateEscrowAmount(makerEscrowUsage, makerOrder.Price, baseToken, quoteToken, Buy);
                    }

                    Runtime.Expect(takerEscrowUsage <= takerAvailableEscrow, "Taker tried to use more escrow than available");
                    Runtime.Expect(makerEscrowUsage <= makerEscrow, "Maker tried to use more escrow than available");

                    if (takerEscrowUsage < GetMinimumSymbolQuantity(takerEscrowSymbol) ||
                        makerEscrowUsage < GetMinimumSymbolQuantity(makerEscrowSymbol))
                    {
                        break;
                    }

                    Runtime.TransferTokens(takerEscrowSymbol, this.Address, makerOrder.Creator, takerEscrowUsage);
                    Runtime.TransferTokens(makerEscrowSymbol, this.Address, takerOrder.Creator, makerEscrowUsage);

                    orderEscrowUsage += takerEscrowUsage;

                    Runtime.Notify(EventKind.OrderFilled, takerOrder.Creator, takerOrder.Uid);
                    Runtime.Notify(EventKind.OrderFilled, makerOrder.Creator, makerOrder.Uid);

                    if (makerEscrowUsage == makerEscrow)
                    {
                        makerOrders.RemoveAt <ExchangeOrder>(bestIndex);
                        _orderMap.Remove(makerOrder.Uid);

                        Runtime.Expect(_escrows.ContainsKey(makerOrder.Uid), "An orderbook entry must have registered escrow");
                        _escrows.Remove(makerOrder.Uid);

                        Runtime.Notify(EventKind.OrderClosed, makerOrder.Creator, makerOrder.Uid);
                    }
                    else
                    {
                        _escrows.Set(makerOrder.Uid, makerEscrow - makerEscrowUsage);
                    }
                }
                else
                {
                    break;
                }
            } while (orderEscrowUsage < orderEscrowAmount);

            var leftoverEscrow = orderEscrowAmount - orderEscrowUsage;

            if (leftoverEscrow == 0 || orderType != Limit)
            {
                orderList.RemoveAt <ExchangeOrder>(orderIndex);
                _orderMap.Remove(thisOrder.Uid);
                _escrows.Remove(thisOrder.Uid);

                if (leftoverEscrow > 0)
                {
                    Runtime.TransferTokens(orderEscrowSymbol, this.Address, thisOrder.Creator, leftoverEscrow);
                    Runtime.Notify(EventKind.OrderCancelled, thisOrder.Creator, thisOrder.Uid);
                }
                else
                {
                    Runtime.Notify(EventKind.OrderClosed, thisOrder.Creator, thisOrder.Uid);
                }
            }
            else
            {
                _escrows.Set(uid, leftoverEscrow);
            }

            //TODO: ADD FEES, SEND THEM TO this.Address FOR NOW
        }
Ejemplo n.º 14
0
 private string BuildOrderKey(ExchangeOrderSide side, string baseSymbol, string quoteSymbol) => $"{side}_{baseSymbol}_{quoteSymbol}";
Ejemplo n.º 15
0
        /*
         * TODO: implement methods that allow cleaning up the order history book.. make sure only the exchange that placed the orders can clear them
         */

        /*
         * TODO: implement code for trail stops and a method to allow a 3rd party to update the trail stop, without revealing user or order info
         */

        public BigInteger CalculateEscrowAmount(BigInteger orderSize, BigInteger orderPrice, TokenInfo baseToken, TokenInfo quoteToken, ExchangeOrderSide side)
        {
            switch (side)
            {
            case Sell:
                return(orderSize);

            case Buy:
                return(UnitConversion.ToBigInteger(UnitConversion.ToDecimal(orderSize, baseToken.Decimals) * UnitConversion.ToDecimal(orderPrice, quoteToken.Decimals), quoteToken.Decimals));

            default: throw new ContractException("invalid order side");
            }
        }