Ejemplo n.º 1
0
        public async Task SwapTokenAToLYRAsync()
        {
            try
            {
                await semaphore.WaitAsync();

                var pool = await client.GetPoolAsync(testTokenA, LyraGlobal.OFFICIALTICKERCODE);

                Assert.IsNotNull(pool.PoolAccountId);
                var poolLatestBlock = pool.GetBlock() as TransactionBlock;

                Assert.IsTrue(poolLatestBlock.Balances[pool.Token0] > 0 && poolLatestBlock.Balances[pool.Token1] > 0, "No liquidate in pool.");

                var w1 = Restore(testPrivateKey);
                await w1.SyncAsync(client);

                var testTokenBalance = w1.GetLastSyncBlock().Balances[testTokenA].ToBalanceDecimal();
                var lyrBalance       = w1.GetLastSyncBlock().Balances[LyraGlobal.OFFICIALTICKERCODE].ToBalanceDecimal();

                var amount = Math.Round((decimal)((new Random().NextDouble() + 0.07) * 1000), 8);

                var cal1 = new SwapCalculator(LyraGlobal.OFFICIALTICKERCODE, testTokenA, poolLatestBlock, testTokenA, amount, 0);

                var result = await w1.SwapTokenAsync(LyraGlobal.OFFICIALTICKERCODE, testTokenA, testTokenA, amount, cal1.MinimumReceived);

                Assert.IsTrue(result.ResultCode == APIResultCodes.Success, $"Failed to swap {testTokenA}: {result.ResultCode}");
                await Task.Delay(5000);

                var poolGenesisResult = await client.GetBlockByIndexAsync(poolLatestBlock.AccountID, 1);

                var block       = poolGenesisResult.GetBlock();
                var poolGenesis = block as PoolGenesisBlock;
                Assert.IsTrue(poolGenesisResult.ResultCode == APIResultCodes.Success, $"get gensis returns {poolGenesisResult.ResultCode}");
                Assert.IsNotNull(poolGenesis, "Can't get pool genesis block.");
                var sc = new SwapCalculator(poolGenesis.Token0, poolGenesis.Token1, poolLatestBlock,
                                            testTokenA, amount, 0);

                var amountToGet = sc.SwapOutAmount;

                await w1.SyncAsync(client);

                var testTokenBalance2 = w1.GetLastSyncBlock().Balances[testTokenA].ToBalanceDecimal();
                var lyrBalance2       = w1.GetLastSyncBlock().Balances[LyraGlobal.OFFICIALTICKERCODE].ToBalanceDecimal();

                Assert.AreEqual(testTokenBalance - amount, testTokenBalance2);
                Assert.AreEqual(lyrBalance - 1 + amountToGet, lyrBalance2);
            }
            finally
            {
                semaphore.Release();
            }
        }
Ejemplo n.º 2
0
        public async Task <SwapCalculator> PoolCalculateAsync(string poolId, string swapFrom, decimal amount, decimal slippage)
        {
            var poolLatest = await NodeService.Dag.Storage.FindLatestBlockAsync(poolId) as TransactionBlock;

            var poolGenesis = await NodeService.Dag.Storage.FindFirstBlockAsync(poolId) as PoolGenesisBlock;

            if (poolLatest != null && poolGenesis != null && poolLatest.Hash != poolGenesis.Hash)
            {
                var cal = new SwapCalculator(poolGenesis.Token0, poolGenesis.Token1,
                                             poolLatest, swapFrom, amount, slippage);
                return(cal);
            }

            throw new Exception("Failed to get pool");
        }
        public void Calculate()
        {
            var X = 10000m; // LYR
            var Y = 20000m; // dai

            var fakeBlock = new SendTransferBlock();

            fakeBlock.Balances = new Dictionary <string, long>();
            fakeBlock.Balances.Add("LYR", X.ToBalanceLong());
            fakeBlock.Balances.Add("DAI", Y.ToBalanceLong());

            var u      = 1000m;  // dai
            var pureTo = X - (X * Y / (Y + u * 0.997m));
            var to     = Math.Round(pureTo * 0.999m, 8);
            var chg    = Math.Round(to / X, 6);
            var price  = Math.Round(to / u, 10);

            Console.WriteLine($"Price {price} Got {to} X, Price Impact: {chg * 100:n} %");

            var cal1 = new SwapCalculator("LYR", "DAI", fakeBlock, "DAI", u, 0);

            Assert.AreEqual(to, cal1.SwapOutAmount);
            Assert.AreEqual("LYR", cal1.SwapOutToken);

            var u2 = 100000;       // eth

            var pureTo2 = Y - (X * Y / (X + u2 * 0.996m));
            var to2     = Math.Round(pureTo2, 8);

            var chg2 = Math.Round(to2 / Y, 6);

            var price2 = Math.Round(to2 / u2, 10);

            var cal2 = new SwapCalculator("LYR", "DAI", fakeBlock, "LYR", u2, 0);

            Assert.AreEqual(to2, cal2.SwapOutAmount);
            Assert.AreEqual("DAI", cal2.SwapOutToken);

            Console.WriteLine($"Price {price2} Got {to2} X, Price Impact: {chg2 * 100:n} %");
        }
Ejemplo n.º 4
0
        public async Task SwapCoinWrongAsync()
        {
            try
            {
                await semaphore.WaitAsync();

                var pool = await client.GetPoolAsync(testTokenA, LyraGlobal.OFFICIALTICKERCODE);

                Assert.IsNotNull(pool.PoolAccountId);
                var poolLatestBlock = pool.GetBlock() as TransactionBlock;

                Assert.IsTrue(poolLatestBlock.Balances[pool.Token0] > 0 && poolLatestBlock.Balances[pool.Token1] > 0, "No liquidate in pool.");

                var w1 = Restore(testPrivateKey);
                await w1.SyncAsync(client);

                var testTokenBalance = w1.GetLastSyncBlock().Balances[testTokenA].ToBalanceDecimal();
                var lyrBalance       = w1.GetLastSyncBlock().Balances[LyraGlobal.OFFICIALTICKERCODE].ToBalanceDecimal();

                // send wrong token
                var amount = Math.Round((decimal)((new Random().NextDouble() + 0.07) * 1000), 8);
                var cal    = new SwapCalculator(LyraGlobal.OFFICIALTICKERCODE, testTokenA, poolLatestBlock, LyraGlobal.OFFICIALTICKERCODE, amount, 0);

                var result = await w1.SwapTokenAsync(LyraGlobal.OFFICIALTICKERCODE, testTokenA, testTokenB, amount, cal.SwapOutAmount);

                Assert.IsTrue(result.ResultCode != APIResultCodes.Success, $"Should failed but: {result.ResultCode}");

                amount = Math.Round((decimal)((new Random().NextDouble() + 0.07) * 1000), 8);
                cal    = new SwapCalculator(LyraGlobal.OFFICIALTICKERCODE, testTokenA, poolLatestBlock, LyraGlobal.OFFICIALTICKERCODE, amount, 0);
                result = await w1.SwapTokenAsync(LyraGlobal.OFFICIALTICKERCODE, testTokenB, LyraGlobal.OFFICIALTICKERCODE, amount, cal.SwapOutAmount);

                Assert.IsTrue(result.ResultCode != APIResultCodes.Success, $"Should failed but: {result.ResultCode}");

                amount = Math.Round((decimal)((new Random().NextDouble() + 0.07) * 1000), 8);
                result = await w1.SwapTokenAsync(testTokenB, testTokenA, LyraGlobal.OFFICIALTICKERCODE, amount, cal.SwapOutAmount);

                Assert.IsTrue(result.ResultCode != APIResultCodes.Success, $"Should failed but: {result.ResultCode}");

                amount = lyrBalance + 1;
                result = await w1.SwapTokenAsync(LyraGlobal.OFFICIALTICKERCODE, testTokenA, LyraGlobal.OFFICIALTICKERCODE, amount, cal.SwapOutAmount);

                Assert.IsTrue(result.ResultCode != APIResultCodes.Success, $"Should failed but: {result.ResultCode}");

                //amount = poolLatestBlock.Balances[pool.Token0].ToBalanceDecimal() / 2 + 1000m;
                //result = await w1.SwapToken(LyraGlobal.OFFICIALTICKERCODE, testTokenA, LyraGlobal.OFFICIALTICKERCODE, amount, cal.SwapOutAmount);
                //Assert.IsTrue(result.ResultCode != APIResultCodes.Success, $"Should failed but: {result.ResultCode}");

                //amount = poolLatestBlock.Balances[pool.Token0].ToBalanceDecimal();
                //result = await w1.SwapToken(LyraGlobal.OFFICIALTICKERCODE, testTokenA, LyraGlobal.OFFICIALTICKERCODE, amount, cal.SwapOutAmount);
                //Assert.IsTrue(result.ResultCode != APIResultCodes.Success, $"Should failed but: {result.ResultCode}");

                amount = 1000000000000m;
                try
                {
                    result = await w1.SwapTokenAsync(LyraGlobal.OFFICIALTICKERCODE, testTokenA, LyraGlobal.OFFICIALTICKERCODE, amount, cal.SwapOutAmount);

                    Assert.Fail("Should has over flow exception.");
                }
                catch { }

                await Task.Delay(3000);

                await w1.SyncAsync(client);

                // make sure the balance is not changed.
                var testTokenBalancex = w1.GetLastSyncBlock().Balances[testTokenA].ToBalanceDecimal();
                var lyrBalancex       = w1.GetLastSyncBlock().Balances[LyraGlobal.OFFICIALTICKERCODE].ToBalanceDecimal();
                Assert.AreEqual(testTokenBalance, testTokenBalancex);
                Assert.AreEqual(lyrBalance, lyrBalancex);

                // then ok token
                amount = Math.Round((decimal)((new Random().NextDouble() + 0.07) * 1000), 8);
                cal    = new SwapCalculator(LyraGlobal.OFFICIALTICKERCODE, testTokenA, poolLatestBlock, LyraGlobal.OFFICIALTICKERCODE, amount, 0);
                result = await w1.SwapTokenAsync(LyraGlobal.OFFICIALTICKERCODE, testTokenA, LyraGlobal.OFFICIALTICKERCODE, amount, cal.MinimumReceived);

                Assert.IsTrue(result.ResultCode == APIResultCodes.Success, $"Failed to swap {LyraGlobal.OFFICIALTICKERCODE}: {result.ResultCode}");

                await Task.Delay(15000);

                var poolGenesisResult = await client.GetBlockByIndexAsync(poolLatestBlock.AccountID, 1);

                var block       = poolGenesisResult.GetBlock();
                var poolGenesis = block as PoolGenesisBlock;
                Assert.IsTrue(poolGenesisResult.ResultCode == APIResultCodes.Success, $"get gensis returns {poolGenesisResult.ResultCode}");
                Assert.IsNotNull(poolGenesis, "Can't get pool genesis block.");
                var sc = new SwapCalculator(poolGenesis.Token0, poolGenesis.Token1, poolLatestBlock,
                                            LyraGlobal.OFFICIALTICKERCODE, amount, 0);
                var amountToGet = sc.SwapOutAmount;

                await w1.SyncAsync(client);

                var testTokenBalance2 = w1.GetLastSyncBlock().Balances[testTokenA].ToBalanceDecimal();
                var lyrBalance2       = w1.GetLastSyncBlock().Balances[LyraGlobal.OFFICIALTICKERCODE].ToBalanceDecimal();

                Assert.AreEqual(testTokenBalance + amountToGet, testTokenBalance2);
                Assert.AreEqual(lyrBalance - 1 - amount, lyrBalance2);
            }
            finally
            {
                semaphore.Release();
            }
        }
Ejemplo n.º 5
0
        public async Task SwapWithSlippageAsync()
        {
            try
            {
                await semaphore.WaitAsync();

                var pool = await client.GetPoolAsync(testTokenA, LyraGlobal.OFFICIALTICKERCODE);

                Assert.IsNotNull(pool.PoolAccountId);
                var poolLatestBlock = pool.GetBlock() as TransactionBlock;

                Assert.IsTrue(poolLatestBlock.Balances[pool.Token0] > 0 && poolLatestBlock.Balances[pool.Token1] > 0, "No liquidate in pool.");

                var w1 = Restore(testPrivateKey);
                await w1.SyncAsync(client);

                var testTokenBalance = w1.GetLastSyncBlock().Balances[testTokenA].ToBalanceDecimal();
                var lyrBalance       = w1.GetLastSyncBlock().Balances[LyraGlobal.OFFICIALTICKERCODE].ToBalanceDecimal();

                // ops, someone swapped
                var w2       = Restore(otherAccountPrivateKey);
                var w2result = await w2.SyncAsync(client);

                Assert.IsTrue(w2result == APIResultCodes.Success, $"W2 sync failed: {w2result}");

                var otherAmount = 1m;// Math.Round((decimal)((new Random().NextDouble() + 0.07) * 1000), 8);

                var cal1 = new SwapCalculator(LyraGlobal.OFFICIALTICKERCODE, testTokenA, poolLatestBlock, LyraGlobal.OFFICIALTICKERCODE, otherAmount, 0);

                var otherResult = await w2.SwapTokenAsync(LyraGlobal.OFFICIALTICKERCODE, testTokenA, LyraGlobal.OFFICIALTICKERCODE, otherAmount, cal1.MinimumReceived);

                Assert.IsTrue(otherResult.ResultCode == APIResultCodes.Success, $"Failed to swap other account {LyraGlobal.OFFICIALTICKERCODE}: {otherResult.ResultCode}");

                await Task.Delay(6000);

                // then the slippage is triggered
                var amount = Math.Round((decimal)((new Random().NextDouble() + 0.07) * 1000), 8);
                var cal2   = new SwapCalculator(LyraGlobal.OFFICIALTICKERCODE, testTokenA, poolLatestBlock, LyraGlobal.OFFICIALTICKERCODE, amount, 0);
                var result = await w1.SwapTokenAsync(LyraGlobal.OFFICIALTICKERCODE, testTokenA, LyraGlobal.OFFICIALTICKERCODE, amount, cal2.SwapOutAmount);

                Assert.IsTrue(result.ResultCode == APIResultCodes.SwapSlippageExcceeded, $"Should Failed to swap {LyraGlobal.OFFICIALTICKERCODE}: {result.ResultCode}");

                amount = Math.Round((decimal)((new Random().NextDouble() + 0.07) * 1000), 8);
                var cal3 = new SwapCalculator(LyraGlobal.OFFICIALTICKERCODE, testTokenA, poolLatestBlock, LyraGlobal.OFFICIALTICKERCODE, amount, 0.001m);
                result = await w1.SwapTokenAsync(LyraGlobal.OFFICIALTICKERCODE, testTokenA, LyraGlobal.OFFICIALTICKERCODE, amount, cal3.SwapOutAmount + 1000);

                Assert.IsTrue(result.ResultCode == APIResultCodes.SwapSlippageExcceeded, $"Should Failed to swap {LyraGlobal.OFFICIALTICKERCODE}: {result.ResultCode}");

                amount = Math.Round((decimal)((new Random().NextDouble() + 0.07) * 1000), 8);
                var cal4 = new SwapCalculator(LyraGlobal.OFFICIALTICKERCODE, testTokenA, poolLatestBlock, LyraGlobal.OFFICIALTICKERCODE, amount, 0.1m);
                result = await w1.SwapTokenAsync(LyraGlobal.OFFICIALTICKERCODE, testTokenA, LyraGlobal.OFFICIALTICKERCODE, amount, cal4.MinimumReceived);

                Assert.IsTrue(result.ResultCode == APIResultCodes.Success, $"Failed to swap {LyraGlobal.OFFICIALTICKERCODE}: {result.ResultCode}");

                await Task.Delay(6000);

                var amountToGet = cal4.MinimumReceived;
                await w1.SyncAsync(client);

                var testTokenBalance2 = w1.GetLastSyncBlock().Balances[testTokenA].ToBalanceDecimal();
                var lyrBalance2       = w1.GetLastSyncBlock().Balances[LyraGlobal.OFFICIALTICKERCODE].ToBalanceDecimal();

                Assert.IsTrue(testTokenBalance + amountToGet <= testTokenBalance2,
                              $"testTokenBalance + amountToGet is {testTokenBalance + amountToGet}, testTokenBalance2 is {testTokenBalance2}");
                Assert.AreEqual(lyrBalance - 1 - amount, lyrBalance2);
            }
            finally
            {
                semaphore.Release();
            }
        }
Ejemplo n.º 6
0
        public async Task SwapLYRToTokenAAsync()
        {
            try
            {
                await semaphore.WaitAsync();

                var pool = await client.GetPoolAsync(testTokenA, LyraGlobal.OFFICIALTICKERCODE);

                Assert.IsNotNull(pool.PoolAccountId);
                var poolLatestBlock = pool.GetBlock() as TransactionBlock;

                Assert.IsTrue(poolLatestBlock.Balances[pool.Token0] > 0 && poolLatestBlock.Balances[pool.Token1] > 0, "No liquidate in pool.");

                var w1 = Restore(testPrivateKey);
                await w1.SyncAsync(client);

                var testTokenBalance = w1.GetLastSyncBlock().Balances[testTokenA].ToBalanceDecimal();
                var lyrBalance       = w1.GetLastSyncBlock().Balances[LyraGlobal.OFFICIALTICKERCODE].ToBalanceDecimal();

                var amount = Math.Round((decimal)((new Random().NextDouble() + 0.07) * 1000), 8);

                var cal1 = new SwapCalculator(LyraGlobal.OFFICIALTICKERCODE, testTokenA, poolLatestBlock, LyraGlobal.OFFICIALTICKERCODE, amount, 0);

                var result = await w1.SwapTokenAsync(LyraGlobal.OFFICIALTICKERCODE, testTokenA, LyraGlobal.OFFICIALTICKERCODE, amount, cal1.MinimumReceived);

                Assert.IsTrue(result.ResultCode == APIResultCodes.Success, $"Failed to swap {LyraGlobal.OFFICIALTICKERCODE}: {result.ResultCode}");
                await Task.Delay(9000);

                // then the pool should receive the funds
                var poolInResult = await client.GetBlockByIndexAsync(pool.PoolAccountId, poolLatestBlock.Height + 1);

                Assert.IsTrue(poolInResult.ResultCode == APIResultCodes.Success, "failed to get pool in block. " + poolInResult.ResultCode);
                var poolIn = poolInResult.GetBlock() as PoolSwapInBlock;
                Assert.IsNotNull(poolIn);

                var chgs = poolIn.GetBalanceChanges(poolLatestBlock);
                Assert.AreEqual(1, chgs.Changes.Count);
                Assert.AreEqual(LyraGlobal.OFFICIALTICKERCODE, chgs.Changes.First().Key);
                Assert.AreEqual(amount, chgs.Changes.First().Value);

                var poolGenesisResult = await client.GetBlockByIndexAsync(poolLatestBlock.AccountID, 1);

                var block       = poolGenesisResult.GetBlock();
                var poolGenesis = block as PoolGenesisBlock;
                Assert.IsTrue(poolGenesisResult.ResultCode == APIResultCodes.Success, $"get gensis returns {poolGenesisResult.ResultCode}");
                Assert.IsNotNull(poolGenesis, "Can't get pool genesis block.");

                var amountToGet = cal1.SwapOutAmount;

                await w1.SyncAsync(client);

                var testTokenBalance2 = w1.GetLastSyncBlock().Balances[testTokenA].ToBalanceDecimal();
                var lyrBalance2       = w1.GetLastSyncBlock().Balances[LyraGlobal.OFFICIALTICKERCODE].ToBalanceDecimal();

                Assert.AreEqual(testTokenBalance + amountToGet, testTokenBalance2);
                Assert.AreEqual(lyrBalance - 1 - amount, lyrBalance2);
            }
            finally
            {
                semaphore.Release();
            }
        }
Ejemplo n.º 7
0
        public override async Task <TransactionBlock> ExtraOpsAsync(DagSystem sys, string reqHash)
        {
            var blocks = await sys.Storage.FindBlocksByRelatedTxAsync(reqHash);

            var swout = blocks.FirstOrDefault(a => a is PoolSwapOutBlock);

            if (swout != null)
            {
                return(null);
            }

            var recv = blocks.FirstOrDefault(a => a is PoolSwapInBlock) as PoolSwapInBlock;

            var swapInBlock   = recv as PoolSwapInBlock;
            var recvBlockPrev = await sys.Storage.FindBlockByHashAsync(recv.PreviousHash) as TransactionBlock;

            var recvChgs    = swapInBlock.GetBalanceChanges(recvBlockPrev);
            var kvp         = recvChgs.Changes.First();
            var poolGenesis = await sys.Storage.FindFirstBlockAsync(swapInBlock.AccountID) as PoolGenesisBlock;

            var cfg = new SwapCalculator(poolGenesis.Token0, poolGenesis.Token1, recvBlockPrev,
                                         kvp.Key, kvp.Value, 0);

            var lsb = await sys.Storage.GetLastServiceBlockAsync();

            var send = await sys.Storage.FindBlockByHashAsync(swapInBlock.SourceHash) as SendTransferBlock;

            var swapOutBlock = new PoolSwapOutBlock
            {
                AccountID            = send.DestinationAccountId,
                ServiceHash          = lsb.Hash,
                DestinationAccountId = send.AccountID,
                Balances             = new Dictionary <string, long>(),
                Tags      = null,
                Fee       = cfg.PayToAuthorizer,
                FeeCode   = LyraGlobal.OFFICIALTICKERCODE,
                FeeType   = AuthorizationFeeTypes.Dynamic,
                RelatedTx = send.Hash
            };

            swapOutBlock.AddTag(Block.MANAGEDTAG, "");   // value is always ignored

            var poolGenesisBlock = await sys.Storage.FindFirstBlockAsync(recv.AccountID) as PoolGenesisBlock;

            var poolLatestBlock = await sys.Storage.FindLatestBlockAsync(recv.AccountID) as TransactionBlock;

            var curBalance  = poolLatestBlock.Balances.ToDecimalDict();
            var nextBalance = poolLatestBlock.Balances.ToDecimalDict();

            var tokenOut = cfg.SwapOutToken;
            var tokenIn  = cfg.SwapInToken;

            if (tokenIn == LyraGlobal.OFFICIALTICKERCODE)
            {
                // tokenIn == LYR
                nextBalance[tokenIn]  = curBalance[tokenIn] - cfg.PayToAuthorizer; // pool fee leave in the pool
                nextBalance[tokenOut] = curBalance[tokenOut] - cfg.SwapOutAmount;
            }
            else
            {
                // tokenIn == other token
                nextBalance[tokenIn]  = curBalance[tokenIn]; // pool fee leave in the pool
                nextBalance[tokenOut] = curBalance[tokenOut] - cfg.SwapOutAmount - cfg.PayToAuthorizer;
            }

            Console.WriteLine($"user should receive {cfg.SwapOutAmount} {cfg.SwapOutToken}");

            swapOutBlock.Balances = nextBalance.ToLongDict();
            swapOutBlock.Shares   = (poolLatestBlock as IPool).Shares;
            await swapOutBlock.InitializeBlockAsync(poolLatestBlock, (hash) => Task.FromResult(Signatures.GetSignature(sys.PosWallet.PrivateKey, hash, sys.PosWallet.AccountId)));

            // verify
            var chgs = swapOutBlock.GetBalanceChanges(poolLatestBlock);

            return(swapOutBlock);
        }
Ejemplo n.º 8
0
        public override async Task <APIResultCodes> PreSendAuthAsync(DagSystem sys, SendTransferBlock block, TransactionBlock lastBlock)
        {
            if (block.Tags.Count > 3 || !block.Tags.ContainsKey("poolid"))
            {
                return(APIResultCodes.InvalidBlockTags);
            }

            if (block.Tags.Count == 3 && !block.Tags.ContainsKey("minrecv"))
            {
                return(APIResultCodes.InvalidBlockTags);
            }

            var vp = await WFPoolAddLiquidate.VerifyPoolAsync(sys, block, lastBlock);

            if (vp != APIResultCodes.Success)
            {
                return(vp);
            }

            var chgs        = block.GetBalanceChanges(lastBlock);
            var poolGenesis = sys.Storage.GetPoolByID(block.Tags["poolid"]);

            if (chgs.Changes.Count != 1)
            {
                return(APIResultCodes.InvalidTokenToSwap);
            }

            string tokenToSwap = null;
            var    kvp         = chgs.Changes.First();

            if (kvp.Key == poolGenesis.Token0)
            {
                tokenToSwap = poolGenesis.Token0;
            }
            else if (kvp.Key == poolGenesis.Token1)
            {
                tokenToSwap = poolGenesis.Token1;
            }

            if (tokenToSwap == null)
            {
                return(APIResultCodes.InvalidTokenToSwap);
            }

            // check amount
            var poolLatest = await sys.Storage.FindLatestBlockAsync(block.DestinationAccountId) as TransactionBlock;

            //if (kvp.Value > poolLatest.Balances[tokenToSwap].ToBalanceDecimal() / 2)
            //    return APIResultCodes.TooManyTokensToSwap;
            // uniswap AMM don't mind how many token want to swap

            if (block.Tags.ContainsKey("minrecv"))
            {
                if (!long.TryParse(block.Tags["minrecv"], out long toGetLong))
                {
                    return(APIResultCodes.InvalidSwapSlippage);
                }

                decimal toGet = toGetLong.ToBalanceDecimal();

                if (toGet <= 0)
                {
                    return(APIResultCodes.InvalidSwapSlippage);
                }

                if (poolLatest.Balances.Any(a => a.Value == 0))
                {
                    // can't calculate rito
                    return(APIResultCodes.PoolOutOfLiquidaty);
                }

                var cal = new SwapCalculator(poolGenesis.Token0, poolGenesis.Token1, poolLatest,
                                             chgs.Changes.First().Key, chgs.Changes.First().Value, 0);

                if (cal.SwapOutAmount < toGet)
                {
                    return(APIResultCodes.SwapSlippageExcceeded);
                }
            }
            return(APIResultCodes.Success);
        }
Ejemplo n.º 9
0
        protected override async Task <APIResultCodes> VerifyWithPrevAsync(DagSystem sys, Block block, Block previousBlock)
        {
            var swapOutBlock = block as PoolSwapOutBlock;

            if (swapOutBlock == null)
            {
                return(APIResultCodes.InvalidBlockType);
            }

            var relatedTransactions = await sys.Storage.FindBlocksByRelatedTxAsync(swapOutBlock.RelatedTx);

            if (relatedTransactions.Count >= 2)
            {
                return(APIResultCodes.PoolOperationAlreadyCompleted);
            }

            var poolId      = (block as PoolSwapOutBlock).AccountID;
            var poolGenesis = await sys.Storage.FindFirstBlockAsync(poolId) as PoolGenesisBlock;

            var poolLatestBlock = await sys.Storage.FindLatestBlockAsync(poolId) as TransactionBlock;

            // get target accountId
            var originalSendBlock = await sys.Storage.FindBlockByHashAsync(swapOutBlock.RelatedTx) as SendTransferBlock;

            if (originalSendBlock == null)
            {
                return(APIResultCodes.InvalidOperation);
            }

            var targetAccountId = originalSendBlock.AccountID;

            if (targetAccountId != swapOutBlock.DestinationAccountId)
            {
                return(APIResultCodes.InvalidPoolSwapOutAccountId);
            }

            if (originalSendBlock.Tags == null || originalSendBlock.Tags[Block.REQSERVICETAG] != BrokerActions.BRK_POOL_SWAP)
            {
                return(APIResultCodes.InvalidPoolOperation);
            }

            var prevPrevBlock = await sys.Storage.FindBlockByHashAsync(previousBlock.PreviousHash) as TransactionBlock;

            var chgs = (previousBlock as TransactionBlock).GetBalanceChanges(prevPrevBlock);

            // calculate rito by prevBlock.prevBlock
            var prevprevBlock = await sys.Storage.FindBlockByHashAsync(previousBlock.PreviousHash) as TransactionBlock;

            if (prevprevBlock == null)
            {
                return(APIResultCodes.InvalidPoolOperation);
            }
            var swapRito = Math.Round(prevprevBlock.Balances[poolGenesis.Token0].ToBalanceDecimal() / prevprevBlock.Balances[poolGenesis.Token1].ToBalanceDecimal(), LyraGlobal.RITOPRECISION);

            if (chgs.Changes.Count != 1)
            {
                return(APIResultCodes.InvalidPoolOperation);
            }
            string tokenIn = chgs.Changes.First().Key;

            if (tokenIn != poolGenesis.Token0 && tokenIn != poolGenesis.Token1)
            {
                return(APIResultCodes.InvalidPoolOperation);
            }

            var kvp = chgs.Changes.First();
            var cfg = new SwapCalculator(poolGenesis.Token0, poolGenesis.Token1, prevprevBlock,
                                         tokenIn, chgs.Changes.First().Value, 0);

            if (cfg.SwapOutToken == null || cfg.SwapOutAmount == 0m)
            {
                return(APIResultCodes.InvalidPoolOperation);
            }

            var currentOutChgs = swapOutBlock.GetBalanceChanges(previousBlock as TransactionBlock);

            if (currentOutChgs.Changes.Count != 1)   //plus the fee: no, fee pay by standard and is not included here
            {
                return(APIResultCodes.InvalidPoolSwapOutToken);
            }
            if (currentOutChgs.Changes.First().Key != cfg.SwapOutToken ||
                currentOutChgs.Changes.First().Value != cfg.SwapOutAmount)
            {
                Console.WriteLine($"Swap out: {currentOutChgs.Changes.First().Value} should be: {cfg.SwapOutAmount}");
                return(APIResultCodes.InvalidPoolSwapOutAmount);
            }

            // balance & share
            var curBalance  = poolLatestBlock.Balances.ToDecimalDict();
            var nextBalance = poolLatestBlock.Balances.ToDecimalDict();

            var tokenOut = cfg.SwapOutToken;

            if (tokenIn == LyraGlobal.OFFICIALTICKERCODE)
            {
                // tokenIn == LYR
                nextBalance[tokenIn]  = curBalance[tokenIn] - cfg.PayToAuthorizer; // pool fee leave in the pool
                nextBalance[tokenOut] = curBalance[tokenOut] - cfg.SwapOutAmount;
            }
            else
            {
                // tokenOut == LYR
                nextBalance[tokenIn]  = curBalance[tokenIn]; // pool fee leave in the pool
                nextBalance[tokenOut] = curBalance[tokenOut] - cfg.SwapOutAmount - cfg.PayToAuthorizer;
            }

            var outBalances = nextBalance.ToLongDict();
            var outShares   = (poolLatestBlock as IPool).Shares;

            if (!swapOutBlock.Balances.OrderBy(a => a.Key)
                .SequenceEqual(outBalances.OrderBy(a => a.Key)))
            {
                return(APIResultCodes.InvalidPoolSwapOutAmount);
            }

            if (!swapOutBlock.Shares.OrderBy(a => a.Key)
                .SequenceEqual(outShares.OrderBy(a => a.Key)))
            {
                return(APIResultCodes.InvalidPoolSwapOutShare);
            }

            _calculator = cfg;
            return(await base.VerifyWithPrevAsync(sys, block, previousBlock));
        }
        private async Task UpdateSwapToBalanceForLyraSwapAsync()
        {
            swapCalculator = null;

            if (walletState.Value.wallet?.GetLatestBlock()?.Balances?.ContainsKey(swapFromToken) == true)
            {
                fromTokenBalance = walletState.Value.wallet?.GetLatestBlock()?.Balances?[swapFromToken].ToBalanceDecimal() ?? 0m;
            }
            else
            {
                fromTokenBalance = 0m;
            }

            // check if pool exists.
            var pool = await lyraClient.GetPool(swapFromToken, swapToToken);

            if (pool.Successful() && pool.PoolAccountId != null)
            {
                IsDisabled = false;

                var token0          = pool.Token0;
                var token1          = pool.Token1;
                var swapRito        = 0m;
                var poolLatestBlock = pool.GetBlock() as TransactionBlock;
                if (poolLatestBlock.Balances.ContainsKey(token0) && !poolLatestBlock.Balances.Any(a => a.Value == 0))
                {
                    swapRito = poolLatestBlock.Balances[token0].ToBalanceDecimal() / poolLatestBlock.Balances[token1].ToBalanceDecimal();
                }

                var sb = new StringBuilder();
                sb.AppendLine($"Liquidate pool for {token0} and {token1}: \n Pool account ID is {pool.PoolAccountId}\n");
                if (swapRito > 0)
                {
                    expectedRito = swapRito;
                    sb.AppendLine($" Pool liquidate of {token0}: {poolLatestBlock.Balances[token0].ToBalanceDecimal()}");
                    sb.AppendLine($" Pool liquidate of {token1}: {poolLatestBlock.Balances[token1].ToBalanceDecimal()}");

                    // calculate it
                    if (swapFromCount > 0)
                    {
                        if (swapFromToken == token0)
                        {
                            swapCalculator = new SwapCalculator(token0, token1, poolLatestBlock, token0, swapFromCount, slippage / 100);                                        // default %
                        }
                        else
                        {
                            swapCalculator = new SwapCalculator(token0, token1, poolLatestBlock, token1, swapFromCount, slippage / 100);
                        }

                        swapToCount = swapCalculator.MinimumReceived;
                    }
                    else
                    {
                        swapToCount = 0;
                    }
                }
                else
                {
                    expectedRito = 0;
                    sb.AppendLine($" Pool doesn't have liquidate yet.");
                }
                PoolInfo = sb.ToString();
            }
            else
            {
                IsDisabled = true;
                PoolInfo   = $"No liquidate pool for {swapFromToken} and {swapToToken}.";
            }

            if (swapCalculator == null || swapCalculator.MinimumReceived <= 0)
            {
                IsDisabled = true;
            }

            await InvokeAsync(() =>
            {
                StateHasChanged();
            });
        }