Refact multicall

This commit is contained in:
2024-08-17 07:57:14 +07:00
parent 7bb6a3638e
commit acaf3f7346
4 changed files with 176 additions and 160 deletions

View File

@@ -102,17 +102,17 @@ builder.Services.AddSwaggerGen(options =>
}); });
builder.WebHost.SetupDiscordBot(); builder.WebHost.SetupDiscordBot();
builder.Services.AddHostedService<FeeWorker>(); // builder.Services.AddHostedService<FeeWorker>();
// builder.Services.AddHostedService<PositionManagerWorker>(); // // builder.Services.AddHostedService<PositionManagerWorker>();
// builder.Services.AddHostedService<PositionFetcher>(); // // builder.Services.AddHostedService<PositionFetcher>();
// builder.Services.AddHostedService<PricesFiveMinutesWorker>(); // // builder.Services.AddHostedService<PricesFiveMinutesWorker>();
builder.Services.AddHostedService<PricesFifteenMinutesWorker>(); // builder.Services.AddHostedService<PricesFifteenMinutesWorker>();
builder.Services.AddHostedService<PricesOneHourWorker>(); // builder.Services.AddHostedService<PricesOneHourWorker>();
// builder.Services.AddHostedService<PricesFourHoursWorker>(); // // builder.Services.AddHostedService<PricesFourHoursWorker>();
builder.Services.AddHostedService<PricesOneDayWorker>(); // builder.Services.AddHostedService<PricesOneDayWorker>();
// builder.Services.AddHostedService<SpotlightWorker>(); // // builder.Services.AddHostedService<SpotlightWorker>();
builder.Services.AddHostedService<TraderWatcher>(); // builder.Services.AddHostedService<TraderWatcher>();
builder.Services.AddHostedService<LeaderboardWorker>(); // builder.Services.AddHostedService<LeaderboardWorker>();
builder.Services.AddHostedService<FundingRatesWatcher>(); builder.Services.AddHostedService<FundingRatesWatcher>();
// App // App

View File

@@ -24,7 +24,7 @@ public static class DiscordHelpers
var embed = new EmbedBuilder var embed = new EmbedBuilder
{ {
Author = new EmbedAuthorBuilder() { Name = "GMX v2" }, Author = new EmbedAuthorBuilder() { Name = "GMX v2" },
Title = $"{title} {DateTime.UtcNow:d}", Title = $"{title} {DateTime.UtcNow:g}",
Color = Color.Gold, Color = Color.Gold,
Fields = fields, Fields = fields,
}.Build(); }.Build();
@@ -36,17 +36,10 @@ public static class DiscordHelpers
{ {
var fields = new List<EmbedFieldBuilder>(); var fields = new List<EmbedFieldBuilder>();
decimal ratePerYear = fundingRate.Rate; // Rate per year var (ratePerYear, ratePerDay, ratePerMonth, ratePerHour) = GetRates(fundingRate);
decimal ratePerDay = ratePerYear / 365; // Rate per day
decimal ratePerMonth = ratePerYear / 12; // Rate per month
decimal ratePerHour = ratePerDay / 24; // Rate per hour
if (oldRate != null) if (oldRate != null)
{ {
var oldRatePerYear = oldRate.Rate; // Rate per year var (oldRatePerYear, oldRatePerDay, oldRatePerMonth, oldRatePerHour) = GetRates(oldRate);
var oldRatePerDay = oldRatePerYear / 365; // Rate per day
var oldRatePerMonth = oldRatePerYear / 12; // Rate per month
var oldRatePerHour = oldRatePerDay / 24; // Rate per hour
fields.Add(new EmbedFieldBuilder fields.Add(new EmbedFieldBuilder
{ {
@@ -66,7 +59,7 @@ public static class DiscordHelpers
var embed = new EmbedBuilder var embed = new EmbedBuilder
{ {
Author = new EmbedAuthorBuilder() { Name = "GMX" }, Author = new EmbedAuthorBuilder() { Name = "GMX" },
Title = $"{title} {DateTime.UtcNow:d}", Title = $"{title} {DateTime.UtcNow:g}",
Color = Color.DarkGreen, Color = Color.DarkGreen,
Fields = fields, Fields = fields,
}.Build(); }.Build();
@@ -115,7 +108,7 @@ public static class DiscordHelpers
var embed = new EmbedBuilder var embed = new EmbedBuilder
{ {
Author = new EmbedAuthorBuilder() { Name = "GMX" }, Author = new EmbedAuthorBuilder() { Name = "GMX" },
Title = $"{title} {DateTime.UtcNow:d}", Title = $"{title} {DateTime.UtcNow:g}",
Color = Color.DarkBlue, Color = Color.DarkBlue,
Fields = fields, Fields = fields,
}.Build(); }.Build();
@@ -129,11 +122,7 @@ public static class DiscordHelpers
foreach (var fundingRate in fundingRates) foreach (var fundingRate in fundingRates)
{ {
decimal ratePerYear = fundingRate.Rate; // Rate per year var (ratePerYear, ratePerDay, ratePerMonth, ratePerHour) = GetRates(fundingRate);
decimal ratePerDay = ratePerYear / 365; // Rate per day
decimal ratePerMonth = ratePerYear / 12; // Rate per month
decimal ratePerHour = ratePerDay / 24; // Rate per hour
fields.Add(new EmbedFieldBuilder fields.Add(new EmbedFieldBuilder
{ {
Name = $"{fundingRate.Ticker}", Name = $"{fundingRate.Ticker}",
@@ -145,11 +134,22 @@ public static class DiscordHelpers
var embed = new EmbedBuilder var embed = new EmbedBuilder
{ {
Author = new EmbedAuthorBuilder() { Name = "GMX" }, Author = new EmbedAuthorBuilder() { Name = "GMX" },
Title = $"Best Funding Rate {DateTime.UtcNow:d}", Title = $"Best Funding Rate {DateTime.UtcNow:g}",
Color = Color.DarkGreen, Color = Color.DarkGreen,
Fields = fields, Fields = fields,
}.Build(); }.Build();
return embed; return embed;
} }
private static (decimal ratePerYear, decimal ratePerDay, decimal ratePerMonth, decimal ratePerHour) GetRates(
FundingRate fundingRate)
{
decimal ratePerHour = fundingRate.Rate; // Rate per hour
decimal ratePerDay = ratePerHour * 24; // Rate per day
decimal ratePerMonth = ratePerDay * 30; // Rate per month
decimal ratePerYear = ratePerDay * 365; // Rate per year
return (ratePerYear, ratePerDay, ratePerMonth, ratePerHour);
}
} }

View File

@@ -99,7 +99,6 @@ namespace Managing.Infrastructure.Messengers.Discord
// Discord started as a game chat service, so it has the option to show what games you are playing // Discord started as a game chat service, so it has the option to show what games you are playing
// Here the bot will display "Playing dead" while listening // Here the bot will display "Playing dead" while listening
await _client.SetGameAsync(_settings.BotActivity, "https://moon.com", ActivityType.Playing); await _client.SetGameAsync(_settings.BotActivity, "https://moon.com", ActivityType.Playing);
_logger.LogInformation(JsonConvert.SerializeObject(_settings, Formatting.Indented));
if (!_settings.HandleUserAction) return; if (!_settings.HandleUserAction) return;
List<ApplicationCommandProperties> applicationCommandProperties = new(); List<ApplicationCommandProperties> applicationCommandProperties = new();

View File

@@ -181,147 +181,164 @@ public class GmxV2Service
} }
public async Task<List<GmxMarketInfo>> GetMarketInfosAsync(Web3 web3) public async Task<List<GmxMarketInfo>> GetMarketInfosAsync(Web3 web3)
{
var markets = await GetMarketsAsync(web3);
var readerResult = new List<GmxMarketInfo>();
var readerCalls = new List<Call>();
var datastoreCalls = new List<Call>();
markets = markets.Where(m => !m.IsSpotOnly).ToList();
foreach (var market in markets)
{ {
var markets = await GetMarketsAsync(web3); var tokensData = await GetTokensData(web3);
var readerResult = new List<GmxMarketInfo>(); var marketPrices = GmxHelpers.GetContractMarketPrices(tokensData, market);
foreach (var market in markets) var marketProps = new MarketsProps()
{ {
var tokensData = await GetTokensData(web3); MarketToken = market.MarketToken,
var marketPrices = GmxHelpers.GetContractMarketPrices(tokensData, market); IndexToken = market.IndexToken,
var marketProps = new MarketsProps() LongToken = market.LongToken,
{ ShortToken = market.ShortToken
MarketToken = market.MarketToken, };
IndexToken = market.IndexToken,
LongToken = market.LongToken,
ShortToken = market.ShortToken
};
var getMarketInfoCallData = new GetMarketInfoFunction
{
DataStore = Arbitrum.AddressV2.DataStore,
Prices = marketPrices,
MarketKey = market.MarketToken
}.GetCallData();
var getMarketInfoCall = new Call
{
Target = Arbitrum.AddressV2.Reader,
CallData = getMarketInfoCallData
};
var getMarketTokenPriceCallData = new GetMarketTokenPriceFunction
{
DataStore = Arbitrum.AddressV2.DataStore,
Market = marketProps,
IndexTokenPrice = marketPrices.IndexTokenPrice,
LongTokenPrice = marketPrices.LongTokenPrice,
ShortTokenPrice = marketPrices.ShortTokenPrice,
PnlFactorType = _helpers.HashString(Constants.GMX.MAX_PNL_FACTOR_FOR_TRADERS),
Maximize = true
}.GetCallData();
var getMarketTokenPriceCall = new Call
{
Target = Arbitrum.AddressV2.Reader,
CallData = getMarketTokenPriceCallData
};
var getMarketTokenPriceMinCallData = new GetMarketTokenPriceFunction
{
DataStore = Arbitrum.AddressV2.DataStore,
Market = marketProps,
IndexTokenPrice = marketPrices.IndexTokenPrice,
LongTokenPrice = marketPrices.LongTokenPrice,
ShortTokenPrice = marketPrices.ShortTokenPrice,
PnlFactorType = _helpers.HashString(Constants.GMX.MAX_PNL_FACTOR_FOR_TRADERS),
Maximize = false
}.GetCallData();
var getMarketTokenPriceMinCall = new Call
{
Target = Arbitrum.AddressV2.Reader,
CallData = getMarketTokenPriceMinCallData
};
var readerMulticall = new AggregateFunction(); var getMarketInfoCallData = new GetMarketInfoFunction
readerMulticall.Calls = new List<Call>(); {
readerMulticall.Calls.Add(getMarketInfoCall); DataStore = Arbitrum.AddressV2.DataStore,
readerMulticall.Calls.Add(getMarketTokenPriceCall); Prices = marketPrices,
readerMulticall.Calls.Add(getMarketTokenPriceMinCall); MarketKey = market.MarketToken
}.GetCallData();
var getMarketInfoCall = new Call
{
Target = Arbitrum.AddressV2.Reader,
CallData = getMarketInfoCallData
};
var queryHandler = web3.Eth.GetContractQueryHandler<AggregateFunction>(); var getMarketTokenPriceCallData = new GetMarketTokenPriceFunction
var readerCallResults = await queryHandler {
.QueryDeserializingToObjectAsync<AggregateOutputDTO>(readerMulticall, Arbitrum.AddressV2.Multicall) DataStore = Arbitrum.AddressV2.DataStore,
.ConfigureAwait(false); Market = marketProps,
IndexTokenPrice = marketPrices.IndexTokenPrice,
LongTokenPrice = marketPrices.LongTokenPrice,
ShortTokenPrice = marketPrices.ShortTokenPrice,
PnlFactorType = _helpers.HashString(Constants.GMX.MAX_PNL_FACTOR_FOR_TRADERS),
Maximize = true
}.GetCallData();
var getMarketTokenPriceCall = new Call
{
Target = Arbitrum.AddressV2.Reader,
CallData = getMarketTokenPriceCallData
};
var marketInfo = new GetMarketInfoOutputDTO().DecodeOutput(readerCallResults.ReturnData[0].ToHex()); var getMarketTokenPriceMinCallData = new GetMarketTokenPriceFunction
var marketTokenPriceMax = {
new GetMarketTokenPriceOutputDTO().DecodeOutput(readerCallResults.ReturnData[1].ToHex()); DataStore = Arbitrum.AddressV2.DataStore,
var marketTokenPriceMin = Market = marketProps,
new GetMarketTokenPriceOutputDTO().DecodeOutput(readerCallResults.ReturnData[2].ToHex()); IndexTokenPrice = marketPrices.IndexTokenPrice,
LongTokenPrice = marketPrices.LongTokenPrice,
ShortTokenPrice = marketPrices.ShortTokenPrice,
PnlFactorType = _helpers.HashString(Constants.GMX.MAX_PNL_FACTOR_FOR_TRADERS),
Maximize = false
}.GetCallData();
var getMarketTokenPriceMinCall = new Call
{
Target = Arbitrum.AddressV2.Reader,
CallData = getMarketTokenPriceMinCallData
};
// Get hashed key to call datastore readerCalls.Add(getMarketInfoCall);
var marketKeys = GmxKeysService.GetMarketKeys(market.MarketToken); readerCalls.Add(getMarketTokenPriceCall);
if (marketKeys == null) readerCalls.Add(getMarketTokenPriceMinCall);
continue;
var longInterestUsingLongTokenCallData = new GetUintFunction() var marketKeys = GmxKeysService.GetMarketKeys(market.MarketToken);
{ if (marketKeys == null)
Key = marketKeys.LongInterestUsingLongToken.HexToByteArray() continue;
}.GetCallData();
var longInterestUsingLongTokenCall = new Call
{
Target = Arbitrum.AddressV2.DataStore,
CallData = longInterestUsingLongTokenCallData
};
var longInterestUsingShortTokenCallData = new GetUintFunction()
{
Key = marketKeys.LongInterestUsingShortToken.HexToByteArray()
}.GetCallData();
var longInterestUsingShortTokenCall = new Call
{
Target = Arbitrum.AddressV2.DataStore,
CallData = longInterestUsingShortTokenCallData
};
var shortInterestUsingLongTokenCallData = new GetUintFunction()
{
Key = marketKeys.ShortInterestUsingLongToken.HexToByteArray()
}.GetCallData();
var shortInterestUsingLongTokenCall = new Call
{
Target = Arbitrum.AddressV2.DataStore,
CallData = shortInterestUsingLongTokenCallData
};
var shortInterestUsingShortTokenCallData = new GetUintFunction()
{
Key = marketKeys.ShortInterestUsingShortToken.HexToByteArray()
}.GetCallData();
var shortInterestUsingShortTokenCall = new Call
{
Target = Arbitrum.AddressV2.DataStore,
CallData = shortInterestUsingShortTokenCallData
};
var dataStoreMulticall = new AggregateFunction(); var longInterestUsingLongTokenCallData = new GetUintFunction
dataStoreMulticall.Calls = new List<Call>(); {
dataStoreMulticall.Calls.Add(longInterestUsingLongTokenCall); Key = marketKeys.LongInterestUsingLongToken.HexToByteArray()
dataStoreMulticall.Calls.Add(longInterestUsingShortTokenCall); }.GetCallData();
dataStoreMulticall.Calls.Add(shortInterestUsingLongTokenCall); var longInterestUsingLongTokenCall = new Call
dataStoreMulticall.Calls.Add(shortInterestUsingShortTokenCall); {
Target = Arbitrum.AddressV2.DataStore,
CallData = longInterestUsingLongTokenCallData
};
var longInterestUsingShortTokenCallData = new GetUintFunction
{
Key = marketKeys.LongInterestUsingShortToken.HexToByteArray()
}.GetCallData();
var longInterestUsingShortTokenCall = new Call
{
Target = Arbitrum.AddressV2.DataStore,
CallData = longInterestUsingShortTokenCallData
};
var shortInterestUsingLongTokenCallData = new GetUintFunction
{
Key = marketKeys.ShortInterestUsingLongToken.HexToByteArray()
}.GetCallData();
var shortInterestUsingLongTokenCall = new Call
{
Target = Arbitrum.AddressV2.DataStore,
CallData = shortInterestUsingLongTokenCallData
};
var shortInterestUsingShortTokenCallData = new GetUintFunction
{
Key = marketKeys.ShortInterestUsingShortToken.HexToByteArray()
}.GetCallData();
var shortInterestUsingShortTokenCall = new Call
{
Target = Arbitrum.AddressV2.DataStore,
CallData = shortInterestUsingShortTokenCallData
};
// Call datastore to get market info datastoreCalls.Add(longInterestUsingLongTokenCall);
var dataStoreQueryHandler = web3.Eth.GetContractQueryHandler<AggregateFunction>(); datastoreCalls.Add(longInterestUsingShortTokenCall);
var dataStoreCallResults = await dataStoreQueryHandler datastoreCalls.Add(shortInterestUsingLongTokenCall);
.QueryDeserializingToObjectAsync<AggregateOutputDTO>(dataStoreMulticall, Arbitrum.AddressV2.Multicall) datastoreCalls.Add(shortInterestUsingShortTokenCall);
.ConfigureAwait(false);
var marketInfos = GmxMappers.Map(marketInfo.ReturnValue1);
readerResult.Add(new GmxMarketInfo()
{
Market = marketInfos,
Infos = DecodeFundingRateOutput(dataStoreCallResults, marketInfos.IsSameCollaterals),
MarketTokenPriceMax = GmxMappers.Map(marketTokenPriceMax),
MarketTokenPriceMin = GmxMappers.Map(marketTokenPriceMin)
});
}
return readerResult;
} }
var readerMulticall = new AggregateFunction { Calls = readerCalls };
var datastoreMulticall = new AggregateFunction { Calls = datastoreCalls };
var queryHandler = web3.Eth.GetContractQueryHandler<AggregateFunction>();
var readerCallResults = await queryHandler
.QueryDeserializingToObjectAsync<AggregateOutputDTO>(readerMulticall, Arbitrum.AddressV2.Multicall)
.ConfigureAwait(false);
var datastoreCallResults = await queryHandler
.QueryDeserializingToObjectAsync<AggregateOutputDTO>(datastoreMulticall, Arbitrum.AddressV2.Multicall)
.ConfigureAwait(false);
int readerCallIndex = 0;
int datastoreCallIndex = 0;
foreach (var market in markets)
{
var marketInfo = new GetMarketInfoOutputDTO().DecodeOutput(readerCallResults.ReturnData[readerCallIndex++].ToHex());
var marketTokenPriceMax = new GetMarketTokenPriceOutputDTO().DecodeOutput(readerCallResults.ReturnData[readerCallIndex++].ToHex());
var marketTokenPriceMin = new GetMarketTokenPriceOutputDTO().DecodeOutput(readerCallResults.ReturnData[readerCallIndex++].ToHex());
var marketKeys = GmxKeysService.GetMarketKeys(market.MarketToken);
if (marketKeys == null)
continue;
var longInterestUsingLongToken = new GetUintOutputDTO().DecodeOutput(datastoreCallResults.ReturnData[datastoreCallIndex++].ToHex()).ReturnValue1;
var longInterestUsingShortToken = new GetUintOutputDTO().DecodeOutput(datastoreCallResults.ReturnData[datastoreCallIndex++].ToHex()).ReturnValue1;
var shortInterestUsingLongToken = new GetUintOutputDTO().DecodeOutput(datastoreCallResults.ReturnData[datastoreCallIndex++].ToHex()).ReturnValue1;
var shortInterestUsingShortToken = new GetUintOutputDTO().DecodeOutput(datastoreCallResults.ReturnData[datastoreCallIndex++].ToHex()).ReturnValue1;
var marketInfos = GmxMappers.Map(marketInfo.ReturnValue1);
readerResult.Add(new GmxMarketInfo
{
Market = marketInfos,
Infos = new GmxMarketInfos
{
LongInterestUsd = longInterestUsingLongToken + longInterestUsingShortToken,
ShortInterestUsd = shortInterestUsingLongToken + shortInterestUsingShortToken
},
MarketTokenPriceMax = GmxMappers.Map(marketTokenPriceMax),
MarketTokenPriceMin = GmxMappers.Map(marketTokenPriceMin)
});
}
return readerResult;
}
private GmxMarketInfos DecodeFundingRateOutput(AggregateOutputDTO results, bool isSameCollaterals) private GmxMarketInfos DecodeFundingRateOutput(AggregateOutputDTO results, bool isSameCollaterals)
{ {
var marketDivisor = new BigInteger(isSameCollaterals ? 2 : 1); var marketDivisor = new BigInteger(isSameCollaterals ? 2 : 1);