From b955f043e3019be1094b9e5291fb75cf5434fd56 Mon Sep 17 00:00:00 2001 From: Russel Date: Fri, 3 Sep 2021 17:00:04 +0300 Subject: [PATCH 1/6] revert tx history to subquery --- fearless.xcodeproj/project.pbxproj | 20 +- ...AssetTransactionData+HistoryItemData.swift | 148 ++++++++++- .../TransactionHistoryMergeManager.swift | 22 +- .../SubqueryHistoryElement+Wallet.swift | 206 --------------- ...bqueryHistoryOperationFactory+Wallet.swift | 33 --- .../Subscan/SubscanHistoryItem+Wallet.swift | 72 ++++++ .../SubscanHistoryOperationFactory.swift | 236 ++++++++++++++++++ .../Wallet/TransactionHistoryContext.swift | 214 ++++++++++++++-- .../Wallet/WalletNetworkFacade+Protocol.swift | 15 +- .../WalletNetworkFacade+TxHistory.swift | 2 +- .../Wallet/WalletRemoteHistoryFiltering.swift | 33 +++ .../Wallet/WalletRemoteHistoryProtocols.swift | 1 - .../ExtrinsicServiceFactory.swift | 2 +- .../SelectValidatorsConfirmViewFactory.swift | 2 +- .../TransactionDetailsConfigurator.swift | 3 +- ...lsViewModelFactory+RewardsAndSlashes.swift | 66 +---- .../TransactionDetailsViewModelFactory.swift | 14 +- 17 files changed, 723 insertions(+), 366 deletions(-) delete mode 100644 fearless/Common/Network/Subquery/SubqueryHistoryElement+Wallet.swift delete mode 100644 fearless/Common/Network/Subquery/SubqueryHistoryOperationFactory+Wallet.swift create mode 100644 fearless/Common/Network/Subscan/SubscanHistoryItem+Wallet.swift create mode 100644 fearless/Common/Network/Subscan/SubscanHistoryOperationFactory.swift create mode 100644 fearless/Common/Network/Wallet/WalletRemoteHistoryFiltering.swift diff --git a/fearless.xcodeproj/project.pbxproj b/fearless.xcodeproj/project.pbxproj index 685d78c62..d20cc0525 100644 --- a/fearless.xcodeproj/project.pbxproj +++ b/fearless.xcodeproj/project.pbxproj @@ -320,6 +320,9 @@ 8430AB1226023C9F005B1066 /* PendingBondedState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8430AB1126023C9F005B1066 /* PendingBondedState.swift */; }; 8430AB1726023D2D005B1066 /* BaseStashNextState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8430AB1626023D2D005B1066 /* BaseStashNextState.swift */; }; 8432E55124EFDF6100B05B58 /* AccountItemMapperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8432E55024EFDF6100B05B58 /* AccountItemMapperTests.swift */; }; + 843461CB26E2590200DCE0CD /* SubscanHistoryOperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843461CA26E2590200DCE0CD /* SubscanHistoryOperationFactory.swift */; }; + 843461CD26E2596E00DCE0CD /* WalletRemoteHistoryFiltering.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843461CC26E2596E00DCE0CD /* WalletRemoteHistoryFiltering.swift */; }; + 843461CF26E25AD400DCE0CD /* SubscanHistoryItem+Wallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843461CE26E25AD400DCE0CD /* SubscanHistoryItem+Wallet.swift */; }; 8434C9E425401EF3009E4191 /* TransactionHistoryItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8434C9E325401EF3009E4191 /* TransactionHistoryItem.swift */; }; 8434C9E625403686009E4191 /* CDTransactionHistoryItem+CoreDataDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8434C9E525403686009E4191 /* CDTransactionHistoryItem+CoreDataDecodable.swift */; }; 8434C9EA2540AE51009E4191 /* ExtrinsicEraTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8434C9E92540AE51009E4191 /* ExtrinsicEraTests.swift */; }; @@ -541,7 +544,6 @@ 846AF8482525E23C00868F37 /* WalletTotalPriceCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846AF8472525E23C00868F37 /* WalletTotalPriceCell.swift */; }; 846AF84A2525E24C00868F37 /* WalletTotalPriceCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 846AF8492525E24C00868F37 /* WalletTotalPriceCell.xib */; }; 846B32A126DCDB7300250E89 /* SubqueryRewardSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846B32A026DCDB7300250E89 /* SubqueryRewardSource.swift */; }; - 846B32A326DCDEB200250E89 /* SubqueryHistoryOperationFactory+Wallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846B32A226DCDEB200250E89 /* SubqueryHistoryOperationFactory+Wallet.swift */; }; 846B32A526DD07AF00250E89 /* rewardErrorResponse.json in Resources */ = {isa = PBXBuildFile; fileRef = 846B32A426DD07AF00250E89 /* rewardErrorResponse.json */; }; 846B32A726DD241C00250E89 /* WalletEventOpenCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846B32A626DD241C00250E89 /* WalletEventOpenCommand.swift */; }; 846C372E26B199D10098F303 /* StakingDurationOperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846C372D26B199D10098F303 /* StakingDurationOperationFactory.swift */; }; @@ -786,7 +788,6 @@ 849ABE862628154900011A2A /* SubscanRawExtrinsicData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849ABE852628154900011A2A /* SubscanRawExtrinsicData.swift */; }; 849ABE8A262833C000011A2A /* PayoutRewardsServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F44CD8F826244EC3005DDF23 /* PayoutRewardsServiceTests.swift */; }; 849AFEB326DADC1300B65924 /* SubqueryHistory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849AFEB226DADC1300B65924 /* SubqueryHistory.swift */; }; - 849AFEB526DB7C8500B65924 /* SubqueryHistoryElement+Wallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849AFEB426DB7C8500B65924 /* SubqueryHistoryElement+Wallet.swift */; }; 849AFEB726DBC0BE00B65924 /* AssetTransactionData+HistoryItemData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849AFEB626DBC0BE00B65924 /* AssetTransactionData+HistoryItemData.swift */; }; 849AFEBD26DCCE3A00B65924 /* SubqueryResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849AFEBC26DCCE3A00B65924 /* SubqueryResponse.swift */; }; 849DEBD425ED015C00C64C19 /* SelectValidatorsConfirmViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849DEBD325ED015C00C64C19 /* SelectValidatorsConfirmViewModel.swift */; }; @@ -1765,6 +1766,9 @@ 8430AB1126023C9F005B1066 /* PendingBondedState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PendingBondedState.swift; sourceTree = ""; }; 8430AB1626023D2D005B1066 /* BaseStashNextState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseStashNextState.swift; sourceTree = ""; }; 8432E55024EFDF6100B05B58 /* AccountItemMapperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountItemMapperTests.swift; sourceTree = ""; }; + 843461CA26E2590200DCE0CD /* SubscanHistoryOperationFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscanHistoryOperationFactory.swift; sourceTree = ""; }; + 843461CC26E2596E00DCE0CD /* WalletRemoteHistoryFiltering.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletRemoteHistoryFiltering.swift; sourceTree = ""; }; + 843461CE26E25AD400DCE0CD /* SubscanHistoryItem+Wallet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SubscanHistoryItem+Wallet.swift"; sourceTree = ""; }; 8434C9E325401EF3009E4191 /* TransactionHistoryItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionHistoryItem.swift; sourceTree = ""; }; 8434C9E525403686009E4191 /* CDTransactionHistoryItem+CoreDataDecodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CDTransactionHistoryItem+CoreDataDecodable.swift"; sourceTree = ""; }; 8434C9E92540AE51009E4191 /* ExtrinsicEraTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtrinsicEraTests.swift; sourceTree = ""; }; @@ -1989,7 +1993,6 @@ 846AF8472525E23C00868F37 /* WalletTotalPriceCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletTotalPriceCell.swift; sourceTree = ""; }; 846AF8492525E24C00868F37 /* WalletTotalPriceCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = WalletTotalPriceCell.xib; sourceTree = ""; }; 846B32A026DCDB7300250E89 /* SubqueryRewardSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubqueryRewardSource.swift; sourceTree = ""; }; - 846B32A226DCDEB200250E89 /* SubqueryHistoryOperationFactory+Wallet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SubqueryHistoryOperationFactory+Wallet.swift"; sourceTree = ""; }; 846B32A426DD07AF00250E89 /* rewardErrorResponse.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = rewardErrorResponse.json; sourceTree = ""; }; 846B32A626DD241C00250E89 /* WalletEventOpenCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletEventOpenCommand.swift; sourceTree = ""; }; 846C372D26B199D10098F303 /* StakingDurationOperationFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingDurationOperationFactory.swift; sourceTree = ""; }; @@ -2238,7 +2241,6 @@ 849ABE80262811CF00011A2A /* NominationsListReducer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NominationsListReducer.swift; sourceTree = ""; }; 849ABE852628154900011A2A /* SubscanRawExtrinsicData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscanRawExtrinsicData.swift; sourceTree = ""; }; 849AFEB226DADC1300B65924 /* SubqueryHistory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubqueryHistory.swift; sourceTree = ""; }; - 849AFEB426DB7C8500B65924 /* SubqueryHistoryElement+Wallet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SubqueryHistoryElement+Wallet.swift"; sourceTree = ""; }; 849AFEB626DBC0BE00B65924 /* AssetTransactionData+HistoryItemData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AssetTransactionData+HistoryItemData.swift"; sourceTree = ""; }; 849AFEBC26DCCE3A00B65924 /* SubqueryResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubqueryResponse.swift; sourceTree = ""; }; 849DEBD325ED015C00C64C19 /* SelectValidatorsConfirmViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SelectValidatorsConfirmViewModel.swift; sourceTree = ""; }; @@ -5453,6 +5455,8 @@ 8494D871252532F000614D8F /* Info */, 8494D86F2525321700614D8F /* SubscanDefinitions.swift */, 8494D8772525343500614D8F /* SubscanOperationFactory.swift */, + 843461CA26E2590200DCE0CD /* SubscanHistoryOperationFactory.swift */, + 843461CE26E25AD400DCE0CD /* SubscanHistoryItem+Wallet.swift */, ); path = Subscan; sourceTree = ""; @@ -5540,6 +5544,7 @@ 84FAB0662542D06B00319F74 /* WalletContactOperationFactory.swift */, 8418E71F2617602000DCF6C8 /* WalletRemoteHistoryProtocols.swift */, 84FB1F6C2526987D00E0242B /* TransactionHistoryContext.swift */, + 843461CC26E2596E00DCE0CD /* WalletRemoteHistoryFiltering.swift */, ); path = Wallet; sourceTree = ""; @@ -5559,8 +5564,6 @@ children = ( 849AFEBB26DCCDDD00B65924 /* Data */, 84412EE026DAC3300049577A /* SubqueryHistoryOperationFactory.swift */, - 849AFEB426DB7C8500B65924 /* SubqueryHistoryElement+Wallet.swift */, - 846B32A226DCDEB200250E89 /* SubqueryHistoryOperationFactory+Wallet.swift */, ); path = Subquery; sourceTree = ""; @@ -7870,7 +7873,6 @@ 845BB8D625E461FC00E5FCDC /* RewardDestination.swift in Sources */, 84CFF1EB26526FBC00DB7CF7 /* StakingBondMoreConfirmViewModel.swift in Sources */, 8490142D24A935FE008F705E /* WebPresentable.swift in Sources */, - 849AFEB526DB7C8500B65924 /* SubqueryHistoryElement+Wallet.swift in Sources */, 842D1E7B24D0667E00C30A7A /* TriangularedButton.swift in Sources */, 8470D6CD253E3170009E9A5D /* AccountInfoSubscription.swift in Sources */, 8430AB052602339B005B1066 /* PendingValidatorState.swift in Sources */, @@ -7943,6 +7945,7 @@ 84FAB076254378FC00319F74 /* ContactsListViewModelFactory.swift in Sources */, 842349C02624E7B40066ACFE /* SubstrateAccountId.swift in Sources */, 8490143024A935FE008F705E /* AlertPresentable.swift in Sources */, + 843461CD26E2596E00DCE0CD /* WalletRemoteHistoryFiltering.swift in Sources */, AE2C84D525EF989A00986716 /* ValidatorInfoWireframe.swift in Sources */, F44CD8F426242825005DDF23 /* PayoutRewardsService+Fetch.swift in Sources */, 2AD0A19525D3D3EC00312428 /* GitHubOperationFactory.swift in Sources */, @@ -8120,6 +8123,7 @@ 84893C0124DA861D008F6A3F /* AccountCreationMetadata.swift in Sources */, 2A84E87825D425750006FE9C /* AlertControllerFactory.swift in Sources */, 84452F6225D5D5AD00F47EC5 /* RuntimeFilesOperationFacade.swift in Sources */, + 843461CB26E2590200DCE0CD /* SubscanHistoryOperationFactory.swift in Sources */, 84CFF1F226526FBC00DB7CF7 /* StakingBondMoreConfirmationVC.swift in Sources */, 84786E1F25FA6C390089DFF7 /* CDStashItem+CoreDataCodable.swift in Sources */, 840882B02514024800177E20 /* SelectedConnectionChanged.swift in Sources */, @@ -8671,6 +8675,7 @@ C7E39E732B9CA6D826FF7910 /* AccountInfoPresenter.swift in Sources */, 8460516D25536C4800A1F0B4 /* ExportOption+ViewModel.swift in Sources */, 84969734251CE9CD00C39524 /* ContactsConfigurator.swift in Sources */, + 843461CF26E25AD400DCE0CD /* SubscanHistoryItem+Wallet.swift in Sources */, F458D3982642911B0055CB75 /* ControllerAccountViewModel.swift in Sources */, 73056D4920BE0E60FAF5073D /* AccountInfoInteractor.swift in Sources */, 84DAC198268D3DD9002D0DF4 /* SNAddressType.swift in Sources */, @@ -8772,7 +8777,6 @@ F4F22967260DBC7200ACFDB8 /* StakingPayoutStatusTableCell.swift in Sources */, 88F3A9FB9CEA464275F1115E /* ExportMnemonicViewFactory.swift in Sources */, F4D551A12643DD240002363F /* AccountSelectionPresentable.swift in Sources */, - 846B32A326DCDEB200250E89 /* SubqueryHistoryOperationFactory+Wallet.swift in Sources */, F48220F8DA16EB51313B5D56 /* ExportMnemonicConfirmWireframe.swift in Sources */, 6D6C6FD2F13603BCE83CFC65 /* ExportMnemonicConfirmInteractor.swift in Sources */, 0CA307BC2F570941CD22C9AA /* ExportMnemonicConfirmViewFactory.swift in Sources */, diff --git a/fearless/Common/Extension/Wallet/AssetTransactionData+HistoryItemData.swift b/fearless/Common/Extension/Wallet/AssetTransactionData+HistoryItemData.swift index ab7087847..51573f8af 100644 --- a/fearless/Common/Extension/Wallet/AssetTransactionData+HistoryItemData.swift +++ b/fearless/Common/Extension/Wallet/AssetTransactionData+HistoryItemData.swift @@ -5,6 +5,150 @@ import IrohaCrypto import FearlessUtils extension AssetTransactionData { + static func createTransaction( + from item: SubscanTransferItemData, + address: String, + networkType: SNAddressType, + asset: WalletAsset, + addressFactory: SS58AddressFactoryProtocol + ) -> AssetTransactionData { + let status: AssetTransactionStatus + + if item.finalized == false { + status = .pending + } else if let state = item.success { + status = state ? .commited : .rejected + } else { + status = .pending + } + + let peerAddress = item.sender == address ? item.receiver : item.sender + + let accountId = try? addressFactory.accountId( + fromAddress: peerAddress, + type: networkType + ) + + let peerId = accountId?.toHex() ?? peerAddress + + let amount = AmountDecimal(string: item.amount) ?? AmountDecimal(value: 0) + let feeValue = BigUInt(item.fee) ?? BigUInt(0) + let feeDecimal = Decimal.fromSubstrateAmount(feeValue, precision: asset.precision) ?? .zero + + let fee = AssetTransactionFee( + identifier: asset.identifier, + assetId: asset.identifier, + amount: AmountDecimal(value: feeDecimal), + context: nil + ) + + let type = item.sender == address ? TransactionType.outgoing : + TransactionType.incoming + + return AssetTransactionData( + transactionId: item.hash, + status: status, + assetId: asset.identifier, + peerId: peerId, + peerFirstName: nil, + peerLastName: nil, + peerName: peerAddress, + details: "", + amount: amount, + fees: [fee], + timestamp: item.timestamp, + type: type.rawValue, + reason: nil, + context: nil + ) + } + + static func createTransaction( + from item: SubscanRewardItemData, + address: String, + networkType: SNAddressType, + asset: WalletAsset, + addressFactory _: SS58AddressFactoryProtocol + ) -> AssetTransactionData { + let status: AssetTransactionStatus + + status = .commited + + let amount: Decimal = { + guard let amountValue = BigUInt(item.amount) else { + return 0.0 + } + + return Decimal.fromSubstrateAmount(amountValue, precision: networkType.precision) ?? 0.0 + }() + + let type = TransactionType(rawValue: item.eventId.uppercased()) + + return AssetTransactionData( + transactionId: item.identifier, + status: status, + assetId: asset.identifier, + peerId: item.extrinsicHash, + peerFirstName: nil, + peerLastName: nil, + peerName: address, + details: "", + amount: AmountDecimal(value: amount), + fees: [], + timestamp: item.timestamp, + type: type?.rawValue ?? "", + reason: nil, + context: nil + ) + } + + static func createTransaction( + from item: SubscanConcreteExtrinsicsItemData, + address: String, + networkType: SNAddressType, + asset: WalletAsset, + addressFactory: SS58AddressFactoryProtocol + ) -> AssetTransactionData { + let amount: Decimal = { + guard let amountValue = BigUInt(item.fee) else { + return 0.0 + } + + return Decimal.fromSubstrateAmount(amountValue, precision: networkType.precision) ?? 0.0 + }() + + let accountId = try? addressFactory.accountId( + fromAddress: address, + type: networkType + ) + let peerId = accountId?.toHex() ?? address + + let status: AssetTransactionStatus + + if let state = item.success { + status = state ? .commited : .rejected + } else { + status = .pending + } + + return AssetTransactionData( + transactionId: item.identifier, + status: status, + assetId: asset.identifier, + peerId: peerId, + peerFirstName: item.callModule, + peerLastName: item.callFunction, + peerName: "\(item.callModule) \(item.callFunction)", + details: "", + amount: AmountDecimal(value: amount), + fees: [], + timestamp: item.timestamp, + type: TransactionType.extrinsic.rawValue, + reason: nil, + context: nil + ) + } + static func createTransaction( from item: TransactionHistoryItem, address: String, @@ -88,7 +232,7 @@ extension AssetTransactionData { timestamp: item.timestamp, type: type.rawValue, reason: nil, - context: [TransactionContextKeys.extrinsicHash: item.txHash] + context: nil ) } @@ -128,7 +272,7 @@ extension AssetTransactionData { timestamp: item.timestamp, type: TransactionType.extrinsic.rawValue, reason: nil, - context: [TransactionContextKeys.extrinsicHash: item.txHash] + context: nil ) } } diff --git a/fearless/Common/Helpers/TransactionHistoryMergeManager.swift b/fearless/Common/Helpers/TransactionHistoryMergeManager.swift index c6b75b157..b4341c9eb 100644 --- a/fearless/Common/Helpers/TransactionHistoryMergeManager.swift +++ b/fearless/Common/Helpers/TransactionHistoryMergeManager.swift @@ -115,30 +115,22 @@ final class TransactionHistoryMergeManager { } func merge( - remoteItems: [WalletRemoteHistoryItemProtocol], + subscanItems: [WalletRemoteHistoryItemProtocol], localItems: [TransactionHistoryItem] ) -> TransactionHistoryMergeResult { - let remoteHashes: [Data] = remoteItems.compactMap { remoteItem in - guard let extrinsicHash = remoteItem.extrinsicHash else { - return nil - } - - return try? Data(hexString: extrinsicHash) - } - - let existingHashes = Set(remoteHashes) - let minRemoteItem = remoteItems.last + let existingHashes = Set(subscanItems.map(\.identifier)) + let minSubscanItem = subscanItems.last let hashesToRemove: [String] = localItems.compactMap { item in - if let localHash = try? Data(hexString: item.txHash), existingHashes.contains(localHash) { + if existingHashes.contains(item.txHash) { return item.txHash } - guard let remoteItem = minRemoteItem else { + guard let subscanItem = minSubscanItem else { return nil } - if item.timestamp < remoteItem.itemTimestamp { + if item.timestamp < subscanItem.itemTimestamp { return item.txHash } @@ -154,7 +146,7 @@ final class TransactionHistoryMergeManager { return TransactionHistoryMergeItem.local(item: item) } - let remoteMergeItems: [TransactionHistoryMergeItem] = remoteItems.map { + let remoteMergeItems: [TransactionHistoryMergeItem] = subscanItems.map { TransactionHistoryMergeItem.remote(remote: $0) } diff --git a/fearless/Common/Network/Subquery/SubqueryHistoryElement+Wallet.swift b/fearless/Common/Network/Subquery/SubqueryHistoryElement+Wallet.swift deleted file mode 100644 index cd109de97..000000000 --- a/fearless/Common/Network/Subquery/SubqueryHistoryElement+Wallet.swift +++ /dev/null @@ -1,206 +0,0 @@ -import Foundation -import IrohaCrypto -import CommonWallet -import BigInt - -extension SubqueryHistoryElement: WalletRemoteHistoryItemProtocol { - var itemBlockNumber: UInt64 { - 0 - } - - var itemExtrinsicIndex: UInt16 { - 0 - } - - var itemTimestamp: Int64 { - Int64(timestamp) ?? 0 - } - - var extrinsicHash: String? { - if let extrinsic = extrinsic { - return extrinsic.hash - } - - if let transfer = transfer { - return transfer.extrinsicHash - } - - return nil - } - - var label: WalletRemoteHistorySourceLabel { - if reward != nil { - return .rewards - } - - if transfer != nil { - return .transfers - } - - return .extrinsics - } - - func createTransactionForAddress( - _ address: String, - networkType: SNAddressType, - asset: WalletAsset, - addressFactory: SS58AddressFactoryProtocol - ) -> AssetTransactionData { - if let rewardOrSlash = reward { - return createTransactionForRewardOrSlash(rewardOrSlash, asset: asset) - } - - if let transfer = transfer { - return createTransactionForTransfer( - transfer, - address: address, - networkType: networkType, - asset: asset, - addressFactory: addressFactory - ) - } - - return createTransactionForExtrinsic( - extrinsic!, - address: address, - networkType: networkType, - asset: asset, - addressFactory: addressFactory - ) - } - - private func createTransactionForExtrinsic( - _ extrinsic: SubqueryExtrinsic, - address: String, - networkType: SNAddressType, - asset: WalletAsset, - addressFactory: SS58AddressFactoryProtocol - ) -> AssetTransactionData { - let amount = Decimal.fromSubstrateAmount( - BigUInt(extrinsic.fee) ?? 0, - precision: asset.precision - ) ?? 0.0 - - let accountId = try? addressFactory.accountId( - fromAddress: address, - type: networkType - ) - - let peerId = accountId?.toHex() ?? address - - let status: AssetTransactionStatus = extrinsic.success ? .commited : .rejected - - return AssetTransactionData( - transactionId: identifier, - status: status, - assetId: asset.identifier, - peerId: peerId, - peerFirstName: extrinsic.module, - peerLastName: extrinsic.call, - peerName: "\(extrinsic.module) \(extrinsic.call)", - details: "", - amount: AmountDecimal(value: amount), - fees: [], - timestamp: itemTimestamp, - type: TransactionType.extrinsic.rawValue, - reason: nil, - context: [TransactionContextKeys.extrinsicHash: extrinsic.hash] - ) - } - - private func createTransactionForTransfer( - _ transfer: SubqueryTransfer, - address: String, - networkType: SNAddressType, - asset: WalletAsset, - addressFactory: SS58AddressFactoryProtocol - ) -> AssetTransactionData { - let status = transfer.success ? AssetTransactionStatus.commited : AssetTransactionStatus.rejected - - let peerAddress = transfer.sender == address ? transfer.receiver : transfer.sender - - let peerAccountId = try? addressFactory.accountId( - fromAddress: peerAddress, - type: networkType - ) - - let amountValue = BigUInt(transfer.amount) ?? 0 - let amountDecimal = Decimal.fromSubstrateAmount(amountValue, precision: asset.precision) ?? .zero - - let feeValue = BigUInt(transfer.fee) ?? 0 - let feeDecimal = Decimal.fromSubstrateAmount(feeValue, precision: asset.precision) ?? .zero - - let fee = AssetTransactionFee( - identifier: asset.identifier, - assetId: asset.identifier, - amount: AmountDecimal(value: feeDecimal), - context: nil - ) - - let type = transfer.sender == address ? TransactionType.outgoing : TransactionType.incoming - - let context: [String: String]? - - if let extrinsicHash = transfer.extrinsicHash { - context = [TransactionContextKeys.extrinsicHash: extrinsicHash] - } else { - context = nil - } - - return AssetTransactionData( - transactionId: identifier, - status: status, - assetId: asset.identifier, - peerId: peerAccountId?.toHex() ?? "", - peerFirstName: nil, - peerLastName: nil, - peerName: peerAddress, - details: "", - amount: AmountDecimal(value: amountDecimal), - fees: [fee], - timestamp: itemTimestamp, - type: type.rawValue, - reason: nil, - context: context - ) - } - - private func createTransactionForRewardOrSlash( - _ rewardOrSlash: SubqueryRewardOrSlash, - asset: WalletAsset - ) -> AssetTransactionData { - let amount = Decimal.fromSubstrateAmount( - BigUInt(rewardOrSlash.amount) ?? 0, - precision: asset.precision - ) ?? 0.0 - - let type = rewardOrSlash.isReward ? TransactionType.reward.rawValue : TransactionType.slash.rawValue - - let validatorAddress = rewardOrSlash.validator ?? "" - - let context: [String: String]? - - if let era = rewardOrSlash.era { - context = [TransactionContextKeys.era: String(era)] - } else { - context = nil - } - - return AssetTransactionData( - transactionId: identifier, - status: .commited, - assetId: asset.identifier, - peerId: validatorAddress, - peerFirstName: nil, - peerLastName: nil, - peerName: validatorAddress, - details: "", - amount: AmountDecimal(value: amount), - fees: [], - timestamp: itemTimestamp, - type: type, - reason: nil, - context: context - ) - } -} diff --git a/fearless/Common/Network/Subquery/SubqueryHistoryOperationFactory+Wallet.swift b/fearless/Common/Network/Subquery/SubqueryHistoryOperationFactory+Wallet.swift deleted file mode 100644 index b65da8ad4..000000000 --- a/fearless/Common/Network/Subquery/SubqueryHistoryOperationFactory+Wallet.swift +++ /dev/null @@ -1,33 +0,0 @@ -import Foundation -import RobinHood - -extension SubqueryHistoryOperationFactory: WalletRemoteHistoryFactoryProtocol { - func createOperationWrapper( - for context: TransactionHistoryContext, - address: String, - count: Int - ) -> CompoundOperationWrapper { - let queryOperation = createOperation(address: address, count: count, cursor: context.cursor) - - let mappingOperation = ClosureOperation { - let response = try queryOperation.extractNoCancellableResultData() - - let pageInfo = response.historyElements.pageInfo - let items = response.historyElements.nodes - - let context = TransactionHistoryContext( - cursor: pageInfo.endCursor, - isComplete: pageInfo.endCursor == nil - ) - - return WalletRemoteHistoryData( - historyItems: items, - context: context - ) - } - - mappingOperation.addDependency(queryOperation) - - return CompoundOperationWrapper(targetOperation: mappingOperation, dependencies: [queryOperation]) - } -} diff --git a/fearless/Common/Network/Subscan/SubscanHistoryItem+Wallet.swift b/fearless/Common/Network/Subscan/SubscanHistoryItem+Wallet.swift new file mode 100644 index 000000000..eac7348f2 --- /dev/null +++ b/fearless/Common/Network/Subscan/SubscanHistoryItem+Wallet.swift @@ -0,0 +1,72 @@ +import Foundation +import CommonWallet +import IrohaCrypto + +extension SubscanRewardItemData: WalletRemoteHistoryItemProtocol { + var identifier: String { "\(recordId)-\(eventIndex)" } + var itemBlockNumber: UInt64 { blockNumber } + var itemExtrinsicIndex: UInt16 { extrinsicIndex } + var itemTimestamp: Int64 { timestamp } + var label: WalletRemoteHistorySourceLabel { .rewards } + + func createTransactionForAddress( + _ address: String, + networkType: SNAddressType, + asset: WalletAsset, + addressFactory: SS58AddressFactoryProtocol + ) -> AssetTransactionData { + AssetTransactionData.createTransaction( + from: self, + address: address, + networkType: networkType, + asset: asset, + addressFactory: addressFactory + ) + } +} + +extension SubscanTransferItemData: WalletRemoteHistoryItemProtocol { + var identifier: String { hash } + var itemBlockNumber: UInt64 { blockNumber } + var itemExtrinsicIndex: UInt16 { extrinsicIndex.value } + var itemTimestamp: Int64 { timestamp } + var label: WalletRemoteHistorySourceLabel { .transfers } + + func createTransactionForAddress( + _ address: String, + networkType: SNAddressType, + asset: WalletAsset, + addressFactory: SS58AddressFactoryProtocol + ) -> AssetTransactionData { + AssetTransactionData.createTransaction( + from: self, + address: address, + networkType: networkType, + asset: asset, + addressFactory: addressFactory + ) + } +} + +extension SubscanConcreteExtrinsicsItemData: WalletRemoteHistoryItemProtocol { + var identifier: String { hash } + var itemBlockNumber: UInt64 { blockNumber } + var itemExtrinsicIndex: UInt16 { extrinsicIndex.value } + var itemTimestamp: Int64 { timestamp } + var label: WalletRemoteHistorySourceLabel { .extrinsics } + + func createTransactionForAddress( + _ address: String, + networkType: SNAddressType, + asset: WalletAsset, + addressFactory: SS58AddressFactoryProtocol + ) -> AssetTransactionData { + AssetTransactionData.createTransaction( + from: self, + address: address, + networkType: networkType, + asset: asset, + addressFactory: addressFactory + ) + } +} diff --git a/fearless/Common/Network/Subscan/SubscanHistoryOperationFactory.swift b/fearless/Common/Network/Subscan/SubscanHistoryOperationFactory.swift new file mode 100644 index 000000000..241834c74 --- /dev/null +++ b/fearless/Common/Network/Subscan/SubscanHistoryOperationFactory.swift @@ -0,0 +1,236 @@ +import Foundation +import RobinHood + +final class SubscanHistoryOperationFactory { + struct MergeResult { + let items: [WalletRemoteHistoryItemProtocol] + let originalCounters: [WalletRemoteHistorySourceLabel: Int] + } + + let internalFactory = SubscanOperationFactory() + + let baseURL: URL + + let filter: WalletRemoteHistoryFiltering? + + init(baseURL: URL, filter: WalletRemoteHistoryFiltering? = nil) { + self.baseURL = baseURL + self.filter = filter + } + + private func createTransfersOperationIfNeeded( + for context: TransactionHistoryContext, + address: String + ) -> BaseOperation? { + guard !context.transfers.isComplete else { + return nil + } + + let transfersURL = baseURL.appendingPathComponent(SubscanApi.transfers) + let transferInfo = HistoryInfo( + address: address, + row: context.transfers.row, + page: context.transfers.page + ) + return internalFactory.fetchTransfersOperation(transfersURL, info: transferInfo) + } + + private func createRewardsOperationIfNeeded( + for context: TransactionHistoryContext, + address: String + ) -> BaseOperation? { + guard !context.rewards.isComplete else { + return nil + } + + let rewardsURL = baseURL.appendingPathComponent(SubscanApi.rewardsAndSlashes) + let rewardInfo = HistoryInfo( + address: address, + row: context.rewards.row, + page: context.rewards.page + ) + return internalFactory.fetchRewardsAndSlashesOperation(rewardsURL, info: rewardInfo) + } + + private func createExtrinsicsOperationIfNeeded( + for context: TransactionHistoryContext, + address: String + ) -> BaseOperation? { + guard !context.extrinsics.isComplete else { + return nil + } + + let extrinsicsURL = baseURL.appendingPathComponent(SubscanApi.extrinsics) + let info = ExtrinsicsInfo( + row: context.extrinsics.row, + page: context.extrinsics.page, + address: address, + moduleName: nil, + callName: nil + ) + + return internalFactory.fetchConcreteExtrinsicsOperation(extrinsicsURL, info: info) + } + + private func createMergeOperation( + dependingOn transfersOperation: BaseOperation?, + rewardsOperation: BaseOperation?, + extrinsicsOperation: BaseOperation?, + context: TransactionHistoryContext + ) -> BaseOperation { + ClosureOperation { + let transferPageData = try transfersOperation? + .extractResultData(throwing: BaseOperationError.parentOperationCancelled) + let rewardPageData = try rewardsOperation? + .extractResultData(throwing: BaseOperationError.parentOperationCancelled) + let extrinsicPageData = try extrinsicsOperation? + .extractNoCancellableResultData() + + let transfers = transferPageData?.transfers ?? [] + let rewards = rewardPageData?.items ?? [] + let extrinsics = extrinsicPageData?.extrinsics ?? [] + + let completionMapping: [WalletRemoteHistorySourceLabel: Bool] = + [ + .transfers: transfers.count < context.transfers.row, + .rewards: rewards.count < context.rewards.row, + .extrinsics: extrinsics.count < context.extrinsics.row + ] + + let originalCounters: [WalletRemoteHistorySourceLabel: Int] = + [ + .transfers: transfers.count, + .rewards: rewards.count, + .extrinsics: extrinsics.count + ] + + let resultItems: [WalletRemoteHistoryItemProtocol] = + (rewards + extrinsics + transfers).sorted { item1, item2 in + if item1.itemBlockNumber > item2.itemBlockNumber { + return true + } else if item1.itemBlockNumber < item2.itemBlockNumber { + return false + } + + return item1.itemExtrinsicIndex >= item2.itemExtrinsicIndex + } + + let transfersIndex = resultItems.lastIndex { $0.label == .transfers } + let rewardsIndex = resultItems.lastIndex { $0.label == .rewards } + let extrinsicsIndex = resultItems.lastIndex { $0.label == .extrinsics } + + let arrayOfIndexes: [(WalletRemoteHistorySourceLabel, Int)] = { + var array = [(WalletRemoteHistorySourceLabel, Int)]() + if let transfersIndex = transfersIndex { + array.append((.transfers, transfersIndex)) + } + if let rewardsIndex = rewardsIndex { + array.append((.rewards, rewardsIndex)) + } + if let extrinsicsIndex = extrinsicsIndex { + array.append((.extrinsics, extrinsicsIndex)) + } + return array + }() + + let truncationLength: Int? = arrayOfIndexes + .sorted { $0.1 < $1.1 } + .first { !(completionMapping[$0.0] ?? false) } + .map { $0.1 + 1 } + + let truncatedItems: [WalletRemoteHistoryItemProtocol] = { + if let length = truncationLength { + return Array(resultItems.prefix(length)) + } else { + return resultItems + } + }() + + return MergeResult(items: truncatedItems, originalCounters: originalCounters) + } + } + + private func createMapOperation( + dependingOn mergeOperation: BaseOperation, + context: TransactionHistoryContext, + filter: WalletRemoteHistoryFiltering? + ) -> BaseOperation { + ClosureOperation { + let mergeResult = try mergeOperation.extractNoCancellableResultData() + let counters = mergeResult.items + .reduce(into: [WalletRemoteHistorySourceLabel: Int]()) { result, item in + result[item.label] = (result[item.label] ?? 0) + 1 + } + + let nextContext = WalletRemoteHistorySourceLabel.allCases.reduce(context) { result, label in + let sourceContext = result.sourceContext(for: label) + + guard !sourceContext.isComplete else { + return result + } + + let mergedCount = counters[label] ?? 0 + let total = (sourceContext.page * sourceContext.row) + mergedCount + let row = total.firstDivider(from: (1 ... result.defaultRow).reversed()) ?? 1 + let nextPage = total / row + + let originalCount = mergeResult.originalCounters[label] ?? 0 + let isCompleted = originalCount == mergedCount ? originalCount < sourceContext.row : false + + let nextSourceContext = result.sourceContext(for: label) + .byReplacingPage(nextPage) + .byReplacingRow(row) + .byReplacingCompletion(isCompleted) + + return result.byReplacingSource(context: nextSourceContext, for: label) + } + + let finalItems: [WalletRemoteHistoryItemProtocol] + + if let filter = filter { + finalItems = mergeResult.items.filter { filter.includes(item: $0) } + } else { + finalItems = mergeResult.items + } + + return WalletRemoteHistoryData( + historyItems: finalItems, + context: nextContext + ) + } + } +} + +extension SubscanHistoryOperationFactory: WalletRemoteHistoryFactoryProtocol { + func createOperationWrapper(for context: TransactionHistoryContext, address: String, count _: Int) + -> CompoundOperationWrapper { + guard !context.isComplete else { + let result = WalletRemoteHistoryData(historyItems: [], context: context) + return CompoundOperationWrapper.createWithResult(result) + } + + let transfersOperation = createTransfersOperationIfNeeded(for: context, address: address) + let rewardsOperation = createRewardsOperationIfNeeded(for: context, address: address) + let extrinsicsOperation = createExtrinsicsOperationIfNeeded(for: context, address: address) + + let sourceOperations: [Operation] = [transfersOperation, rewardsOperation, extrinsicsOperation] + .compactMap { $0 } + + let mergeOperation = createMergeOperation( + dependingOn: transfersOperation, + rewardsOperation: rewardsOperation, + extrinsicsOperation: extrinsicsOperation, + context: context + ) + + sourceOperations.forEach { mergeOperation.addDependency($0) } + + let mapOperation = createMapOperation(dependingOn: mergeOperation, context: context, filter: filter) + + mapOperation.addDependency(mergeOperation) + + let dependencies = sourceOperations + [mergeOperation] + + return CompoundOperationWrapper(targetOperation: mapOperation, dependencies: dependencies) + } +} diff --git a/fearless/Common/Network/Wallet/TransactionHistoryContext.swift b/fearless/Common/Network/Wallet/TransactionHistoryContext.swift index e1028dacc..1b152a200 100644 --- a/fearless/Common/Network/Wallet/TransactionHistoryContext.swift +++ b/fearless/Common/Network/Wallet/TransactionHistoryContext.swift @@ -1,39 +1,217 @@ import Foundation -enum TransactionContextKeys { - static let extrinsicHash = "extrinsicHash" - static let era = "era" +struct TransactionHistorySourceContext { + static let pageKey = "history.page" + static let rowKey = "history.row" + static let completeKey = "history.complete" + + let page: Int + let row: Int + let isComplete: Bool + let keySuffix: String + + init(context: [String: String], defaultRow: Int, keySuffix: String) { + self.keySuffix = keySuffix + page = Self.extract(for: Self.pageKey + keySuffix, from: context, defaultValue: 0) + row = Self.extract(for: Self.rowKey + keySuffix, from: context, defaultValue: defaultRow) + isComplete = Self.extract(for: Self.completeKey + keySuffix, from: context, defaultValue: false) + } + + init( + page: Int, + row: Int, + isComplete: Bool, + keySuffix: String + ) { + self.page = page + self.row = row + self.isComplete = isComplete + self.keySuffix = keySuffix + } + + func toContext() -> [String: String] { + [ + Self.pageKey + keySuffix: String(page), + Self.rowKey + keySuffix: String(row), + Self.completeKey + keySuffix: String(isComplete) + ] + } + + func byReplacingPage(_ newPage: Int) -> TransactionHistorySourceContext { + TransactionHistorySourceContext( + page: newPage, + row: row, + isComplete: isComplete, + keySuffix: keySuffix + ) + } + + func byReplacingRow(_ newRow: Int) -> TransactionHistorySourceContext { + TransactionHistorySourceContext( + page: page, + row: newRow, + isComplete: isComplete, + keySuffix: keySuffix + ) + } + + func byReplacingCompletion(_ newCompletion: Bool) -> TransactionHistorySourceContext { + TransactionHistorySourceContext( + page: page, + row: row, + isComplete: newCompletion, + keySuffix: keySuffix + ) + } + + private static func extract( + for key: String, + from context: [String: String], + defaultValue: T + ) -> T { + if let completeString = context[key], let value = T(completeString) { + return value + } else { + return defaultValue + } + } } struct TransactionHistoryContext { - static let cursor = "cursor" - static let isComplete = "isComplete" + static let transfersSuffix = ".transfers" + static let rewardsSuffix = ".rewards" + static let extrinsicsSuffix = ".extrinsics" - let cursor: String? - let isComplete: Bool + let transfers: TransactionHistorySourceContext + let rewards: TransactionHistorySourceContext + let extrinsics: TransactionHistorySourceContext + let defaultRow: Int + + var isComplete: Bool { transfers.isComplete && rewards.isComplete && extrinsics.isComplete } init( - cursor: String?, - isComplete: Bool + transfers: TransactionHistorySourceContext, + rewards: TransactionHistorySourceContext, + extrinsics: TransactionHistorySourceContext, + defaultRow: Int ) { - self.isComplete = isComplete - self.cursor = cursor + self.transfers = transfers + self.rewards = rewards + self.extrinsics = extrinsics + self.defaultRow = defaultRow } } extension TransactionHistoryContext { - init(context: [String: String]) { - cursor = context[Self.cursor] ?? nil - isComplete = context[Self.isComplete].map { Bool($0) ?? false } ?? false + init(context: [String: String], defaultRow: Int) { + self.defaultRow = defaultRow + + transfers = TransactionHistorySourceContext( + context: context, + defaultRow: defaultRow, + keySuffix: Self.transfersSuffix + ) + + rewards = TransactionHistorySourceContext( + context: context, + defaultRow: defaultRow, + keySuffix: Self.rewardsSuffix + ) + + extrinsics = TransactionHistorySourceContext( + context: context, + defaultRow: defaultRow, + keySuffix: Self.extrinsicsSuffix + ) } func toContext() -> [String: String] { - var context = [Self.isComplete: String(isComplete)] + [transfers, rewards, extrinsics].reduce([String: String]()) { result, item in + result.merging(item.toContext()) { str1, _ in str1 } + } + } + + func byReplacingTransfers(_ value: TransactionHistorySourceContext) -> TransactionHistoryContext { + TransactionHistoryContext( + transfers: value, + rewards: rewards, + extrinsics: extrinsics, + defaultRow: defaultRow + ) + } + + func byReplacingRewards(_ value: TransactionHistorySourceContext) -> TransactionHistoryContext { + TransactionHistoryContext( + transfers: transfers, + rewards: value, + extrinsics: extrinsics, + defaultRow: defaultRow + ) + } - if let cursor = cursor { - context[Self.cursor] = cursor + func byReplacingExtrinsics(_ value: TransactionHistorySourceContext) -> TransactionHistoryContext { + TransactionHistoryContext( + transfers: transfers, + rewards: rewards, + extrinsics: value, + defaultRow: defaultRow + ) + } + + func sourceContext(for label: WalletRemoteHistorySourceLabel) -> TransactionHistorySourceContext { + switch label { + case .transfers: + return transfers + case .rewards: + return rewards + case .extrinsics: + return extrinsics + } + } + + func byReplacingSource( + context: TransactionHistorySourceContext, + for label: WalletRemoteHistorySourceLabel + ) -> TransactionHistoryContext { + switch label { + case .transfers: + return byReplacingTransfers(context) + case .rewards: + return byReplacingRewards(context) + case .extrinsics: + return byReplacingExtrinsics(context) } + } - return context + func byApplying(filter: WalletHistoryFilter) -> TransactionHistoryContext { + WalletRemoteHistorySourceLabel.allCases.reduce(self) { context, source in + context.byApplyingIfNeeded(filter: filter, for: source) + } + } + + private func byApplyingIfNeeded( + filter: WalletHistoryFilter, + for label: WalletRemoteHistorySourceLabel + ) -> TransactionHistoryContext { + switch label { + case .transfers: + if !filter.contains(.transfers) { + return byReplacingTransfers(transfers.byReplacingCompletion(true)) + } else { + return self + } + case .rewards: + if !filter.contains(.rewardsAndSlashes) { + return byReplacingRewards(rewards.byReplacingCompletion(true)) + } else { + return self + } + case .extrinsics: + if !filter.contains(.extrinsics) { + return byReplacingExtrinsics(extrinsics.byReplacingCompletion(true)) + } else { + return self + } + } } } diff --git a/fearless/Common/Network/Wallet/WalletNetworkFacade+Protocol.swift b/fearless/Common/Network/Wallet/WalletNetworkFacade+Protocol.swift index f116e566c..3faeb5121 100644 --- a/fearless/Common/Network/Wallet/WalletNetworkFacade+Protocol.swift +++ b/fearless/Common/Network/Wallet/WalletNetworkFacade+Protocol.swift @@ -115,7 +115,10 @@ extension WalletNetworkFacade: WalletNetworkOperationFactoryProtocol { ) -> CompoundOperationWrapper { let filter = WalletHistoryFilter(string: request.filter) - let historyContext = TransactionHistoryContext(context: pagination.context ?? [:]) + let historyContext = TransactionHistoryContext( + context: pagination.context ?? [:], + defaultRow: pagination.count + ).byApplying(filter: filter) guard !historyContext.isComplete, let asset = accountSettings.assets.first(where: { $0.identifier != totalPriceAssetId.rawValue }), @@ -133,10 +136,10 @@ extension WalletNetworkFacade: WalletNetworkOperationFactoryProtocol { let remoteHistoryWrapper: CompoundOperationWrapper - if let url = assetId.subqueryHistoryUrl { - let remoteHistoryFactory = SubqueryHistoryOperationFactory( - url: url, - filter: filter + if let baseUrl = assetId.subscanUrl { + let remoteHistoryFactory = SubscanHistoryOperationFactory( + baseURL: baseUrl, + filter: WalletRemoteHistoryClosureFilter.transfersInExtrinsics ) remoteHistoryWrapper = remoteHistoryFactory.createOperationWrapper( @@ -145,7 +148,7 @@ extension WalletNetworkFacade: WalletNetworkOperationFactoryProtocol { count: pagination.count ) } else { - let context = TransactionHistoryContext(context: [:]) + let context = TransactionHistoryContext(context: [:], defaultRow: 0) let result = WalletRemoteHistoryData(historyItems: [], context: context) remoteHistoryWrapper = CompoundOperationWrapper.createWithResult(result) } diff --git a/fearless/Common/Network/Wallet/WalletNetworkFacade+TxHistory.swift b/fearless/Common/Network/Wallet/WalletNetworkFacade+TxHistory.swift index d3874fcce..d35a7722a 100644 --- a/fearless/Common/Network/Wallet/WalletNetworkFacade+TxHistory.swift +++ b/fearless/Common/Network/Wallet/WalletNetworkFacade+TxHistory.swift @@ -25,7 +25,7 @@ extension WalletNetworkFacade { addressFactory: addressFactory ) return manager.merge( - remoteItems: remoteTransactions, + subscanItems: remoteTransactions, localItems: localTransactions ) } else { diff --git a/fearless/Common/Network/Wallet/WalletRemoteHistoryFiltering.swift b/fearless/Common/Network/Wallet/WalletRemoteHistoryFiltering.swift new file mode 100644 index 000000000..f3bc8ce59 --- /dev/null +++ b/fearless/Common/Network/Wallet/WalletRemoteHistoryFiltering.swift @@ -0,0 +1,33 @@ +import Foundation + +protocol WalletRemoteHistoryFiltering { + func includes(item: WalletRemoteHistoryItemProtocol) -> Bool +} + +final class WalletRemoteHistoryClosureFilter: WalletRemoteHistoryFiltering { + let block: (WalletRemoteHistoryItemProtocol) -> Bool + + init(block: @escaping (WalletRemoteHistoryItemProtocol) -> Bool) { + self.block = block + } + + func includes(item: WalletRemoteHistoryItemProtocol) -> Bool { + block(item) + } +} + +extension WalletRemoteHistoryClosureFilter { + static var transfersInExtrinsics: WalletRemoteHistoryClosureFilter { + let module = "balances" + let calls = ["transfer", "transfer_keep_alive", "force_transfer"] + + return WalletRemoteHistoryClosureFilter { item in + guard let extrinsic = item as? SubscanConcreteExtrinsicsItemData else { + return true + } + + return !(extrinsic.callModule.lowercased() == module && + calls.contains(extrinsic.callFunction.lowercased())) + } + } +} diff --git a/fearless/Common/Network/Wallet/WalletRemoteHistoryProtocols.swift b/fearless/Common/Network/Wallet/WalletRemoteHistoryProtocols.swift index d1b47c740..212277905 100644 --- a/fearless/Common/Network/Wallet/WalletRemoteHistoryProtocols.swift +++ b/fearless/Common/Network/Wallet/WalletRemoteHistoryProtocols.swift @@ -13,7 +13,6 @@ protocol WalletRemoteHistoryItemProtocol { var identifier: String { get } var itemBlockNumber: UInt64 { get } var itemExtrinsicIndex: UInt16 { get } - var extrinsicHash: String? { get } var itemTimestamp: Int64 { get } var label: WalletRemoteHistorySourceLabel { get } diff --git a/fearless/Common/Services/ExtrinsicService/ExtrinsicServiceFactory.swift b/fearless/Common/Services/ExtrinsicService/ExtrinsicServiceFactory.swift index ff1886841..9c65996d4 100644 --- a/fearless/Common/Services/ExtrinsicService/ExtrinsicServiceFactory.swift +++ b/fearless/Common/Services/ExtrinsicService/ExtrinsicServiceFactory.swift @@ -40,7 +40,7 @@ extension ExtrinsicServiceFactory: ExtrinsicServiceFactoryProtocol { accountItem: AccountItem, connectionItem: ConnectionItem ) -> SigningWrapperProtocol { - var settings = InMemorySettingsManager() + let settings = InMemorySettingsManager() settings.selectedAccount = accountItem settings.selectedConnection = connectionItem diff --git a/fearless/Modules/Staking/SelectValidatorsFlow/SelectValidatorsConfirm/SelectValidatorsConfirmViewFactory.swift b/fearless/Modules/Staking/SelectValidatorsFlow/SelectValidatorsConfirm/SelectValidatorsConfirmViewFactory.swift index a4b9b82c2..a3fe15390 100644 --- a/fearless/Modules/Staking/SelectValidatorsFlow/SelectValidatorsConfirm/SelectValidatorsConfirmViewFactory.swift +++ b/fearless/Modules/Staking/SelectValidatorsFlow/SelectValidatorsConfirm/SelectValidatorsConfirmViewFactory.swift @@ -211,7 +211,7 @@ final class SelectValidatorsConfirmViewFactory: SelectValidatorsConfirmViewFacto operationManager: operationManager ) - var controllerSettings = InMemorySettingsManager() + let controllerSettings = InMemorySettingsManager() controllerSettings.selectedAccount = nomination.bonding.controllerAccount controllerSettings.selectedConnection = networkSettings diff --git a/fearless/Modules/Wallet/TransactionDetails/TransactionDetailsConfigurator.swift b/fearless/Modules/Wallet/TransactionDetails/TransactionDetailsConfigurator.swift index 32d235465..572ca8be3 100644 --- a/fearless/Modules/Wallet/TransactionDetails/TransactionDetailsConfigurator.swift +++ b/fearless/Modules/Wallet/TransactionDetails/TransactionDetailsConfigurator.swift @@ -13,8 +13,7 @@ final class TransactionDetailsConfigurator { address: address, assets: assets, dateFormatter: DateFormatter.txDetails, - amountFormatterFactory: amountFormatterFactory, - quantityFormatter: NumberFormatter.quantity.localizableResource() + amountFormatterFactory: amountFormatterFactory ) } diff --git a/fearless/Modules/Wallet/TransactionDetails/TransactionDetailsViewModelFactory+RewardsAndSlashes.swift b/fearless/Modules/Wallet/TransactionDetails/TransactionDetailsViewModelFactory+RewardsAndSlashes.swift index 1d02e0e84..874bc9a54 100644 --- a/fearless/Modules/Wallet/TransactionDetails/TransactionDetailsViewModelFactory+RewardsAndSlashes.swift +++ b/fearless/Modules/Wallet/TransactionDetails/TransactionDetailsViewModelFactory+RewardsAndSlashes.swift @@ -25,17 +25,8 @@ extension TransactionDetailsViewModelFactory { locale: locale ) - populateValidatorId( - in: &viewModels, - data: data, - chain: chain, - commandFactory: commandFactory, - locale: locale - ) - populateStatus(into: &viewModels, data: data, locale: locale) populateTime(into: &viewModels, data: data, locale: locale) - populateEra(into: &viewModels, data: data, locale: locale) let title = isReward ? R.string.localizable.stakingReward(preferredLanguages: locale.rLanguages) : @@ -60,12 +51,13 @@ extension TransactionDetailsViewModelFactory { commandFactory: WalletCommandFactoryProtocol, locale: Locale ) { - let title = R.string.localizable.stakingCommonEventId(preferredLanguages: locale.rLanguages) + let title = R.string.localizable + .transactionDetailsHashTitle(preferredLanguages: locale.rLanguages) let actionIcon = R.image.iconMore() - let command = WalletEventOpenCommand( - eventId: data.transactionId, + let command = WalletExtrinsicOpenCommand( + extrinsicHash: data.peerId, chain: chain, commandFactory: commandFactory, locale: locale @@ -73,60 +65,12 @@ extension TransactionDetailsViewModelFactory { let viewModel = WalletCompoundDetailsViewModel( title: title, - details: data.transactionId, + details: data.peerId, mainIcon: nil, actionIcon: actionIcon, command: command, enabled: true ) - viewModelList.append(viewModel) } - - func populateValidatorId( - in viewModelList: inout [WalletFormViewBindingProtocol], - data: AssetTransactionData, - chain: Chain, - commandFactory: WalletCommandFactoryProtocol, - locale: Locale - ) { - let title = R.string.localizable.stakingCommonValidator(preferredLanguages: locale.rLanguages) - - populatePeerViewModel( - in: &viewModelList, - title: title, - address: data.peerId, - chain: chain, - commandFactory: commandFactory, - locale: locale - ) - } - - func populateEra( - into viewModelList: inout [WalletFormViewBindingProtocol], - data: AssetTransactionData, - locale: Locale - ) { - guard - let eraString = data.context?[TransactionContextKeys.era], - let era = EraIndex(eraString), - let displayEra = quantityFormatter.value(for: locale) - .string(from: NSNumber(value: era)) else { - return - } - - let title = R.string.localizable.stakingCommonEra(preferredLanguages: locale.rLanguages) - - let details = "#\(displayEra)" - - let viewModel = WalletNewFormDetailsViewModel( - title: title, - titleIcon: nil, - details: details, - detailsIcon: nil - ) - - let separator = WalletFormSeparatedViewModel(content: viewModel, borderType: [.bottom]) - viewModelList.append(separator) - } } diff --git a/fearless/Modules/Wallet/TransactionDetails/TransactionDetailsViewModelFactory.swift b/fearless/Modules/Wallet/TransactionDetails/TransactionDetailsViewModelFactory.swift index 2d57e1693..8028595c1 100644 --- a/fearless/Modules/Wallet/TransactionDetails/TransactionDetailsViewModelFactory.swift +++ b/fearless/Modules/Wallet/TransactionDetails/TransactionDetailsViewModelFactory.swift @@ -7,7 +7,6 @@ final class TransactionDetailsViewModelFactory { let address: String let amountFormatterFactory: NumberFormatterFactoryProtocol let dateFormatter: LocalizableResource - let quantityFormatter: LocalizableResource let assets: [WalletAsset] let iconGenerator = PolkadotIconGenerator() @@ -16,14 +15,12 @@ final class TransactionDetailsViewModelFactory { address: String, assets: [WalletAsset], dateFormatter: LocalizableResource, - amountFormatterFactory: NumberFormatterFactoryProtocol, - quantityFormatter: LocalizableResource + amountFormatterFactory: NumberFormatterFactoryProtocol ) { self.address = address self.assets = assets self.dateFormatter = dateFormatter self.amountFormatterFactory = amountFormatterFactory - self.quantityFormatter = quantityFormatter } func populateStatus( @@ -172,17 +169,13 @@ final class TransactionDetailsViewModelFactory { commandFactory: WalletCommandFactoryProtocol, locale: Locale ) { - guard let extrinsicHash = data.context?[TransactionContextKeys.extrinsicHash] else { - return - } - let title = R.string.localizable .transactionDetailsHashTitle(preferredLanguages: locale.rLanguages) let actionIcon = R.image.iconMore() let command = WalletExtrinsicOpenCommand( - extrinsicHash: extrinsicHash, + extrinsicHash: data.transactionId, chain: chain, commandFactory: commandFactory, locale: locale @@ -190,13 +183,12 @@ final class TransactionDetailsViewModelFactory { let viewModel = WalletCompoundDetailsViewModel( title: title, - details: extrinsicHash, + details: data.transactionId, mainIcon: nil, actionIcon: actionIcon, command: command, enabled: true ) - viewModelList.append(viewModel) } From f4be42de4e9050f7f9c63374f4edefbb16865621 Mon Sep 17 00:00:00 2001 From: Russel Date: Fri, 3 Sep 2021 17:57:08 +0300 Subject: [PATCH 2/6] replace total rewards with single request to subquery --- fearless.xcodeproj/project.pbxproj | 16 +-- .../SingleValueProviderFactory.swift | 7 +- .../Rewards/SubqueryRewardSource.swift | 129 +++--------------- fearless/Common/Model/TotalRewardItem.swift | 1 - .../Subquery/Data/SubqueryHistory.swift | 8 ++ .../SubqueryRewardOperationFactory.swift | 74 ++++++++++ .../DataProvider/RewardDataSourceTests.swift | 33 ++--- fearlessTests/Helper/WestendStub.swift | 1 - .../Mocks/Network/TotalRewardMock.swift | 9 +- .../Resources/rewardFirstResponse.json | 1 - fearlessTests/Resources/rewardResponse.json | 1 + .../Resources/rewardSecondResponse.json | 1 - 12 files changed, 127 insertions(+), 154 deletions(-) create mode 100644 fearless/Common/Network/Subquery/SubqueryRewardOperationFactory.swift delete mode 100644 fearlessTests/Resources/rewardFirstResponse.json create mode 100644 fearlessTests/Resources/rewardResponse.json delete mode 100644 fearlessTests/Resources/rewardSecondResponse.json diff --git a/fearless.xcodeproj/project.pbxproj b/fearless.xcodeproj/project.pbxproj index d20cc0525..28dde6513 100644 --- a/fearless.xcodeproj/project.pbxproj +++ b/fearless.xcodeproj/project.pbxproj @@ -323,6 +323,7 @@ 843461CB26E2590200DCE0CD /* SubscanHistoryOperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843461CA26E2590200DCE0CD /* SubscanHistoryOperationFactory.swift */; }; 843461CD26E2596E00DCE0CD /* WalletRemoteHistoryFiltering.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843461CC26E2596E00DCE0CD /* WalletRemoteHistoryFiltering.swift */; }; 843461CF26E25AD400DCE0CD /* SubscanHistoryItem+Wallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843461CE26E25AD400DCE0CD /* SubscanHistoryItem+Wallet.swift */; }; + 843461D126E2641500DCE0CD /* SubqueryRewardOperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843461D026E2641500DCE0CD /* SubqueryRewardOperationFactory.swift */; }; 8434C9E425401EF3009E4191 /* TransactionHistoryItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8434C9E325401EF3009E4191 /* TransactionHistoryItem.swift */; }; 8434C9E625403686009E4191 /* CDTransactionHistoryItem+CoreDataDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8434C9E525403686009E4191 /* CDTransactionHistoryItem+CoreDataDecodable.swift */; }; 8434C9EA2540AE51009E4191 /* ExtrinsicEraTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8434C9E92540AE51009E4191 /* ExtrinsicEraTests.swift */; }; @@ -641,8 +642,7 @@ 8489EDD4264DDF6C00FF997E /* InconsistentStateMigrator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8489EDD3264DDF6C00FF997E /* InconsistentStateMigrator.swift */; }; 8489EDDA264DE42500FF997E /* InconsistentStateMigrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8489EDD9264DE42500FF997E /* InconsistentStateMigrationTests.swift */; }; 848C3D0926248A3B005481C3 /* TransferCall.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848C3D0826248A3B005481C3 /* TransferCall.swift */; }; - 848DB98E260638340055DDE7 /* rewardFirstResponse.json in Resources */ = {isa = PBXBuildFile; fileRef = 848DB98D260638340055DDE7 /* rewardFirstResponse.json */; }; - 848DB993260638440055DDE7 /* rewardSecondResponse.json in Resources */ = {isa = PBXBuildFile; fileRef = 848DB992260638440055DDE7 /* rewardSecondResponse.json */; }; + 848DB993260638440055DDE7 /* rewardResponse.json in Resources */ = {isa = PBXBuildFile; fileRef = 848DB992260638440055DDE7 /* rewardResponse.json */; }; 848DB998260639C70055DDE7 /* TotalRewardMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848DB997260639C70055DDE7 /* TotalRewardMock.swift */; }; 848DB99E26063BC40055DDE7 /* RewardDataSourceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848DB99D26063BC40055DDE7 /* RewardDataSourceTests.swift */; }; 848EAEB02659310A00676CEA /* CrowdloanStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 848EAEAF2659310A00676CEA /* CrowdloanStatus.swift */; }; @@ -1769,6 +1769,7 @@ 843461CA26E2590200DCE0CD /* SubscanHistoryOperationFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscanHistoryOperationFactory.swift; sourceTree = ""; }; 843461CC26E2596E00DCE0CD /* WalletRemoteHistoryFiltering.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletRemoteHistoryFiltering.swift; sourceTree = ""; }; 843461CE26E25AD400DCE0CD /* SubscanHistoryItem+Wallet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SubscanHistoryItem+Wallet.swift"; sourceTree = ""; }; + 843461D026E2641500DCE0CD /* SubqueryRewardOperationFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubqueryRewardOperationFactory.swift; sourceTree = ""; }; 8434C9E325401EF3009E4191 /* TransactionHistoryItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransactionHistoryItem.swift; sourceTree = ""; }; 8434C9E525403686009E4191 /* CDTransactionHistoryItem+CoreDataDecodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CDTransactionHistoryItem+CoreDataDecodable.swift"; sourceTree = ""; }; 8434C9E92540AE51009E4191 /* ExtrinsicEraTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtrinsicEraTests.swift; sourceTree = ""; }; @@ -2090,8 +2091,7 @@ 8489EDD3264DDF6C00FF997E /* InconsistentStateMigrator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InconsistentStateMigrator.swift; sourceTree = ""; }; 8489EDD9264DE42500FF997E /* InconsistentStateMigrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InconsistentStateMigrationTests.swift; sourceTree = ""; }; 848C3D0826248A3B005481C3 /* TransferCall.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransferCall.swift; sourceTree = ""; }; - 848DB98D260638340055DDE7 /* rewardFirstResponse.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = rewardFirstResponse.json; sourceTree = ""; }; - 848DB992260638440055DDE7 /* rewardSecondResponse.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = rewardSecondResponse.json; sourceTree = ""; }; + 848DB992260638440055DDE7 /* rewardResponse.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = rewardResponse.json; sourceTree = ""; }; 848DB997260639C70055DDE7 /* TotalRewardMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TotalRewardMock.swift; sourceTree = ""; }; 848DB99D26063BC40055DDE7 /* RewardDataSourceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RewardDataSourceTests.swift; sourceTree = ""; }; 848EAEAF2659310A00676CEA /* CrowdloanStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdloanStatus.swift; sourceTree = ""; }; @@ -5564,6 +5564,7 @@ children = ( 849AFEBB26DCCDDD00B65924 /* Data */, 84412EE026DAC3300049577A /* SubqueryHistoryOperationFactory.swift */, + 843461D026E2641500DCE0CD /* SubqueryRewardOperationFactory.swift */, ); path = Subquery; sourceTree = ""; @@ -6247,8 +6248,7 @@ children = ( 84F438B125DA548700AEDA56 /* runtimeTestMetadata */, 84FACB2C25F562CB00F32ED4 /* westend-metadata */, - 848DB98D260638340055DDE7 /* rewardFirstResponse.json */, - 848DB992260638440055DDE7 /* rewardSecondResponse.json */, + 848DB992260638440055DDE7 /* rewardResponse.json */, 846B32A426DD07AF00250E89 /* rewardErrorResponse.json */, ); path = Resources; @@ -7489,13 +7489,12 @@ files = ( 84FACB2D25F562CB00F32ED4 /* westend-metadata in Resources */, 846B32A526DD07AF00250E89 /* rewardErrorResponse.json in Resources */, - 848DB993260638440055DDE7 /* rewardSecondResponse.json in Resources */, + 848DB993260638440055DDE7 /* rewardResponse.json in Resources */, 8467FD0624E5E0A5005D486C /* invalidKeystore.json in Resources */, 84F438B225DA548700AEDA56 /* runtimeTestMetadata in Resources */, 8467FD3F24EAD66F005D486C /* validEcdsaKeystore.json in Resources */, 8467FD0A24E5E258005D486C /* validSrKeystore.json in Resources */, 8467FD3E24EAD66F005D486C /* validEd25519Keystore.json in Resources */, - 848DB98E260638340055DDE7 /* rewardFirstResponse.json in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -8047,6 +8046,7 @@ AEE5FB0126415E2A002B8FDC /* StakingRebondSetupInteractor.swift in Sources */, 84C1B98624F5424700FE5470 /* ManagedAccountViewModelFactory.swift in Sources */, AEE5FB1026457806002B8FDC /* StakingRewardDestSetupViewFactory.swift in Sources */, + 843461D126E2641500DCE0CD /* SubqueryRewardOperationFactory.swift in Sources */, 840882B82514A68100177E20 /* SelectConnection+AccountCreateWireframe.swift in Sources */, 849ABE49262763BB00011A2A /* Longrun.swift in Sources */, 84644A30256722D2004EAA4B /* TriangularedBlurButton+Inspectable.swift in Sources */, diff --git a/fearless/Common/DataProvider/SingleValueProviderFactory.swift b/fearless/Common/DataProvider/SingleValueProviderFactory.swift index 5bd5da087..5f04fbb1e 100644 --- a/fearless/Common/DataProvider/SingleValueProviderFactory.swift +++ b/fearless/Common/DataProvider/SingleValueProviderFactory.swift @@ -221,7 +221,7 @@ extension SingleValueProviderFactory: SingleValueProviderFactoryProtocol { ) throws -> AnySingleValueProvider { clearIfNeeded() - guard let historyURL = assetId.subqueryHistoryUrl else { + guard let url = assetId.subqueryHistoryUrl else { throw DataProviderError.unexpectedSourceResult } @@ -240,10 +240,7 @@ extension SingleValueProviderFactory: SingleValueProviderFactoryProtocol { let trigger = DataProviderProxyTrigger() - let operationFactory = SubqueryHistoryOperationFactory( - url: historyURL, - filter: [.rewardsAndSlashes] - ) + let operationFactory = SubqueryRewardOperationFactory(url: url) let source = SubqueryRewardSource( address: address, diff --git a/fearless/Common/DataProvider/Sources/Rewards/SubqueryRewardSource.swift b/fearless/Common/DataProvider/Sources/Rewards/SubqueryRewardSource.swift index 9149689c4..aefef83fe 100644 --- a/fearless/Common/DataProvider/Sources/Rewards/SubqueryRewardSource.swift +++ b/fearless/Common/DataProvider/Sources/Rewards/SubqueryRewardSource.swift @@ -6,24 +6,17 @@ import CommonWallet final class SubqueryRewardSource { typealias Model = TotalRewardItem - struct SyncState { - let lastId: String? - let receivedCount: Int - let reward: Decimal? - } - let address: String let chain: Chain let targetIdentifier: String let repository: AnyDataProviderRepository - let operationFactory: SubqueryHistoryOperationFactoryProtocol + let operationFactory: SubqueryRewardOperationFactoryProtocol let trigger: DataProviderTriggerProtocol let operationManager: OperationManagerProtocol - let pageSize: Int let logger: LoggerProtocol? private var lastSyncError: Error? - private var syncing: SyncState? + private var syncing: Bool = false private var totalReward: TotalRewardItem? private let mutex = NSLock() @@ -32,10 +25,9 @@ final class SubqueryRewardSource { chain: Chain, targetIdentifier: String, repository: AnyDataProviderRepository, - operationFactory: SubqueryHistoryOperationFactoryProtocol, + operationFactory: SubqueryRewardOperationFactoryProtocol, trigger: DataProviderTriggerProtocol, operationManager: OperationManagerProtocol, - pageSize: Int = 100, logger: LoggerProtocol? = nil ) { self.address = address @@ -45,7 +37,6 @@ final class SubqueryRewardSource { self.operationFactory = operationFactory self.trigger = trigger self.operationManager = operationManager - self.pageSize = pageSize self.logger = logger sync() @@ -74,34 +65,19 @@ final class SubqueryRewardSource { } private func sync() { - guard syncing == nil else { + guard !syncing else { return } - syncing = SyncState( - lastId: nil, - receivedCount: 0, - reward: nil - ) + syncing = true - fetch(cursor: nil) + fetch() } - private func fetch(cursor: String?) { - let localWrapper = createLocalFetchWrapper() - - let remoteOperation = operationFactory.createOperation( - address: address, - count: pageSize, - cursor: cursor - ) - - let syncOperation = Operation() + private func fetch() { + let remoteOperation = operationFactory.createOperation(address: address) - localWrapper.allOperations.forEach { syncOperation.addDependency($0) } - syncOperation.addDependency(remoteOperation) - - syncOperation.completionBlock = { + remoteOperation.completionBlock = { DispatchQueue.global(qos: .userInitiated).async { self.mutex.lock() @@ -109,96 +85,30 @@ final class SubqueryRewardSource { self.mutex.unlock() } - self.processOperations( - localWrapper.targetOperation, - remoteOperation: remoteOperation, - cursor: cursor - ) + self.processOperations(remoteOperation: remoteOperation) } } - let allOperations = localWrapper.allOperations + [remoteOperation, syncOperation] - operationManager.enqueue(operations: allOperations, in: .transient) + operationManager.enqueue(operations: [remoteOperation], in: .transient) } - private func processOperations( - _ localOperation: BaseOperation, - remoteOperation: BaseOperation, - cursor _: String? - ) { + private func processOperations(remoteOperation: BaseOperation) { do { - let totalReward = try localOperation.extractNoCancellableResultData() let remoteData = try remoteOperation.extractNoCancellableResultData() + let newReward = calculateReward(from: remoteData.historyElements.nodes) - let endIndex: Int? - - if let reward = totalReward { - endIndex = remoteData.historyElements.nodes.firstIndex { - $0.identifier == reward.lastId - } - } else { - endIndex = nil - } - - let allRemoteItems = remoteData.historyElements.nodes - let count = endIndex ?? allRemoteItems.count - - let newRemoteItems = Array(allRemoteItems[0 ..< count]) - let pageReward = calculateReward(from: newRemoteItems) - - let receivedCount = (syncing?.receivedCount ?? 0) + newRemoteItems.count - - syncing = SyncState( - lastId: syncing?.lastId ?? newRemoteItems.first?.identifier, - receivedCount: receivedCount, - reward: (syncing?.reward ?? 0.0) + pageReward - ) - - logger?.debug("Synced id: \(String(describing: allRemoteItems.last?.identifier))") - logger?.debug("Persistent id: \(String(describing: totalReward?.lastId))") - logger?.debug("Page reward: \(pageReward)") - - let newCursor = remoteData.historyElements.pageInfo.endCursor - - if endIndex != nil || newCursor == nil { - finalize(with: totalReward) - } else { - fetch(cursor: newCursor) - } + logger?.debug("New total reward: \(newReward)") + finalize(with: newReward) } catch { finalize(with: error) } } - private func finalize(with previousReward: TotalRewardItem?) { - guard let syncState = syncing else { - logger?.warning("Can't finalize sync because of nil") - return - } + private func finalize(with newReward: Decimal) { + syncing = false - if let lastId = syncState.lastId, let reward = syncState.reward { - let newAmount = reward + (previousReward?.amount.decimalValue ?? 0.0) - totalReward = TotalRewardItem( - address: address, - lastId: lastId, - amount: AmountDecimal(value: newAmount) - ) - - syncing = nil - - logger?.debug("Did receive new reward: \(reward)") - } else { - logger?.debug("Sync completed: nothing changed") - - totalReward = TotalRewardItem( - address: address, - lastId: previousReward?.lastId ?? "", - amount: previousReward?.amount ?? AmountDecimal(value: 0.0) - ) - - syncing = nil - } + totalReward = TotalRewardItem(address: address, amount: AmountDecimal(value: newReward)) DispatchQueue.global().async { self.trigger.delegate?.didTrigger() @@ -206,7 +116,6 @@ final class SubqueryRewardSource { } private func restartSync() { - syncing = nil totalReward = nil lastSyncError = nil @@ -220,7 +129,7 @@ final class SubqueryRewardSource { private func finalize(with error: Error) { totalReward = nil lastSyncError = error - syncing = nil + syncing = false logger?.error("Did receive sync error: \(error)") diff --git a/fearless/Common/Model/TotalRewardItem.swift b/fearless/Common/Model/TotalRewardItem.swift index cb0b0cea6..0fb1ab8c2 100644 --- a/fearless/Common/Model/TotalRewardItem.swift +++ b/fearless/Common/Model/TotalRewardItem.swift @@ -3,6 +3,5 @@ import CommonWallet struct TotalRewardItem: Codable, Equatable { let address: String - let lastId: String let amount: AmountDecimal } diff --git a/fearless/Common/Network/Subquery/Data/SubqueryHistory.swift b/fearless/Common/Network/Subquery/Data/SubqueryHistory.swift index 6ae9f942d..e218e4036 100644 --- a/fearless/Common/Network/Subquery/Data/SubqueryHistory.swift +++ b/fearless/Common/Network/Subquery/Data/SubqueryHistory.swift @@ -69,3 +69,11 @@ struct SubqueryHistoryData: Decodable { let historyElements: HistoryElements } + +struct SubqueryRewardOrSlashData: Decodable { + struct HistoryElements: Decodable { + let nodes: [SubqueryHistoryElement] + } + + let historyElements: HistoryElements +} diff --git a/fearless/Common/Network/Subquery/SubqueryRewardOperationFactory.swift b/fearless/Common/Network/Subquery/SubqueryRewardOperationFactory.swift new file mode 100644 index 000000000..75893c01f --- /dev/null +++ b/fearless/Common/Network/Subquery/SubqueryRewardOperationFactory.swift @@ -0,0 +1,74 @@ +import Foundation +import RobinHood +import FearlessUtils + +protocol SubqueryRewardOperationFactoryProtocol { + func createOperation(address: String) -> BaseOperation +} + +final class SubqueryRewardOperationFactory { + let url: URL + + init(url: URL) { + self.url = url + } + + private func prepareQueryForAddress(_ address: String) -> String { + """ + { + historyElements( + orderBy: TIMESTAMP_DESC, + filter: { + address: { equalTo: \"\(address)\"}, + reward: { isNull: false } + } + ) { + id + timestamp + address + reward + extrinsic + transfer + } + } + """ + } +} + +extension SubqueryRewardOperationFactory: SubqueryRewardOperationFactoryProtocol { + func createOperation(address: String) -> BaseOperation { + let queryString = prepareQueryForAddress(address) + + let requestFactory = BlockNetworkRequestFactory { + var request = URLRequest(url: self.url) + + let info = JSON.dictionaryValue(["query": JSON.stringValue(queryString)]) + request.httpBody = try JSONEncoder().encode(info) + request.setValue( + HttpContentType.json.rawValue, + forHTTPHeaderField: HttpHeaderKey.contentType.rawValue + ) + + request.httpMethod = HttpMethod.post.rawValue + return request + } + + let resultFactory = AnyNetworkResultFactory { data in + let response = try JSONDecoder().decode( + SubqueryResponse.self, + from: data + ) + + switch response { + case let .errors(error): + throw error + case let .data(response): + return response + } + } + + let operation = NetworkOperation(requestFactory: requestFactory, resultFactory: resultFactory) + + return operation + } +} diff --git a/fearlessTests/Common/DataProvider/RewardDataSourceTests.swift b/fearlessTests/Common/DataProvider/RewardDataSourceTests.swift index e6f15785a..310a1a612 100644 --- a/fearlessTests/Common/DataProvider/RewardDataSourceTests.swift +++ b/fearlessTests/Common/DataProvider/RewardDataSourceTests.swift @@ -4,39 +4,31 @@ import RobinHood class RewardDataSourceTests: NetworkBaseTests { - func testCorrectSyncAfterMultipleUpdates() { + func testCorrectSync() { do { // given let storageFacade = SubstrateStorageTestFacade() let url = WalletAssetId.westend.subqueryHistoryUrl - TotalRewardMock.register(mock: .westendFirst, url: url!) + TotalRewardMock.register(mock: .westend, url: url!) - let expectedRewardAfterFirst: Decimal = 2.0 - let expectedRewardAfterSecond: Decimal = 5.0 + let expectedReward: Decimal = 5.0 // when let repository: CoreDataRepository = storageFacade.createRepository() - let rewardAfterFirstCall = try performRewardRequest(for: AnyDataProviderRepository(repository), - address: WestendStub.address, - assetId: .westend, - chain: .westend).get() + let actualRewardItem = try performRewardRequest( + for: AnyDataProviderRepository(repository), + address: WestendStub.address, + assetId: .westend, + chain: .westend + ).get() // then - XCTAssertEqual(rewardAfterFirstCall?.amount.decimalValue, expectedRewardAfterFirst) - - TotalRewardMock.register(mock: .westendSecond, url: url!) - - let rewardAfterSecondCall = try performRewardRequest(for: AnyDataProviderRepository(repository), - address: WestendStub.address, - assetId: .westend, - chain: .westend).get() - - XCTAssertEqual(rewardAfterSecondCall?.amount.decimalValue, expectedRewardAfterSecond) + XCTAssertEqual(expectedReward, actualRewardItem?.amount.decimalValue) } catch { XCTFail("Unexpected error: \(error)") } @@ -83,9 +75,8 @@ class RewardDataSourceTests: NetworkBaseTests { let trigger = DataProviderProxyTrigger() - let operationFactory = SubqueryHistoryOperationFactory( - url: assetId.subqueryHistoryUrl!, - filter: [.rewardsAndSlashes] + let operationFactory = SubqueryRewardOperationFactory( + url: assetId.subqueryHistoryUrl! ) let source = SubqueryRewardSource(address: address, diff --git a/fearlessTests/Helper/WestendStub.swift b/fearlessTests/Helper/WestendStub.swift index 3b133949a..b1175b439 100644 --- a/fearlessTests/Helper/WestendStub.swift +++ b/fearlessTests/Helper/WestendStub.swift @@ -17,7 +17,6 @@ struct WestendStub { static let totalReward: TotalRewardItem = { TotalRewardItem( address: "5DnQFjSrJUiCnDb9mrbbCkGRXwKZc5v31M261PMMTTMFDawq", - lastId: "777-0", amount: AmountDecimal(value: 777) ) }() diff --git a/fearlessTests/Mocks/Network/TotalRewardMock.swift b/fearlessTests/Mocks/Network/TotalRewardMock.swift index 93256f33a..031e12ec2 100644 --- a/fearlessTests/Mocks/Network/TotalRewardMock.swift +++ b/fearlessTests/Mocks/Network/TotalRewardMock.swift @@ -2,8 +2,7 @@ import Foundation import FireMock enum TotalRewardMock: FireMockProtocol { - case westendFirst - case westendSecond + case westend case error var bundle: Bundle { Bundle(for: NetworkBaseTests.self) } @@ -18,10 +17,8 @@ enum TotalRewardMock: FireMockProtocol { func mockFile() -> String { switch self { - case .westendFirst: - return "rewardFirstResponse.json" - case .westendSecond: - return "rewardSecondResponse.json" + case .westend: + return "rewardResponse.json" case .error: return "rewardErrorResponse.json" } diff --git a/fearlessTests/Resources/rewardFirstResponse.json b/fearlessTests/Resources/rewardFirstResponse.json deleted file mode 100644 index ebd7259b3..000000000 --- a/fearlessTests/Resources/rewardFirstResponse.json +++ /dev/null @@ -1 +0,0 @@ -{"data":{"historyElements":{"pageInfo":{"startCursor":"WyJ0aW1lc3RhbXBfZGVzYyIsWyIxNjE3MDk4MjY4IiwiNDk5NTY1Ny0xMjQiXV0=","endCursor":null},"nodes":[{"id":"4995657-124","timestamp":"1617098268","address":"5FCj3BzHo5274Jwd6PFdsGzSgDtQ724k7o7GRYTzAf7n37vk","reward":{"era":3498,"amount":"1000000000000","isReward":true,"validator":"5GNy7frYA4BwWpKwxKAFWt4eBsZ9oAvXrp9SyDj6qzJAaNzB"},"extrinsic":null,"transfer":null},{"id":"4995657-47","timestamp":"1617098268","address":"5FCj3BzHo5274Jwd6PFdsGzSgDtQ724k7o7GRYTzAf7n37vk","reward":{"era":3497,"amount":"1000000000000","isReward":true,"validator":"5GNy7frYA4BwWpKwxKAFWt4eBsZ9oAvXrp9SyDj6qzJAaNzB"},"extrinsic":null,"transfer":null}]}}} diff --git a/fearlessTests/Resources/rewardResponse.json b/fearlessTests/Resources/rewardResponse.json new file mode 100644 index 000000000..c91f7ef39 --- /dev/null +++ b/fearlessTests/Resources/rewardResponse.json @@ -0,0 +1 @@ +{"data":{"historyElements":{"nodes":[{"id":"5004569-100","timestamp":"1617154614","address":"5FCj3BzHo5274Jwd6PFdsGzSgDtQ724k7o7GRYTzAf7n37vk","reward":{"era":3500,"amount":"1000000000000","isReward":true,"validator":"5ECtQ5MLGRMaGgtwUE7WY1zU5P2dnaVdkiFazU3svpNkh3GP"},"extrinsic":null,"transfer":null},{"id":"5004569-47","timestamp":"1617154614","address":"5FCj3BzHo5274Jwd6PFdsGzSgDtQ724k7o7GRYTzAf7n37vk","reward":{"era":3499,"amount":"2000000000000","isReward":true,"validator":"5GNy7frYA4BwWpKwxKAFWt4eBsZ9oAvXrp9SyDj6qzJAaNzB"},"extrinsic":null,"transfer":null},{"id":"4995657-124","timestamp":"1617098268","address":"5FCj3BzHo5274Jwd6PFdsGzSgDtQ724k7o7GRYTzAf7n37vk","reward":{"era":3498,"amount":"1000000000000","isReward":true,"validator":"5GNy7frYA4BwWpKwxKAFWt4eBsZ9oAvXrp9SyDj6qzJAaNzB"},"extrinsic":null,"transfer":null},{"id":"4995657-47","timestamp":"1617098268","address":"5FCj3BzHo5274Jwd6PFdsGzSgDtQ724k7o7GRYTzAf7n37vk","reward":{"era":3497,"amount":"1000000000000","isReward":true,"validator":"5GNy7frYA4BwWpKwxKAFWt4eBsZ9oAvXrp9SyDj6qzJAaNzB"},"extrinsic":null,"transfer":null}]}}} diff --git a/fearlessTests/Resources/rewardSecondResponse.json b/fearlessTests/Resources/rewardSecondResponse.json deleted file mode 100644 index 05e55b4ca..000000000 --- a/fearlessTests/Resources/rewardSecondResponse.json +++ /dev/null @@ -1 +0,0 @@ -{"data":{"historyElements":{"pageInfo":{"startCursor":"WyJ0aW1lc3RhbXBfZGVzYyIsWyIxNjE3MTU0NjE0IiwiNTAwNDU2OS0xMDAiXV0=","endCursor":null},"nodes":[{"id":"5004569-100","timestamp":"1617154614","address":"5FCj3BzHo5274Jwd6PFdsGzSgDtQ724k7o7GRYTzAf7n37vk","reward":{"era":3500,"amount":"1000000000000","isReward":true,"validator":"5ECtQ5MLGRMaGgtwUE7WY1zU5P2dnaVdkiFazU3svpNkh3GP"},"extrinsic":null,"transfer":null},{"id":"5004569-47","timestamp":"1617154614","address":"5FCj3BzHo5274Jwd6PFdsGzSgDtQ724k7o7GRYTzAf7n37vk","reward":{"era":3499,"amount":"2000000000000","isReward":true,"validator":"5GNy7frYA4BwWpKwxKAFWt4eBsZ9oAvXrp9SyDj6qzJAaNzB"},"extrinsic":null,"transfer":null},{"id":"4995657-124","timestamp":"1617098268","address":"5FCj3BzHo5274Jwd6PFdsGzSgDtQ724k7o7GRYTzAf7n37vk","reward":{"era":3498,"amount":"1000000000000","isReward":true,"validator":"5GNy7frYA4BwWpKwxKAFWt4eBsZ9oAvXrp9SyDj6qzJAaNzB"},"extrinsic":null,"transfer":null},{"id":"4995657-47","timestamp":"1617098268","address":"5FCj3BzHo5274Jwd6PFdsGzSgDtQ724k7o7GRYTzAf7n37vk","reward":{"era":3497,"amount":"1000000000000","isReward":true,"validator":"5GNy7frYA4BwWpKwxKAFWt4eBsZ9oAvXrp9SyDj6qzJAaNzB"},"extrinsic":null,"transfer":null}]}}} From c15c13bdff922860234b3eb5733bce622bb9d4c8 Mon Sep 17 00:00:00 2001 From: Russel Date: Fri, 3 Sep 2021 18:18:32 +0300 Subject: [PATCH 3/6] fix subquery request --- .../Subquery/SubqueryRewardOperationFactory.swift | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/fearless/Common/Network/Subquery/SubqueryRewardOperationFactory.swift b/fearless/Common/Network/Subquery/SubqueryRewardOperationFactory.swift index 75893c01f..739d8e2e5 100644 --- a/fearless/Common/Network/Subquery/SubqueryRewardOperationFactory.swift +++ b/fearless/Common/Network/Subquery/SubqueryRewardOperationFactory.swift @@ -23,12 +23,14 @@ final class SubqueryRewardOperationFactory { reward: { isNull: false } } ) { - id - timestamp - address - reward - extrinsic - transfer + nodes { + id + timestamp + address + reward + extrinsic + transfer + } } } """ From a8fb4a889c5dd095303323b4b23ef36d6e726dba Mon Sep 17 00:00:00 2001 From: Russel Date: Fri, 3 Sep 2021 20:55:38 +0300 Subject: [PATCH 4/6] fix review comments --- ...AssetTransactionData+HistoryItemData.swift | 46 +++++++------------ 1 file changed, 17 insertions(+), 29 deletions(-) diff --git a/fearless/Common/Extension/Wallet/AssetTransactionData+HistoryItemData.swift b/fearless/Common/Extension/Wallet/AssetTransactionData+HistoryItemData.swift index 51573f8af..ed878a28a 100644 --- a/fearless/Common/Extension/Wallet/AssetTransactionData+HistoryItemData.swift +++ b/fearless/Common/Extension/Wallet/AssetTransactionData+HistoryItemData.swift @@ -67,20 +67,16 @@ extension AssetTransactionData { from item: SubscanRewardItemData, address: String, networkType: SNAddressType, - asset: WalletAsset, - addressFactory _: SS58AddressFactoryProtocol + asset: WalletAsset ) -> AssetTransactionData { let status: AssetTransactionStatus status = .commited - let amount: Decimal = { - guard let amountValue = BigUInt(item.amount) else { - return 0.0 - } - - return Decimal.fromSubstrateAmount(amountValue, precision: networkType.precision) ?? 0.0 - }() + let amount: Decimal = Decimal.fromSubstrateAmount( + BigUInt(item.amount) ?? 0, + precision: asset.precision + ) ?? .zero let type = TransactionType(rawValue: item.eventId.uppercased()) @@ -109,13 +105,10 @@ extension AssetTransactionData { asset: WalletAsset, addressFactory: SS58AddressFactoryProtocol ) -> AssetTransactionData { - let amount: Decimal = { - guard let amountValue = BigUInt(item.fee) else { - return 0.0 - } - - return Decimal.fromSubstrateAmount(amountValue, precision: networkType.precision) ?? 0.0 - }() + let amount: Decimal = Decimal.fromSubstrateAmount( + BigUInt(item.fee) ?? 0, + precision: asset.precision + ) ?? .zero let accountId = try? addressFactory.accountId( fromAddress: address, @@ -190,13 +183,11 @@ extension AssetTransactionData { ) let peerId = accountId?.toHex() ?? peerAddress - let feeDecimal: Decimal = { - guard let feeValue = BigUInt(item.fee) else { - return .zero - } - return Decimal.fromSubstrateAmount(feeValue, precision: networkType.precision) ?? .zero - }() + let feeDecimal: Decimal = Decimal.fromSubstrateAmount( + BigUInt(item.fee) ?? 0, + precision: asset.precision + ) ?? .zero let fee = AssetTransactionFee( identifier: asset.identifier, @@ -243,13 +234,10 @@ extension AssetTransactionData { asset: WalletAsset, addressFactory: SS58AddressFactoryProtocol ) -> AssetTransactionData { - let amount: Decimal = { - guard let amountValue = BigUInt(item.fee) else { - return 0.0 - } - - return Decimal.fromSubstrateAmount(amountValue, precision: networkType.precision) ?? 0.0 - }() + let amount: Decimal = Decimal.fromSubstrateAmount( + BigUInt(item.fee) ?? 0, + precision: asset.precision + ) ?? .zero let accountId = try? addressFactory.accountId( fromAddress: item.sender, From e3c8b9c05ffb03e791496ca7a516f7262e02b94f Mon Sep 17 00:00:00 2001 From: Russel Date: Fri, 3 Sep 2021 21:14:15 +0300 Subject: [PATCH 5/6] fix patract node --- .../Extension/Model/ConnectionItem+Default.swift | 4 ++-- .../Wallet/AssetTransactionData+HistoryItemData.swift | 10 +++++----- .../Network/Subscan/SubscanHistoryItem+Wallet.swift | 5 ++--- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/fearless/Common/Extension/Model/ConnectionItem+Default.swift b/fearless/Common/Extension/Model/ConnectionItem+Default.swift index 88b538c19..6274583fa 100644 --- a/fearless/Common/Extension/Model/ConnectionItem+Default.swift +++ b/fearless/Common/Extension/Model/ConnectionItem+Default.swift @@ -24,7 +24,7 @@ extension ConnectionItem { ), ConnectionItem( title: "Kusama, Patract node", - url: URL(string: "wss://kusama.elara.patract.io")!, + url: URL(string: "wss://pub.elara.patract.io/kusama")!, type: SNAddressType.kusamaMain ), ConnectionItem( @@ -39,7 +39,7 @@ extension ConnectionItem { ), ConnectionItem( title: "Polkadot, Patract node", - url: URL(string: "wss://polkadot.elara.patract.io")!, + url: URL(string: "wss://pub.elara.patract.io/polkadot")!, type: SNAddressType.polkadotMain ), ConnectionItem( diff --git a/fearless/Common/Extension/Wallet/AssetTransactionData+HistoryItemData.swift b/fearless/Common/Extension/Wallet/AssetTransactionData+HistoryItemData.swift index ed878a28a..69d89aef4 100644 --- a/fearless/Common/Extension/Wallet/AssetTransactionData+HistoryItemData.swift +++ b/fearless/Common/Extension/Wallet/AssetTransactionData+HistoryItemData.swift @@ -66,14 +66,14 @@ extension AssetTransactionData { static func createTransaction( from item: SubscanRewardItemData, address: String, - networkType: SNAddressType, + networkType _: SNAddressType, asset: WalletAsset ) -> AssetTransactionData { let status: AssetTransactionStatus status = .commited - let amount: Decimal = Decimal.fromSubstrateAmount( + let amount = Decimal.fromSubstrateAmount( BigUInt(item.amount) ?? 0, precision: asset.precision ) ?? .zero @@ -105,7 +105,7 @@ extension AssetTransactionData { asset: WalletAsset, addressFactory: SS58AddressFactoryProtocol ) -> AssetTransactionData { - let amount: Decimal = Decimal.fromSubstrateAmount( + let amount = Decimal.fromSubstrateAmount( BigUInt(item.fee) ?? 0, precision: asset.precision ) ?? .zero @@ -184,7 +184,7 @@ extension AssetTransactionData { let peerId = accountId?.toHex() ?? peerAddress - let feeDecimal: Decimal = Decimal.fromSubstrateAmount( + let feeDecimal = Decimal.fromSubstrateAmount( BigUInt(item.fee) ?? 0, precision: asset.precision ) ?? .zero @@ -234,7 +234,7 @@ extension AssetTransactionData { asset: WalletAsset, addressFactory: SS58AddressFactoryProtocol ) -> AssetTransactionData { - let amount: Decimal = Decimal.fromSubstrateAmount( + let amount = Decimal.fromSubstrateAmount( BigUInt(item.fee) ?? 0, precision: asset.precision ) ?? .zero diff --git a/fearless/Common/Network/Subscan/SubscanHistoryItem+Wallet.swift b/fearless/Common/Network/Subscan/SubscanHistoryItem+Wallet.swift index eac7348f2..9cbef8a02 100644 --- a/fearless/Common/Network/Subscan/SubscanHistoryItem+Wallet.swift +++ b/fearless/Common/Network/Subscan/SubscanHistoryItem+Wallet.swift @@ -13,14 +13,13 @@ extension SubscanRewardItemData: WalletRemoteHistoryItemProtocol { _ address: String, networkType: SNAddressType, asset: WalletAsset, - addressFactory: SS58AddressFactoryProtocol + addressFactory _: SS58AddressFactoryProtocol ) -> AssetTransactionData { AssetTransactionData.createTransaction( from: self, address: address, networkType: networkType, - asset: asset, - addressFactory: addressFactory + asset: asset ) } } From 579154a56c63b9785f7eb27bb9482e14615a8d20 Mon Sep 17 00:00:00 2001 From: Russel Date: Fri, 3 Sep 2021 23:03:26 +0300 Subject: [PATCH 6/6] fix tx history initial loading --- Podfile | 4 ++-- Podfile.lock | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Podfile b/Podfile index 1a0373ef6..6800dab60 100644 --- a/Podfile +++ b/Podfile @@ -9,7 +9,7 @@ abstract_target 'fearlessAll' do pod 'SoraKeystore' pod 'SoraUI', '~> 1.10.3' pod 'RobinHood', '~> 2.6.0' - pod 'CommonWallet/Core', :git => 'https://github.com/soramitsu/Capital-iOS.git', :commit => '32bbf882c14751edf6cdc27005c6abc997b01f3f' + pod 'CommonWallet/Core', :git => 'https://github.com/soramitsu/Capital-iOS.git', :commit => '4133ff9b81cda094dd8e2b7f32129172224b0227' pod 'SoraFoundation', '~> 1.0.0' pod 'SwiftyBeaver' pod 'Starscream', :git => 'https://github.com/ERussel/Starscream.git', :branch => 'feature/without-origin' @@ -30,7 +30,7 @@ abstract_target 'fearlessAll' do pod 'FireMock', :inhibit_warnings => true pod 'SoraKeystore' pod 'RobinHood', '~> 2.6.0' - pod 'CommonWallet/Core', :git => 'https://github.com/soramitsu/Capital-iOS.git', :commit => '32bbf882c14751edf6cdc27005c6abc997b01f3f' + pod 'CommonWallet/Core', :git => 'https://github.com/soramitsu/Capital-iOS.git', :commit => '4133ff9b81cda094dd8e2b7f32129172224b0227' pod 'Sourcery', '~> 1.4' end diff --git a/Podfile.lock b/Podfile.lock index f8a4b95dd..f4ea6122e 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -113,7 +113,7 @@ PODS: - xxHash-Swift (1.0.13) DEPENDENCIES: - - CommonWallet/Core (from `https://github.com/soramitsu/Capital-iOS.git`, commit `32bbf882c14751edf6cdc27005c6abc997b01f3f`) + - CommonWallet/Core (from `https://github.com/soramitsu/Capital-iOS.git`, commit `4133ff9b81cda094dd8e2b7f32129172224b0227`) - Cuckoo - FearlessUtils - FireMock @@ -160,7 +160,7 @@ SPEC REPOS: EXTERNAL SOURCES: CommonWallet: - :commit: 32bbf882c14751edf6cdc27005c6abc997b01f3f + :commit: 4133ff9b81cda094dd8e2b7f32129172224b0227 :git: https://github.com/soramitsu/Capital-iOS.git Starscream: :branch: feature/without-origin @@ -171,7 +171,7 @@ EXTERNAL SOURCES: CHECKOUT OPTIONS: CommonWallet: - :commit: 32bbf882c14751edf6cdc27005c6abc997b01f3f + :commit: 4133ff9b81cda094dd8e2b7f32129172224b0227 :git: https://github.com/soramitsu/Capital-iOS.git Starscream: :commit: b9e69390d96e71427463469f47cdafb8c0db1b21 @@ -208,6 +208,6 @@ SPEC CHECKSUMS: TweetNacl: 3abf4d1d2082b0114e7a67410e300892448951e6 xxHash-Swift: 30bd6a7507b3b7348a277c49b1cb6346c2905ec7 -PODFILE CHECKSUM: eb7e972783401bd9aded2ca6e5526391591cc23b +PODFILE CHECKSUM: 2b66ed0117007f5bb0c55590f608dfd3e90323ea COCOAPODS: 1.10.2