From b19c967e7ee8849ea3ed0fc8bcab88e41d7009ed Mon Sep 17 00:00:00 2001 From: David Hintermann <David.Hintermann@ost.ch> Date: Tue, 26 Nov 2024 20:59:08 +0000 Subject: [PATCH] wip: use generated functions from ABI and Bytecode https://playground.nethereum.com/ --- Frontend/Functions/ApproveMaxFunctrion.cs | 13 +++ Frontend/Functions/ExactInputFunction.cs | 21 +++++ Frontend/Functions/ExactSingleParamBase.cs | 38 +++++++++ .../Functions/SwapExactInputSingleFunction.cs | 22 +++--- Frontend/PoolV3Client.cs | 79 ++++++++++++++++--- Frontend/TokenClient.cs | 21 ++++- 6 files changed, 170 insertions(+), 24 deletions(-) create mode 100644 Frontend/Functions/ApproveMaxFunctrion.cs create mode 100644 Frontend/Functions/ExactInputFunction.cs create mode 100644 Frontend/Functions/ExactSingleParamBase.cs diff --git a/Frontend/Functions/ApproveMaxFunctrion.cs b/Frontend/Functions/ApproveMaxFunctrion.cs new file mode 100644 index 0000000..c27a0d6 --- /dev/null +++ b/Frontend/Functions/ApproveMaxFunctrion.cs @@ -0,0 +1,13 @@ + +using System.Numerics; +using Nethereum.ABI.FunctionEncoding.Attributes; +using Nethereum.Contracts; + +namespace Frontend.Functions; public partial class ApproveMaxFunction : ApproveMaxFunctionBase { } + +[Function("approveMax")] +public class ApproveMaxFunctionBase : FunctionMessage +{ + [Parameter("address", "token", 1)] + public virtual string Token { get; set; } +} \ No newline at end of file diff --git a/Frontend/Functions/ExactInputFunction.cs b/Frontend/Functions/ExactInputFunction.cs new file mode 100644 index 0000000..4bcff67 --- /dev/null +++ b/Frontend/Functions/ExactInputFunction.cs @@ -0,0 +1,21 @@ +using Nethereum.ABI.FunctionEncoding.Attributes; +using Nethereum.Contracts; +using System.Numerics; + +namespace Frontend.Functions; + +[Function("exactInput")] +class ExactInputFunction : FunctionMessage +{ + [Parameter("uint256", "amountIn", 1)] + public BigInteger AmountIn { get; set; } + + [Parameter("uint256", "amountOutMinimum", 2)] + public BigInteger AmountOutMinimum { get; set; } + + [Parameter("address[]", "path", 3)] + public string[] Path { get; set; } + + [Parameter("address", "to", 4)] + public string To { get; set; } +} \ No newline at end of file diff --git a/Frontend/Functions/ExactSingleParamBase.cs b/Frontend/Functions/ExactSingleParamBase.cs new file mode 100644 index 0000000..ae54ab1 --- /dev/null +++ b/Frontend/Functions/ExactSingleParamBase.cs @@ -0,0 +1,38 @@ +using System.Numerics; +using Nethereum.Hex.HexTypes; +using Nethereum.ABI.FunctionEncoding.Attributes; +using Nethereum.Web3; +using Nethereum.RPC.Eth.DTOs; +using Nethereum.Contracts.CQS; +using Nethereum.Contracts; + +namespace Frontend.Functions; + public class ExactInputSingleParamsBase + { + [Parameter("address", "tokenIn", 1)] + public virtual string TokenIn { get; set; } + [Parameter("address", "tokenOut", 2)] + public virtual string TokenOut { get; set; } + [Parameter("uint24", "fee", 3)] + public virtual uint Fee { get; set; } + [Parameter("address", "recipient", 4)] + public virtual string Recipient { get; set; } + [Parameter("uint256", "amountIn", 5)] + public virtual BigInteger AmountIn { get; set; } + [Parameter("uint256", "amountOutMinimum", 6)] + public virtual BigInteger AmountOutMinimum { get; set; } + [Parameter("uint160", "sqrtPriceLimitX96", 7)] + public virtual BigInteger SqrtPriceLimitX96 { get; set; } + } + + public partial class ExactInputSingleParams : ExactInputSingleParamsBase { } + + + [Function("exactInputSingle", "uint256")] + public class ExactInputSingleFunctionBase : FunctionMessage + { + [Parameter("tuple", "params", 1)] + public virtual ExactInputSingleParams Params { get; set; } + } + + public partial class ExactInputSingleFunction : ExactInputSingleFunctionBase { } \ No newline at end of file diff --git a/Frontend/Functions/SwapExactInputSingleFunction.cs b/Frontend/Functions/SwapExactInputSingleFunction.cs index 6629e94..4d03789 100644 --- a/Frontend/Functions/SwapExactInputSingleFunction.cs +++ b/Frontend/Functions/SwapExactInputSingleFunction.cs @@ -4,27 +4,29 @@ using Nethereum.Contracts; using HexBigInteger = Nethereum.Hex.HexTypes.HexBigInteger; namespace Frontend.Functions; -[Function("exactInputSingle", "uint256")] +[Function("exactInputSingle")] public class SwapExactInputSingleFunction : FunctionMessage { - [Parameter("address", "tokenIn",1)] + [Parameter("address", "tokenIn")] public string TokenIn { get; set; } - [Parameter("address", "tokenOut",2)] + [Parameter("address", "tokenOut")] public string TokenOut { get; set; } - - [Parameter("uint24", "fee",3)] + + [Parameter("uint24", "fee")] public BigInteger Fee { get; set; } - - [Parameter("address", "recipient",4)] + + [Parameter("address", "recipient")] public string Recipient { get; set; } - [Parameter("uint256", "amountIn",5)] + [Parameter("uint256", "amountIn")] public BigInteger AmountIn { get; set; } - [Parameter("uint256", "amountOutMinimum",6)] + [Parameter("uint256", "amountOutMinimum")] public BigInteger AmountOutMinimum { get; set; } - [Parameter("uint160", "sqrtPriceLimitX96",7)] + [Parameter("uint160", "sqrtPriceLimitX96")] public BigInteger SqrtPriceLimitX96 { get; set; } + [Parameter("uint256", "deadline")] + public BigInteger Deadline { get; set; } } \ No newline at end of file diff --git a/Frontend/PoolV3Client.cs b/Frontend/PoolV3Client.cs index 73d6f5a..2aba84b 100644 --- a/Frontend/PoolV3Client.cs +++ b/Frontend/PoolV3Client.cs @@ -7,6 +7,9 @@ using Nethereum.Web3; using Nethereum.Web3.Accounts; using Frontend.Configuration; +using Microsoft.AspNetCore.Components.Forms; +using System.Reflection.Metadata.Ecma335; +using Nethereum.Contracts.Extensions; namespace Frontend; @@ -99,34 +102,86 @@ public class PoolV3Client /* this function should swap the tokens in the pool */ - public async Task<decimal> SwapAsync(string fromTokenAddress, string toTokenAddress, decimal amount, Account account, decimal amountOutMinimum=0, uint sqrtPriceLimitX96=0) + public async Task<decimal> SwapAsync(string fromTokenAddress, string toTokenAddress, decimal amount, Account account, decimal amountOutMinimum = 0, uint sqrtPriceLimitX96 = 0) { - var swapFunction = new SwapExactInputSingleFunction + /* var swapFunction = new SwapExactInputSingleFunction + { + TokenIn = fromTokenAddress, + TokenOut = toTokenAddress, + Fee = new BigInteger(await getPoolFeeTier()), + Recipient = account.Address, + AmountIn = Web3.Convert.ToWei(amount), + AmountOutMinimum = Web3.Convert.ToWei(amountOutMinimum), // Set your minimum amount out + SqrtPriceLimitX96 = sqrtPriceLimitX96, + Deadline = new BigInteger(DateTimeOffset.UtcNow.ToUnixTimeSeconds() + 60 ) // 20 minutes from now + }; + + swapFunction.Gas= new BigInteger(300000); + + var handler = _web3.Eth.GetContractTransactionHandler<SwapExactInputSingleFunction>(); + + var transactionReceipt = await handler.SendRequestAndWaitForReceiptAsync(_chainSettings.Uniswap.SwapRouterV2Address, swapFunction); + var swapEvent = transactionReceipt.DecodeAllEvents<SwapEventDTO>(); + if (swapEvent.Count > 0) + { + var receivedAmount = swapEvent[0].Event.AmountOut; + return Web3.Convert.FromWei(receivedAmount); + } + + + throw new Exception("Swap event not found in transaction receipt");*/ + var contractHandler = _web3.Eth.GetContractHandler(_chainSettings.Uniswap.SwapRouterV2Address); + var exactInputSingleFunction = new ExactInputSingleFunction(); + exactInputSingleFunction.Params = new ExactInputSingleParams { TokenIn = fromTokenAddress, TokenOut = toTokenAddress, + Fee = await getPoolFeeTier(), + Recipient = account.Address, AmountIn = Web3.Convert.ToWei(amount), AmountOutMinimum = Web3.Convert.ToWei(amountOutMinimum), // Set your minimum amount out - Recipient = account.Address, - Fee = new BigInteger(await getPoolFeeTier()), - SqrtPriceLimitX96 = sqrtPriceLimitX96 + SqrtPriceLimitX96 = sqrtPriceLimitX96, }; + var exactInputSingleFunctionTxnReceipt = await contractHandler.SendRequestAndWaitForReceiptAsync(exactInputSingleFunction); + var swapEvent = exactInputSingleFunctionTxnReceipt.DecodeAllEvents<SwapEventDTO>(); + if (swapEvent.Count > 0) + { + var receivedAmount = swapEvent[0].Event.AmountOut; + return Web3.Convert.FromWei(receivedAmount); + } + throw new Exception("Swap event not found in transaction receipt"); + } + public async Task<decimal> SwapAsync2(string fromTokenAddress, string toTokenAddress, decimal amount, Account account, decimal amountOutMinimum = 0, uint sqrtPriceLimitX96 = 0) + { + var contract = _web3.Eth.GetContract( + File.ReadAllText( + Path.Combine( + Directory.GetCurrentDirectory(), + "Configuration", + "Abi", + "swapRouterV2.abi.json" + ) + ), + _chainSettings.Uniswap.SwapRouterV2Address + ); - swapFunction.Gas= new BigInteger(300000); + var exactInputSingle = contract.GetFunction("exactInputSingle"); - var handler = _web3.Eth.GetContractTransactionHandler<SwapExactInputSingleFunction>(); - - var transactionReceipt = await handler.SendRequestAndWaitForReceiptAsync(_chainSettings.Uniswap.SwapRouterV2Address, swapFunction); - var swapEvent = transactionReceipt.DecodeAllEvents<SwapEventDTO>(); + var reciept = await exactInputSingle.SendTransactionAndWaitForReceiptAsync(account.Address, null, fromTokenAddress, toTokenAddress, await getPoolFeeTier(), account.Address, Web3.Convert.ToWei(amount), Web3.Convert.ToWei(amountOutMinimum), sqrtPriceLimitX96); + var swapEvent = reciept.DecodeAllEvents<SwapEventDTO>(); if (swapEvent.Count > 0) { var receivedAmount = swapEvent[0].Event.AmountOut; return Web3.Convert.FromWei(receivedAmount); } - - throw new Exception("Swap event not found in transaction receipt"); } + public async Task approveMax(string tokenAddress){ + var contractHandler = _web3.Eth.GetContractHandler(_chainSettings.Uniswap.SwapRouterV2Address); + var approveMaxFunction = new ApproveMaxFunction(); + approveMaxFunction.Token = tokenAddress; + var approveMaxFunctionTxnReceipt = await contractHandler.SendRequestAndWaitForReceiptAsync(approveMaxFunction); + } } \ No newline at end of file diff --git a/Frontend/TokenClient.cs b/Frontend/TokenClient.cs index 809e038..1a79d7b 100644 --- a/Frontend/TokenClient.cs +++ b/Frontend/TokenClient.cs @@ -16,7 +16,7 @@ public class TokenClient private readonly string _tokenAddress; private readonly string _tokenAbi; - private Contract Contract + private Contract Contract { get => _web3Client.Eth.GetContract(_tokenAbi, _tokenAddress); } @@ -27,7 +27,8 @@ public class TokenClient string tokenAbi, string accountPrivateKey, int chainId - ) { + ) + { _tokenAddress = tokenAddress; _tokenAbi = tokenAbi; _account = new(accountPrivateKey, chainId: chainId); @@ -69,4 +70,20 @@ public class TokenClient { return (decimal)(smallUnit / (BigInteger)Math.Pow(10, Decimals)); } + + + public async Task<BigInteger> GetAllowanceAsync(string ownerAddress, string spenderAddress) + { + var allowanceFunction = new AllowanceFunction + { + Owner = ownerAddress, + Spender = spenderAddress + }; + + var handler = _web3Client.Eth.GetContractQueryHandler<AllowanceFunction>(); + var allowance = await handler.QueryAsync<BigInteger>(_tokenAddress, allowanceFunction); + + return allowance; + } + } -- GitLab