Esempio n. 1
0
 private IStakingPower MapStakingPower(IStakeSettings stakeInfo, DataStakingPower stakePower, CurrencyCode currencyCode)
 {
     return(new BusinessStakingPower()
     {
         Symbol = stakeInfo.Symbol,
         Date = stakePower?.Date ?? stakeInfo.InceptionDate,
         Power = CurrencyConverter.Convert(stakePower?.Power ?? decimal.Zero, currencyCode),
         Summary = stakePower?.Summary
                   .Select(fs => new BusinessStakingPowerSummary()
         {
             Symbol = GetFunds()
                      .Single(x =>
                              x.ContractAddress.Address.Equals(fs.ContractAddress, StringComparison.OrdinalIgnoreCase))
                      .Symbol,
             Power = CurrencyConverter.Convert(fs.Power, currencyCode),
         })
                   .ToList()
                   ?? new List <BusinessStakingPowerSummary>(),
         Breakdown = stakePower?.Breakdown
                     .Select(fp => new BusinessStakingPowerFund()
         {
             Symbol = GetFunds()
                      .Single(x =>
                              x.ContractAddress.Address.Equals(fp.ContractAddress, StringComparison.OrdinalIgnoreCase))
                      .Symbol,
             FundModifier = fp.FundModifier,
             Quantity = fp.Events.Sum(x => x.Quantity),
             ModifiedQuantity = fp.Events.Sum(x => x.Quantity * x.TimeModifier * fp.FundModifier),
             Power = CurrencyConverter.Convert(fp.PricePerToken * fp.Events.Sum(x => x.Quantity * x.TimeModifier * fp.FundModifier), currencyCode),
         })
                     .ToList()
                     ?? new List <BusinessStakingPowerFund>()
     });
 }
Esempio n. 2
0
        private async Task SyncStakingPowerAsync(
            IFundService fundService,
            IStakeService stakeService,
            IStakingPowerRepository stakingRepository,
            IStakeSettings stake,
            DateTimeOffset startDate,
            DateTimeOffset endDate,
            CancellationToken cancellationToken)
        {
            var currentDate      = GetHourlyDate(startDate.UtcDateTime).UtcDateTime;
            var lastStakingPower = await stakingRepository.GetStakingPowerAsync(stake.ContractAddress, currentDate.AddHours(-1));

            var stakingEvents = await stakeService.ListStakeEventsAsync(stake.Symbol, startDate.UtcDateTime, endDate.UtcDateTime)
                                .ToListAsync(cancellationToken);

            var hourlyGroups = stakingEvents
                               .OrderBy(x => x.ConfirmedAt)
                               .GroupBy(x => GetHourlyDate(x.ConfirmedAt))
                               .ToList();

            do
            {
                try
                {
                    var fundPowers   = new List <DataStakingPowerFund>();
                    var hourlyEvents = hourlyGroups.SingleOrDefault(g => g.Key == currentDate)
                                       ?? Enumerable.Empty <IStakeEvent>();

                    foreach (var symbol in stake.FundMultipliers.Keys)
                    {
                        var fund = AppSettings.Funds
                                   .Cast <IFundSettings>()
                                   .Single(x => x.Symbol == symbol);

                        var events = lastStakingPower?.Breakdown.SingleOrDefault(x =>
                                                                                 x.ContractAddress.Equals(fund.ContractAddress.Address, StringComparison.OrdinalIgnoreCase))
                                     ?.Events.ToList()
                                     ?? new List <DataStakingEvent>();

                        events.AddRange(hourlyEvents
                                        .Where(e =>
                                               e.ContractAddress == fund.ContractAddress &&
                                               e.Type == StakeEventType.Lockup)
                                        .Select(e => new DataStakingEvent()
                        {
                            UserAddress  = e.UserAddress,
                            StakedAt     = e.ConfirmedAt,
                            Quantity     = e.Change,
                            ExpiresAt    = e.Lock.ExpiresAt,
                            TimeModifier = stake.TimeMultipliers
                                           .SingleOrDefault(tm =>
                                                            tm.RangeMin <= e.Lock.Duration.Days &&
                                                            tm.RangeMax >= e.Lock.Duration.Days)
                                           ?.Multiplier ?? 1
                        }));

                        foreach (var releaseEvent in hourlyEvents
                                 .Where(e =>
                                        e.ContractAddress == fund.ContractAddress &&
                                        e.Type != StakeEventType.Lockup))
                        {
                            var approximateQuantity = releaseEvent.Release.Quantity + (releaseEvent.Release.FeeQuantity ?? decimal.Zero);
                            var userStakes          = events
                                                      .Where(e => e.UserAddress.Equals(releaseEvent.UserAddress.Address, StringComparison.OrdinalIgnoreCase))
                                                      .ToList();

                            var lockUp = userStakes.Count > 0
                                ? userStakes.Count == 1
                                    ? userStakes.Single()
                                    : userStakes
                                         .OrderBy(x => x.StakedAt)
                                         .FirstOrDefault(e => Math.Abs(e.Quantity - approximateQuantity) <= Precision)
                                : null;

                            if (lockUp != null)
                            {
                                events.Remove(lockUp);
                            }
                        }

                        if (events.Any())
                        {
                            var prices = await fundService.ListPerformanceAsync(
                                symbol,
                                PriceMode.Raw,
                                currentDate.Date.AddDays(-1),
                                currentDate.Date.AddDays(2),
                                CurrencyCode.USD)
                                         .ToListAsync(cancellationToken);

                            var closestPrice = prices
                                               .OrderBy(i => Math.Abs(
                                                            new DateTimeOffset(i.Date, TimeSpan.Zero).ToUnixTimeSeconds() -
                                                            new DateTimeOffset(currentDate, TimeSpan.Zero).ToUnixTimeSeconds()))
                                               .FirstOrDefault()
                                               ?? throw new PermanentException($"No Price data could be found for date {currentDate}");

                            fundPowers.Add(new DataStakingPowerFund()
                            {
                                ContractAddress = fund.ContractAddress,
                                FundModifier    = stake.FundMultipliers[symbol],
                                PricePerToken   = closestPrice.NetAssetValuePerToken,
                                Events          = events
                            });
                        }
                    }

                    lastStakingPower = new DataStakingPower()
                    {
                        Address   = stake.ContractAddress,
                        Date      = currentDate.AddHours(1),
                        Power     = fundPowers.Sum(fp => fp.PricePerToken * fp.Events.Sum(fpe => fpe.Quantity * fpe.TimeModifier * fp.FundModifier)),
                        Breakdown = fundPowers,
                        Summary   = fundPowers
                                    .Select(fp => new DataStakingPowerSummary()
                        {
                            ContractAddress = fp.ContractAddress,
                            Power           = fp.PricePerToken * fp.Events.Sum(fpe => fpe.Quantity * fpe.TimeModifier * fp.FundModifier)
                        })
                                    .ToList()
                    };

                    await stakingRepository.UploadItemsAsync(lastStakingPower);
                }
                finally
                {
                    currentDate = currentDate.AddHours(1);
                }
            }while (!cancellationToken.IsCancellationRequested && currentDate < endDate.Round());
        }