From a0ef1d88edeb8bf56b55cc6629ddc69af68724ec Mon Sep 17 00:00:00 2001 From: Andri Joos <andri@joos.io> Date: Fri, 29 Nov 2024 16:54:14 +0100 Subject: [PATCH] marketplace buy --- .../Interfaces/IPotatoMarketplace.cs | 9 +-- .../Marketplaces/PotatoMarketplaceMock.cs | 69 +++++++++++++++---- Frontend/Program.cs | 16 ++++- 3 files changed, 73 insertions(+), 21 deletions(-) diff --git a/Frontend/Marketplaces/Interfaces/IPotatoMarketplace.cs b/Frontend/Marketplaces/Interfaces/IPotatoMarketplace.cs index 702b893..b42f07e 100644 --- a/Frontend/Marketplaces/Interfaces/IPotatoMarketplace.cs +++ b/Frontend/Marketplaces/Interfaces/IPotatoMarketplace.cs @@ -1,4 +1,6 @@ +using System.Numerics; using Frontend.Assets; +using Nethereum.Web3; namespace Frontend.Marketplaces.Interfaces { @@ -7,9 +9,8 @@ namespace Frontend.Marketplaces.Interfaces public Task<double> EthPriceInChf { get; } public Task<double> PotatoKgPriceInChf { get; } public Task<double> PotatoKgPriceInEth { get; } - public double PotatoKgToChf(double kg); - public double ChfToPotatoKg(double chf); - public PotatoTransaction Buy(double amountInChf); - public double Sell(PotatoTransaction transaction); + public Task<bool> Approve(Web3 approverClient, BigInteger amount); + public Task<PotatoTransaction?> Buy(string ownerAddress); + // public double Sell(PotatoTransaction transaction); } } diff --git a/Frontend/Marketplaces/PotatoMarketplaceMock.cs b/Frontend/Marketplaces/PotatoMarketplaceMock.cs index dfbd2a2..1445f45 100644 --- a/Frontend/Marketplaces/PotatoMarketplaceMock.cs +++ b/Frontend/Marketplaces/PotatoMarketplaceMock.cs @@ -1,36 +1,72 @@ +using System.Numerics; using Frontend.Assets; using Frontend.Marketplaces.Interfaces; +using Nethereum.Contracts.Standards.ERC20.ContractDefinition; +using Nethereum.Web3; +using Nethereum.Web3.Accounts; using Newtonsoft.Json.Linq; namespace Frontend.Marketplaces; -public class PotatoMarketplaceMock() : IPotatoMarketPlace +public class PotatoMarketplaceMock( + Account marketplaceAccount, + Web3 marketplaceWeb3Client, + string wethAddress +) : IPotatoMarketPlace { private const double potatoKgChfPrice = 2.02; // source: https://www.blw.admin.ch/blw/de/home/markt/marktbeobachtung/kartoffeln.html + private readonly Account account = marketplaceAccount; + private readonly Web3 web3 = marketplaceWeb3Client; + private readonly string wethAddress = wethAddress; + public Task<double> EthPriceInChf => EthChfPrice(); public Task<double> PotatoKgPriceInChf => Task.FromResult(potatoKgChfPrice); public Task<double> PotatoKgPriceInEth => PotatoKgEthPrice(); - public double ChfToPotatoKg(double chf) + public async Task<bool> Approve(Web3 approverClient, BigInteger amountInWei) { - return chf / potatoKgChfPrice; - } + var approveHandler = approverClient.Eth.GetContractTransactionHandler<ApproveFunction>(); + var approveFunction = new ApproveFunction + { + Spender = account.Address, + Value = amountInWei, + }; - public double PotatoKgToChf(double kg) - { - return kg * potatoKgChfPrice; + var receipt = await approveHandler.SendRequestAndWaitForReceiptAsync(wethAddress, approveFunction); + return receipt.Status.Value == 1; } - public PotatoTransaction Buy(double amountInChf) + public async Task<PotatoTransaction?> Buy(string ownerAddress) { - var amountInKg = ChfToPotatoKg(amountInChf); - return new() { Weight = amountInKg }; - } + var allowanceHandler = web3.Eth.GetContractQueryHandler<AllowanceFunction>(); + var allowanceFunction = new AllowanceFunction + { + Owner = ownerAddress, + Spender = account.Address + }; - public double Sell(PotatoTransaction transaction) - { - return PotatoKgToChf(transaction.Weight); + var allowance = await allowanceHandler.QueryAsync<BigInteger>(wethAddress, allowanceFunction); + + var transferHandler = web3.Eth.GetContractTransactionHandler<TransferFromFunction>(); + var transferFunction = new TransferFromFunction + { + From = ownerAddress, + To = account.Address, + Value = allowance, + }; + + var receipt = await transferHandler.SendRequestAndWaitForReceiptAsync(wethAddress, transferFunction); + if (receipt.Status.Value == 0) + { + return null; + } + + var potatoWeight = (double)allowance / (double)await PotatoKgWeiPrice(); + return new PotatoTransaction + { + Weight = potatoWeight + }; } private static async Task<double> EthChfPrice() @@ -51,4 +87,9 @@ public class PotatoMarketplaceMock() : IPotatoMarketPlace var chfEthPrice = 1 / await EthChfPrice(); return chfEthPrice * potatoKgChfPrice; } + + private static async Task<BigInteger> PotatoKgWeiPrice() + { + return Web3.Convert.ToWei(await PotatoKgEthPrice()); + } } diff --git a/Frontend/Program.cs b/Frontend/Program.cs index 4a788d5..142bd0d 100644 --- a/Frontend/Program.cs +++ b/Frontend/Program.cs @@ -13,6 +13,7 @@ using Microsoft.EntityFrameworkCore; using OpenTelemetry.Metrics; using OpenTelemetry.Resources; using Org.BouncyCastle.Utilities; +using System.Numerics; // the location differ in dev and releas mode. var tokenAbiLocation = Environment.GetEnvironmentVariable("TOKEN_ABI_LOCATION")!; @@ -20,6 +21,7 @@ var tokenAbi = File.ReadAllText(tokenAbiLocation)!; var chainApiUrl = Environment.GetEnvironmentVariable("API_URL")!; var accountPrivateKey = Environment.GetEnvironmentVariable("ACCOUNT_PRIVATE_KEY")!; +var marketplaceAccountPrivateKey = Environment.GetEnvironmentVariable("MARKETPLACE_ACCOUNT_PRIVATE_KEY")!; var postgresHost = Environment.GetEnvironmentVariable("POSTGRES_HOST")!; var postgresUser = Environment.GetEnvironmentVariable("POSTGRES_USER")!; var postgresPassword = Environment.GetEnvironmentVariable("POSTGRES_PASSWORD")!; @@ -37,13 +39,17 @@ builder.Services.AddHostedService<PrometheusService>(); builder.Services.AddSingleton<Erc20TokenMetrics>(); builder.Services.AddSingleton<PotatoStorageMetrics>(); builder.Services.AddSingleton<PotatoMarketplaceMetrics>(); -builder.Services.AddSingleton<IPotatoMarketPlace>(sp => new PotatoMarketplaceMock()); Account account = new Account( accountPrivateKey, chainId: chainSettings.ChainId ); +Account marketplaceAccount = new( + marketplaceAccountPrivateKey, + chainId: chainSettings.ChainId +); + builder.Services.AddSingleton(provider => chainSettings); @@ -56,8 +62,12 @@ builder.Services.AddTransient<Web3>(sp => }); builder.Services.AddSingleton<PoolMetrics>(); - - +builder.Services.AddSingleton<IPotatoMarketPlace>(sp => +{ + var chainSettings = sp.GetRequiredService<ChainSettings>(); + var web3Client = new Web3(marketplaceAccount, chainApiUrl); + return new PotatoMarketplaceMock(marketplaceAccount, web3Client, chainSettings.WethTokenAddress); +}); builder.Services.AddDbContextFactory<PotatoStorage>(options => options.UseNpgsql($"Host={postgresHost};Database={postgresDb};Username={postgresUser};Password={postgresPassword}")); -- GitLab