docker files fixes from liaqat

This commit is contained in:
alirehmani
2024-05-03 16:39:25 +05:00
commit 464a8730e8
587 changed files with 44288 additions and 0 deletions

View File

@@ -0,0 +1,620 @@
using Managing.Application.Abstractions.Repositories;
using Managing.Domain.Evm;
using NBitcoin;
using Nethereum.Contracts;
using Nethereum.Hex.HexTypes;
using Nethereum.Signer;
using Nethereum.Web3;
using Nethereum.HdWallet;
using System.Numerics;
using System.Net.Http.Json;
using Managing.Infrastructure.Evm.Services;
using Managing.Domain.Candles;
using Managing.Infrastructure.Evm.Abstractions;
using Managing.Core;
using static Managing.Common.Enums;
using Managing.Infrastructure.Evm.Services.Gmx;
using Nethereum.Contracts.Standards.ERC20.ContractDefinition;
using Managing.Common;
using Managing.Domain.Trades;
using Managing.Domain.Accounts;
using Managing.Infrastructure.Evm.Models.Gmx;
using Managing.Infrastructure.Evm.Referentials;
namespace Managing.Infrastructure.Evm;
public class EvmManager : IEvmManager
{
private readonly Web3 _web3;
private readonly HttpClient _httpClient;
private readonly string _password = "!StrongPassword94";
private readonly IEnumerable<ISubgraphPrices> _subgraphs;
private Dictionary<string, Dictionary<string, decimal>> _geckoPrices;
public EvmManager(IEnumerable<ISubgraphPrices> subgraphs)
{
var defaultChain = ChainService.GetEthereum();
_web3 = new Web3(defaultChain.RpcUrl);
_httpClient = new HttpClient();
_subgraphs = subgraphs;
_geckoPrices = _geckoPrices != null && _geckoPrices.Any() ? _geckoPrices : new Dictionary<string, Dictionary<string, decimal>>();
SetupPrices();
}
public void SetupPrices()
{
try
{
var geckoIds = new List<string>();
foreach (var ticker in Enum.GetValues<Ticker>())
{
var geckoId = TokenService.GetGeckoToken(ticker.ToString())?.Id;
if (geckoId != null)
{
geckoIds.Add(geckoId);
}
}
if (geckoIds != null && geckoIds.Count > 0 && !_geckoPrices.Any())
{
_geckoPrices = GetPrices(geckoIds).Result;
}
}
catch (Exception ex)
{
// TODO : Handle error
}
}
public async Task<decimal> GetAddressBalance(string address)
{
var balance = await _web3.Eth.GetBalance.SendRequestAsync(address);
var etherAmount = Web3.Convert.FromWei(balance.Value);
return etherAmount;
}
public async Task<List<Holder>> GetContractHolders(string contractAddress, DateTime since)
{
var holders = new List<Holder>();
var contract = _web3.Eth.ERC721.GetContractService(contractAddress);
// Retrieve total supply to iterate over all token id generated within the contract
var totalSupply = await contract.TotalSupplyQueryAsync();
for (int tokenId = 1; tokenId < 10; tokenId++)
{
// Retrieve the owner of the nft
var tokenOwner = await contract.OwnerOfQueryAsync(tokenId);
// If holder already have an nft we get the holder
// Otherwise we create a new holder
var holder = holders.FirstOrDefault(h => h.HolderAddress == tokenOwner) ?? new Holder(tokenOwner);
// Retrieve all events related to the owner on the contract address
var nfts = await GetNftEvent(contractAddress, tokenOwner);
// Get tokenId related event
var nftEvent = nfts.FirstOrDefault(n => n.Event.TokenId == new BigInteger(tokenId));
if (nftEvent != null)
{
// Retrieve the date of the nft event that occur in the blocknumber
var blockDate = await GetBlockDate(nftEvent.Log.BlockNumber);
var nft = new Nft(contractAddress, tokenId, blockDate);
// Verify if the date of the holding is before the date passed from the parameters
if (blockDate <= since)
{
holder.AddNft(nft);
// If holder do not exist in the list we add it
if (!holders.Exists(h => h.HolderAddress == tokenOwner))
{
holders.Add(holder);
}
}
else
{
Console.WriteLine($"TokenId #{tokenId} for owner {tokenOwner} date not in range ({blockDate:f})");
}
}
else
{
Console.WriteLine($"Error when getting tokenId #{tokenId} for owner {tokenOwner}");
}
UpdateLine(tokenId, (int)totalSupply, holders.Count);
}
return holders;
}
public async Task<List<EventLog<Nethereum.Contracts.Standards.ERC721.ContractDefinition.TransferEventDTO>>> GetNftEvent(string contractAddress, string tokenOwner)
{
return await NftService.GetNftEvent(_web3, tokenOwner, contractAddress);
}
public async Task<DateTime> GetBlockDate(int blockNumber)
{
return await GetBlockDate(new HexBigInteger(blockNumber));
}
public async Task<DateTime> GetBlockDate(HexBigInteger blockNumber)
{
var block = await _web3.Eth.Blocks.GetBlockWithTransactionsByNumber.SendRequestAsync(blockNumber);
var date = DateHelpers.GetFromUnixTimestamp((int)block.Timestamp.Value);
return date;
}
private void UpdateLine(int count, int total, int holders)
{
Console.WriteLine($"{count}/{total} - {(((decimal)count * 100m) / (decimal)total)} % - Holders : {holders}");
}
public string VerifySignature(string signature, string message)
{
var signer = new EthereumMessageSigner();
var addressRecovered = signer.EncodeUTF8AndEcRecover(message, signature);
return addressRecovered;
}
public string SignMessage(string message, string privateKey)
{
var signer = new EthereumMessageSigner();
var signature = signer.EncodeUTF8AndSign(message, new EthECKey(privateKey));
return signature;
}
public (string Key, string Secret) GenerateAddress()
{
var mnemo = new Mnemonic(Wordlist.English, WordCount.Twelve);
var wallet = new Wallet(mnemo.ToString(), _password);
var account = wallet.GetAccount(0);
return (account.Address, mnemo.ToString());
}
public string GetAddressFromMnemo(string mnemo)
{
var wallet = new Wallet(mnemo, _password);
return wallet.GetAccount(0).Address;
}
public async Task<EvmBalance> GetEtherBalance(Domain.Evm.Chain chain, string account)
{
var web3 = new Web3(chain.RpcUrl);
var etherBalance = Web3.Convert.FromWei(await web3.Eth.GetBalance.SendRequestAsync(account));
var etherPrice = (await GetPrices(new List<string> { "ethereum"}))["ethereum"]["usd"];
return new EvmBalance() { Balance = etherBalance, Price = etherPrice, TokenName = "ETH", Value = etherBalance * etherPrice };
}
public async Task<List<EvmBalance>> GetAllBalances(Domain.Evm.Chain chain, string publicAddress)
{
var balances = new List<EvmBalance>();
var web3 = new Web3(chain.RpcUrl);
SetupPrices();
foreach (var ticker in Enum.GetValues<Ticker>())
{
try
{
var balance = await GetTokenBalance(chain.Name, ticker, publicAddress);
if (balance != null && balance.Balance > 0)
{
balances.Add(balance);
}
}
catch (Exception ex)
{
// TODO : handle exception
}
}
var etherBalance = await GetEtherBalance(chain, publicAddress);
etherBalance.Chain = chain;
balances.Add(etherBalance);
//var pageSize = 50;
//var tokenCount = TokenService.GetTokens().Count;
//for (int i = 0; i < (tokenCount / pageSize); i++)
//{
// var pageBalances = await GetBalances(chain, i, pageSize, publicAddress).ConfigureAwait(false);
// balances.AddRange(pageBalances);
//}
return balances;
}
public async Task<EvmBalance> GetTokenBalance(string chainName, Ticker ticker, string publicAddress)
{
var chain = ChainService.GetChain(chainName);
var web3 = new Web3(chain.RpcUrl);
var balanceOfMessage = new BalanceOfFunction() { Owner = publicAddress };
//Creating a new query handler
var queryHandler = web3.Eth.GetContractQueryHandler<BalanceOfFunction>();
var contractAddress = TokenService.GetContractAddress(ticker);
if (contractAddress == Arbitrum.Address.Zero)
return null;
var balance = await queryHandler
.QueryAsync<BigInteger>(contractAddress, balanceOfMessage)
.ConfigureAwait(false);
var geckoId = TokenService.GetGeckoToken(ticker.ToString())?.Id;
if (geckoId == null)
return null;
var tokenUsdPrice = _geckoPrices[geckoId][Constants.Stablecoins.Usd.ToLowerInvariant()];
var tokenDecimal = TokenService.GetDecimal(ticker);
var balanceFromWei = Web3.Convert.FromWei(balance, tokenDecimal);
var evmBalance = new EvmBalance
{
TokenName = ticker.ToString(),
Balance = balanceFromWei,
TokenAddress = contractAddress,
Value = tokenUsdPrice * balanceFromWei,
Price = tokenUsdPrice,
Chain = chain
};
return evmBalance;
}
public async Task<List<EvmBalance>> GetBalances(Domain.Evm.Chain chain, int page, int pageSize, string publicAddress)
{
var callList = new List<IMulticallInputOutput>();
var startItem = (page * pageSize);
var tokens = TokenService.GetTokens();
var totaItemsToFetch = startItem + pageSize <= tokens.Count ? startItem + pageSize : tokens.Count + startItem;
for (int i = startItem; i < totaItemsToFetch; i++)
{
var balanceOfMessage = new BalanceOfFunction() { Owner = publicAddress };
var call = new MulticallInputOutput<BalanceOfFunction, BalanceOfOutputDTO>(balanceOfMessage,
tokens[i].Address);
callList.Add(call);
}
var evmTokens = new List<(EvmBalance Balance, GeckoToken GeckoToken)>();
try
{
var web3 = new Web3(chain.RpcUrl);
var geckoTokens = TokenService.GetGeckoTokens();
await web3.Eth.GetMultiQueryHandler().MultiCallAsync(callList.ToArray());
for (int i = startItem; i < totaItemsToFetch; i++)
{
var balance = ((MulticallInputOutput<BalanceOfFunction, BalanceOfOutputDTO>)callList[i - startItem]).Output.Balance;
if (balance > 0)
{
var tokenBalance = new EvmBalance()
{
Balance = Web3.Convert.FromWei(balance, tokens[i].Decimals),
TokenName = tokens[i].Symbol,
TokenAddress = tokens[i].Address,
Chain = chain
};
var geckoToken = geckoTokens.FirstOrDefault(x => string.Equals(x.Symbol, tokens[i].Symbol, StringComparison.InvariantCultureIgnoreCase));
evmTokens.Add((tokenBalance, geckoToken));
}
}
if (evmTokens.Count > 0)
{
var ids = evmTokens.Select(x => x.GeckoToken?.Id).Distinct().ToList();
var prices = await GetPrices(ids).ConfigureAwait(false);
foreach (var balance in evmTokens)
{
if (balance.GeckoToken != null)
{
var price = prices[balance.GeckoToken.Id.ToLower()];
balance.Balance.Price = price["usd"];
balance.Balance.Value = balance.Balance.Price * balance.Balance.Balance;
}
}
}
}
catch (Exception ex)
{
// TODO : Handle error
// No enable to reach rpc
}
return evmTokens.Select(e => e.Balance).ToList();
}
public async Task<Dictionary<string, Dictionary<string, decimal>>> GetPrices(List<string> geckoIds)
{
var idsCombined = string.Join(",", geckoIds);
return await _httpClient.GetFromJsonAsync<Dictionary<string, Dictionary<string, decimal>>>("https://api.coingecko.com/api/v3/simple/price?ids=" + idsCombined + "&vs_currencies=usd");
}
public async Task<List<EvmBalance>> GetAllBalancesOnAllChain(string publicAddress)
{
var chainBalances = new List<EvmBalance>();
var chains = ChainService.GetChains();
foreach (var chain in chains)
{
chainBalances.AddRange(await GetAllBalances(chain, publicAddress));
}
return chainBalances;
}
public async Task<List<Candle>> GetCandles(SubgraphProvider subgraphProvider, Ticker ticker, DateTime startDate, Timeframe timeframe)
{
string gmxTimeframe = GmxHelpers.GeTimeframe(timeframe);
var gmxPrices = await _httpClient.GetFromJsonAsync<GmxPrices>($"https://stats.gmx.io/api/candles/{ticker}?preferableChainId=42161&period={gmxTimeframe}&from={startDate.ToUnixTimestamp()}&preferableSource=fast");
//var subgraph = _subgraphs.First(s => s.GetProvider() == subgraphProvider);
//var prices = await subgraph.GetPrices(ticker, startDate, timeframe);
//if (prices == null)
//{
// foreach (var subgraphFallback in _subgraphs.Where(s => s.GetProvider() != subgraphProvider))
// {
// prices = await subgraphFallback.GetPrices(ticker, startDate, timeframe);
// if (prices != null)
// break;
// }
//}
if (gmxPrices == null)
return null;
gmxPrices.prices.RemoveAt(gmxPrices.prices.Count - 1);
return gmxPrices.prices.Select(p => GmxMappers.Map(p, ticker, timeframe)).ToList();
}
public decimal GetVolume(SubgraphProvider subgraphProvider, Ticker ticker)
{
var subgraph = GetSubgraph(subgraphProvider);
var volume = subgraph.GetVolume(ticker).Result;
return volume;
}
private ISubgraphPrices GetSubgraph(SubgraphProvider subgraphProvider)
{
return _subgraphs.First(s => s.GetProvider() == subgraphProvider);
}
public async Task<List<Ticker>> GetAvailableTicker()
{
var subgraph = GetSubgraph(SubgraphProvider.Gbc);
var pairs = await subgraph.GetTickers();
return pairs.ToList();
}
public async Task<Candle> GetCandle(SubgraphProvider subgraphProvider, Ticker ticker)
{
var lastPrices = await GetCandles(subgraphProvider, ticker, DateTime.UtcNow.AddMinutes(-15), Timeframe.FiveMinutes);
return lastPrices.Last();
}
public async Task<bool> InitAddress(string chainName, string publicAddress, string privateKey)
{
try
{
var chain = ChainService.GetChain(chainName);
var account = new Wallet(privateKey, _password).GetAccount(publicAddress);
var web3 = new Web3(account, chain.RpcUrl);
var tickers = await GetAvailableTicker();
await GmxService.InitAccountForTrading(web3, publicAddress, tickers);
return true;
}
catch (Exception ex)
{
return false;
}
}
public async Task<bool> ApproveTicker(string publicAddress, string privateKey, Ticker ticker)
{
try
{
var account = new Wallet(privateKey, _password).GetAccount(publicAddress);
var contractAddress = TokenService.GetContractAddress(ticker);
await GmxService.ApproveToken(_web3, publicAddress, contractAddress);
return true;
}
catch (Exception ex)
{
return false;
}
}
public async Task<bool> Send(
Domain.Evm.Chain chain,
Ticker ticker,
decimal amount,
string publicAddress,
string privateKey,
string receiverAddress)
{
var account = new Wallet(privateKey, _password).GetAccount(publicAddress);
var web3 = new Web3(account, chain.RpcUrl);
try
{
if (ticker == Ticker.ETH)
{
return await SendEth(amount, receiverAddress, web3);
}
else
{
return await SendToken(ticker, amount, publicAddress, receiverAddress, web3);
}
}
catch (Exception ex)
{
return false;
}
}
private static async Task<bool> SendEth(decimal amount, string receiverAddress, Web3 web3)
{
web3.TransactionManager.UseLegacyAsDefault = true;
var ethService = web3.Eth.GetEtherTransferService();
var gas = await ethService.EstimateGasAsync(receiverAddress, amount);
var transaction = await ethService.TransferEtherAndWaitForReceiptAsync(receiverAddress, amount, gas: gas);
return transaction.Status.Value == 1;
}
private static async Task<bool> SendToken(
Ticker ticker,
decimal amount,
string senderAddress,
string receiverAddress,
Web3 web3)
{
var contractAddress = TokenService.GetContractAddress(ticker);
var transactionMessage = new TransferFunction
{
FromAddress = senderAddress,
To = receiverAddress,
Value = Web3.Convert.ToWei(amount)
};
var transferHandler = web3.Eth.GetContractTransactionHandler<TransferFunction>();
var transferReceipt =
await transferHandler.SendRequestAndWaitForReceiptAsync(contractAddress, transactionMessage);
var transaction = await web3.Eth.Transactions.GetTransactionByHash.SendRequestAsync(transferReceipt.TransactionHash);
return transaction != null;
}
public async Task<bool> CancelOrders(Account account, Ticker ticker)
{
var wallet = new Wallet(account.Secret, _password).GetAccount(account.Key);
var chain = ChainService.GetChain(Constants.Chains.Arbitrum);
var web3 = new Web3(wallet, chain.RpcUrl);
return await GmxService.CancelOrders(web3, account.Key, ticker);
}
public async Task<Trade> IncreasePosition(
Account account,
Ticker ticker,
TradeDirection direction,
decimal price,
decimal quantity,
decimal? leverage)
{
var wallet = new Wallet(account.Secret, _password).GetAccount(account.Key);
var chain = ChainService.GetChain(Constants.Chains.Arbitrum);
var web3 = new Web3(wallet, chain.RpcUrl);
Trade trade = null;
try
{
trade = await GmxService.IncreasePosition(web3, account.Key, ticker, direction, price, quantity, leverage);
}
catch (Exception ex)
{
throw;
}
return trade;
}
public async Task<Trade> DecreasePosition(
Account account,
Ticker ticker,
TradeDirection direction,
decimal price,
decimal quantity,
decimal? leverage)
{
var wallet = new Wallet(account.Secret, _password).GetAccount(account.Key);
var chain = ChainService.GetChain(Constants.Chains.Arbitrum);
var web3 = new Web3(wallet, chain.RpcUrl);
Trade trade = null;
try
{
trade = await GmxService.DecreasePosition(web3, account.Key, ticker, direction, price, quantity, leverage);
}
catch (Exception ex)
{
throw;
}
return trade;
}
public async Task<Trade> DecreaseOrder(Account account, TradeType tradeType, Ticker ticker, TradeDirection direction, decimal price, decimal quantity, decimal? leverage)
{
var wallet = new Wallet(account.Secret, _password).GetAccount(account.Key);
var chain = ChainService.GetChain(Constants.Chains.Arbitrum);
var web3 = new Web3(wallet, chain.RpcUrl);
Trade trade = null;
try
{
trade = await GmxService.DecreaseOrder(web3, tradeType, account.Key, ticker, direction, price, quantity, leverage);
}
catch (Exception ex)
{
throw;
}
return trade;
}
public async Task<Trade> GetTrade(Account account, string chainName, Ticker ticker)
{
return await GetTrade(account.Key, chainName, ticker);
}
public async Task<Trade> GetTrade(string reference, string chainName, Ticker ticker)
{
var chain = ChainService.GetChain(chainName);
var web3 = new Web3(chain.RpcUrl);
return await GmxService.GetTrade(web3, reference, ticker);
}
public async Task<decimal> QuantityInPosition(string chainName, string publicAddress, Ticker ticker)
{
var chain = ChainService.GetChain(chainName);
var web3 = new Web3(chain.RpcUrl);
var quantity = await GmxService.QuantityInPosition(web3, publicAddress, ticker);
return quantity;
}
public async Task<decimal> GetFee(string chainName)
{
var chain = ChainService.GetChain(chainName);
var web3 = new Web3(chain.RpcUrl);
var etherPrice = (await GetPrices(new List<string> { "ethereum" }))["ethereum"]["usd"];
var fee = await GmxService.GetFee(web3, etherPrice);
return fee;
}
public async Task<List<Trade>> GetOrders(Account account, Ticker ticker)
{
var wallet = new Wallet(account.Secret, _password).GetAccount(account.Key);
var chain = ChainService.GetChain(Constants.Chains.Arbitrum);
var web3 = new Web3(wallet, chain.RpcUrl);
var orders = await GmxService.GetOrders(web3, account.Key, ticker);
return GmxHelpers.Map(orders, ticker);
}
}