From 2db0b7f40ec81794488a6fa90cd0bc4567b1f8c4 Mon Sep 17 00:00:00 2001
From: David Hintermann <David.Hintermann@ost.ch>
Date: Sat, 30 Nov 2024 13:39:25 +0000
Subject: [PATCH] feat(pool): implement rebalance swap

---
 Frontend/Functions/LiquidityFunction.cs |  9 ++++
 Frontend/PoolV3Client.cs                | 56 +++++++++++++++----------
 2 files changed, 44 insertions(+), 21 deletions(-)
 create mode 100644 Frontend/Functions/LiquidityFunction.cs

diff --git a/Frontend/Functions/LiquidityFunction.cs b/Frontend/Functions/LiquidityFunction.cs
new file mode 100644
index 0000000..fdc7cb2
--- /dev/null
+++ b/Frontend/Functions/LiquidityFunction.cs
@@ -0,0 +1,9 @@
+using Nethereum.ABI.FunctionEncoding.Attributes;
+using Nethereum.Contracts;
+
+namespace Frontend.Functions;
+
+[Function("liquiditry", "uint128")]
+public class LiquidityFunction : FunctionMessage{
+
+}
\ No newline at end of file
diff --git a/Frontend/PoolV3Client.cs b/Frontend/PoolV3Client.cs
index 5d1cba4..af1e6a5 100644
--- a/Frontend/PoolV3Client.cs
+++ b/Frontend/PoolV3Client.cs
@@ -93,12 +93,16 @@ public class PoolV3Client
     }
 
     public async Task<decimal> GetPairRatio()
+    {
+        return (decimal)SqrtPriceX96ToPrice(await GetSqrtPriceX96());
+    }
+
+    public async Task<BigInteger> GetSqrtPriceX96()
     {
         var handler = _web3.Eth.GetContractQueryHandler<Slot0Funtion>();
         var func = new Slot0Funtion();
         var slot0Result = await handler.QueryDeserializingToObjectAsync<Slot0OutputDTO>(func, _pool.Address);
-        var sqrtPriceX96 = slot0Result.SqrtPriceX96;
-        return (decimal)SqrtPriceX96ToPrice(sqrtPriceX96);
+        return slot0Result.SqrtPriceX96;
     }
 
     public double SqrtPriceX96ToPrice(BigInteger sqrtPriceX96)
@@ -138,7 +142,7 @@ public class PoolV3Client
         return _token1Address;
     }
 
-    public async Task<uint> getPoolFeeTier()
+    public async Task<uint> QueryPoolFee()
     {
         if (null == _poolFeeTier)
         {
@@ -150,6 +154,12 @@ public class PoolV3Client
         return (uint)_poolFeeTier;
     }
 
+    public async Task<BigInteger> QueryLiquidity(){
+        var handler = _web3.Eth.GetContractQueryHandler<LiquidityFunction>();
+        var func = new LiquidityFunction();
+        return await handler.QueryAsync<BigInteger>(_pool.Address, func);
+    }
+
 
     /*
     this function should swap the tokens in the pool
@@ -181,7 +191,7 @@ public class PoolV3Client
         {
             TokenIn = fromTokenAddress,
             TokenOut = toTokenAddress,
-            Fee = await getPoolFeeTier(),
+            Fee = await QueryPoolFee(),
             Recipient = _account.Address,
             AmountIn = Web3.Convert.ToWei(amount),
             AmountOutMinimum = Web3.Convert.ToWei(amountOutMinimum), // Set your minimum amount out
@@ -201,26 +211,30 @@ public class PoolV3Client
     /// This function should swap the tokens in the pool to create a desired quote
     /// </summary>
     /// <param name="desiredQuote">the ration between token1/token0</param>
-    /// <returns></returns>
+    /// <returns>Quote after the swap</returns>
     public async Task<decimal> PerformSwapToCreatDesiredQuote(decimal desiredQuote)
     {
-        var currentQuote = await GetPairRatio();
-        throw new NotImplementedException();
-        var amount = 0.0M;
-        if (currentQuote < desiredQuote)
-        {
-            // we sell some of token1 to buy token0
-            amount = (desiredQuote - currentQuote) / desiredQuote;
-            throw new NotImplementedException();
-            await SwapAsync(Token1Address, Token0Address, amount);
-        }
-        else
-        {
-            amount = 1;
-            throw new NotImplementedException();
-            await SwapAsync(Token1Address, Token0Address, amount);
+        var sqrtPriceX96= await GetSqrtPriceX96();
+        var desiredSqrtPriceX96=PriceToSqrtPriceX96((double)desiredQuote);
+        string[] tokenAddresses=[Token0Address,Token1Address];
+        var fromTokenIndex=0;
+        var amount = 0.0;
+        var liquidity=await QueryLiquidity();
+        if(desiredSqrtPriceX96>sqrtPriceX96){ // we have to by token0 to increase demand and drive the price up
+            fromTokenIndex=1; // we want to swap from token1 to token0
+
+            // Taken from getNextSqrtPriceFromAmount1RoundingDown see https://github.com/Uniswap/v3-core/blob/main/contracts/libraries/SqrtPriceMath.sol
+            amount=(double)(liquidity*(desiredSqrtPriceX96-sqrtPriceX96));
+        }else{ // whe have to sell token0 to lower the price 
+        
+            // Taken from getNextSqrtPriceFromAmount0ReoundingUp see https://github.com/Uniswap/v3-core/blob/main/contracts/libraries/SqrtPriceMath.sol
+            amount=(double)(liquidity*(sqrtPriceX96-desiredSqrtPriceX96))/(double)(desiredSqrtPriceX96*sqrtPriceX96);
         }
-        throw new NotImplementedException();
+        amount *= 1+ (int)await QueryPoolFee()/1000.0; // add the fees
+        
+        var receipt=await SwapAsync(tokenAddresses[fromTokenIndex],tokenAddresses[(fromTokenIndex+1)%2],Web3.Convert.FromWei(new BigInteger(amount)));
+        
+        return await GetPairRatio();
     }
 
 }
\ No newline at end of file
-- 
GitLab