Skip to content

Commit

Permalink
Merge pull request #1284 from novasamatech/fix/polkadot-inflation
Browse files Browse the repository at this point in the history
Support runtime api for predicting inflation
  • Loading branch information
ERussel authored Nov 19, 2024
2 parents a9f00ff + 46d5e1c commit e3cfa5e
Show file tree
Hide file tree
Showing 8 changed files with 223 additions and 10 deletions.
6 changes: 3 additions & 3 deletions Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ abstract_target 'novawalletAll' do
use_frameworks!

pod 'DSF_QRCode', '~> 18.0.0'
pod 'SubstrateSdk', :git => 'https://github.com/nova-wallet/substrate-sdk-ios.git', :tag => '3.3.2'
pod 'SubstrateSdk', :git => 'https://github.com/nova-wallet/substrate-sdk-ios.git', :tag => '3.4.0'
pod 'SwiftLint'
pod 'R.swift', :inhibit_warnings => true
pod 'SoraKeystore', '~> 1.0.0'
Expand Down Expand Up @@ -40,7 +40,7 @@ abstract_target 'novawalletAll' do
inherit! :search_paths

pod 'Cuckoo'
pod 'SubstrateSdk', :git => 'https://github.com/nova-wallet/substrate-sdk-ios.git', :tag => '3.3.2'
pod 'SubstrateSdk', :git => 'https://github.com/nova-wallet/substrate-sdk-ios.git', :tag => '3.4.0'
pod 'SoraFoundation', :git => 'https://github.com/ERussel/Foundation-iOS.git', :tag => '1.1.0'
pod 'R.swift', :inhibit_warnings => true
pod 'FireMock', :inhibit_warnings => true
Expand All @@ -67,7 +67,7 @@ abstract_target 'novawalletAll' do
pod 'SoraKeystore', '~> 1.0.0'
pod 'Operation-iOS', :git => 'https://github.com/novasamatech/Operation-iOS', :tag => '2.0.1'
pod 'Sourcery', '~> 1.4'
pod 'SubstrateSdk', :git => 'https://github.com/nova-wallet/substrate-sdk-ios.git', :tag => '3.3.2'
pod 'SubstrateSdk', :git => 'https://github.com/nova-wallet/substrate-sdk-ios.git', :tag => '3.4.0'
pod 'SwiftyBeaver'
pod 'IrohaCrypto', :git => 'https://github.com/novasamatech/IrohaCrypto', :tag => '0.9.1'
pod 'secp256k1.c', :git => 'https://github.com/novasamatech/secp256k1.c', :tag => '0.1.3'
Expand Down
12 changes: 6 additions & 6 deletions Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1450,7 +1450,7 @@ PODS:
- SoraUI/Skrull (1.13.0)
- Sourcery (1.4.1)
- Starscream (4.0.12)
- SubstrateSdk (3.3.2):
- SubstrateSdk (3.4.0):
- BigInt (~> 5.0)
- IrohaCrypto/ed25519 (~> 0.9.0)
- IrohaCrypto/Scrypt (~> 0.9.0)
Expand Down Expand Up @@ -1554,7 +1554,7 @@ DEPENDENCIES:
- SoraUI (from `https://github.com/ERussel/UIkit-iOS.git`, tag `1.13.0`)
- Sourcery (~> 1.4)
- Starscream (from `https://github.com/novasamatech/Starscream.git`, tag `4.0.12`)
- SubstrateSdk (from `https://github.com/nova-wallet/substrate-sdk-ios.git`, tag `3.3.2`)
- SubstrateSdk (from `https://github.com/nova-wallet/substrate-sdk-ios.git`, tag `3.4.0`)
- SwiftAlgorithms (~> 1.0.0)
- SwiftDraw (~> 0.18.0)
- SwiftFormat/CLI (~> 0.47.13)
Expand Down Expand Up @@ -1651,7 +1651,7 @@ EXTERNAL SOURCES:
:tag: 4.0.12
SubstrateSdk:
:git: https://github.com/nova-wallet/substrate-sdk-ios.git
:tag: 3.3.2
:tag: 3.4.0
SwiftRLP:
:git: https://github.com/ERussel/SwiftRLP.git
WalletConnectSwiftV2:
Expand Down Expand Up @@ -1694,7 +1694,7 @@ CHECKOUT OPTIONS:
:tag: 4.0.12
SubstrateSdk:
:git: https://github.com/nova-wallet/substrate-sdk-ios.git
:tag: 3.3.2
:tag: 3.4.0
SwiftRLP:
:commit: 809e68a002d19ee3d8bbeb72577224b7513e7e8e
:git: https://github.com/ERussel/SwiftRLP.git
Expand Down Expand Up @@ -1754,7 +1754,7 @@ SPEC CHECKSUMS:
SoraUI: 1d1a25881d1d597f19bc55f82c99ee236cc1ab11
Sourcery: db66600e8b285c427701821598d07cf3c7e6c476
Starscream: 9265e4163aeea93d4a74c49bc8cb4c0b9c6ff350
SubstrateSdk: a5af2260b57982600f2f852f53e9408a024f8cbb
SubstrateSdk: ee92f2ede60ffc3a80c73d57870c2cea05741ab4
SwiftAlgorithms: 38dda4731d19027fdeee1125f973111bf3386b53
SwiftDraw: f63484562ddd30d9682b5576acc1d98acc2bec8f
SwiftFormat: 73573b89257437c550b03d934889725fbf8f75e5
Expand All @@ -1771,6 +1771,6 @@ SPEC CHECKSUMS:
ZMarkupParser: a92d31ba40695b790f1da5fec98c3d4505341aff
ZNSTextAttachment: 1ddd53660a8d3c42dbb716bf6866ffce22c44181

PODFILE CHECKSUM: dd6c64a61e6814d9b2ea8830d58e302b349524e1
PODFILE CHECKSUM: f485e2dc6e10abfdd79cae68f47ca4679c0cd84f

COCOAPODS: 1.15.2
8 changes: 8 additions & 0 deletions novawallet.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -727,6 +727,8 @@
0CF193D32A84FC7C003F12F6 /* SelectedStakingViewModelFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CF193D22A84FC7C003F12F6 /* SelectedStakingViewModelFactory.swift */; };
0CF193D52A861926003F12F6 /* PredefinedTimeShortcut.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CF193D42A861925003F12F6 /* PredefinedTimeShortcut.swift */; };
0CF193D72A861D7E003F12F6 /* StartStakingInfoConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CF193D62A861D7E003F12F6 /* StartStakingInfoConstants.swift */; };
0CF4ADFF2CECACF9009C51FA /* PolkadotRewardParamsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CF4ADFE2CECACF9009C51FA /* PolkadotRewardParamsService.swift */; };
0CF4AE0B2CECDCF1009C51FA /* PolkadotRewardEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CF4AE0A2CECDCF1009C51FA /* PolkadotRewardEngine.swift */; };
0CF609332B9438BD00DD4DB3 /* OperatingCall.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CF609322B9438BD00DD4DB3 /* OperatingCall.swift */; };
0CF609352B9442F400DD4DB3 /* PushNotificationsServiceFacade.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CF609342B9442F400DD4DB3 /* PushNotificationsServiceFacade.swift */; };
0CF692892C20E2B1000FC395 /* BackupManualWarningPresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CF692882C20E2B1000FC395 /* BackupManualWarningPresentable.swift */; };
Expand Down Expand Up @@ -5913,6 +5915,8 @@
0CF193D22A84FC7C003F12F6 /* SelectedStakingViewModelFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectedStakingViewModelFactory.swift; sourceTree = "<group>"; };
0CF193D42A861925003F12F6 /* PredefinedTimeShortcut.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PredefinedTimeShortcut.swift; sourceTree = "<group>"; };
0CF193D62A861D7E003F12F6 /* StartStakingInfoConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartStakingInfoConstants.swift; sourceTree = "<group>"; };
0CF4ADFE2CECACF9009C51FA /* PolkadotRewardParamsService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PolkadotRewardParamsService.swift; sourceTree = "<group>"; };
0CF4AE0A2CECDCF1009C51FA /* PolkadotRewardEngine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PolkadotRewardEngine.swift; sourceTree = "<group>"; };
0CF609322B9438BD00DD4DB3 /* OperatingCall.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OperatingCall.swift; sourceTree = "<group>"; };
0CF609342B9442F400DD4DB3 /* PushNotificationsServiceFacade.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PushNotificationsServiceFacade.swift; sourceTree = "<group>"; };
0CF692882C20E2B1000FC395 /* BackupManualWarningPresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackupManualWarningPresentable.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -21313,6 +21317,8 @@
84C1DBC429C27D9800F295A5 /* RewardCalculatorParamsServiceFactory.swift */,
0C846B882BE50BF2000EBFC2 /* VaraRewardEngine.swift */,
0C846B8A2BE52FBD000EBFC2 /* VaraRewardParamsService.swift */,
0CF4ADFE2CECACF9009C51FA /* PolkadotRewardParamsService.swift */,
0CF4AE0A2CECDCF1009C51FA /* PolkadotRewardEngine.swift */,
);
path = RelayChain;
sourceTree = "<group>";
Expand Down Expand Up @@ -25987,6 +25993,7 @@
0C77B5652A8374EA00B5AE08 /* StaticValidatorListPresenter.swift in Sources */,
2D4F55112CCB7C4C00B65B76 /* SendAssetOperationCollectionDataSource.swift in Sources */,
8418167528251BBC0007684A /* StorageListSyncResult.swift in Sources */,
0CF4ADFF2CECACF9009C51FA /* PolkadotRewardParamsService.swift in Sources */,
84DD261929ACA9880032A598 /* BagList+CodingPath.swift in Sources */,
8465DA3F298EEC6C00C7CFF1 /* GovernanceAddDelegationTracksInteractor.swift in Sources */,
2DBB288D2CD42C5200DFA0AD /* QRCreationOperationFactory.swift in Sources */,
Expand Down Expand Up @@ -27205,6 +27212,7 @@
0CAB7DA32C471AAE0070CE4D /* DirectStkRecommendingValidationFactory.swift in Sources */,
84002A9E2992444300A80672 /* GovernanceNewDelegation.swift in Sources */,
845B822126EF8F1A00D25C72 /* ManagedMetaAccountMapper.swift in Sources */,
0CF4AE0B2CECDCF1009C51FA /* PolkadotRewardEngine.swift in Sources */,
0C9C64302A8D6779004DC078 /* StakingNPoolsPresenter.swift in Sources */,
8457F91026EB8288006803E1 /* StorageMigrator+Sync.swift in Sources */,
F48220F8DA16EB51313B5D56 /* ExportMnemonicConfirmWireframe.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import Foundation
import BigInt
import SubstrateSdk

final class PolkadotRewardEngine: RewardCalculatorEngine {
let inflationPrediction: RuntimeApiInflationPrediction

init(
chainId: ChainModel.Id,
assetPrecision: Int16,
inflationPrediction: RuntimeApiInflationPrediction,
totalIssuance: BigUInt,
validators: [EraValidatorInfo],
eraDurationInSeconds: TimeInterval
) {
self.inflationPrediction = inflationPrediction

super.init(
chainId: chainId,
assetPrecision: assetPrecision,
totalIssuance: totalIssuance,
validators: validators,
eraDurationInSeconds: eraDurationInSeconds
)
}

override func calculateAnnualInflation() -> Decimal {
guard let validatorsMint = inflationPrediction.nextMint.items.first else {
return 0
}

let validatorsMintDecimal = Decimal.fromSubstrateAmount(
validatorsMint,
precision: assetPrecision
) ?? 0

let daysInYear = TimeInterval(CalculationPeriod.year.inDays)
let erasInYear = daysInYear * TimeInterval.secondsInDay / eraDurationInSeconds

let inflationPerMint = validatorsMintDecimal / totalIssuance

return inflationPerMint * Decimal(erasInYear)
}

override func calculateEraReturn(from annualReturn: Decimal) -> Decimal {
guard eraDurationInSeconds > 0 else {
return 0
}

let daysInYear = TimeInterval(CalculationPeriod.year.inDays)
let erasInYear = daysInYear * TimeInterval.secondsInDay / eraDurationInSeconds

guard erasInYear > 0 else {
return 0
}

let rawAnnualReturn = (annualReturn as NSDecimalNumber).doubleValue
let result = pow(rawAnnualReturn + 1.0, 1.0 / Double(erasInYear)) - 1.0

return Decimal(result)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import Foundation
import SubstrateSdk
import BigInt
import Operation_iOS

enum PolkadotRewardParamsServiceError: Error {
case runtimeApiNotFound
}

struct RuntimeApiInflationPrediction: Decodable, Equatable {
struct NextMint: Decodable, Equatable {
let items: [BigUInt]

init(from decoder: any Decoder) throws {
let container = try decoder.singleValueContainer()

items = try container.decode([StringScaleMapper<BigUInt>].self).map(\.value)
}
}

@StringCodable var inflation: BigUInt
let nextMint: NextMint
}

final class PolkadotRewardParamsService: BaseSyncService {
let connection: JSONRPCEngine
let runtimeCodingService: RuntimeCodingServiceProtocol
let stateCallFactory: StateCallRequestFactoryProtocol
let operationQueue: OperationQueue

private var cancellableStore = CancellableCallStore()

private var stateObserver = Observable<RuntimeApiInflationPrediction?>(state: nil)

init(
connection: JSONRPCEngine,
runtimeCodingService: RuntimeCodingServiceProtocol,
stateCallFactory: StateCallRequestFactoryProtocol,
operationQueue: OperationQueue
) {
self.connection = connection
self.runtimeCodingService = runtimeCodingService
self.stateCallFactory = stateCallFactory
self.operationQueue = operationQueue
}

override func performSyncUp() {
let codingFactoryOperation = runtimeCodingService.fetchCoderFactoryOperation()

let fetchWrapper = OperationCombiningService<RuntimeApiInflationPrediction>.compoundNonOptionalWrapper(
operationManager: OperationManager(operationQueue: operationQueue)
) {
let codingFactory = try codingFactoryOperation.extractNoCancellableResultData()

guard let runtimeApi = codingFactory.metadata.getRuntimeApiMethod(
for: "Inflation",
methodName: "experimental_inflation_prediction_info"
) else {
throw PolkadotRewardParamsServiceError.runtimeApiNotFound
}

return self.stateCallFactory.createWrapper(
for: runtimeApi.callName,
paramsClosure: nil,
codingFactoryClosure: { codingFactory },
connection: self.connection,
queryType: String(runtimeApi.method.output)
)
}

fetchWrapper.addDependency(operations: [codingFactoryOperation])

let totalWrapper = fetchWrapper.insertingHead(operations: [codingFactoryOperation])

executeCancellable(
wrapper: totalWrapper,
inOperationQueue: operationQueue,
backingCallIn: cancellableStore,
runningCallbackIn: nil,
mutex: mutex
) { [weak self] result in
switch result {
case let .success(model):
self?.completeImmediate(nil)
self?.stateObserver.state = model
case let .failure(error):
self?.completeImmediate(error)
}
}
}

override func stopSyncUp() {
cancellableStore.cancel()
}
}

extension PolkadotRewardParamsService: RewardCalculatorParamsServiceProtocol {
func subcribe(
using notificationQueue: DispatchQueue,
notificationClosure: @escaping (Result<RewardCalculatorParams, Error>) -> Void
) {
mutex.lock()

stateObserver.addObserver(with: self, queue: notificationQueue) { _, newPrediction in
guard let newPrediction else {
return
}

notificationClosure(.success(.polkadot(inflationPrediction: newPrediction)))
}

mutex.unlock()

setup()
}

func unsubscribe() {
mutex.lock()

stateObserver.removeObserver(by: self)

mutex.unlock()

throttle()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,15 @@ final class RewardCalculatorEngineFactory {
config: config,
parachainsCount: params.parachainsCount ?? 0
)
case let .polkadot(inflationPrediction):
return PolkadotRewardEngine(
chainId: chainId,
assetPrecision: assetPrecision,
inflationPrediction: inflationPrediction,
totalIssuance: totalIssuance,
validators: validators,
eraDurationInSeconds: eraDurationInSeconds
)
case let .vara(inflation):
return VaraRewardEngine(
chainId: chainId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ enum RewardCalculatorParams {
case noParams
case inflation(parachainsCount: Int)
case vara(inflation: BigUInt)
case polkadot(inflationPrediction: RuntimeApiInflationPrediction)

var parachainsCount: Int? {
switch self {
case let .inflation(parachainsCount):
return parachainsCount
case .noParams, .vara:
case .noParams, .vara, .polkadot:
return nil
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ final class RewardCalculatorParamsServiceFactory {
runtimeCodingService: runtimeService,
operationQueue: operationQueue
)
case KnowChainId.polkadot:
PolkadotRewardParamsService(
connection: connection,
runtimeCodingService: runtimeService,
stateCallFactory: StateCallRequestFactory(),
operationQueue: operationQueue
)
default:
InflationRewardCalculatorParamsService(
connection: connection,
Expand Down

0 comments on commit e3cfa5e

Please sign in to comment.