From 5df275e538b88f8f974052b23aac03e2ce81f70f Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Tue, 9 Jan 2024 17:37:19 +0300 Subject: [PATCH 01/60] add layout --- novawallet.xcodeproj/project.pbxproj | 64 +++++++++++- .../View/NetworkFeeInfoView.swift} | 10 +- .../ViewModel/NetworkFeeInfoViewModel.swift | 4 + .../StakingSetupProxy/ProxyDepositView.swift | 25 +++++ .../StakingSetupProxyInteractor.swift | 7 ++ .../StakingSetupProxyPresenter.swift | 23 +++++ .../StakingSetupProxyProtocols.swift | 13 +++ .../StakingSetupProxyViewController.swift | 98 +++++++++++++++++++ .../StakingSetupProxyViewFactory.swift | 18 ++++ .../StakingSetupProxyViewLayout.swift | 60 ++++++++++++ .../StakingSetupProxyWireframe.swift | 3 + .../Base/View/SwapNetworkFeeViewCell.swift | 4 +- .../Model/SwapConfirmViewModelFactory.swift | 4 +- .../Swaps/Confirm/SwapConfirmProtocols.swift | 2 +- .../Confirm/SwapConfirmViewController.swift | 2 +- .../Swaps/Setup/Model/SwapViewModels.swift | 5 - .../Model/SwapsSetupViewModelFactory.swift | 4 +- .../Swaps/Setup/SwapSetupProtocols.swift | 2 +- .../Swaps/Setup/SwapSetupViewController.swift | 2 +- novawallet/en.lproj/Localizable.strings | 4 + novawallet/ru.lproj/Localizable.strings | 4 + .../StakingSetupProxyTests.swift | 16 +++ 22 files changed, 350 insertions(+), 24 deletions(-) rename novawallet/{Modules/Swaps/Base/View/SwapNetworkFeeView.swift => Common/View/NetworkFeeInfoView.swift} (92%) create mode 100644 novawallet/Common/ViewModel/NetworkFeeInfoViewModel.swift create mode 100644 novawallet/Modules/Staking/StakingSetupProxy/ProxyDepositView.swift create mode 100644 novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyInteractor.swift create mode 100644 novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyPresenter.swift create mode 100644 novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyProtocols.swift create mode 100644 novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewController.swift create mode 100644 novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewFactory.swift create mode 100644 novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewLayout.swift create mode 100644 novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyWireframe.swift create mode 100644 novawalletTests/Modules/StakingSetupProxy/StakingSetupProxyTests.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index f0a14df081..44aab1b886 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -515,6 +515,7 @@ 331186FCF0903BA793C6D930 /* DelegationListViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7D8A9948F319AD0D154D1EC4 /* DelegationListViewFactory.swift */; }; 33431341505ABC30172D34E3 /* GovernanceRevokeDelegationTracksWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 461A9E7672D247C9CCF0B45D /* GovernanceRevokeDelegationTracksWireframe.swift */; }; 3349B35F5D5DDD2D46FF2E48 /* LedgerInstructionsViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1F9B478321689D963F51C4E /* LedgerInstructionsViewFactory.swift */; }; + 3365B7C300AB4AC432F1BED0 /* StakingSetupProxyWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1399884D5F4905DA0BD1E5C3 /* StakingSetupProxyWireframe.swift */; }; 33991FF16853D0F885C520A5 /* GovernanceRevokeDelegationConfirmViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67544C56A83D617405414E28 /* GovernanceRevokeDelegationConfirmViewLayout.swift */; }; 33B0D1D29AB3FC3CA23567B6 /* LedgerWalletAccountConfirmationWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DEC8CCF0671304A658AD606 /* LedgerWalletAccountConfirmationWireframe.swift */; }; 3403F3DCDE932B9F9C6D32B6 /* ReferendumDetailsViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1565588CB7E044C02B091FB /* ReferendumDetailsViewLayout.swift */; }; @@ -588,6 +589,7 @@ 4448B591D4A193DBC9E2E3BF /* AccountCreateInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A7B39A61DB0D2F0F1B1DBA1 /* AccountCreateInteractor.swift */; }; 4453EA83AD59FFD0EF894D58 /* LedgerNetworkSelectionViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2915C2DF1B65C5CA6009AC28 /* LedgerNetworkSelectionViewLayout.swift */; }; 44D9F74D7851B874F2045E7E /* LedgerInstructionsProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = B14E9691A7628B66958F8744 /* LedgerInstructionsProtocols.swift */; }; + 450BF207003E4DD3F5FE4D9B /* StakingSetupProxyViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D927D2CCA2C24FE116D7CE5C /* StakingSetupProxyViewController.swift */; }; 4541F886953E046C16E42997 /* LedgerWalletConfirmInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96340EDDE0EAA7F9B6D33E96 /* LedgerWalletConfirmInteractor.swift */; }; 454D41CC5C7CC2FDAB778026 /* CreateWatchOnlyInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D9C85AB0C9D53B522DCF3C5 /* CreateWatchOnlyInteractor.swift */; }; 46298240F3528B5C62AEC29E /* GovernanceUnlockSetupWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 856BF961EACEB9703B2B37C7 /* GovernanceUnlockSetupWireframe.swift */; }; @@ -642,11 +644,13 @@ 5510625BDA756B939ED7C586 /* AddDelegationPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68D44AF5C59681B54ECD7658 /* AddDelegationPresenter.swift */; }; 5619C10BFFAEAF89883227B4 /* WalletConnectPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BC9AC96424DB8AB8038ED59 /* WalletConnectPresenter.swift */; }; 561F5B387B0A1682CE5DE7E4 /* ParitySignerTxScanViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEADC45D0C53E7A06A854DEB /* ParitySignerTxScanViewFactory.swift */; }; + 5628E716AB0D71B2DC6D3647 /* StakingSetupProxyViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845FB5F69EE4029CDC9DF35B /* StakingSetupProxyViewLayout.swift */; }; 5678BAE4B652C5C5E4284F28 /* AccountManagementViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E18B94164B49123E62FA60B7 /* AccountManagementViewFactory.swift */; }; 575A729D07A6B984851E6DD0 /* DAppAuthConfirmPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F80D885306E1EFE4ABE321C /* DAppAuthConfirmPresenter.swift */; }; 576010F6494B3E2A6CA0B444 /* CreateWatchOnlyViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39907750D40A8DD7FE1288C8 /* CreateWatchOnlyViewController.swift */; }; 577918C3D4AA22D887F605B5 /* ParaStkStakeSetupPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1AC788C6E0A621B6D88D1BC /* ParaStkStakeSetupPresenter.swift */; }; 57E20F0723C4748D576C4882 /* StakingUnbondSetupViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = A82E373FFFBF708D7CF0973E /* StakingUnbondSetupViewFactory.swift */; }; + 584BB6F9C4B51C70B3C68DF9 /* StakingSetupProxyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54407B75B62CE8607D5829AF /* StakingSetupProxyTests.swift */; }; 5869563D0EA593FBD02C169C /* StakingPayoutConfirmationProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52F8D055D0481469073AA859 /* StakingPayoutConfirmationProtocols.swift */; }; 58D5B4F17DA37C241FF96A5F /* ParaStkRebondViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FDF5963FA924F8C815F3BCF /* ParaStkRebondViewController.swift */; }; 58F385F41D42CC96373EDA42 /* TokensManageProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05AA59AFC801F52B79DDBBCF /* TokensManageProtocols.swift */; }; @@ -873,6 +877,8 @@ 779A8F992A04BAC000BE31B3 /* StakingRewardActionControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 779A8F982A04BAC000BE31B3 /* StakingRewardActionControl.swift */; }; 779A8F9B2A050C4400BE31B3 /* StakingRewardDateCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 779A8F9A2A050C4400BE31B3 /* StakingRewardDateCell.swift */; }; 779C8BE82AA1DD1B001A4A3C /* NominationPoolsBondMoreHintsFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 779C8BE72AA1DD1B001A4A3C /* NominationPoolsBondMoreHintsFactory.swift */; }; + 779F1F8B2B4D807200EF1EE9 /* ProxyDepositView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 779F1F8A2B4D807200EF1EE9 /* ProxyDepositView.swift */; }; + 779F1F8D2B4D8A9100EF1EE9 /* NetworkFeeInfoViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 779F1F8C2B4D8A9100EF1EE9 /* NetworkFeeInfoViewModel.swift */; }; 77A0B2ED2A3B7F3300CBF653 /* DAppCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77A0B2EC2A3B7F3300CBF653 /* DAppCollectionViewCell.swift */; }; 77A0B2EF2A3B85B700CBF653 /* BlurBackgroundCollectionReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77A0B2EE2A3B85B700CBF653 /* BlurBackgroundCollectionReusableView.swift */; }; 77A0B2F32A3CA37E00CBF653 /* StakingMoreOptionsViewModelFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77A0B2F22A3CA37E00CBF653 /* StakingMoreOptionsViewModelFactory.swift */; }; @@ -959,7 +965,7 @@ 77EA2A2A2A333C1500B0670B /* weird_input.json in Resources */ = {isa = PBXBuildFile; fileRef = 77EA2A202A333C1500B0670B /* weird_input.json */; }; 77EA2A2B2A333C1500B0670B /* structures_input.json in Resources */ = {isa = PBXBuildFile; fileRef = 77EA2A212A333C1500B0670B /* structures_input.json */; }; 77EAABA52B2726A500CA7305 /* SectionTextHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77EAABA42B2726A500CA7305 /* SectionTextHeaderView.swift */; }; - 77ECB4702ACEEE2E0015CE9F /* SwapNetworkFeeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77ECB46F2ACEEE2D0015CE9F /* SwapNetworkFeeView.swift */; }; + 77ECB4702ACEEE2E0015CE9F /* NetworkFeeInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77ECB46F2ACEEE2D0015CE9F /* NetworkFeeInfoView.swift */; }; 77ED167A2A0CF41700E1FC8C /* StakingRewardFiltersViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77ED16792A0CF41600E1FC8C /* StakingRewardFiltersViewModel.swift */; }; 77ED167C2A0CF42E00E1FC8C /* StakingRewardFiltersPeriod.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77ED167B2A0CF42E00E1FC8C /* StakingRewardFiltersPeriod.swift */; }; 77ED167E2A0D0AE900E1FC8C /* Lenses.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77ED167D2A0D0AE900E1FC8C /* Lenses.swift */; }; @@ -3374,6 +3380,7 @@ 886A278829E93D2A003B269F /* CommonOperationWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 886A278729E93D2A003B269F /* CommonOperationWrapper.swift */; }; 886CA9622977E9B300FC255A /* GovernanceDelegateTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 886CA9602977E9B200FC255A /* GovernanceDelegateTableViewCell.swift */; }; 886CA9632977E9B300FC255A /* GovernanceDelegateBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 886CA9612977E9B200FC255A /* GovernanceDelegateBanner.swift */; }; + 886E599110019177E0489999 /* StakingSetupProxyInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E662972946C16B2DA92EA232 /* StakingSetupProxyInteractor.swift */; }; 886E8CF81EF2566D98D9693E /* ExportSeedViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62FA66143B25AA70B02CE461 /* ExportSeedViewFactory.swift */; }; 887248082924F54900B0D2CC /* URL+Matchable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 887248072924F54900B0D2CC /* URL+Matchable.swift */; }; 887404B229826FB100EE270A /* InAppUpdatesServiceFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 887404B129826FB100EE270A /* InAppUpdatesServiceFactory.swift */; }; @@ -3622,6 +3629,7 @@ A748D64F6048192E16E5BE44 /* ParaStkUnstakeConfirmViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CD36AD8C414F8973CDA8A0F /* ParaStkUnstakeConfirmViewLayout.swift */; }; A8115BE0BFA6558B46CEA101 /* ParaStkCollatorInfoPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4C96F37D7166820D6C9CC62 /* ParaStkCollatorInfoPresenter.swift */; }; A83ED3518F2FD1C7B1C48D9E /* StartStakingInfoViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9D4A8C06D94C748124E6AA5 /* StartStakingInfoViewLayout.swift */; }; + A8515273213D048B0F9AFD15 /* StakingSetupProxyProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 173BB84A4695492A77AE206D /* StakingSetupProxyProtocols.swift */; }; A871B6ABACAE8A811010F792 /* StakingPayoutConfirmationWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5ACCFD31E14AF4D30955288 /* StakingPayoutConfirmationWireframe.swift */; }; A8F69AC9D7294E7DCBA50470 /* SelectValidatorsStartPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B6244A9538B39AFCD3A6F3A /* SelectValidatorsStartPresenter.swift */; }; A97F32D057BFEFBCC478A09C /* DAppTxDetailsViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = A028BD1A81CA95BE0DB66031 /* DAppTxDetailsViewFactory.swift */; }; @@ -3762,6 +3770,7 @@ B071927DF8DD5C3CA84494BA /* RecommendedValidatorListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F61D8973ADEB461DE2AD3E13 /* RecommendedValidatorListViewController.swift */; }; B09F155D14D146377FB2952A /* StakingRebagConfirmWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2E005960E331E8882A8C6FD /* StakingRebagConfirmWireframe.swift */; }; B19BA6D7071BC7BE1EFFDE6D /* NPoolsClaimRewardsProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = E12E4AA5C56575FD3ABA7693 /* NPoolsClaimRewardsProtocols.swift */; }; + B1A789A7E8D60223F18AA407 /* StakingSetupProxyPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B882BFEED7C8CB1EA5A853D /* StakingSetupProxyPresenter.swift */; }; B1B0F4818510EB082ACA83AB /* MoonbeamTermsViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 313CDB5EB70518DEC1BDB392 /* MoonbeamTermsViewLayout.swift */; }; B1BB78684B059A113AB3AD30 /* DAppPhishingViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36AE1C39767C4CBE3229089D /* DAppPhishingViewFactory.swift */; }; B1CCC5B7BF30F6ACA309B112 /* StakingRedeemViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB7F5F9B54BE4234C5682BDE /* StakingRedeemViewController.swift */; }; @@ -4148,6 +4157,7 @@ FA894DFA8EEBB0B4562CD788 /* LedgerAccountConfirmationViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 392B5AA43C68E640C9FDEE04 /* LedgerAccountConfirmationViewFactory.swift */; }; FB405A41F9B89097016D4C78 /* ChainAddressDetailsWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 245DED717B5B3FC380C24E3D /* ChainAddressDetailsWireframe.swift */; }; FBB0A83A6F48E4E0EE15E11A /* DelegateVotedReferendaInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E09466B1FD637D4649D7CED /* DelegateVotedReferendaInteractor.swift */; }; + FC963F2AFEA3984B2CB14A34 /* StakingSetupProxyViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90D17F206E8C9D755346CFCC /* StakingSetupProxyViewFactory.swift */; }; FCBFD26B960C4837646A0D86 /* NPoolsClaimRewardsWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF389223A781CA2088C7A4DD /* NPoolsClaimRewardsWireframe.swift */; }; FD322DC05438902ED369E8FA /* NPoolsRedeemWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A651A934B32A7978850D639 /* NPoolsRedeemWireframe.swift */; }; FD43B68CFBD5C3497B446F53 /* ChangeWatchOnlyProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAB80E4CA0D5FA56612318A2 /* ChangeWatchOnlyProtocols.swift */; }; @@ -4565,6 +4575,7 @@ 12BEE17030110A1531A231EE /* DelegationReferendumVotersPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DelegationReferendumVotersPresenter.swift; sourceTree = ""; }; 12C822BAC40271396E36ACBB /* NPoolsUnstakeConfirmViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = NPoolsUnstakeConfirmViewLayout.swift; sourceTree = ""; }; 1366336078BCA34EFB4C6FF9 /* CrowdloanContributionConfirmInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CrowdloanContributionConfirmInteractor.swift; sourceTree = ""; }; + 1399884D5F4905DA0BD1E5C3 /* StakingSetupProxyWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingSetupProxyWireframe.swift; sourceTree = ""; }; 14383723F0B56C91A0B3016E /* MessageSheetWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = MessageSheetWireframe.swift; sourceTree = ""; }; 14E3337CDD7C831AEAA4582F /* CustomValidatorListPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CustomValidatorListPresenter.swift; sourceTree = ""; }; 1521715CA2071056FCE9D360 /* TransferSetupProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TransferSetupProtocols.swift; sourceTree = ""; }; @@ -4575,6 +4586,7 @@ 16A05911AC400226DD29AE20 /* DAppWalletAuthViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppWalletAuthViewLayout.swift; sourceTree = ""; }; 172A76B6B50406CEA464FAC6 /* GovernanceDelegateConfirmProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = GovernanceDelegateConfirmProtocols.swift; sourceTree = ""; }; 172B3E9BE51A339D7A09BDA3 /* UsernameSetupPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = UsernameSetupPresenter.swift; sourceTree = ""; }; + 173BB84A4695492A77AE206D /* StakingSetupProxyProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingSetupProxyProtocols.swift; sourceTree = ""; }; 1754AB91CF4744E49D1310AE /* ChangeWatchOnlyPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ChangeWatchOnlyPresenter.swift; sourceTree = ""; }; 1768C3415D7D9CEEA8A8C700 /* GovernanceUnavailableTracksPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = GovernanceUnavailableTracksPresenter.swift; sourceTree = ""; }; 17C0AC11A4A195BB697578CE /* StakingPayoutConfirmationPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingPayoutConfirmationPresenter.swift; sourceTree = ""; }; @@ -4830,6 +4842,7 @@ 53B5C1C920BFDA8F5C9C89D9 /* ParaStkRedeemInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkRedeemInteractor.swift; sourceTree = ""; }; 53BE9DEF100A373868EDD03F /* ParaStkSelectCollatorsWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkSelectCollatorsWireframe.swift; sourceTree = ""; }; 53C2612BBF75CF0FBD91764E /* ParaStkCollatorsSearchWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkCollatorsSearchWireframe.swift; sourceTree = ""; }; + 54407B75B62CE8607D5829AF /* StakingSetupProxyTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingSetupProxyTests.swift; sourceTree = ""; }; 5467B9B6AEDB33F565D130A1 /* ParaStkUnstakeViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkUnstakeViewFactory.swift; sourceTree = ""; }; 54FB887490A8B33890B4E0E4 /* ControllerAccountConfirmationPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ControllerAccountConfirmationPresenter.swift; sourceTree = ""; }; 5544826542EC3A92FCB2B1D7 /* DelegateVotedReferendaPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DelegateVotedReferendaPresenter.swift; sourceTree = ""; }; @@ -4856,6 +4869,7 @@ 5AD16D5FA4115F2A525BDE4F /* ParaStkRedeemViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkRedeemViewController.swift; sourceTree = ""; }; 5AFA57BC935878DEBBE32EEA /* GovernanceRevokeDelegationConfirmInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = GovernanceRevokeDelegationConfirmInteractor.swift; sourceTree = ""; }; 5B675B6727754E3727CBC7BE /* DAppWalletAuthViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppWalletAuthViewController.swift; sourceTree = ""; }; + 5B882BFEED7C8CB1EA5A853D /* StakingSetupProxyPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingSetupProxyPresenter.swift; sourceTree = ""; }; 5B8B0940B2CB25AD9C36206E /* SelectValidatorsConfirmViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SelectValidatorsConfirmViewController.swift; sourceTree = ""; }; 5BA3C305F49A4E609C7A5C14 /* GovernanceDelegateConfirmViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = GovernanceDelegateConfirmViewController.swift; sourceTree = ""; }; 5BC9AC96424DB8AB8038ED59 /* WalletConnectPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = WalletConnectPresenter.swift; sourceTree = ""; }; @@ -5061,6 +5075,8 @@ 779A8F982A04BAC000BE31B3 /* StakingRewardActionControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingRewardActionControl.swift; sourceTree = ""; }; 779A8F9A2A050C4400BE31B3 /* StakingRewardDateCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StakingRewardDateCell.swift; sourceTree = ""; }; 779C8BE72AA1DD1B001A4A3C /* NominationPoolsBondMoreHintsFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NominationPoolsBondMoreHintsFactory.swift; sourceTree = ""; }; + 779F1F8A2B4D807200EF1EE9 /* ProxyDepositView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProxyDepositView.swift; sourceTree = ""; }; + 779F1F8C2B4D8A9100EF1EE9 /* NetworkFeeInfoViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkFeeInfoViewModel.swift; sourceTree = ""; }; 77A0B2EC2A3B7F3300CBF653 /* DAppCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DAppCollectionViewCell.swift; sourceTree = ""; }; 77A0B2EE2A3B85B700CBF653 /* BlurBackgroundCollectionReusableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlurBackgroundCollectionReusableView.swift; sourceTree = ""; }; 77A0B2F22A3CA37E00CBF653 /* StakingMoreOptionsViewModelFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingMoreOptionsViewModelFactory.swift; sourceTree = ""; }; @@ -5149,7 +5165,7 @@ 77EA2A202A333C1500B0670B /* weird_input.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = weird_input.json; sourceTree = ""; }; 77EA2A212A333C1500B0670B /* structures_input.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = structures_input.json; sourceTree = ""; }; 77EAABA42B2726A500CA7305 /* SectionTextHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionTextHeaderView.swift; sourceTree = ""; }; - 77ECB46F2ACEEE2D0015CE9F /* SwapNetworkFeeView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwapNetworkFeeView.swift; sourceTree = ""; }; + 77ECB46F2ACEEE2D0015CE9F /* NetworkFeeInfoView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkFeeInfoView.swift; sourceTree = ""; }; 77ED16792A0CF41600E1FC8C /* StakingRewardFiltersViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingRewardFiltersViewModel.swift; sourceTree = ""; }; 77ED167B2A0CF42E00E1FC8C /* StakingRewardFiltersPeriod.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingRewardFiltersPeriod.swift; sourceTree = ""; }; 77ED167D2A0D0AE900E1FC8C /* Lenses.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Lenses.swift; sourceTree = ""; }; @@ -6015,6 +6031,7 @@ 845F49EC2928F31100BD6D11 /* ChainModel+Evm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ChainModel+Evm.swift"; sourceTree = ""; }; 845F49EE292901D200BD6D11 /* CallCodingPath+Evm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CallCodingPath+Evm.swift"; sourceTree = ""; }; 845F8E1E293771BA00EA6AD0 /* SubstrateDataModel7.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = SubstrateDataModel7.xcdatamodel; sourceTree = ""; }; + 845FB5F69EE4029CDC9DF35B /* StakingSetupProxyViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingSetupProxyViewLayout.swift; sourceTree = ""; }; 845FB6722A22285C0003BCA6 /* MultistakingSyncService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultistakingSyncService.swift; sourceTree = ""; }; 845FB6742A2274890003BCA6 /* MultistakingRepositoryFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultistakingRepositoryFactory.swift; sourceTree = ""; }; 845FB6762A227F050003BCA6 /* MultistakingProviderFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultistakingProviderFactory.swift; sourceTree = ""; }; @@ -7783,6 +7800,7 @@ 906C55FC079AF6112AF0745B /* YourValidatorListWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = YourValidatorListWireframe.swift; sourceTree = ""; }; 90BA9C7259E59AC6CB422F82 /* TokensAddSelectNetworkProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TokensAddSelectNetworkProtocols.swift; sourceTree = ""; }; 90C2A8B3F0006DBCB4B7337A /* StakingRebagConfirmProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingRebagConfirmProtocols.swift; sourceTree = ""; }; + 90D17F206E8C9D755346CFCC /* StakingSetupProxyViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingSetupProxyViewFactory.swift; sourceTree = ""; }; 91C760EDD8CDD8073063D76D /* NominationPoolBondMoreSetupViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = NominationPoolBondMoreSetupViewFactory.swift; sourceTree = ""; }; 91D44421CCD7AD220A05CD0E /* PurchaseInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = PurchaseInteractor.swift; sourceTree = ""; }; 92381CBE193B3317F477D377 /* GovernanceRevokeDelegationConfirmViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = GovernanceRevokeDelegationConfirmViewController.swift; sourceTree = ""; }; @@ -8144,6 +8162,7 @@ D8C4C48E50DC14085258AB6D /* NftDetailsViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = NftDetailsViewController.swift; sourceTree = ""; }; D9046DB927451ED700C29F2E /* ParallelContributionSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParallelContributionSource.swift; sourceTree = ""; }; D9046DBB27453D5C00C29F2E /* ParallelContributionResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParallelContributionResponse.swift; sourceTree = ""; }; + D927D2CCA2C24FE116D7CE5C /* StakingSetupProxyViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingSetupProxyViewController.swift; sourceTree = ""; }; D9D163632744F60D00681C1F /* ExternalContribution.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExternalContribution.swift; sourceTree = ""; }; D9D163652744F9BF00681C1F /* ExternalContributionSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExternalContributionSource.swift; sourceTree = ""; }; D9DFFBEFB45E0A03FAA142C3 /* ReferendumsFiltersViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumsFiltersViewController.swift; sourceTree = ""; }; @@ -8193,6 +8212,7 @@ E5C144CEF4852B97149A1848 /* DAppAuthSettingsViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppAuthSettingsViewLayout.swift; sourceTree = ""; }; E5CC1FB277A878E9C9B7EAEB /* AccountImportInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AccountImportInteractor.swift; sourceTree = ""; }; E63ECD1205B2CCCDA2E66A1E /* ParaStkYieldBoostSetupViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkYieldBoostSetupViewLayout.swift; sourceTree = ""; }; + E662972946C16B2DA92EA232 /* StakingSetupProxyInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingSetupProxyInteractor.swift; sourceTree = ""; }; E675B4C5BE36C0004564105B /* DAppOperationConfirmProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppOperationConfirmProtocols.swift; sourceTree = ""; }; E697F5EF3AD8EE7281FBF6CB /* WalletConnectSessionsViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = WalletConnectSessionsViewLayout.swift; sourceTree = ""; }; E6DDBA4DD86CEFAAE236B23B /* GovernanceDelegateSetupPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = GovernanceDelegateSetupPresenter.swift; sourceTree = ""; }; @@ -10101,7 +10121,6 @@ 771901A72AE8FF9F00D9C918 /* SwapNetworkFeeViewCell.swift */, 771901A52AE8FF7E00D9C918 /* SwapInfoViewCell.swift */, 77740BBF2AD4A80D00E8C06F /* SwapInfoView.swift */, - 77ECB46F2ACEEE2D0015CE9F /* SwapNetworkFeeView.swift */, ); path = View; sourceTree = ""; @@ -10231,6 +10250,14 @@ path = AssetOperation; sourceTree = ""; }; + 77597583F6E03AC6726ED7F8 /* StakingSetupProxy */ = { + isa = PBXGroup; + children = ( + 54407B75B62CE8607D5829AF /* StakingSetupProxyTests.swift */, + ); + path = StakingSetupProxy; + sourceTree = ""; + }; 77799AE32A792ACB00B7E564 /* Model */ = { isa = PBXGroup; children = ( @@ -14366,6 +14393,7 @@ 842D8B772A4098C300660005 /* ShimmeringLabel.swift */, 88A95FA728FAA99D00BE26F3 /* DAppView.swift */, 77740BBB2AD4A7B800E8C06F /* CollapsableContainerView.swift */, + 77ECB46F2ACEEE2D0015CE9F /* NetworkFeeInfoView.swift */, ); path = View; sourceTree = ""; @@ -14550,6 +14578,7 @@ 0C9951D22AE2DB0200B65615 /* PromotionViewModelFactory.swift */, 8828F4F428AD2763009E0B7C /* BalanceViewModelFactoryFacade.swift */, 0C13DFD22AF949B400E5F355 /* BalanceViewModelFactoryFacade+Formatting.swift */, + 779F1F8C2B4D8A9100EF1EE9 /* NetworkFeeInfoViewModel.swift */, ); path = ViewModel; sourceTree = ""; @@ -15277,6 +15306,7 @@ 84B7C705289BFA79001A3566 /* AccountManagement */, 84B7C708289BFA79001A3566 /* WalletList */, 84B7C70A289BFA79001A3566 /* ControllerAccount */, + 77597583F6E03AC6726ED7F8 /* StakingSetupProxy */, ); path = Modules; sourceTree = ""; @@ -17069,6 +17099,7 @@ 7066B343B912F72345D541F2 /* StakingSetupAmount */, 17432B4B5D8D9DC5C22CA238 /* StakingType */, 92CDAD21CEED554306CAF5D8 /* StartStakingConfirm */, + A4542BFD7BBCF6B05FB2D3E4 /* StakingSetupProxy */, ); path = Staking; sourceTree = ""; @@ -18056,6 +18087,21 @@ path = AssetsSearch; sourceTree = ""; }; + A4542BFD7BBCF6B05FB2D3E4 /* StakingSetupProxy */ = { + isa = PBXGroup; + children = ( + 173BB84A4695492A77AE206D /* StakingSetupProxyProtocols.swift */, + 1399884D5F4905DA0BD1E5C3 /* StakingSetupProxyWireframe.swift */, + 5B882BFEED7C8CB1EA5A853D /* StakingSetupProxyPresenter.swift */, + E662972946C16B2DA92EA232 /* StakingSetupProxyInteractor.swift */, + D927D2CCA2C24FE116D7CE5C /* StakingSetupProxyViewController.swift */, + 845FB5F69EE4029CDC9DF35B /* StakingSetupProxyViewLayout.swift */, + 90D17F206E8C9D755346CFCC /* StakingSetupProxyViewFactory.swift */, + 779F1F8A2B4D807200EF1EE9 /* ProxyDepositView.swift */, + ); + path = StakingSetupProxy; + sourceTree = ""; + }; A798A35104CE0BC5AD2645F3 /* DAppTxDetails */ = { isa = PBXGroup; children = ( @@ -21354,7 +21400,7 @@ 88C5F082297F0706001CCADE /* ReleaseVersion.swift in Sources */, 849013E224A9288B008F705E /* Language.swift in Sources */, 840D92A1278D8D6F0007B979 /* DAppBrowserStateError.swift in Sources */, - 77ECB4702ACEEE2E0015CE9F /* SwapNetworkFeeView.swift in Sources */, + 77ECB4702ACEEE2E0015CE9F /* NetworkFeeInfoView.swift in Sources */, 84FC190B29B7DB9F00BCCAA5 /* ExtrinsicServiceTypes.swift in Sources */, 849707A128F3E0AC00DD0A02 /* ReferendumVoterLocal.swift in Sources */, 774091FC2ACC053000172516 /* SwapAssetView.swift in Sources */, @@ -21939,6 +21985,7 @@ 0C0CB3852AC561FB00EAC516 /* AssetHubSwapOperationFactory.swift in Sources */, 775F19512A5811FA009915B6 /* StartStakingParachainInteractor.swift in Sources */, 8828F4F328AD2734009E0B7C /* CrowdloansCalculator.swift in Sources */, + 779F1F8D2B4D8A9100EF1EE9 /* NetworkFeeInfoViewModel.swift in Sources */, 8487583627F06AF300495306 /* QRScannerViewController.swift in Sources */, 846B749A28B4BA1700C39B93 /* LedgerChainAccount.swift in Sources */, 8436B6DA2848119C00F24360 /* AccountDetailsSelectionCell.swift in Sources */, @@ -21952,6 +21999,7 @@ 8454C21D2632A78900657DAD /* EventRecord.swift in Sources */, 84AE7AB527D39DCA00495267 /* NetworkViewModel.swift in Sources */, 0C9C64342A8D67AF004DC078 /* StakingNPoolsWireframe.swift in Sources */, + 779F1F8B2B4D807200EF1EE9 /* ProxyDepositView.swift in Sources */, 84C4C2F9255DB9510045B582 /* PinChangeInteractor.swift in Sources */, 840874D82978284B00ACFA55 /* GovernanceDelegateMetadataRemote.swift in Sources */, 8473F4B2282BD584007CC55A /* StakingRelaychainPresenter.swift in Sources */, @@ -24032,6 +24080,13 @@ 7136E160BD5C6A19F9C20A5B /* ProxiedsUpdateViewController.swift in Sources */, 5DCEEE88DD1E09DC8110BF0C /* ProxiedsUpdateViewLayout.swift in Sources */, 93E203248735DCCEC1BA96AF /* ProxiedsUpdateViewFactory.swift in Sources */, + A8515273213D048B0F9AFD15 /* StakingSetupProxyProtocols.swift in Sources */, + 3365B7C300AB4AC432F1BED0 /* StakingSetupProxyWireframe.swift in Sources */, + B1A789A7E8D60223F18AA407 /* StakingSetupProxyPresenter.swift in Sources */, + 886E599110019177E0489999 /* StakingSetupProxyInteractor.swift in Sources */, + 450BF207003E4DD3F5FE4D9B /* StakingSetupProxyViewController.swift in Sources */, + 5628E716AB0D71B2DC6D3647 /* StakingSetupProxyViewLayout.swift in Sources */, + FC963F2AFEA3984B2CB14A34 /* StakingSetupProxyViewFactory.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -24194,6 +24249,7 @@ 84B7C748289BFA79001A3566 /* WalletListTests.swift in Sources */, 84B7C720289BFA79001A3566 /* ReferralCrowdloanTests.swift in Sources */, F4897BB126AED13D0075F291 /* EraCountdownOperationFactoryStub.swift in Sources */, + 584BB6F9C4B51C70B3C68DF9 /* StakingSetupProxyTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/novawallet/Modules/Swaps/Base/View/SwapNetworkFeeView.swift b/novawallet/Common/View/NetworkFeeInfoView.swift similarity index 92% rename from novawallet/Modules/Swaps/Base/View/SwapNetworkFeeView.swift rename to novawallet/Common/View/NetworkFeeInfoView.swift index 2212f759f1..9d7faee5da 100644 --- a/novawallet/Modules/Swaps/Base/View/SwapNetworkFeeView.swift +++ b/novawallet/Common/View/NetworkFeeInfoView.swift @@ -3,7 +3,7 @@ import UIKit import SoraUI import Kingfisher -final class SwapNetworkFeeView: GenericTitleValueView>, +final class NetworkFeeInfoView: GenericTitleValueView>, SkeletonableView { var titleButton: RoundedButton { titleView } var valueTopButton: RoundedButton { valueView.fView } @@ -60,8 +60,8 @@ final class SwapNetworkFeeView: GenericTitleValueView) { + func bind(loadableViewModel: LoadableViewModelState) { switch loadableViewModel { case let .cached(value), let .loaded(value): isLoading = false @@ -82,7 +82,7 @@ extension SwapNetworkFeeView { } } -extension SwapNetworkFeeView { +extension NetworkFeeInfoView { func createSkeletons(for spaceSize: CGSize) -> [Skeletonable] { let size = CGSize(width: 68, height: 8) let offset = CGPoint( diff --git a/novawallet/Common/ViewModel/NetworkFeeInfoViewModel.swift b/novawallet/Common/ViewModel/NetworkFeeInfoViewModel.swift new file mode 100644 index 0000000000..7552283b76 --- /dev/null +++ b/novawallet/Common/ViewModel/NetworkFeeInfoViewModel.swift @@ -0,0 +1,4 @@ +struct NetworkFeeInfoViewModel { + var isEditable: Bool + var balanceViewModel: BalanceViewModelProtocol +} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/ProxyDepositView.swift b/novawallet/Modules/Staking/StakingSetupProxy/ProxyDepositView.swift new file mode 100644 index 0000000000..8dd27089ed --- /dev/null +++ b/novawallet/Modules/Staking/StakingSetupProxy/ProxyDepositView.swift @@ -0,0 +1,25 @@ +import SoraUI + +final class ProxyDepositView: RowView> { + var imageView: UIImageView { rowContentView.imageView } + var titleButton: RoundedButton { rowContentView.detailsView.titleButton } + var valueTopButton: RoundedButton { rowContentView.detailsView.titleButton } + var valueBottomLabel: UILabel { rowContentView.detailsView.valueBottomLabel } + + override init(frame: CGRect) { + super.init(frame: frame) + + configureStyle() + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func configureStyle() { + preferredHeight = 44 + roundedBackgroundView.highlightedFillColor = R.color.colorCellBackgroundPressed()! + borderView.borderType = .none + } +} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyInteractor.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyInteractor.swift new file mode 100644 index 0000000000..cd2b8cbe44 --- /dev/null +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyInteractor.swift @@ -0,0 +1,7 @@ +import UIKit + +final class StakingSetupProxyInteractor { + weak var presenter: StakingSetupProxyInteractorOutputProtocol? +} + +extension StakingSetupProxyInteractor: StakingSetupProxyInteractorInputProtocol {} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyPresenter.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyPresenter.swift new file mode 100644 index 0000000000..bd8f5aa226 --- /dev/null +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyPresenter.swift @@ -0,0 +1,23 @@ +import Foundation + +final class StakingSetupProxyPresenter { + weak var view: StakingSetupProxyViewProtocol? + let wireframe: StakingSetupProxyWireframeProtocol + let interactor: StakingSetupProxyInteractorInputProtocol + + init( + interactor: StakingSetupProxyInteractorInputProtocol, + wireframe: StakingSetupProxyWireframeProtocol + ) { + self.interactor = interactor + self.wireframe = wireframe + } +} + +extension StakingSetupProxyPresenter: StakingSetupProxyPresenterProtocol { + func setup() {} + func complete(authority _: String) {} + func showDepositInfo() {} +} + +extension StakingSetupProxyPresenter: StakingSetupProxyInteractorOutputProtocol {} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyProtocols.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyProtocols.swift new file mode 100644 index 0000000000..4b44772785 --- /dev/null +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyProtocols.swift @@ -0,0 +1,13 @@ +protocol StakingSetupProxyViewProtocol: AnyObject {} + +protocol StakingSetupProxyPresenterProtocol: AnyObject { + func setup() + func complete(authority: String) + func showDepositInfo() +} + +protocol StakingSetupProxyInteractorInputProtocol: AnyObject {} + +protocol StakingSetupProxyInteractorOutputProtocol: AnyObject {} + +protocol StakingSetupProxyWireframeProtocol: AnyObject {} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewController.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewController.swift new file mode 100644 index 0000000000..2d3eee6a80 --- /dev/null +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewController.swift @@ -0,0 +1,98 @@ +import UIKit +import SoraFoundation + +final class StakingSetupProxyViewController: UIViewController, ViewHolder { + typealias RootViewType = StakingSetupProxyViewLayout + + let presenter: StakingSetupProxyPresenterProtocol + private var token: String = "" + + init( + presenter: StakingSetupProxyPresenterProtocol, + localizationManager: LocalizationManagerProtocol + ) { + self.presenter = presenter + super.init(nibName: nil, bundle: nil) + self.localizationManager = localizationManager + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func loadView() { + view = StakingSetupProxyViewLayout() + } + + override func viewDidLoad() { + super.viewDidLoad() + + presenter.setup() + + setupLocalization() + setupHandlers() + } + + private func setupLocalization() { + let languages = selectedLocale.rLanguages + let strings = R.string.localizable.self + + rootView.titleLabel.text = strings.stakingSetupProxyTitle(token, preferredLanguages: languages) + rootView.authorityLabel.text = strings.stakingSetupProxyAuthority(preferredLanguages: languages) + + let selectYourWalletTitle = strings.assetsSelectSendYourWallets(preferredLanguages: languages) + rootView.yourWalletsControl.bind(model: .init( + name: selectYourWalletTitle, + image: R.image.iconUsers() + )) + + rootView.proxyView.titleButton.imageWithTitleView?.title = strings.stakingSetupProxyDeposit( + preferredLanguages: languages + ) + rootView.feeView.locale = selectedLocale + } + + private func setupHandlers() { + rootView.proxyView.addTarget( + self, + action: #selector(proxyInfoAction), + for: .touchUpInside + ) + rootView.accountInputView.delegate = self + } + + @objc + private func proxyInfoAction() { + presenter.showDepositInfo() + } +} + +extension StakingSetupProxyViewController: StakingSetupProxyViewProtocol {} + +extension StakingSetupProxyViewController: Localizable { + func applyLocalization() { + if isViewLoaded { + setupLocalization() + } + } +} + +extension StakingSetupProxyViewController: AccountInputViewDelegate { + func accountInputViewWillStartEditing(_: AccountInputView) {} + + func accountInputViewDidEndEditing(_ inputView: AccountInputView) { + presenter.complete(authority: inputView.textField.text ?? "") + } + + func accountInputViewShouldReturn(_ inputView: AccountInputView) -> Bool { + inputView.textField.resignFirstResponder() + return true + } + + func accountInputViewDidPaste(_ inputView: AccountInputView) { + if !inputView.textField.isFirstResponder { + presenter.complete(authority: inputView.textField.text ?? "") + } + } +} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewFactory.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewFactory.swift new file mode 100644 index 0000000000..46ae95c667 --- /dev/null +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewFactory.swift @@ -0,0 +1,18 @@ +import Foundation +import SoraFoundation + +struct StakingSetupProxyViewFactory { + static func createView() -> StakingSetupProxyViewProtocol? { + let interactor = StakingSetupProxyInteractor() + let wireframe = StakingSetupProxyWireframe() + + let presenter = StakingSetupProxyPresenter(interactor: interactor, wireframe: wireframe) + + let view = StakingSetupProxyViewController(presenter: presenter, localizationManager: LocalizationManager.shared) + + presenter.view = view + interactor.presenter = presenter + + return view + } +} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewLayout.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewLayout.swift new file mode 100644 index 0000000000..cac85423b6 --- /dev/null +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewLayout.swift @@ -0,0 +1,60 @@ +import UIKit +import SoraFoundation + +final class StakingSetupProxyViewLayout: ScrollableContainerLayoutView { + let actionButton: TriangularedButton = .create { + $0.applyDefaultStyle() + } + + let titleLabel: UILabel = .create { + $0.apply(style: .boldTitle2Primary) + } + + let authorityLabel: UILabel = .create { + $0.apply(style: .footnoteSecondary) + } + + let yourWalletsControl: YourWalletsControl = .create { + $0.apply(state: .hidden) + $0.setContentHuggingPriority(.defaultHigh, for: .horizontal) + $0.setContentCompressionResistancePriority(.required, for: .horizontal) + } + + let accountInputView: AccountInputView = .create { + $0.localizablePlaceholder = LocalizableResource { locale in + R.string.localizable.transferSetupRecipientInputPlaceholder(preferredLanguages: locale.rLanguages) + } + } + + let proxyView: ProxyDepositView = .create { + $0.imageView.image = R.image.iconLock()! + } + + let feeView: NetworkFeeView = { + let view = UIFactory.default.createNetworkFeeView() + view.verticalOffset = 13 + return view + }() + + override func setupLayout() { + addSubview(actionButton) + actionButton.snp.makeConstraints { make in + make.leading.trailing.equalToSuperview().inset(UIConstants.horizontalInset) + make.bottom.equalTo(safeAreaLayoutGuide).inset(UIConstants.actionBottomInset) + make.height.equalTo(UIConstants.actionHeight) + } + + addArrangedSubview(titleLabel, spacingAfter: 16) + + let titleStackView = UIStackView(arrangedSubviews: [ + authorityLabel, + FlexibleSpaceView(), + yourWalletsControl + ]) + + addArrangedSubview(titleStackView, spacingAfter: 8) + addArrangedSubview(accountInputView, spacingAfter: 40) + addArrangedSubview(proxyView, spacingAfter: 0) + addArrangedSubview(feeView) + } +} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyWireframe.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyWireframe.swift new file mode 100644 index 0000000000..b825d239c6 --- /dev/null +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyWireframe.swift @@ -0,0 +1,3 @@ +import Foundation + +final class StakingSetupProxyWireframe: StakingSetupProxyWireframeProtocol {} diff --git a/novawallet/Modules/Swaps/Base/View/SwapNetworkFeeViewCell.swift b/novawallet/Modules/Swaps/Base/View/SwapNetworkFeeViewCell.swift index 6b7ef4cc54..77f0fdda33 100644 --- a/novawallet/Modules/Swaps/Base/View/SwapNetworkFeeViewCell.swift +++ b/novawallet/Modules/Swaps/Base/View/SwapNetworkFeeViewCell.swift @@ -1,11 +1,11 @@ import SoraUI -final class SwapNetworkFeeViewCell: RowView, StackTableViewCellProtocol { +final class SwapNetworkFeeViewCell: RowView, StackTableViewCellProtocol { var titleButton: RoundedButton { rowContentView.titleView } var valueTopButton: RoundedButton { rowContentView.valueView.fView } var valueBottomLabel: UILabel { rowContentView.valueView.sView } - func bind(loadableViewModel: LoadableViewModelState) { + func bind(loadableViewModel: LoadableViewModelState) { rowContentView.bind(loadableViewModel: loadableViewModel) } diff --git a/novawallet/Modules/Swaps/Confirm/Model/SwapConfirmViewModelFactory.swift b/novawallet/Modules/Swaps/Confirm/Model/SwapConfirmViewModelFactory.swift index 5a4b925c97..60196159c2 100644 --- a/novawallet/Modules/Swaps/Confirm/Model/SwapConfirmViewModelFactory.swift +++ b/novawallet/Modules/Swaps/Confirm/Model/SwapConfirmViewModelFactory.swift @@ -17,7 +17,7 @@ protocol SwapConfirmViewModelFactoryProtocol: SwapBaseViewModelFactoryProtocol { chainAsset: ChainAsset, priceData: PriceData?, locale: Locale - ) -> SwapFeeViewModel + ) -> NetworkFeeInfoViewModel func walletViewModel(walletAddress: WalletDisplayAddress) -> WalletAccountViewModel? } @@ -79,7 +79,7 @@ extension SwapConfirmViewModelFactory: SwapConfirmViewModelFactoryProtocol { chainAsset: ChainAsset, priceData: PriceData?, locale: Locale - ) -> SwapFeeViewModel { + ) -> NetworkFeeInfoViewModel { let amountDecimal = Decimal.fromSubstrateAmount( fee, precision: chainAsset.assetDisplayInfo.assetPrecision diff --git a/novawallet/Modules/Swaps/Confirm/SwapConfirmProtocols.swift b/novawallet/Modules/Swaps/Confirm/SwapConfirmProtocols.swift index a4d7e0881a..6503259cbf 100644 --- a/novawallet/Modules/Swaps/Confirm/SwapConfirmProtocols.swift +++ b/novawallet/Modules/Swaps/Confirm/SwapConfirmProtocols.swift @@ -7,7 +7,7 @@ protocol SwapConfirmViewProtocol: ControllerBackedProtocol { func didReceiveRate(viewModel: LoadableViewModelState) func didReceivePriceDifference(viewModel: LoadableViewModelState?) func didReceiveSlippage(viewModel: String) - func didReceiveNetworkFee(viewModel: LoadableViewModelState) + func didReceiveNetworkFee(viewModel: LoadableViewModelState) func didReceiveWallet(viewModel: WalletAccountViewModel?) func didReceiveWarning(viewModel: String?) func didReceiveNotification(viewModel: String?) diff --git a/novawallet/Modules/Swaps/Confirm/SwapConfirmViewController.swift b/novawallet/Modules/Swaps/Confirm/SwapConfirmViewController.swift index cd6ceb36ce..8bba6f0954 100644 --- a/novawallet/Modules/Swaps/Confirm/SwapConfirmViewController.swift +++ b/novawallet/Modules/Swaps/Confirm/SwapConfirmViewController.swift @@ -100,7 +100,7 @@ extension SwapConfirmViewController: SwapConfirmViewProtocol { rootView.slippageCell.bind(loadableViewModel: .loaded(value: viewModel)) } - func didReceiveNetworkFee(viewModel: LoadableViewModelState) { + func didReceiveNetworkFee(viewModel: LoadableViewModelState) { rootView.networkFeeCell.bind(loadableViewModel: viewModel) } diff --git a/novawallet/Modules/Swaps/Setup/Model/SwapViewModels.swift b/novawallet/Modules/Swaps/Setup/Model/SwapViewModels.swift index ed061e0a90..b6eb31f2ad 100644 --- a/novawallet/Modules/Swaps/Setup/Model/SwapViewModels.swift +++ b/novawallet/Modules/Swaps/Setup/Model/SwapViewModels.swift @@ -17,11 +17,6 @@ enum SwapAssetInputViewModel { case empty(EmptySwapsAssetViewModel) } -struct SwapFeeViewModel { - var isEditable: Bool - var balanceViewModel: BalanceViewModelProtocol -} - enum TextFieldFocus { case payAsset case receiveAsset diff --git a/novawallet/Modules/Swaps/Setup/Model/SwapsSetupViewModelFactory.swift b/novawallet/Modules/Swaps/Setup/Model/SwapsSetupViewModelFactory.swift index a388cff814..857242f917 100644 --- a/novawallet/Modules/Swaps/Setup/Model/SwapsSetupViewModelFactory.swift +++ b/novawallet/Modules/Swaps/Setup/Model/SwapsSetupViewModelFactory.swift @@ -34,7 +34,7 @@ protocol SwapsSetupViewModelFactoryProtocol: SwapBaseViewModelFactoryProtocol, S isEditable: Bool, priceData: PriceData?, locale: Locale - ) -> SwapFeeViewModel + ) -> NetworkFeeInfoViewModel func amountFromValue(_ decimal: Decimal, chainAsset: ChainAsset, locale: Locale) -> String } @@ -225,7 +225,7 @@ extension SwapsSetupViewModelFactory: SwapsSetupViewModelFactoryProtocol { isEditable: Bool, priceData: PriceData?, locale: Locale - ) -> SwapFeeViewModel { + ) -> NetworkFeeInfoViewModel { let amountDecimal = Decimal.fromSubstrateAmount( amount, precision: assetDisplayInfo.assetPrecision diff --git a/novawallet/Modules/Swaps/Setup/SwapSetupProtocols.swift b/novawallet/Modules/Swaps/Setup/SwapSetupProtocols.swift index b15568591d..6831d7d779 100644 --- a/novawallet/Modules/Swaps/Setup/SwapSetupProtocols.swift +++ b/novawallet/Modules/Swaps/Setup/SwapSetupProtocols.swift @@ -12,7 +12,7 @@ protocol SwapSetupViewProtocol: ControllerBackedProtocol { func didReceiveAmountInputPrice(receiveViewModel: SwapPriceDifferenceViewModel?) func didReceiveTitle(receiveViewModel viewModel: TitleHorizontalMultiValueView.Model) func didReceiveRate(viewModel: LoadableViewModelState) - func didReceiveNetworkFee(viewModel: LoadableViewModelState) + func didReceiveNetworkFee(viewModel: LoadableViewModelState) func didReceiveDetailsState(isAvailable: Bool) func didReceiveSettingsState(isAvailable: Bool) func didReceive(issues: [SwapSetupViewIssue]) diff --git a/novawallet/Modules/Swaps/Setup/SwapSetupViewController.swift b/novawallet/Modules/Swaps/Setup/SwapSetupViewController.swift index def687e843..ed6be01c75 100644 --- a/novawallet/Modules/Swaps/Setup/SwapSetupViewController.swift +++ b/novawallet/Modules/Swaps/Setup/SwapSetupViewController.swift @@ -251,7 +251,7 @@ extension SwapSetupViewController: SwapSetupViewProtocol { rootView.rateCell.bind(loadableViewModel: viewModel) } - func didReceiveNetworkFee(viewModel: LoadableViewModelState) { + func didReceiveNetworkFee(viewModel: LoadableViewModelState) { rootView.networkFeeCell.bind(loadableViewModel: viewModel) if !toggledDetailsManually, !rootView.detailsView.expanded { diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index 27c06a2603..5eb0eb88f6 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -1372,6 +1372,10 @@ "staking.pool.is.not.open.title" = "Pool is not open"; "staking.start.balance" = "Available balance: %@"; "staking.start.no.account" = "No %@ account"; +"staking.setup.proxy.title" = "Add delegation for %@ staking"; +"staking.setup.proxy.authority" = "Give authority to"; +"staking.setup.proxy.deposit" = "Proxy deposit"; +"staking.setup.proxy.deposit.details" = "The deposit stays reserved on your account until the proxy is removed."; "common.time.in" = "in"; "common.and" = " and "; "common.time.period.after" = "after"; diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index 8da6154e15..2b8bd54b46 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1372,6 +1372,10 @@ "staking.pool.is.not.open.title" = "Пул не открыт"; "staking.start.balance" = "Доступный баланс: %@"; "staking.start.no.account" = "Нет %@ аккаунта"; +"staking.setup.proxy.title" = "Добавить делегацию для %@ стекинга"; +"staking.setup.proxy.authority" = "Дать доступ"; +"staking.setup.proxy.deposit" = "Прокси депозит"; +"staking.setup.proxy.deposit.details" = "Депозит остается зарезервированным на вашем счете до тех пор, пока прокси не будет удален."; "common.time.in" = "через"; "common.and" = " и "; "common.time.period.after" = "через"; diff --git a/novawalletTests/Modules/StakingSetupProxy/StakingSetupProxyTests.swift b/novawalletTests/Modules/StakingSetupProxy/StakingSetupProxyTests.swift new file mode 100644 index 0000000000..0ab728899f --- /dev/null +++ b/novawalletTests/Modules/StakingSetupProxy/StakingSetupProxyTests.swift @@ -0,0 +1,16 @@ +import XCTest + +class StakingSetupProxyTests: XCTestCase { + + override func setUp() { + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } + + func testExample() { + XCTFail("Did you forget to add tests?") + } +} From aa172b9b198b1885aede877cbbcc385ebad12a50 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Wed, 10 Jan 2024 23:59:41 +0300 Subject: [PATCH 02/60] add subscription --- novawallet.xcodeproj/project.pbxproj | 4 ++ .../StakingLocalSubscriptionFactory.swift | 23 ++++++++ .../Subscription/DecodedProviderTypes.swift | 1 + .../StakingLocalStorageSubscriber.swift | 52 +++++++++++++++++-- .../StakingLocalSubscriptionHandler.swift | 12 +++++ .../Common/Services/Proxy/ProxyModels.swift | 2 +- .../Calls/Proxy/Proxy+StorageCodingPath.swift | 5 ++ .../Common/Substrate/Types/Proxy/Proxy.swift | 2 +- .../Staking/Model/StakingManageOption.swift | 15 ++++++ ...ingRelaychainInteractor+Subscription.swift | 7 +++ .../StakingRelaychainInteractor.swift | 1 + .../StakingRelaychainPresenter.swift | 11 ++++ .../StakingRelaychainProtocols.swift | 2 + .../StakingRelaychainWireframe.swift | 8 +++ .../StakingStateMachineProtocols.swift | 1 + .../States/BaseStakingState.swift | 1 + .../States/BaseStashNextState.swift | 7 +++ .../StateMachine/States/StashState.swift | 7 +++ .../StakingStateViewModelFactory.swift | 3 ++ .../StakingSetupProxy/ProxyDepositView.swift | 2 +- .../StakingSetupProxyProtocols.swift | 2 +- .../StakingSetupProxyViewController.swift | 1 + .../StakingSetupProxyViewLayout.swift | 9 ++-- novawallet/en.lproj/Localizable.strings | 2 + novawallet/ru.lproj/Localizable.strings | 2 + 25 files changed, 172 insertions(+), 10 deletions(-) create mode 100644 novawallet/Common/Substrate/Calls/Proxy/Proxy+StorageCodingPath.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 44aab1b886..780777126d 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -795,6 +795,7 @@ 772540382AC45D22002B3FD4 /* PurchasePresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 772540372AC45D22002B3FD4 /* PurchasePresentable.swift */; }; 7725EB442B2AC9BA007E1A8A /* ChainProxyChangesCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7725EB432B2AC9BA007E1A8A /* ChainProxyChangesCalculator.swift */; }; 7726CD552A9728D700CE9064 /* StakingTypeSelectedStakingViewModelFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7726CD542A9728D700CE9064 /* StakingTypeSelectedStakingViewModelFactory.swift */; }; + 7727C1392B4E92AE0019BFB5 /* Proxy+StorageCodingPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7727C1382B4E92AE0019BFB5 /* Proxy+StorageCodingPath.swift */; }; 7728E58B2A123AEE007901E0 /* ReferendumsSearchOperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7728E58A2A123AEE007901E0 /* ReferendumsSearchOperationFactory.swift */; }; 7728E58D2A123B42007901E0 /* SearchOperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7728E58C2A123B42007901E0 /* SearchOperationFactory.swift */; }; 7728E58F2A123B70007901E0 /* ReferendumsState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7728E58E2A123B70007901E0 /* ReferendumsState.swift */; }; @@ -4992,6 +4993,7 @@ 772540372AC45D22002B3FD4 /* PurchasePresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PurchasePresentable.swift; sourceTree = ""; }; 7725EB432B2AC9BA007E1A8A /* ChainProxyChangesCalculator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChainProxyChangesCalculator.swift; sourceTree = ""; }; 7726CD542A9728D700CE9064 /* StakingTypeSelectedStakingViewModelFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingTypeSelectedStakingViewModelFactory.swift; sourceTree = ""; }; + 7727C1382B4E92AE0019BFB5 /* Proxy+StorageCodingPath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Proxy+StorageCodingPath.swift"; sourceTree = ""; }; 7728E58A2A123AEE007901E0 /* ReferendumsSearchOperationFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumsSearchOperationFactory.swift; sourceTree = ""; }; 7728E58C2A123B42007901E0 /* SearchOperationFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchOperationFactory.swift; sourceTree = ""; }; 7728E58E2A123B70007901E0 /* ReferendumsState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumsState.swift; sourceTree = ""; }; @@ -8844,6 +8846,7 @@ isa = PBXGroup; children = ( 0C495B8F2B4290A900B8D339 /* Proxy+Call.swift */, + 7727C1382B4E92AE0019BFB5 /* Proxy+StorageCodingPath.swift */, ); path = Proxy; sourceTree = ""; @@ -21616,6 +21619,7 @@ 84D8754028EB1A59004065BD /* ReferendumsInteractorError.swift in Sources */, 883DB17C297A520300EFB7D8 /* GovernanceDelegatesFilter.swift in Sources */, 77ED167A2A0CF41700E1FC8C /* StakingRewardFiltersViewModel.swift in Sources */, + 7727C1392B4E92AE0019BFB5 /* Proxy+StorageCodingPath.swift in Sources */, 849014A624AA801B008F705E /* TextSharingSource.swift in Sources */, 840AD5FC26B4512100E09D6A /* SelectedLanguageMigrator.swift in Sources */, 8804AD83295B7596001C4E09 /* DAppDesktopModeSettingsView.swift in Sources */, diff --git a/novawallet/Common/DataProvider/StakingLocalSubscriptionFactory.swift b/novawallet/Common/DataProvider/StakingLocalSubscriptionFactory.swift index c4fde3a095..b2b2c21c82 100644 --- a/novawallet/Common/DataProvider/StakingLocalSubscriptionFactory.swift +++ b/novawallet/Common/DataProvider/StakingLocalSubscriptionFactory.swift @@ -61,6 +61,11 @@ protocol StakingLocalSubscriptionFactoryProtocol { for accountId: AccountId, chainId: ChainModel.Id ) throws -> AnyDataProvider + + func getProxyListProvider( + for accountId: AccountId, + chainId: ChainModel.Id + ) throws -> AnyDataProvider } final class StakingLocalSubscriptionFactory: SubstrateLocalSubscriptionFactory, @@ -355,4 +360,22 @@ final class StakingLocalSubscriptionFactory: SubstrateLocalSubscriptionFactory, return provider } + + func getProxyListProvider(for accountId: AccountId, chainId: ChainModel.Id) throws -> AnyDataProvider { + clearIfNeeded() + + let codingPath = StorageCodingPath.proxy + let localKey = try LocalStorageKeyFactory().createFromStoragePath( + codingPath, + accountId: accountId, + chainId: chainId + ) + + return try getDataProvider( + for: localKey, + chainId: chainId, + storageCodingPath: codingPath, + shouldUseFallback: false + ) + } } diff --git a/novawallet/Common/DataProvider/Subscription/DecodedProviderTypes.swift b/novawallet/Common/DataProvider/Subscription/DecodedProviderTypes.swift index b2adc18c7b..325d4a0df1 100644 --- a/novawallet/Common/DataProvider/Subscription/DecodedProviderTypes.swift +++ b/novawallet/Common/DataProvider/Subscription/DecodedProviderTypes.swift @@ -20,3 +20,4 @@ typealias DecodedBondedPool = ChainStorageDecodedItem typealias DecodedSubPools = ChainStorageDecodedItem typealias DecodedPoolId = ChainStorageDecodedItem> +typealias DecodedProxyDefinition = ChainStorageDecodedItem diff --git a/novawallet/Common/DataProvider/Subscription/StakingLocalStorageSubscriber.swift b/novawallet/Common/DataProvider/Subscription/StakingLocalStorageSubscriber.swift index 64eefef189..5a9c0b24ec 100644 --- a/novawallet/Common/DataProvider/Subscription/StakingLocalStorageSubscriber.swift +++ b/novawallet/Common/DataProvider/Subscription/StakingLocalStorageSubscriber.swift @@ -51,10 +51,10 @@ protocol StakingLocalStorageSubscriber where Self: AnyObject { assetPrecision: Int16 ) -> AnySingleValueProvider? - func subscribeStashItemProvider( - for address: AccountAddress, + func subscribeProxies( + for accountId: AccountId, chainId: ChainModel.Id - ) -> StreamableProvider? + ) -> AnyDataProvider? } extension StakingLocalStorageSubscriber { @@ -653,6 +653,52 @@ extension StakingLocalStorageSubscriber { return provider } + + func subscribeProxies( + for accountId: AccountId, + chainId: ChainModel.Id + ) -> AnyDataProvider? { + guard let provider = try? stakingLocalSubscriptionFactory.getProxyListProvider( + for: accountId, + chainId: chainId + ) else { + return nil + } + + let updateClosure = { [weak self] (changes: [DataProviderChange]) in + let proxies = changes.reduceToLastChange() + self?.stakingLocalSubscriptionHandler.handleProxies( + result: .success(proxies?.item), + accountId: accountId, + chainId: chainId + ) + return + } + + let failureClosure = { [weak self] (error: Error) in + self?.stakingLocalSubscriptionHandler.handleProxies( + result: .failure(error), + accountId: accountId, + chainId: chainId + ) + return + } + + let options = DataProviderObserverOptions( + alwaysNotifyOnRefresh: false, + waitsInProgressSyncOnAdd: false + ) + + provider.addObserver( + self, + deliverOn: .main, + executing: updateClosure, + failing: failureClosure, + options: options + ) + + return provider + } } extension StakingLocalStorageSubscriber where Self: StakingLocalSubscriptionHandler { diff --git a/novawallet/Common/DataProvider/Subscription/StakingLocalSubscriptionHandler.swift b/novawallet/Common/DataProvider/Subscription/StakingLocalSubscriptionHandler.swift index 45a6aca6bf..a5ac5d4ac4 100644 --- a/novawallet/Common/DataProvider/Subscription/StakingLocalSubscriptionHandler.swift +++ b/novawallet/Common/DataProvider/Subscription/StakingLocalSubscriptionHandler.swift @@ -49,6 +49,12 @@ protocol StakingLocalSubscriptionHandler { func handleActiveEra(result: Result, chainId: ChainModel.Id) func handleCurrentEra(result: Result, chainId: ChainModel.Id) + + func handleProxies( + result: Result, + accountId: AccountId, + chainId: ChainModel.Id + ) } extension StakingLocalSubscriptionHandler { @@ -103,4 +109,10 @@ extension StakingLocalSubscriptionHandler { func handleActiveEra(result _: Result, chainId _: ChainModel.Id) {} func handleCurrentEra(result _: Result, chainId _: ChainModel.Id) {} + + func handleProxies( + result _: Result, + accountId _: AccountId, + chainId _: ChainModel.Id + ) {} } diff --git a/novawallet/Common/Services/Proxy/ProxyModels.swift b/novawallet/Common/Services/Proxy/ProxyModels.swift index 0218df6085..863dfaacd6 100644 --- a/novawallet/Common/Services/Proxy/ProxyModels.swift +++ b/novawallet/Common/Services/Proxy/ProxyModels.swift @@ -31,7 +31,7 @@ struct AccountIdKey: JSONListConvertible, Hashable { } } -struct ProxyDefinition: Decodable { +struct ProxyDefinition: Decodable, Equatable { let definition: [Proxy.ProxyDefinition] init(from decoder: Decoder) throws { diff --git a/novawallet/Common/Substrate/Calls/Proxy/Proxy+StorageCodingPath.swift b/novawallet/Common/Substrate/Calls/Proxy/Proxy+StorageCodingPath.swift new file mode 100644 index 0000000000..d9a57e514b --- /dev/null +++ b/novawallet/Common/Substrate/Calls/Proxy/Proxy+StorageCodingPath.swift @@ -0,0 +1,5 @@ +extension StorageCodingPath { + static var proxy: StorageCodingPath { + StorageCodingPath(moduleName: Proxy.name, itemName: "proxy") + } +} diff --git a/novawallet/Common/Substrate/Types/Proxy/Proxy.swift b/novawallet/Common/Substrate/Types/Proxy/Proxy.swift index a166ca5c43..de0081945f 100644 --- a/novawallet/Common/Substrate/Types/Proxy/Proxy.swift +++ b/novawallet/Common/Substrate/Types/Proxy/Proxy.swift @@ -5,7 +5,7 @@ import BigInt enum Proxy { static var name: String { "Proxy" } - struct ProxyDefinition: Decodable { + struct ProxyDefinition: Decodable, Equatable { enum CodingKeys: String, CodingKey { case proxy = "delegate" case proxyType diff --git a/novawallet/Modules/Staking/Model/StakingManageOption.swift b/novawallet/Modules/Staking/Model/StakingManageOption.swift index d3df5c938b..1f72834b1d 100644 --- a/novawallet/Modules/Staking/Model/StakingManageOption.swift +++ b/novawallet/Modules/Staking/Model/StakingManageOption.swift @@ -10,6 +10,7 @@ enum StakingManageOption { case controllerAccount case yourValidator case yieldBoost(enabled: Bool) + case proxies(count: Int) func titleForLocale(_ locale: Locale, statics: StakingMainStaticViewModelProtocol?) -> String { switch self { @@ -35,6 +36,9 @@ enum StakingManageOption { return R.string.localizable.stakingYourValidatorTitle(preferredLanguages: locale.rLanguages) case .yieldBoost: return R.string.localizable.commonYieldBoost(preferredLanguages: locale.rLanguages) + case let .proxies(count): + return count > 0 ? R.string.localizable.stakingSetupYourProxies(preferredLanguages: locale.rLanguages) : + R.string.localizable.stakingSetupAddYourProxy(preferredLanguages: locale.rLanguages) } } @@ -56,6 +60,15 @@ enum StakingManageOption { } } + if case let .proxies(count) = self { + guard count > 0 else { + return nil + } + + let formatter = NumberFormatter.quantity.localizableResource().value(for: locale) + return formatter.string(from: NSNumber(value: count)) + } + return nil } @@ -75,6 +88,8 @@ enum StakingManageOption { return R.image.iconControllerAccount() case .yieldBoost: return R.image.iconYieldBoost() + case .proxies: + return R.image.iconDelegate() } } } diff --git a/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainInteractor+Subscription.swift b/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainInteractor+Subscription.swift index 6b1880023d..3445da6078 100644 --- a/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainInteractor+Subscription.swift +++ b/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainInteractor+Subscription.swift @@ -13,6 +13,7 @@ extension StakingRelaychainInteractor { clear(dataProvider: &payeeProvider) clear(streamableProvider: &controllerAccountProvider) clear(streamableProvider: &stashAccountProvider) + clear(dataProvider: &proxyProvider) if let stashItem = stashItem, @@ -25,6 +26,7 @@ extension StakingRelaychainInteractor { nominatorProvider = subscribeNomination(for: stashAccountId, chainId: chainId) validatorProvider = subscribeValidator(for: stashAccountId, chainId: chainId) payeeProvider = subscribePayee(for: stashAccountId, chainId: chainId) + proxyProvider = subscribeProxies(for: stashAccountId, chainId: chainId) performTotalRewardSubscription() @@ -102,6 +104,7 @@ extension StakingRelaychainInteractor { clear(singleValueProvider: &totalRewardProvider) clear(dataProvider: &payeeProvider) clear(streamableProvider: &stashControllerProvider) + clear(dataProvider: &proxyProvider) } func performStashControllerSubscription() { @@ -259,6 +262,10 @@ extension StakingRelaychainInteractor: StakingLocalStorageSubscriber, StakingLoc presenter?.didReceiveBagListScoreFactor(result: .failure(error)) } } + + func handleProxies(result: Result, accountId _: AccountId, chainId _: ChainModel.Id) { + presenter?.didReceiveProxy(result: result) + } } extension StakingRelaychainInteractor: PriceLocalStorageSubscriber, PriceLocalSubscriptionHandler { diff --git a/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainInteractor.swift b/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainInteractor.swift index d4ec71ecc2..b726174b2f 100644 --- a/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainInteractor.swift +++ b/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainInteractor.swift @@ -53,6 +53,7 @@ final class StakingRelaychainInteractor: RuntimeConstantFetching, AnyCancellable var bagListSizeProvider: AnyDataProvider? var totalIssuanceProvider: AnyDataProvider? var totalRewardInterval: (startTimestamp: Int64?, endTimestamp: Int64?)? + var proxyProvider: AnyDataProvider? init( selectedWalletSettings: SelectedWalletSettings, diff --git a/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainPresenter.swift b/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainPresenter.swift index c518fd7ce5..92192a7620 100644 --- a/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainPresenter.swift +++ b/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainPresenter.swift @@ -342,6 +342,8 @@ extension StakingRelaychainPresenter: StakingMainChildPresenterProtocol { let stashAddress = validatorState.stashItem.stash wireframe.showYourValidatorInfo(stashAddress, from: view) } + case .proxies: + wireframe.showAddProxies(from: view) default: logger?.warning("Unsupported action: \(action)") } @@ -604,4 +606,13 @@ extension StakingRelaychainPresenter: StakingRelaychainInteractorOutputProtocol handle(error: error) } } + + func didReceiveProxy(result: Result) { + switch result { + case let .success(proxy): + stateMachine.state.process(proxy: proxy) + case let .failure(error): + handle(error: error) + } + } } diff --git a/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainProtocols.swift b/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainProtocols.swift index ed5e3bdd2d..fa7f5c9fe1 100644 --- a/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainProtocols.swift +++ b/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainProtocols.swift @@ -42,6 +42,7 @@ protocol StakingRelaychainInteractorOutputProtocol: AnyObject { func didReceiveMaxNominatorsPerValidator(result: Result) func didReceiveAccount(_ account: MetaChainAccountResponse?, for accountId: AccountId) + func didReceiveProxy(result: Result) } protocol StakingRelaychainWireframeProtocol: AlertPresentable, ErrorPresentable, StakingErrorPresentable { @@ -63,4 +64,5 @@ protocol StakingRelaychainWireframeProtocol: AlertPresentable, ErrorPresentable, func showRebagConfirm(from view: ControllerBackedProtocol?) func showYourValidatorInfo(_ stashAddress: AccountAddress, from view: ControllerBackedProtocol?) + func showAddProxies(from view: ControllerBackedProtocol?) } diff --git a/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainWireframe.swift b/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainWireframe.swift index 82b1e9642b..b03ef05d2f 100644 --- a/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainWireframe.swift +++ b/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainWireframe.swift @@ -151,4 +151,12 @@ extension StakingRelaychainWireframe: StakingRelaychainWireframeProtocol { let navigationController = NovaNavigationController(rootViewController: validatorInfoView.controller) view?.controller.present(navigationController, animated: true, completion: nil) } + + func showAddProxies(from view: ControllerBackedProtocol?) { + guard let setupProxyView = StakingSetupProxyViewFactory.createView() else { + return + } + let navigationController = NovaNavigationController(rootViewController: setupProxyView.controller) + view?.controller.present(navigationController, animated: true, completion: nil) + } } diff --git a/novawallet/Modules/Staking/StakingMain/Relaychain/StateMachine/StakingStateMachineProtocols.swift b/novawallet/Modules/Staking/StakingMain/Relaychain/StateMachine/StakingStateMachineProtocols.swift index a94e62d9fe..92cd64b85a 100644 --- a/novawallet/Modules/Staking/StakingMain/Relaychain/StateMachine/StakingStateMachineProtocols.swift +++ b/novawallet/Modules/Staking/StakingMain/Relaychain/StateMachine/StakingStateMachineProtocols.swift @@ -37,6 +37,7 @@ protocol StakingStateProtocol { func process(bagListScoreFactor: BigUInt?) func process(eraCountdown: EraCountdown) func process(totalRewardFilter: StakingRewardFiltersPeriod?) + func process(proxy: ProxyDefinition?) } protocol StakingStateMachineProtocol: AnyObject { diff --git a/novawallet/Modules/Staking/StakingMain/Relaychain/StateMachine/States/BaseStakingState.swift b/novawallet/Modules/Staking/StakingMain/Relaychain/StateMachine/States/BaseStakingState.swift index 22b82c4025..620267d410 100644 --- a/novawallet/Modules/Staking/StakingMain/Relaychain/StateMachine/States/BaseStakingState.swift +++ b/novawallet/Modules/Staking/StakingMain/Relaychain/StateMachine/States/BaseStakingState.swift @@ -127,6 +127,7 @@ class BaseStakingState: StakingStateProtocol { func process(totalReward _: TotalRewardItem?) {} func process(payee _: Staking.RewardDestinationArg?) {} func process(bagListNode _: BagList.Node?) {} + func process(proxy _: ProxyDefinition?) {} func process(eraCountdown: EraCountdown) { commonData = commonData.byReplacing(eraCountdown: eraCountdown) diff --git a/novawallet/Modules/Staking/StakingMain/Relaychain/StateMachine/States/BaseStashNextState.swift b/novawallet/Modules/Staking/StakingMain/Relaychain/StateMachine/States/BaseStashNextState.swift index cf54590636..06fef4798b 100644 --- a/novawallet/Modules/Staking/StakingMain/Relaychain/StateMachine/States/BaseStashNextState.swift +++ b/novawallet/Modules/Staking/StakingMain/Relaychain/StateMachine/States/BaseStashNextState.swift @@ -5,6 +5,7 @@ class BaseStashNextState: BaseStakingState { private(set) var totalReward: TotalRewardItem? private(set) var payee: Staking.RewardDestinationArg? private(set) var bagListNode: BagList.Node? + private(set) var proxy: ProxyDefinition? init( stateMachine: StakingStateMachineProtocol, @@ -70,4 +71,10 @@ class BaseStashNextState: BaseStakingState { stateMachine?.transit(to: self) } + + override func process(proxy: ProxyDefinition?) { + self.proxy = proxy + + stateMachine?.transit(to: self) + } } diff --git a/novawallet/Modules/Staking/StakingMain/Relaychain/StateMachine/States/StashState.swift b/novawallet/Modules/Staking/StakingMain/Relaychain/StateMachine/States/StashState.swift index c3c501cc75..bf53443b7c 100644 --- a/novawallet/Modules/Staking/StakingMain/Relaychain/StateMachine/States/StashState.swift +++ b/novawallet/Modules/Staking/StakingMain/Relaychain/StateMachine/States/StashState.swift @@ -6,6 +6,7 @@ final class StashState: BaseStakingState { private(set) var payee: Staking.RewardDestinationArg? private(set) var ledgerInfo: StakingLedger? private(set) var bagListNode: BagList.Node? + private(set) var proxy: ProxyDefinition? init( stateMachine: StakingStateMachineProtocol, @@ -156,4 +157,10 @@ final class StashState: BaseStakingState { stateMachine?.transit(to: self) } + + override func process(proxy: ProxyDefinition?) { + self.proxy = proxy + + stateMachine?.transit(to: self) + } } diff --git a/novawallet/Modules/Staking/StakingMain/Relaychain/ViewModel/StakingStateViewModelFactory.swift b/novawallet/Modules/Staking/StakingMain/Relaychain/ViewModel/StakingStateViewModelFactory.swift index 90a2c35737..9bb4cd8e00 100644 --- a/novawallet/Modules/Staking/StakingMain/Relaychain/ViewModel/StakingStateViewModelFactory.swift +++ b/novawallet/Modules/Staking/StakingMain/Relaychain/ViewModel/StakingStateViewModelFactory.swift @@ -255,6 +255,7 @@ extension StakingStateViewModelFactory: StakingStateVisitorProtocol { .unstake, .rewardDestination, .setupValidators, + .proxies(count: state.proxy?.definition.count ?? 0), .controllerAccount ] @@ -319,6 +320,7 @@ extension StakingStateViewModelFactory: StakingStateVisitorProtocol { .rewardDestination, .pendingRewards, .changeValidators(count: state.nomination.targets.count), + .proxies(count: state.proxy?.definition.count ?? 0), .controllerAccount ] @@ -383,6 +385,7 @@ extension StakingStateViewModelFactory: StakingStateVisitorProtocol { .rewardDestination, .pendingRewards, .yourValidator, + .proxies(count: state.proxy?.definition.count ?? 0), .controllerAccount ] diff --git a/novawallet/Modules/Staking/StakingSetupProxy/ProxyDepositView.swift b/novawallet/Modules/Staking/StakingSetupProxy/ProxyDepositView.swift index 8dd27089ed..52812ce19a 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/ProxyDepositView.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/ProxyDepositView.swift @@ -3,7 +3,7 @@ import SoraUI final class ProxyDepositView: RowView> { var imageView: UIImageView { rowContentView.imageView } var titleButton: RoundedButton { rowContentView.detailsView.titleButton } - var valueTopButton: RoundedButton { rowContentView.detailsView.titleButton } + var valueTopButton: RoundedButton { rowContentView.detailsView.valueTopButton } var valueBottomLabel: UILabel { rowContentView.detailsView.valueBottomLabel } override init(frame: CGRect) { diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyProtocols.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyProtocols.swift index 4b44772785..77ac3ec08f 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyProtocols.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyProtocols.swift @@ -1,4 +1,4 @@ -protocol StakingSetupProxyViewProtocol: AnyObject {} +protocol StakingSetupProxyViewProtocol: ControllerBackedProtocol {} protocol StakingSetupProxyPresenterProtocol: AnyObject { func setup() diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewController.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewController.swift index 2d3eee6a80..bde9b5423e 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewController.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewController.swift @@ -51,6 +51,7 @@ final class StakingSetupProxyViewController: UIViewController, ViewHolder { preferredLanguages: languages ) rootView.feeView.locale = selectedLocale + rootView.accountInputView.locale = selectedLocale } private func setupHandlers() { diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewLayout.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewLayout.swift index cac85423b6..c632a9fc76 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewLayout.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewLayout.swift @@ -27,7 +27,8 @@ final class StakingSetupProxyViewLayout: ScrollableContainerLayoutView { } let proxyView: ProxyDepositView = .create { - $0.imageView.image = R.image.iconLock()! + $0.imageView.image = R.image.iconLock()!.withTintColor(R.color.colorIconSecondary()!) + $0.contentInsets = .zero } let feeView: NetworkFeeView = { @@ -37,6 +38,8 @@ final class StakingSetupProxyViewLayout: ScrollableContainerLayoutView { }() override func setupLayout() { + super.setupLayout() + addSubview(actionButton) actionButton.snp.makeConstraints { make in make.leading.trailing.equalToSuperview().inset(UIConstants.horizontalInset) @@ -44,7 +47,7 @@ final class StakingSetupProxyViewLayout: ScrollableContainerLayoutView { make.height.equalTo(UIConstants.actionHeight) } - addArrangedSubview(titleLabel, spacingAfter: 16) + addArrangedSubview(titleLabel, spacingAfter: 8) let titleStackView = UIStackView(arrangedSubviews: [ authorityLabel, @@ -52,7 +55,7 @@ final class StakingSetupProxyViewLayout: ScrollableContainerLayoutView { yourWalletsControl ]) - addArrangedSubview(titleStackView, spacingAfter: 8) + addArrangedSubview(titleStackView, spacingAfter: 0) addArrangedSubview(accountInputView, spacingAfter: 40) addArrangedSubview(proxyView, spacingAfter: 0) addArrangedSubview(feeView) diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index 5eb0eb88f6..9212b2488e 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -1376,6 +1376,8 @@ "staking.setup.proxy.authority" = "Give authority to"; "staking.setup.proxy.deposit" = "Proxy deposit"; "staking.setup.proxy.deposit.details" = "The deposit stays reserved on your account until the proxy is removed."; +"staking.setup.your.proxies" = "Your delegations"; +"staking.setup.add.your.proxy" = "Add delegated authority (Proxy)"; "common.time.in" = "in"; "common.and" = " and "; "common.time.period.after" = "after"; diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index 2b8bd54b46..86fff8b2d8 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1376,6 +1376,8 @@ "staking.setup.proxy.authority" = "Дать доступ"; "staking.setup.proxy.deposit" = "Прокси депозит"; "staking.setup.proxy.deposit.details" = "Депозит остается зарезервированным на вашем счете до тех пор, пока прокси не будет удален."; +"staking.setup.your.proxies" = "Ваши делегации"; +"staking.setup.add.your.proxy" = "Добавить делегацию (Прокси)"; "common.time.in" = "через"; "common.and" = " и "; "common.time.period.after" = "через"; From 54cd582e2b486173f21ef8d941ba46dc49ecfd92 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Thu, 11 Jan 2024 11:16:04 +0300 Subject: [PATCH 03/60] refactor --- novawallet.xcodeproj/project.pbxproj | 4 - .../StakingLocalSubscriptionFactory.swift | 7 +- .../StakingAccountSubscription.swift | 2 + .../Calls/Proxy/Proxy+StorageCodingPath.swift | 5 - .../Staking/Model/StakingManageOption.swift | 26 +- .../StakingRelaychainPresenter.swift | 5 +- .../States/BaseStakingState.swift | 7 +- .../States/BaseStashNextState.swift | 7 - .../States/StakingStateCommonData.swift | 346 ++++-------------- .../StateMachine/States/StashState.swift | 7 - .../StakingStateViewModelFactory.swift | 6 +- 11 files changed, 111 insertions(+), 311 deletions(-) delete mode 100644 novawallet/Common/Substrate/Calls/Proxy/Proxy+StorageCodingPath.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 6c8586f427..6c9f818cac 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -801,7 +801,6 @@ 772540382AC45D22002B3FD4 /* PurchasePresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 772540372AC45D22002B3FD4 /* PurchasePresentable.swift */; }; 7725EB442B2AC9BA007E1A8A /* ChainProxyChangesCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7725EB432B2AC9BA007E1A8A /* ChainProxyChangesCalculator.swift */; }; 7726CD552A9728D700CE9064 /* StakingTypeSelectedStakingViewModelFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7726CD542A9728D700CE9064 /* StakingTypeSelectedStakingViewModelFactory.swift */; }; - 7727C1392B4E92AE0019BFB5 /* Proxy+StorageCodingPath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7727C1382B4E92AE0019BFB5 /* Proxy+StorageCodingPath.swift */; }; 7728E58B2A123AEE007901E0 /* ReferendumsSearchOperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7728E58A2A123AEE007901E0 /* ReferendumsSearchOperationFactory.swift */; }; 7728E58D2A123B42007901E0 /* SearchOperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7728E58C2A123B42007901E0 /* SearchOperationFactory.swift */; }; 7728E58F2A123B70007901E0 /* ReferendumsState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7728E58E2A123B70007901E0 /* ReferendumsState.swift */; }; @@ -5006,7 +5005,6 @@ 772540372AC45D22002B3FD4 /* PurchasePresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PurchasePresentable.swift; sourceTree = ""; }; 7725EB432B2AC9BA007E1A8A /* ChainProxyChangesCalculator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChainProxyChangesCalculator.swift; sourceTree = ""; }; 7726CD542A9728D700CE9064 /* StakingTypeSelectedStakingViewModelFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingTypeSelectedStakingViewModelFactory.swift; sourceTree = ""; }; - 7727C1382B4E92AE0019BFB5 /* Proxy+StorageCodingPath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Proxy+StorageCodingPath.swift"; sourceTree = ""; }; 7728E58A2A123AEE007901E0 /* ReferendumsSearchOperationFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumsSearchOperationFactory.swift; sourceTree = ""; }; 7728E58C2A123B42007901E0 /* SearchOperationFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchOperationFactory.swift; sourceTree = ""; }; 7728E58E2A123B70007901E0 /* ReferendumsState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumsState.swift; sourceTree = ""; }; @@ -8864,7 +8862,6 @@ isa = PBXGroup; children = ( 0C495B8F2B4290A900B8D339 /* Proxy+Call.swift */, - 7727C1382B4E92AE0019BFB5 /* Proxy+StorageCodingPath.swift */, ); path = Proxy; sourceTree = ""; @@ -21655,7 +21652,6 @@ 84D8754028EB1A59004065BD /* ReferendumsInteractorError.swift in Sources */, 883DB17C297A520300EFB7D8 /* GovernanceDelegatesFilter.swift in Sources */, 77ED167A2A0CF41700E1FC8C /* StakingRewardFiltersViewModel.swift in Sources */, - 7727C1392B4E92AE0019BFB5 /* Proxy+StorageCodingPath.swift in Sources */, 849014A624AA801B008F705E /* TextSharingSource.swift in Sources */, 840AD5FC26B4512100E09D6A /* SelectedLanguageMigrator.swift in Sources */, 8804AD83295B7596001C4E09 /* DAppDesktopModeSettingsView.swift in Sources */, diff --git a/novawallet/Common/DataProvider/StakingLocalSubscriptionFactory.swift b/novawallet/Common/DataProvider/StakingLocalSubscriptionFactory.swift index b2b2c21c82..e82195964c 100644 --- a/novawallet/Common/DataProvider/StakingLocalSubscriptionFactory.swift +++ b/novawallet/Common/DataProvider/StakingLocalSubscriptionFactory.swift @@ -361,10 +361,13 @@ final class StakingLocalSubscriptionFactory: SubstrateLocalSubscriptionFactory, return provider } - func getProxyListProvider(for accountId: AccountId, chainId: ChainModel.Id) throws -> AnyDataProvider { + func getProxyListProvider( + for accountId: AccountId, + chainId: ChainModel.Id + ) throws -> AnyDataProvider { clearIfNeeded() - let codingPath = StorageCodingPath.proxy + let codingPath = Proxy.proxyList let localKey = try LocalStorageKeyFactory().createFromStoragePath( codingPath, accountId: accountId, diff --git a/novawallet/Common/Services/RemoteSubscription/Substrate/StakingAccountSubscription.swift b/novawallet/Common/Services/RemoteSubscription/Substrate/StakingAccountSubscription.swift index abce7705c5..f08b2a64cc 100644 --- a/novawallet/Common/Services/RemoteSubscription/Substrate/StakingAccountSubscription.swift +++ b/novawallet/Common/Services/RemoteSubscription/Substrate/StakingAccountSubscription.swift @@ -130,6 +130,8 @@ final class StakingAccountSubscription: WebSocketSubscribing { ) } + requests.append(.init(storagePath: Proxy.proxyList, accountId: stashId)) + return requests } diff --git a/novawallet/Common/Substrate/Calls/Proxy/Proxy+StorageCodingPath.swift b/novawallet/Common/Substrate/Calls/Proxy/Proxy+StorageCodingPath.swift deleted file mode 100644 index d9a57e514b..0000000000 --- a/novawallet/Common/Substrate/Calls/Proxy/Proxy+StorageCodingPath.swift +++ /dev/null @@ -1,5 +0,0 @@ -extension StorageCodingPath { - static var proxy: StorageCodingPath { - StorageCodingPath(moduleName: Proxy.name, itemName: "proxy") - } -} diff --git a/novawallet/Modules/Staking/Model/StakingManageOption.swift b/novawallet/Modules/Staking/Model/StakingManageOption.swift index 1f72834b1d..ddc750b3e6 100644 --- a/novawallet/Modules/Staking/Model/StakingManageOption.swift +++ b/novawallet/Modules/Staking/Model/StakingManageOption.swift @@ -10,7 +10,8 @@ enum StakingManageOption { case controllerAccount case yourValidator case yieldBoost(enabled: Bool) - case proxies(count: Int) + case addProxy + case editProxies(currentCount: Int) func titleForLocale(_ locale: Locale, statics: StakingMainStaticViewModelProtocol?) -> String { switch self { @@ -36,9 +37,10 @@ enum StakingManageOption { return R.string.localizable.stakingYourValidatorTitle(preferredLanguages: locale.rLanguages) case .yieldBoost: return R.string.localizable.commonYieldBoost(preferredLanguages: locale.rLanguages) - case let .proxies(count): - return count > 0 ? R.string.localizable.stakingSetupYourProxies(preferredLanguages: locale.rLanguages) : - R.string.localizable.stakingSetupAddYourProxy(preferredLanguages: locale.rLanguages) + case .addProxy: + return R.string.localizable.stakingSetupAddYourProxy(preferredLanguages: locale.rLanguages) + case let .editProxies: + return R.string.localizable.stakingSetupYourProxies(preferredLanguages: locale.rLanguages) } } @@ -60,11 +62,7 @@ enum StakingManageOption { } } - if case let .proxies(count) = self { - guard count > 0 else { - return nil - } - + if case let .editProxies(count) = self { let formatter = NumberFormatter.quantity.localizableResource().value(for: locale) return formatter.string(from: NSNumber(value: count)) } @@ -88,8 +86,16 @@ enum StakingManageOption { return R.image.iconControllerAccount() case .yieldBoost: return R.image.iconYieldBoost() - case .proxies: + case .addProxy, .editProxies: return R.image.iconDelegate() } } + + static func proxyAction(from proxyDefinition: ProxyDefinition?) -> StakingManageOption { + guard let proxiesCount = proxyDefinition?.definition.count, proxiesCount > 0 else { + return .addProxy + } + + return .editProxies(currentCount: proxiesCount) + } } diff --git a/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainPresenter.swift b/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainPresenter.swift index 92192a7620..fa6be97c17 100644 --- a/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainPresenter.swift +++ b/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainPresenter.swift @@ -342,8 +342,11 @@ extension StakingRelaychainPresenter: StakingMainChildPresenterProtocol { let stashAddress = validatorState.stashItem.stash wireframe.showYourValidatorInfo(stashAddress, from: view) } - case .proxies: + case .addProxy: wireframe.showAddProxies(from: view) + case .editProxies: + // TODO: show proxy list + fallthrough default: logger?.warning("Unsupported action: \(action)") } diff --git a/novawallet/Modules/Staking/StakingMain/Relaychain/StateMachine/States/BaseStakingState.swift b/novawallet/Modules/Staking/StakingMain/Relaychain/StateMachine/States/BaseStakingState.swift index 620267d410..b5ae852c6d 100644 --- a/novawallet/Modules/Staking/StakingMain/Relaychain/StateMachine/States/BaseStakingState.swift +++ b/novawallet/Modules/Staking/StakingMain/Relaychain/StateMachine/States/BaseStakingState.swift @@ -127,7 +127,6 @@ class BaseStakingState: StakingStateProtocol { func process(totalReward _: TotalRewardItem?) {} func process(payee _: Staking.RewardDestinationArg?) {} func process(bagListNode _: BagList.Node?) {} - func process(proxy _: ProxyDefinition?) {} func process(eraCountdown: EraCountdown) { commonData = commonData.byReplacing(eraCountdown: eraCountdown) @@ -140,4 +139,10 @@ class BaseStakingState: StakingStateProtocol { stateMachine?.transit(to: self) } + + func process(proxy: ProxyDefinition?) { + commonData = commonData.byReplacing(proxy: proxy) + + stateMachine?.transit(to: self) + } } diff --git a/novawallet/Modules/Staking/StakingMain/Relaychain/StateMachine/States/BaseStashNextState.swift b/novawallet/Modules/Staking/StakingMain/Relaychain/StateMachine/States/BaseStashNextState.swift index 06fef4798b..cf54590636 100644 --- a/novawallet/Modules/Staking/StakingMain/Relaychain/StateMachine/States/BaseStashNextState.swift +++ b/novawallet/Modules/Staking/StakingMain/Relaychain/StateMachine/States/BaseStashNextState.swift @@ -5,7 +5,6 @@ class BaseStashNextState: BaseStakingState { private(set) var totalReward: TotalRewardItem? private(set) var payee: Staking.RewardDestinationArg? private(set) var bagListNode: BagList.Node? - private(set) var proxy: ProxyDefinition? init( stateMachine: StakingStateMachineProtocol, @@ -71,10 +70,4 @@ class BaseStashNextState: BaseStakingState { stateMachine?.transit(to: self) } - - override func process(proxy: ProxyDefinition?) { - self.proxy = proxy - - stateMachine?.transit(to: self) - } } diff --git a/novawallet/Modules/Staking/StakingMain/Relaychain/StateMachine/States/StakingStateCommonData.swift b/novawallet/Modules/Staking/StakingMain/Relaychain/StateMachine/States/StakingStateCommonData.swift index c2fbe7804e..ca8635c257 100644 --- a/novawallet/Modules/Staking/StakingMain/Relaychain/StateMachine/States/StakingStateCommonData.swift +++ b/novawallet/Modules/Staking/StakingMain/Relaychain/StateMachine/States/StakingStateCommonData.swift @@ -2,21 +2,22 @@ import Foundation import BigInt struct StakingStateCommonData { - let address: String? - let chainAsset: ChainAsset? - let accountBalance: AssetBalance? - let price: PriceData? - let calculatorEngine: RewardCalculatorEngineProtocol? - let eraStakersInfo: EraStakersInfo? - let minStake: BigUInt? - let maxNominatorsPerValidator: UInt32? - let minNominatorBond: BigUInt? - let counterForNominators: UInt32? - let maxNominatorsCount: UInt32? - let bagListSize: UInt32? - let bagListScoreFactor: BigUInt? - let eraCountdown: EraCountdown? - let totalRewardFilter: StakingRewardFiltersPeriod? + private(set) var address: String? + private(set) var chainAsset: ChainAsset? + private(set) var accountBalance: AssetBalance? + private(set) var price: PriceData? + private(set) var calculatorEngine: RewardCalculatorEngineProtocol? + private(set) var eraStakersInfo: EraStakersInfo? + private(set) var minStake: BigUInt? + private(set) var maxNominatorsPerValidator: UInt32? + private(set) var minNominatorBond: BigUInt? + private(set) var counterForNominators: UInt32? + private(set) var maxNominatorsCount: UInt32? + private(set) var bagListSize: UInt32? + private(set) var bagListScoreFactor: BigUInt? + private(set) var eraCountdown: EraCountdown? + private(set) var totalRewardFilter: StakingRewardFiltersPeriod? + private(set) var proxy: ProxyDefinition? } extension StakingStateCommonData { @@ -36,307 +37,110 @@ extension StakingStateCommonData { bagListSize: nil, bagListScoreFactor: nil, eraCountdown: nil, - totalRewardFilter: nil + totalRewardFilter: nil, + proxy: nil ) } func byReplacing(address: String?) -> StakingStateCommonData { - StakingStateCommonData( - address: address, - chainAsset: chainAsset, - accountBalance: accountBalance, - price: price, - calculatorEngine: calculatorEngine, - eraStakersInfo: eraStakersInfo, - minStake: minStake, - maxNominatorsPerValidator: maxNominatorsPerValidator, - minNominatorBond: minNominatorBond, - counterForNominators: counterForNominators, - maxNominatorsCount: maxNominatorsCount, - bagListSize: bagListSize, - bagListScoreFactor: bagListScoreFactor, - eraCountdown: eraCountdown, - totalRewardFilter: totalRewardFilter - ) + replace { + $0.address = address + } } func byReplacing(chainAsset: ChainAsset?) -> StakingStateCommonData { - StakingStateCommonData( - address: address, - chainAsset: chainAsset, - accountBalance: accountBalance, - price: price, - calculatorEngine: calculatorEngine, - eraStakersInfo: eraStakersInfo, - minStake: minStake, - maxNominatorsPerValidator: maxNominatorsPerValidator, - minNominatorBond: minNominatorBond, - counterForNominators: counterForNominators, - maxNominatorsCount: maxNominatorsCount, - bagListSize: bagListSize, - bagListScoreFactor: bagListScoreFactor, - eraCountdown: eraCountdown, - totalRewardFilter: totalRewardFilter - ) + replace { + $0.chainAsset = chainAsset + } } func byReplacing(accountBalance: AssetBalance?) -> StakingStateCommonData { - StakingStateCommonData( - address: address, - chainAsset: chainAsset, - accountBalance: accountBalance, - price: price, - calculatorEngine: calculatorEngine, - eraStakersInfo: eraStakersInfo, - minStake: minStake, - maxNominatorsPerValidator: maxNominatorsPerValidator, - minNominatorBond: minNominatorBond, - counterForNominators: counterForNominators, - maxNominatorsCount: maxNominatorsCount, - bagListSize: bagListSize, - bagListScoreFactor: bagListScoreFactor, - eraCountdown: eraCountdown, - totalRewardFilter: totalRewardFilter - ) + replace { + $0.accountBalance = accountBalance + } } func byReplacing(price: PriceData?) -> StakingStateCommonData { - StakingStateCommonData( - address: address, - chainAsset: chainAsset, - accountBalance: accountBalance, - price: price, - calculatorEngine: calculatorEngine, - eraStakersInfo: eraStakersInfo, - minStake: minStake, - maxNominatorsPerValidator: maxNominatorsPerValidator, - minNominatorBond: minNominatorBond, - counterForNominators: counterForNominators, - maxNominatorsCount: maxNominatorsCount, - bagListSize: bagListSize, - bagListScoreFactor: bagListScoreFactor, - eraCountdown: eraCountdown, - totalRewardFilter: totalRewardFilter - ) + replace { + $0.price = price + } } func byReplacing(calculatorEngine: RewardCalculatorEngineProtocol?) -> StakingStateCommonData { - StakingStateCommonData( - address: address, - chainAsset: chainAsset, - accountBalance: accountBalance, - price: price, - calculatorEngine: calculatorEngine, - eraStakersInfo: eraStakersInfo, - minStake: minStake, - maxNominatorsPerValidator: maxNominatorsPerValidator, - minNominatorBond: minNominatorBond, - counterForNominators: counterForNominators, - maxNominatorsCount: maxNominatorsCount, - bagListSize: bagListSize, - bagListScoreFactor: bagListScoreFactor, - eraCountdown: eraCountdown, - totalRewardFilter: totalRewardFilter - ) + replace { + $0.calculatorEngine = calculatorEngine + } } func byReplacing(eraStakersInfo: EraStakersInfo?) -> StakingStateCommonData { - StakingStateCommonData( - address: address, - chainAsset: chainAsset, - accountBalance: accountBalance, - price: price, - calculatorEngine: calculatorEngine, - eraStakersInfo: eraStakersInfo, - minStake: minStake, - maxNominatorsPerValidator: maxNominatorsPerValidator, - minNominatorBond: minNominatorBond, - counterForNominators: counterForNominators, - maxNominatorsCount: maxNominatorsCount, - bagListSize: bagListSize, - bagListScoreFactor: bagListScoreFactor, - eraCountdown: eraCountdown, - totalRewardFilter: totalRewardFilter - ) + replace { + $0.eraStakersInfo = eraStakersInfo + } } func byReplacing(minStake: BigUInt?) -> StakingStateCommonData { - StakingStateCommonData( - address: address, - chainAsset: chainAsset, - accountBalance: accountBalance, - price: price, - calculatorEngine: calculatorEngine, - eraStakersInfo: eraStakersInfo, - minStake: minStake, - maxNominatorsPerValidator: maxNominatorsPerValidator, - minNominatorBond: minNominatorBond, - counterForNominators: counterForNominators, - maxNominatorsCount: maxNominatorsCount, - bagListSize: bagListSize, - bagListScoreFactor: bagListScoreFactor, - eraCountdown: eraCountdown, - totalRewardFilter: totalRewardFilter - ) + replace { + $0.minStake = minStake + } } func byReplacing(maxNominatorsPerValidator: UInt32?) -> StakingStateCommonData { - StakingStateCommonData( - address: address, - chainAsset: chainAsset, - accountBalance: accountBalance, - price: price, - calculatorEngine: calculatorEngine, - eraStakersInfo: eraStakersInfo, - minStake: minStake, - maxNominatorsPerValidator: maxNominatorsPerValidator, - minNominatorBond: minNominatorBond, - counterForNominators: counterForNominators, - maxNominatorsCount: maxNominatorsCount, - bagListSize: bagListSize, - bagListScoreFactor: bagListScoreFactor, - eraCountdown: eraCountdown, - totalRewardFilter: totalRewardFilter - ) + replace { + $0.maxNominatorsPerValidator = maxNominatorsPerValidator + } } func byReplacing(minNominatorBond: BigUInt?) -> StakingStateCommonData { - StakingStateCommonData( - address: address, - chainAsset: chainAsset, - accountBalance: accountBalance, - price: price, - calculatorEngine: calculatorEngine, - eraStakersInfo: eraStakersInfo, - minStake: minStake, - maxNominatorsPerValidator: maxNominatorsPerValidator, - minNominatorBond: minNominatorBond, - counterForNominators: counterForNominators, - maxNominatorsCount: maxNominatorsCount, - bagListSize: bagListSize, - bagListScoreFactor: bagListScoreFactor, - eraCountdown: eraCountdown, - totalRewardFilter: totalRewardFilter - ) + replace { + $0.minNominatorBond = minNominatorBond + } } func byReplacing(counterForNominators: UInt32?) -> StakingStateCommonData { - StakingStateCommonData( - address: address, - chainAsset: chainAsset, - accountBalance: accountBalance, - price: price, - calculatorEngine: calculatorEngine, - eraStakersInfo: eraStakersInfo, - minStake: minStake, - maxNominatorsPerValidator: maxNominatorsPerValidator, - minNominatorBond: minNominatorBond, - counterForNominators: counterForNominators, - maxNominatorsCount: maxNominatorsCount, - bagListSize: bagListSize, - bagListScoreFactor: bagListScoreFactor, - eraCountdown: eraCountdown, - totalRewardFilter: totalRewardFilter - ) + replace { + $0.counterForNominators = counterForNominators + } } func byReplacing(maxNominatorsCount: UInt32?) -> StakingStateCommonData { - StakingStateCommonData( - address: address, - chainAsset: chainAsset, - accountBalance: accountBalance, - price: price, - calculatorEngine: calculatorEngine, - eraStakersInfo: eraStakersInfo, - minStake: minStake, - maxNominatorsPerValidator: maxNominatorsPerValidator, - minNominatorBond: minNominatorBond, - counterForNominators: counterForNominators, - maxNominatorsCount: maxNominatorsCount, - bagListSize: bagListSize, - bagListScoreFactor: bagListScoreFactor, - eraCountdown: eraCountdown, - totalRewardFilter: totalRewardFilter - ) + replace { + $0.maxNominatorsCount = maxNominatorsCount + } } func byReplacing(bagListSize: UInt32?) -> StakingStateCommonData { - StakingStateCommonData( - address: address, - chainAsset: chainAsset, - accountBalance: accountBalance, - price: price, - calculatorEngine: calculatorEngine, - eraStakersInfo: eraStakersInfo, - minStake: minStake, - maxNominatorsPerValidator: maxNominatorsPerValidator, - minNominatorBond: minNominatorBond, - counterForNominators: counterForNominators, - maxNominatorsCount: maxNominatorsCount, - bagListSize: bagListSize, - bagListScoreFactor: bagListScoreFactor, - eraCountdown: eraCountdown, - totalRewardFilter: totalRewardFilter - ) + replace { + $0.bagListSize = bagListSize + } } func byReplacing(bagListScoreFactor: BigUInt?) -> StakingStateCommonData { - StakingStateCommonData( - address: address, - chainAsset: chainAsset, - accountBalance: accountBalance, - price: price, - calculatorEngine: calculatorEngine, - eraStakersInfo: eraStakersInfo, - minStake: minStake, - maxNominatorsPerValidator: maxNominatorsPerValidator, - minNominatorBond: minNominatorBond, - counterForNominators: counterForNominators, - maxNominatorsCount: maxNominatorsCount, - bagListSize: bagListSize, - bagListScoreFactor: bagListScoreFactor, - eraCountdown: eraCountdown, - totalRewardFilter: totalRewardFilter - ) + replace { + $0.bagListScoreFactor = bagListScoreFactor + } } func byReplacing(eraCountdown: EraCountdown?) -> StakingStateCommonData { - StakingStateCommonData( - address: address, - chainAsset: chainAsset, - accountBalance: accountBalance, - price: price, - calculatorEngine: calculatorEngine, - eraStakersInfo: eraStakersInfo, - minStake: minStake, - maxNominatorsPerValidator: maxNominatorsPerValidator, - minNominatorBond: minNominatorBond, - counterForNominators: counterForNominators, - maxNominatorsCount: maxNominatorsCount, - bagListSize: bagListSize, - bagListScoreFactor: bagListScoreFactor, - eraCountdown: eraCountdown, - totalRewardFilter: totalRewardFilter - ) + replace { + $0.eraCountdown = eraCountdown + } } func byReplacing(totalRewardFilter: StakingRewardFiltersPeriod?) -> StakingStateCommonData { - StakingStateCommonData( - address: address, - chainAsset: chainAsset, - accountBalance: accountBalance, - price: price, - calculatorEngine: calculatorEngine, - eraStakersInfo: eraStakersInfo, - minStake: minStake, - maxNominatorsPerValidator: maxNominatorsPerValidator, - minNominatorBond: minNominatorBond, - counterForNominators: counterForNominators, - maxNominatorsCount: maxNominatorsCount, - bagListSize: bagListSize, - bagListScoreFactor: bagListScoreFactor, - eraCountdown: eraCountdown, - totalRewardFilter: totalRewardFilter - ) + replace { + $0.totalRewardFilter = totalRewardFilter + } + } + + func byReplacing(proxy: ProxyDefinition?) -> StakingStateCommonData { + replace { + $0.proxy = proxy + } + } + + private func replace(builder: (inout StakingStateCommonData) -> Void) -> StakingStateCommonData { + var data = self + builder(&data) + return data } } diff --git a/novawallet/Modules/Staking/StakingMain/Relaychain/StateMachine/States/StashState.swift b/novawallet/Modules/Staking/StakingMain/Relaychain/StateMachine/States/StashState.swift index bf53443b7c..c3c501cc75 100644 --- a/novawallet/Modules/Staking/StakingMain/Relaychain/StateMachine/States/StashState.swift +++ b/novawallet/Modules/Staking/StakingMain/Relaychain/StateMachine/States/StashState.swift @@ -6,7 +6,6 @@ final class StashState: BaseStakingState { private(set) var payee: Staking.RewardDestinationArg? private(set) var ledgerInfo: StakingLedger? private(set) var bagListNode: BagList.Node? - private(set) var proxy: ProxyDefinition? init( stateMachine: StakingStateMachineProtocol, @@ -157,10 +156,4 @@ final class StashState: BaseStakingState { stateMachine?.transit(to: self) } - - override func process(proxy: ProxyDefinition?) { - self.proxy = proxy - - stateMachine?.transit(to: self) - } } diff --git a/novawallet/Modules/Staking/StakingMain/Relaychain/ViewModel/StakingStateViewModelFactory.swift b/novawallet/Modules/Staking/StakingMain/Relaychain/ViewModel/StakingStateViewModelFactory.swift index 9bb4cd8e00..9c04e33b83 100644 --- a/novawallet/Modules/Staking/StakingMain/Relaychain/ViewModel/StakingStateViewModelFactory.swift +++ b/novawallet/Modules/Staking/StakingMain/Relaychain/ViewModel/StakingStateViewModelFactory.swift @@ -255,7 +255,7 @@ extension StakingStateViewModelFactory: StakingStateVisitorProtocol { .unstake, .rewardDestination, .setupValidators, - .proxies(count: state.proxy?.definition.count ?? 0), + .proxyAction(from: state.commonData.proxy), .controllerAccount ] @@ -320,7 +320,7 @@ extension StakingStateViewModelFactory: StakingStateVisitorProtocol { .rewardDestination, .pendingRewards, .changeValidators(count: state.nomination.targets.count), - .proxies(count: state.proxy?.definition.count ?? 0), + .proxyAction(from: state.commonData.proxy), .controllerAccount ] @@ -385,7 +385,7 @@ extension StakingStateViewModelFactory: StakingStateVisitorProtocol { .rewardDestination, .pendingRewards, .yourValidator, - .proxies(count: state.proxy?.definition.count ?? 0), + .proxyAction(from: state.commonData.proxy), .controllerAccount ] From 0393ebc52890a05d2a620da5b260a20579442b23 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Thu, 11 Jan 2024 11:17:41 +0300 Subject: [PATCH 04/60] remove tests --- novawallet.xcodeproj/project.pbxproj | 12 ------------ .../StakingSetupProxyTests.swift | 16 ---------------- 2 files changed, 28 deletions(-) delete mode 100644 novawalletTests/Modules/StakingSetupProxy/StakingSetupProxyTests.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 6c9f818cac..0ce9da8ace 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -656,7 +656,6 @@ 576010F6494B3E2A6CA0B444 /* CreateWatchOnlyViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39907750D40A8DD7FE1288C8 /* CreateWatchOnlyViewController.swift */; }; 577918C3D4AA22D887F605B5 /* ParaStkStakeSetupPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1AC788C6E0A621B6D88D1BC /* ParaStkStakeSetupPresenter.swift */; }; 57E20F0723C4748D576C4882 /* StakingUnbondSetupViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = A82E373FFFBF708D7CF0973E /* StakingUnbondSetupViewFactory.swift */; }; - 584BB6F9C4B51C70B3C68DF9 /* StakingSetupProxyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54407B75B62CE8607D5829AF /* StakingSetupProxyTests.swift */; }; 5869563D0EA593FBD02C169C /* StakingPayoutConfirmationProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52F8D055D0481469073AA859 /* StakingPayoutConfirmationProtocols.swift */; }; 58D5B4F17DA37C241FF96A5F /* ParaStkRebondViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FDF5963FA924F8C815F3BCF /* ParaStkRebondViewController.swift */; }; 58F385F41D42CC96373EDA42 /* TokensManageProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05AA59AFC801F52B79DDBBCF /* TokensManageProtocols.swift */; }; @@ -4855,7 +4854,6 @@ 53B5C1C920BFDA8F5C9C89D9 /* ParaStkRedeemInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkRedeemInteractor.swift; sourceTree = ""; }; 53BE9DEF100A373868EDD03F /* ParaStkSelectCollatorsWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkSelectCollatorsWireframe.swift; sourceTree = ""; }; 53C2612BBF75CF0FBD91764E /* ParaStkCollatorsSearchWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkCollatorsSearchWireframe.swift; sourceTree = ""; }; - 54407B75B62CE8607D5829AF /* StakingSetupProxyTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingSetupProxyTests.swift; sourceTree = ""; }; 5467B9B6AEDB33F565D130A1 /* ParaStkUnstakeViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkUnstakeViewFactory.swift; sourceTree = ""; }; 54FB887490A8B33890B4E0E4 /* ControllerAccountConfirmationPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ControllerAccountConfirmationPresenter.swift; sourceTree = ""; }; 5544826542EC3A92FCB2B1D7 /* DelegateVotedReferendaPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DelegateVotedReferendaPresenter.swift; sourceTree = ""; }; @@ -10268,14 +10266,6 @@ path = AssetOperation; sourceTree = ""; }; - 77597583F6E03AC6726ED7F8 /* StakingSetupProxy */ = { - isa = PBXGroup; - children = ( - 54407B75B62CE8607D5829AF /* StakingSetupProxyTests.swift */, - ); - path = StakingSetupProxy; - sourceTree = ""; - }; 77799AE32A792ACB00B7E564 /* Model */ = { isa = PBXGroup; children = ( @@ -15327,7 +15317,6 @@ 84B7C705289BFA79001A3566 /* AccountManagement */, 84B7C708289BFA79001A3566 /* WalletList */, 84B7C70A289BFA79001A3566 /* ControllerAccount */, - 77597583F6E03AC6726ED7F8 /* StakingSetupProxy */, ); path = Modules; sourceTree = ""; @@ -24293,7 +24282,6 @@ 84B7C748289BFA79001A3566 /* WalletListTests.swift in Sources */, 84B7C720289BFA79001A3566 /* ReferralCrowdloanTests.swift in Sources */, F4897BB126AED13D0075F291 /* EraCountdownOperationFactoryStub.swift in Sources */, - 584BB6F9C4B51C70B3C68DF9 /* StakingSetupProxyTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/novawalletTests/Modules/StakingSetupProxy/StakingSetupProxyTests.swift b/novawalletTests/Modules/StakingSetupProxy/StakingSetupProxyTests.swift deleted file mode 100644 index 0ab728899f..0000000000 --- a/novawalletTests/Modules/StakingSetupProxy/StakingSetupProxyTests.swift +++ /dev/null @@ -1,16 +0,0 @@ -import XCTest - -class StakingSetupProxyTests: XCTestCase { - - override func setUp() { - // Put setup code here. This method is called before the invocation of each test method in the class. - } - - override func tearDown() { - // Put teardown code here. This method is called after the invocation of each test method in the class. - } - - func testExample() { - XCTFail("Did you forget to add tests?") - } -} From e4012e27067428008041fa5d70841edc9f539e97 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Thu, 11 Jan 2024 15:35:50 +0300 Subject: [PATCH 05/60] PR fixes --- .../StakingLocalStorageSubscriber.swift | 5 +++-- .../Common/Services/Proxy/ProxyModels.swift | 10 ++++++++++ .../Substrate/StakingAccountSubscription.swift | 8 ++++++-- .../Substrate/StakingAccountUpdatingService.swift | 7 +++++-- .../Common/Substrate/Types/Proxy/Proxy.swift | 15 +++++++++++++++ .../RelaychainStakingSharedState.swift | 3 ++- .../RelaychainStartStakingState.swift | 3 ++- .../Relaychain/StakingRelaychainPresenter.swift | 5 ++--- .../Relaychain/StakingRelaychainProtocols.swift | 3 ++- .../Relaychain/StakingRelaychainWireframe.swift | 6 +++++- 10 files changed, 52 insertions(+), 13 deletions(-) diff --git a/novawallet/Common/DataProvider/Subscription/StakingLocalStorageSubscriber.swift b/novawallet/Common/DataProvider/Subscription/StakingLocalStorageSubscriber.swift index 5a9c0b24ec..0a813754ec 100644 --- a/novawallet/Common/DataProvider/Subscription/StakingLocalStorageSubscriber.swift +++ b/novawallet/Common/DataProvider/Subscription/StakingLocalStorageSubscriber.swift @@ -666,9 +666,10 @@ extension StakingLocalStorageSubscriber { } let updateClosure = { [weak self] (changes: [DataProviderChange]) in - let proxies = changes.reduceToLastChange() + let proxies = changes.reduceToLastChange()?.item?.filterStakingProxy() + self?.stakingLocalSubscriptionHandler.handleProxies( - result: .success(proxies?.item), + result: .success(proxies), accountId: accountId, chainId: chainId ) diff --git a/novawallet/Common/Services/Proxy/ProxyModels.swift b/novawallet/Common/Services/Proxy/ProxyModels.swift index 863dfaacd6..c19a074768 100644 --- a/novawallet/Common/Services/Proxy/ProxyModels.swift +++ b/novawallet/Common/Services/Proxy/ProxyModels.swift @@ -38,4 +38,14 @@ struct ProxyDefinition: Decodable, Equatable { var container = try decoder.unkeyedContainer() definition = try container.decode([Proxy.ProxyDefinition].self) } + + init(definition: [Proxy.ProxyDefinition]) { + self.definition = definition + } +} + +extension ProxyDefinition { + func filterStakingProxy() -> ProxyDefinition { + .init(definition: definition.filter { $0.proxyType.allowStaking }) + } } diff --git a/novawallet/Common/Services/RemoteSubscription/Substrate/StakingAccountSubscription.swift b/novawallet/Common/Services/RemoteSubscription/Substrate/StakingAccountSubscription.swift index f08b2a64cc..10b546281b 100644 --- a/novawallet/Common/Services/RemoteSubscription/Substrate/StakingAccountSubscription.swift +++ b/novawallet/Common/Services/RemoteSubscription/Substrate/StakingAccountSubscription.swift @@ -39,7 +39,7 @@ final class StakingAccountSubscription: WebSocketSubscribing { let childSubscriptionFactory: ChildSubscriptionFactoryProtocol let operationQueue: OperationQueue let logger: LoggerProtocol? - + let chainHasProxy: Bool private let mutex = NSLock() private var subscription: Subscription? @@ -48,6 +48,7 @@ final class StakingAccountSubscription: WebSocketSubscribing { accountId: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat, + chainHasProxy: Bool, chainRegistry: ChainRegistryProtocol, provider: StreamableProvider, childSubscriptionFactory: ChildSubscriptionFactoryProtocol, @@ -57,6 +58,7 @@ final class StakingAccountSubscription: WebSocketSubscribing { self.accountId = accountId self.chainId = chainId self.chainFormat = chainFormat + self.chainHasProxy = chainHasProxy self.chainRegistry = chainRegistry self.provider = provider self.childSubscriptionFactory = childSubscriptionFactory @@ -130,7 +132,9 @@ final class StakingAccountSubscription: WebSocketSubscribing { ) } - requests.append(.init(storagePath: Proxy.proxyList, accountId: stashId)) + if chainHasProxy { + requests.append(.init(storagePath: Proxy.proxyList, accountId: stashId)) + } return requests } diff --git a/novawallet/Common/Services/RemoteSubscription/Substrate/StakingAccountUpdatingService.swift b/novawallet/Common/Services/RemoteSubscription/Substrate/StakingAccountUpdatingService.swift index b706d6dfaf..34aa486c32 100644 --- a/novawallet/Common/Services/RemoteSubscription/Substrate/StakingAccountUpdatingService.swift +++ b/novawallet/Common/Services/RemoteSubscription/Substrate/StakingAccountUpdatingService.swift @@ -5,7 +5,8 @@ protocol StakingAccountUpdatingServiceProtocol { func setupSubscription( for accountId: AccountId, chainId: ChainModel.Id, - chainFormat: ChainFormat + chainFormat: ChainFormat, + chainHasProxy: Bool ) throws func clearSubscription() @@ -40,7 +41,8 @@ class StakingAccountUpdatingService: StakingAccountUpdatingServiceProtocol { func setupSubscription( for accountId: AccountId, chainId: ChainModel.Id, - chainFormat: ChainFormat + chainFormat: ChainFormat, + chainHasProxy: Bool ) throws { let address = try accountId.toAddress(using: chainFormat) let stashItemProvider = substrateDataProviderFactory.createStashItemProvider(for: address, chainId: chainId) @@ -49,6 +51,7 @@ class StakingAccountUpdatingService: StakingAccountUpdatingServiceProtocol { accountId: accountId, chainId: chainId, chainFormat: chainFormat, + chainHasProxy: chainHasProxy, chainRegistry: chainRegistry, provider: stashItemProvider, childSubscriptionFactory: childSubscriptionFactory, diff --git a/novawallet/Common/Substrate/Types/Proxy/Proxy.swift b/novawallet/Common/Substrate/Types/Proxy/Proxy.swift index de0081945f..74587a8f85 100644 --- a/novawallet/Common/Substrate/Types/Proxy/Proxy.swift +++ b/novawallet/Common/Substrate/Types/Proxy/Proxy.swift @@ -91,5 +91,20 @@ enum Proxy { try container.encode(JSON.null) } + + var allowStaking: Bool { + switch self { + case .any, .nonTransfer, .staking: + return true + case .governance, + .staking, + .nominationPools, + .identityJudgement, + .cancelProxy, + .auction, + .other: + return false + } + } } } diff --git a/novawallet/Modules/Staking/Model/StakingSharedState/RelaychainStakingSharedState.swift b/novawallet/Modules/Staking/Model/StakingSharedState/RelaychainStakingSharedState.swift index 548f85a656..504b08d1e6 100644 --- a/novawallet/Modules/Staking/Model/StakingSharedState/RelaychainStakingSharedState.swift +++ b/novawallet/Modules/Staking/Model/StakingSharedState/RelaychainStakingSharedState.swift @@ -82,7 +82,8 @@ final class RelaychainStakingSharedState: RelaychainStakingSharedStateProtocol { try accountRemoteSubscriptionService.setupSubscription( for: accountId, chainId: chain.chainId, - chainFormat: chain.chainFormat + chainFormat: chain.chainFormat, + chainHasProxy: chain.hasProxy ) logger.debug("Relaychain staking account data subscription succeeded") diff --git a/novawallet/Modules/Staking/Model/StakingSharedState/RelaychainStartStakingState.swift b/novawallet/Modules/Staking/Model/StakingSharedState/RelaychainStartStakingState.swift index 848535598f..0ae944826a 100644 --- a/novawallet/Modules/Staking/Model/StakingSharedState/RelaychainStartStakingState.swift +++ b/novawallet/Modules/Staking/Model/StakingSharedState/RelaychainStartStakingState.swift @@ -137,7 +137,8 @@ final class RelaychainStartStakingState: RelaychainStartStakingStateProtocol { try relaychainAccountSubscriptionService.setupSubscription( for: accountId, chainId: chainId, - chainFormat: chainAsset.chain.chainFormat + chainFormat: chainAsset.chain.chainFormat, + chainHasProxy: chainAsset.chain.hasProxy ) npAccountService = try npAccountSubscriptionServiceFactory?.create( diff --git a/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainPresenter.swift b/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainPresenter.swift index fa6be97c17..e016b0c643 100644 --- a/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainPresenter.swift +++ b/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainPresenter.swift @@ -343,10 +343,9 @@ extension StakingRelaychainPresenter: StakingMainChildPresenterProtocol { wireframe.showYourValidatorInfo(stashAddress, from: view) } case .addProxy: - wireframe.showAddProxies(from: view) + wireframe.showAddProxy(from: view) case .editProxies: - // TODO: show proxy list - fallthrough + wireframe.showEditProxies(from: view) default: logger?.warning("Unsupported action: \(action)") } diff --git a/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainProtocols.swift b/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainProtocols.swift index fa7f5c9fe1..d6ad576fb4 100644 --- a/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainProtocols.swift +++ b/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainProtocols.swift @@ -64,5 +64,6 @@ protocol StakingRelaychainWireframeProtocol: AlertPresentable, ErrorPresentable, func showRebagConfirm(from view: ControllerBackedProtocol?) func showYourValidatorInfo(_ stashAddress: AccountAddress, from view: ControllerBackedProtocol?) - func showAddProxies(from view: ControllerBackedProtocol?) + func showAddProxy(from view: ControllerBackedProtocol?) + func showEditProxies(from view: ControllerBackedProtocol?) } diff --git a/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainWireframe.swift b/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainWireframe.swift index b03ef05d2f..a92bd50ebd 100644 --- a/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainWireframe.swift +++ b/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainWireframe.swift @@ -152,11 +152,15 @@ extension StakingRelaychainWireframe: StakingRelaychainWireframeProtocol { view?.controller.present(navigationController, animated: true, completion: nil) } - func showAddProxies(from view: ControllerBackedProtocol?) { + func showAddProxy(from view: ControllerBackedProtocol?) { guard let setupProxyView = StakingSetupProxyViewFactory.createView() else { return } let navigationController = NovaNavigationController(rootViewController: setupProxyView.controller) view?.controller.present(navigationController, animated: true, completion: nil) } + + func showEditProxies(from _: ControllerBackedProtocol?) { + // TODO: Proxy List + } } From 757731e299699df49aaeeecec9c3d56742bbfd74 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Fri, 12 Jan 2024 18:15:46 +0300 Subject: [PATCH 06/60] init --- novawallet.xcodeproj/project.pbxproj | 20 ++ .../Calls/Common/SubstrateCallFactory.swift | 11 + .../Types/Proxy/Proxy+CodingPath.swift | 10 + .../Common/Substrate/Types/Proxy/Proxy.swift | 2 +- .../StakingRelaychainWireframe.swift | 2 +- .../Base/ProxyDepositCalculator.swift | 18 ++ .../Base/StakingProxyBaseInteractor.swift | 280 ++++++++++++++++++ .../Base/StakingProxyBaseProtocols.swift | 25 ++ .../StakingSetupProxy/ProxyDepositView.swift | 6 +- .../StakingSetupProxyInteractor.swift | 6 +- .../StakingSetupProxyPresenter.swift | 87 +++++- .../StakingSetupProxyProtocols.swift | 10 +- .../StakingSetupProxyViewController.swift | 22 +- .../StakingSetupProxyViewFactory.swift | 76 ++++- .../StakingSetupProxyViewLayout.swift | 4 +- 15 files changed, 558 insertions(+), 21 deletions(-) create mode 100644 novawallet/Modules/Staking/StakingSetupProxy/Base/ProxyDepositCalculator.swift create mode 100644 novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseInteractor.swift create mode 100644 novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseProtocols.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 3a3dcaa514..207abfc333 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -828,6 +828,9 @@ 774A980D2B0D0873009146CA /* OpenScreenUrlParsingService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 774A980C2B0D0873009146CA /* OpenScreenUrlParsingService.swift */; }; 774A980F2B0D08A6009146CA /* OpenScreenUrlParsingServiceFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 774A980E2B0D08A6009146CA /* OpenScreenUrlParsingServiceFactory.swift */; }; 7750D6D52B2272DC00E1ABD7 /* ProxiedsUpdateFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7750D6D42B2272DC00E1ABD7 /* ProxiedsUpdateFactory.swift */; }; + 7754BD532B501E330099C13E /* StakingProxyBaseInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7754BD522B501E330099C13E /* StakingProxyBaseInteractor.swift */; }; + 7754BD562B5021C30099C13E /* StakingProxyBaseProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7754BD552B5021C30099C13E /* StakingProxyBaseProtocols.swift */; }; + 7754BD582B50232C0099C13E /* ProxyDepositCalculator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7754BD572B50232C0099C13E /* ProxyDepositCalculator.swift */; }; 7756927D2A20B88200220756 /* TokenOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7756927C2A20B88200220756 /* TokenOperation.swift */; }; 775F194D2A56EEAC009915B6 /* StartStakingInfoRelaychainPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 775F194C2A56EEAC009915B6 /* StartStakingInfoRelaychainPresenter.swift */; }; 775F19512A5811FA009915B6 /* StartStakingParachainInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 775F19502A5811FA009915B6 /* StartStakingParachainInteractor.swift */; }; @@ -5033,6 +5036,9 @@ 774A980C2B0D0873009146CA /* OpenScreenUrlParsingService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenScreenUrlParsingService.swift; sourceTree = ""; }; 774A980E2B0D08A6009146CA /* OpenScreenUrlParsingServiceFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenScreenUrlParsingServiceFactory.swift; sourceTree = ""; }; 7750D6D42B2272DC00E1ABD7 /* ProxiedsUpdateFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProxiedsUpdateFactory.swift; sourceTree = ""; }; + 7754BD522B501E330099C13E /* StakingProxyBaseInteractor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StakingProxyBaseInteractor.swift; sourceTree = ""; }; + 7754BD552B5021C30099C13E /* StakingProxyBaseProtocols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingProxyBaseProtocols.swift; sourceTree = ""; }; + 7754BD572B50232C0099C13E /* ProxyDepositCalculator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProxyDepositCalculator.swift; sourceTree = ""; }; 7756927C2A20B88200220756 /* TokenOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokenOperation.swift; sourceTree = ""; }; 775F194C2A56EEAC009915B6 /* StartStakingInfoRelaychainPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartStakingInfoRelaychainPresenter.swift; sourceTree = ""; }; 775F19502A5811FA009915B6 /* StartStakingParachainInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartStakingParachainInteractor.swift; sourceTree = ""; }; @@ -10256,6 +10262,16 @@ path = Model; sourceTree = ""; }; + 7754BD542B501E3C0099C13E /* Base */ = { + isa = PBXGroup; + children = ( + 7754BD522B501E330099C13E /* StakingProxyBaseInteractor.swift */, + 7754BD552B5021C30099C13E /* StakingProxyBaseProtocols.swift */, + 7754BD572B50232C0099C13E /* ProxyDepositCalculator.swift */, + ); + path = Base; + sourceTree = ""; + }; 775692822A24CA5100220756 /* AssetOperation */ = { isa = PBXGroup; children = ( @@ -18104,6 +18120,7 @@ A4542BFD7BBCF6B05FB2D3E4 /* StakingSetupProxy */ = { isa = PBXGroup; children = ( + 7754BD542B501E3C0099C13E /* Base */, 173BB84A4695492A77AE206D /* StakingSetupProxyProtocols.swift */, 1399884D5F4905DA0BD1E5C3 /* StakingSetupProxyWireframe.swift */, 5B882BFEED7C8CB1EA5A853D /* StakingSetupProxyPresenter.swift */, @@ -20941,6 +20958,7 @@ 0C13DFC92AF4FFC200E5F355 /* SwapErrorPresentableParams.swift in Sources */, 8401620B25E144D50087A5F3 /* AmountInputAccessoryView.swift in Sources */, 88F19DE028D8D0F600F6E459 /* LoadableViewModelState+Addition.swift in Sources */, + 7754BD532B501E330099C13E /* StakingProxyBaseInteractor.swift in Sources */, 844C3E652A07627E00C4305F /* DAppWalletAuthViewModel.swift in Sources */, 77799AE52A792AE700B7E564 /* StakingTypeViewModel.swift in Sources */, 84A3B8A22836DA2600DE2669 /* LastAccountIdKeyWrapper.swift in Sources */, @@ -22797,6 +22815,7 @@ 8489A6CE27FC5C5E0040C066 /* StakingActionsView.swift in Sources */, 8455F19E2A1E4956003F072D /* RelaychainMultistakingUpdateService.swift in Sources */, 8455F1A42A1F606B003F072D /* OnchainStorage.swift in Sources */, + 7754BD582B50232C0099C13E /* ProxyDepositCalculator.swift in Sources */, 84DED40B266656D400A153BB /* KaruraBonusService.swift in Sources */, 845B07EF2915951A005785D3 /* DemocracyVoteThreshold.swift in Sources */, 885551F78A5926D16D5AF0CB /* ControllerAccountPresenter.swift in Sources */, @@ -23115,6 +23134,7 @@ 9F3E2D64D77BF89B474BF1E3 /* DAppOperationConfirmViewController.swift in Sources */, 7BD09D3022967C4D90AB4693 /* DAppOperationConfirmViewLayout.swift in Sources */, F63A83EA1CA85D7A43103098 /* DAppOperationConfirmViewFactory.swift in Sources */, + 7754BD562B5021C30099C13E /* StakingProxyBaseProtocols.swift in Sources */, D600448CB75095E6873E542F /* DAppTxDetailsProtocols.swift in Sources */, 84E25BE827E751B400290BF1 /* Charset+Encoding.swift in Sources */, 847999B12888A4FF00D1BAD2 /* SwitchAccount+CreateWatchOnlyWireframe.swift in Sources */, diff --git a/novawallet/Common/Substrate/Calls/Common/SubstrateCallFactory.swift b/novawallet/Common/Substrate/Calls/Common/SubstrateCallFactory.swift index fcf60da1b9..10798c0296 100644 --- a/novawallet/Common/Substrate/Calls/Common/SubstrateCallFactory.swift +++ b/novawallet/Common/Substrate/Calls/Common/SubstrateCallFactory.swift @@ -61,6 +61,8 @@ protocol SubstrateCallFactoryProtocol { extras: EquilibriumAssetExtras, amount: BigUInt ) -> RuntimeCall + + func addProxy(accountId: AccountId, type: Proxy.ProxyType) -> RuntimeCall } final class SubstrateCallFactory: SubstrateCallFactoryProtocol { @@ -221,6 +223,15 @@ final class SubstrateCallFactory: SubstrateCallFactoryProtocol { $0.moduleName == module }) ?? rebagCall.defaultRuntimeCall } + + func addProxy(accountId: AccountId, type: Proxy.ProxyType) -> RuntimeCall { + let proxyCall = Proxy.ProxyDefinition( + proxy: accountId, + proxyType: type, + delay: 0 + ) + return RuntimeCall(moduleName: Proxy.name, callName: "add_proxy", args: proxyCall) + } } extension SubstrateCallFactory { diff --git a/novawallet/Common/Substrate/Types/Proxy/Proxy+CodingPath.swift b/novawallet/Common/Substrate/Types/Proxy/Proxy+CodingPath.swift index 1011fcbdc1..f27576b00b 100644 --- a/novawallet/Common/Substrate/Types/Proxy/Proxy+CodingPath.swift +++ b/novawallet/Common/Substrate/Types/Proxy/Proxy+CodingPath.swift @@ -5,3 +5,13 @@ extension Proxy { .init(moduleName: Proxy.name, itemName: "Proxies") } } + +extension Proxy { + static var depositBase: ConstantCodingPath { + .init(moduleName: Proxy.name, constantName: "ProxyDepositBase") + } + + static var depositFactor: ConstantCodingPath { + .init(moduleName: Proxy.name, constantName: "ProxyDepositFactor") + } +} diff --git a/novawallet/Common/Substrate/Types/Proxy/Proxy.swift b/novawallet/Common/Substrate/Types/Proxy/Proxy.swift index 74587a8f85..7202a5d998 100644 --- a/novawallet/Common/Substrate/Types/Proxy/Proxy.swift +++ b/novawallet/Common/Substrate/Types/Proxy/Proxy.swift @@ -5,7 +5,7 @@ import BigInt enum Proxy { static var name: String { "Proxy" } - struct ProxyDefinition: Decodable, Equatable { + struct ProxyDefinition: Codable, Equatable { enum CodingKeys: String, CodingKey { case proxy = "delegate" case proxyType diff --git a/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainWireframe.swift b/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainWireframe.swift index a92bd50ebd..0d12c3252a 100644 --- a/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainWireframe.swift +++ b/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainWireframe.swift @@ -153,7 +153,7 @@ extension StakingRelaychainWireframe: StakingRelaychainWireframeProtocol { } func showAddProxy(from view: ControllerBackedProtocol?) { - guard let setupProxyView = StakingSetupProxyViewFactory.createView() else { + guard let setupProxyView = StakingSetupProxyViewFactory.createView(state: state) else { return } let navigationController = NovaNavigationController(rootViewController: setupProxyView.controller) diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Base/ProxyDepositCalculator.swift b/novawallet/Modules/Staking/StakingSetupProxy/Base/ProxyDepositCalculator.swift new file mode 100644 index 0000000000..1b8daf5485 --- /dev/null +++ b/novawallet/Modules/Staking/StakingSetupProxy/Base/ProxyDepositCalculator.swift @@ -0,0 +1,18 @@ +import BigInt + +struct ProxyDepositCalculator { + var base: BigUInt? + var factor: BigUInt? + var proxyCount: Int? + + func calculate() -> BigUInt? { + guard let base = self.base, let factor = self.factor, let proxyCount = self.proxyCount else { + return nil + } + + let currentDeposit = base + BigUInt(proxyCount) * factor + let newDeposit = base + BigUInt(proxyCount + 1) * factor + + return newDeposit - currentDeposit + } +} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseInteractor.swift b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseInteractor.swift new file mode 100644 index 0000000000..0c845cdea4 --- /dev/null +++ b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseInteractor.swift @@ -0,0 +1,280 @@ +import UIKit +import BigInt +import RobinHood + +class StakingProxyBaseInteractor: RuntimeConstantFetching { + weak var basePresenter: StakingProxyBaseInteractorOutputProtocol? + let runtimeService: RuntimeCodingServiceProtocol + let selectedAccount: ChainAccountResponse + let chainAsset: ChainAsset + let stakingLocalSubscriptionFactory: StakingLocalSubscriptionFactoryProtocol + let walletLocalSubscriptionFactory: WalletLocalSubscriptionFactoryProtocol + let accountProviderFactory: AccountProviderFactoryProtocol + let priceLocalSubscriptionFactory: PriceProviderFactoryProtocol + let callFactory: SubstrateCallFactoryProtocol + let feeProxy: ExtrinsicFeeProxyProtocol + let extrinsicServiceFactory: ExtrinsicServiceFactoryProtocol + + private lazy var operationManager = OperationManager(operationQueue: operationQueue) + private var calculator = ProxyDepositCalculator() + private var proxyProvider: AnyDataProvider? + private let operationQueue: OperationQueue + + private var balanceProvider: StreamableProvider? + private var extrinsicService: ExtrinsicServiceProtocol? + private var controllerAccountProvider: StreamableProvider? + private var stashAccountProvider: StreamableProvider? + private var priceProvider: StreamableProvider? + private var stashItemProvider: StreamableProvider? + private var stashItem: StashItem? + + init( + runtimeService: RuntimeCodingServiceProtocol, + stakingLocalSubscriptionFactory: StakingLocalSubscriptionFactoryProtocol, + walletLocalSubscriptionFactory: WalletLocalSubscriptionFactoryProtocol, + accountProviderFactory: AccountProviderFactoryProtocol, + priceLocalSubscriptionFactory: PriceProviderFactoryProtocol, + callFactory: SubstrateCallFactoryProtocol, + feeProxy: ExtrinsicFeeProxyProtocol, + extrinsicServiceFactory: ExtrinsicServiceFactoryProtocol, + selectedAccount: ChainAccountResponse, + chainAsset: ChainAsset, + currencyManager: CurrencyManagerProtocol, + operationQueue: OperationQueue + ) { + self.runtimeService = runtimeService + self.stakingLocalSubscriptionFactory = stakingLocalSubscriptionFactory + self.walletLocalSubscriptionFactory = walletLocalSubscriptionFactory + self.accountProviderFactory = accountProviderFactory + self.priceLocalSubscriptionFactory = priceLocalSubscriptionFactory + self.extrinsicServiceFactory = extrinsicServiceFactory + self.callFactory = callFactory + self.feeProxy = feeProxy + self.chainAsset = chainAsset + self.selectedAccount = selectedAccount + self.operationQueue = operationQueue + self.currencyManager = currencyManager + } + + private func fetchConstants() { + fetchConstant( + for: Proxy.depositBase, + runtimeCodingService: runtimeService, + operationManager: operationManager + ) { [weak self] (result: Result) in + switch result { + case let .success(depositBase): + self?.calculator.base = depositBase + case let .failure(error): + self?.basePresenter?.didReceive(baseError: .fetchDepositBase(error)) + } + } + + fetchConstant( + for: Proxy.depositFactor, + runtimeCodingService: runtimeService, + operationManager: operationManager + ) { [weak self] (result: Result) in + switch result { + case let .success(depositFactor): + self?.calculator.factor = depositFactor + case let .failure(error): + self?.basePresenter?.didReceive(baseError: .fetchDepositFactor(error)) + } + } + } + + private func performPriceSubscription() { + clear(streamableProvider: &priceProvider) + + guard let priceId = chainAsset.asset.priceId else { + basePresenter?.didReceive(price: nil) + return + } + + priceProvider = subscribeToPrice(for: priceId, currency: selectedCurrency) + } + + func handle(stashItem: StashItem?) { + self.stashItem = stashItem + + clear(streamableProvider: &balanceProvider) + clear(streamableProvider: &stashAccountProvider) + clear(dataProvider: &proxyProvider) + + if + let stashItem = stashItem, + let stashAccountId = try? stashItem.stash.toAccountId() { + let chainId = chainAsset.chain.chainId + proxyProvider = subscribeProxies(for: stashAccountId, chainId: chainId) + balanceProvider = subscribeToAssetBalanceProvider( + for: stashAccountId, + chainId: chainAsset.chain.chainId, + assetId: chainAsset.asset.assetId + ) + + subscribeToControllerAccount(address: stashItem.controller, chain: chainAsset.chain) + + if stashItem.controller != stashItem.stash { + subscribeToStashAccount(address: stashItem.stash, chain: chainAsset.chain) + } + + estimateFee() + } + } + + private func updateProxyDeposit() { + let deposit = calculator.calculate() + basePresenter?.didReceive(proxyDeposit: deposit) + } + + private func subscribeToControllerAccount(address: AccountAddress, chain: ChainModel) { + clear(streamableProvider: &controllerAccountProvider) + guard controllerAccountProvider == nil, let accountId = try? address.toAccountId() else { + return + } + + controllerAccountProvider = subscribeForAccountId(accountId, chain: chain) + } + + private func subscribeToStashAccount(address: AccountAddress, chain: ChainModel) { + clear(streamableProvider: &stashAccountProvider) + guard stashAccountProvider == nil, let accountId = try? address.toAccountId() else { + return + } + + stashAccountProvider = subscribeForAccountId(accountId, chain: chain) + } +} + +extension StakingProxyBaseInteractor: StakingProxyBaseInteractorInputProtocol { + func setup() { + if let address = selectedAccount.toAddress() { + stashItemProvider = subscribeStashItemProvider(for: address, chainId: chainAsset.chain.chainId) + } + + feeProxy.delegate = self + + fetchConstants() + performPriceSubscription() + } + + func estimateFee() { + guard + let stashAccountId = try? stashItem?.stash.toAccountId(), + let extrinsicService = self.extrinsicService, + let amount = StakingConstants.feeEstimation.toSubstrateAmount( + precision: chainAsset.assetDisplayInfo.assetPrecision + ) else { + return + } + + let call = callFactory.addProxy( + accountId: stashAccountId, + type: .staking + ) + + feeProxy.estimateFee(using: extrinsicService, reuseIdentifier: call.callName) { builder in + try builder.adding(call: call) + } + } +} + +extension StakingProxyBaseInteractor: StakingLocalStorageSubscriber, StakingLocalSubscriptionHandler, + AnyProviderAutoCleaning { + func handleStashItem(result: Result, for _: AccountAddress) { + switch result { + case let .success(stashItem): + handle(stashItem: stashItem) + case let .failure(error): + basePresenter?.didReceive(baseError: .stashItem(error)) + } + } + + func handleProxies(result: Result, accountId _: AccountId, chainId _: ChainModel.Id) { + switch result { + case let .success(proxy): + let proxyCount = proxy?.definition.count ?? 0 + calculator.proxyCount = proxyCount + updateProxyDeposit() + case let .failure(error): + basePresenter?.didReceive(baseError: .handleProxies(error)) + } + } +} + +extension StakingProxyBaseInteractor: PriceLocalStorageSubscriber, PriceLocalSubscriptionHandler { + func handlePrice(result: Result, priceId: AssetModel.PriceId) { + if chainAsset.asset.priceId == priceId { + switch result { + case let .success(priceData): + basePresenter?.didReceive(price: priceData) + case let .failure(error): + basePresenter?.didReceive(baseError: .price(error)) + } + } + } +} + +extension StakingProxyBaseInteractor: WalletLocalStorageSubscriber, WalletLocalSubscriptionHandler { + func handleAssetBalance( + result: Result, + accountId _: AccountId, + chainId _: ChainModel.Id, + assetId _: AssetModel.Id + ) { + switch result { + case let .success(assetBalance): + basePresenter?.didReceive(assetBalance: assetBalance) + case let .failure(error): + basePresenter?.didReceive(baseError: .balance(error)) + } + } +} + +extension StakingProxyBaseInteractor: ExtrinsicFeeProxyDelegate { + func didReceiveFee(result: Result, for _: TransactionFeeId) { + switch result { + case let .success(fee): + basePresenter?.didReceive(fee: fee) + case let .failure(error): + basePresenter?.didReceive(baseError: .fee(error)) + } + } +} + +extension StakingProxyBaseInteractor: SelectedCurrencyDepending { + func applyCurrency() { + guard basePresenter != nil, + let priceId = chainAsset.asset.priceId else { + return + } + + priceProvider = subscribeToPrice(for: priceId, currency: selectedCurrency) + } +} + +extension StakingProxyBaseInteractor: AccountLocalSubscriptionHandler, AccountLocalStorageSubscriber { + func handleAccountResponse( + result: Result, + accountId: AccountId, + chain _: ChainModel + ) { + switch result { + case let .success(optAccount): + if let account = optAccount { + extrinsicService = extrinsicServiceFactory.createService( + account: account.chainAccount, + chain: chainAsset.chain + ) + estimateFee() + } + + basePresenter?.didReceiveAccount(optAccount, for: accountId) + case .failure: + extrinsicService = nil + estimateFee() + basePresenter?.didReceiveAccount(nil, for: accountId) + } + } +} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseProtocols.swift b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseProtocols.swift new file mode 100644 index 0000000000..47a701d429 --- /dev/null +++ b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseProtocols.swift @@ -0,0 +1,25 @@ +import BigInt + +protocol StakingProxyBaseInteractorOutputProtocol: AnyObject { + func didReceive(baseError: StakingProxyBaseError) + func didReceive(proxyDeposit: BigUInt?) + func didReceive(assetBalance: AssetBalance?) + func didReceive(fee: ExtrinsicFeeProtocol?) + func didReceive(price: PriceData?) + func didReceiveAccount(_ account: MetaChainAccountResponse?, for accountId: AccountId) +} + +enum StakingProxyBaseError: Error { + case fetchDepositBase(Error) + case fetchDepositFactor(Error) + case handleProxies(Error) + case balance(Error) + case price(Error) + case stashItem(Error) + case fee(Error) +} + +protocol StakingProxyBaseInteractorInputProtocol: AnyObject { + func setup() + func estimateFee() +} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/ProxyDepositView.swift b/novawallet/Modules/Staking/StakingSetupProxy/ProxyDepositView.swift index 52812ce19a..064ed9c480 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/ProxyDepositView.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/ProxyDepositView.swift @@ -1,6 +1,6 @@ import SoraUI -final class ProxyDepositView: RowView> { +final class ProxyDepositView: RowView> { var imageView: UIImageView { rowContentView.imageView } var titleButton: RoundedButton { rowContentView.detailsView.titleButton } var valueTopButton: RoundedButton { rowContentView.detailsView.valueTopButton } @@ -22,4 +22,8 @@ final class ProxyDepositView: RowView) { + rowContentView.detailsView.bind(loadableViewModel: loadableViewModel) + } } diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyInteractor.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyInteractor.swift index cd2b8cbe44..ecd4ed8898 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyInteractor.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyInteractor.swift @@ -1,7 +1,9 @@ import UIKit -final class StakingSetupProxyInteractor { - weak var presenter: StakingSetupProxyInteractorOutputProtocol? +final class StakingSetupProxyInteractor: StakingProxyBaseInteractor { + weak var presenter: StakingSetupProxyInteractorOutputProtocol? { + basePresenter as? StakingSetupProxyInteractorOutputProtocol + } } extension StakingSetupProxyInteractor: StakingSetupProxyInteractorInputProtocol {} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyPresenter.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyPresenter.swift index bd8f5aa226..1b4e08a041 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyPresenter.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyPresenter.swift @@ -1,23 +1,104 @@ import Foundation +import BigInt +import SoraFoundation final class StakingSetupProxyPresenter { weak var view: StakingSetupProxyViewProtocol? let wireframe: StakingSetupProxyWireframeProtocol let interactor: StakingSetupProxyInteractorInputProtocol + let balanceViewModelFactory: BalanceViewModelFactoryProtocol + let chainAsset: ChainAsset + private var assetBalance: AssetBalance? + private var proxyDeposit: BigUInt? + private var priceData: PriceData? + private var fee: ExtrinsicFeeProtocol? init( + chainAsset: ChainAsset, interactor: StakingSetupProxyInteractorInputProtocol, - wireframe: StakingSetupProxyWireframeProtocol + wireframe: StakingSetupProxyWireframeProtocol, + balanceViewModelFactory: BalanceViewModelFactoryProtocol, + localizationManager: LocalizationManagerProtocol ) { + self.chainAsset = chainAsset self.interactor = interactor self.wireframe = wireframe + self.balanceViewModelFactory = balanceViewModelFactory + self.localizationManager = localizationManager + } + + private func provideProxyDeposit() { + guard let amount = proxyDeposit?.decimal(precision: chainAsset.asset.precision) else { + view?.didReceiveProxyDeposit(viewModel: .loading) + return + } + let proxyDepositViewModel = balanceViewModelFactory.balanceFromPrice( + amount, + priceData: priceData + ).value(for: selectedLocale) + view?.didReceiveProxyDeposit(viewModel: .loaded(value: .init( + isEditable: false, + balanceViewModel: proxyDepositViewModel + ))) + } + + private func provideFee() { + guard let fee = fee?.amount.decimal(precision: chainAsset.asset.precision) else { + view?.didReceiveFee(viewModel: nil) + return + } + let feeViewModel = balanceViewModelFactory.balanceFromPrice( + fee, + priceData: priceData + ).value(for: selectedLocale) + view?.didReceiveFee(viewModel: feeViewModel) + } + + private func updateView() { + provideProxyDeposit() + provideFee() } } extension StakingSetupProxyPresenter: StakingSetupProxyPresenterProtocol { - func setup() {} + func setup() { + view?.didReceive(token: chainAsset.assetDisplayInfo.symbol) + interactor.setup() + } + func complete(authority _: String) {} func showDepositInfo() {} } -extension StakingSetupProxyPresenter: StakingSetupProxyInteractorOutputProtocol {} +extension StakingSetupProxyPresenter: StakingSetupProxyInteractorOutputProtocol { + func didReceive(baseError _: StakingProxyBaseError) {} + func didReceive(proxyDeposit: BigUInt?) { + self.proxyDeposit = proxyDeposit + provideProxyDeposit() + } + + func didReceive(assetBalance: AssetBalance?) { + self.assetBalance = assetBalance + } + + func didReceive(fee: ExtrinsicFeeProtocol?) { + self.fee = fee + provideFee() + } + + func didReceive(price: PriceData?) { + priceData = price + provideProxyDeposit() + provideFee() + } + + func didReceiveAccount(_: MetaChainAccountResponse?, for _: AccountId) {} +} + +extension StakingSetupProxyPresenter: Localizable { + func applyLocalization() { + if view?.isSetup == true { + updateView() + } + } +} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyProtocols.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyProtocols.swift index 77ac3ec08f..f225fb998b 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyProtocols.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyProtocols.swift @@ -1,4 +1,8 @@ -protocol StakingSetupProxyViewProtocol: ControllerBackedProtocol {} +protocol StakingSetupProxyViewProtocol: ControllerBackedProtocol { + func didReceiveProxyDeposit(viewModel: LoadableViewModelState) + func didReceiveFee(viewModel: BalanceViewModelProtocol?) + func didReceive(token: String) +} protocol StakingSetupProxyPresenterProtocol: AnyObject { func setup() @@ -6,8 +10,8 @@ protocol StakingSetupProxyPresenterProtocol: AnyObject { func showDepositInfo() } -protocol StakingSetupProxyInteractorInputProtocol: AnyObject {} +protocol StakingSetupProxyInteractorInputProtocol: StakingProxyBaseInteractorInputProtocol {} -protocol StakingSetupProxyInteractorOutputProtocol: AnyObject {} +protocol StakingSetupProxyInteractorOutputProtocol: StakingProxyBaseInteractorOutputProtocol {} protocol StakingSetupProxyWireframeProtocol: AnyObject {} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewController.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewController.swift index bde9b5423e..45b35f27d9 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewController.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewController.swift @@ -47,7 +47,7 @@ final class StakingSetupProxyViewController: UIViewController, ViewHolder { image: R.image.iconUsers() )) - rootView.proxyView.titleButton.imageWithTitleView?.title = strings.stakingSetupProxyDeposit( + rootView.proxyDepositView.titleButton.imageWithTitleView?.title = strings.stakingSetupProxyDeposit( preferredLanguages: languages ) rootView.feeView.locale = selectedLocale @@ -55,7 +55,7 @@ final class StakingSetupProxyViewController: UIViewController, ViewHolder { } private func setupHandlers() { - rootView.proxyView.addTarget( + rootView.proxyDepositView.addTarget( self, action: #selector(proxyInfoAction), for: .touchUpInside @@ -69,7 +69,23 @@ final class StakingSetupProxyViewController: UIViewController, ViewHolder { } } -extension StakingSetupProxyViewController: StakingSetupProxyViewProtocol {} +extension StakingSetupProxyViewController: StakingSetupProxyViewProtocol { + func didReceiveProxyDeposit(viewModel: LoadableViewModelState) { + rootView.proxyDepositView.bind(loadableViewModel: viewModel) + } + + func didReceiveFee(viewModel: BalanceViewModelProtocol?) { + rootView.feeView.bind(viewModel: viewModel) + } + + func didReceive(token: String) { + self.token = token + rootView.titleLabel.text = R.string.localizable.stakingSetupProxyTitle( + token, + preferredLanguages: selectedLocale.rLanguages + ) + } +} extension StakingSetupProxyViewController: Localizable { func applyLocalization() { diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewFactory.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewFactory.swift index 46ae95c667..416c1930a5 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewFactory.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewFactory.swift @@ -2,17 +2,83 @@ import Foundation import SoraFoundation struct StakingSetupProxyViewFactory { - static func createView() -> StakingSetupProxyViewProtocol? { - let interactor = StakingSetupProxyInteractor() + static func createView(state: RelaychainStakingSharedStateProtocol) -> StakingSetupProxyViewProtocol? { + guard let currencyManager = CurrencyManager.shared else { + return nil + } + guard let interactor = createInteractor(state: state) else { + return nil + } let wireframe = StakingSetupProxyWireframe() + let chainAsset = state.stakingOption.chainAsset - let presenter = StakingSetupProxyPresenter(interactor: interactor, wireframe: wireframe) + let priceAssetInfoFactory = PriceAssetInfoFactory(currencyManager: currencyManager) + let balanceViewModelFactory = BalanceViewModelFactory( + targetAssetInfo: chainAsset.assetDisplayInfo, + priceAssetInfoFactory: priceAssetInfoFactory + ) - let view = StakingSetupProxyViewController(presenter: presenter, localizationManager: LocalizationManager.shared) + let presenter = StakingSetupProxyPresenter( + chainAsset: chainAsset, + interactor: interactor, + wireframe: wireframe, + balanceViewModelFactory: balanceViewModelFactory, + localizationManager: LocalizationManager.shared + ) + + let view = StakingSetupProxyViewController( + presenter: presenter, + localizationManager: LocalizationManager.shared + ) presenter.view = view - interactor.presenter = presenter + interactor.basePresenter = presenter return view } + + private static func createInteractor( + state: RelaychainStakingSharedStateProtocol + ) -> StakingSetupProxyInteractor? { + let chainRegistry = ChainRegistryFacade.sharedRegistry + let chainAsset = state.stakingOption.chainAsset + + guard + let selectedAccount = SelectedWalletSettings.shared.value.fetch( + for: chainAsset.chain.accountRequest() + ), + let connection = chainRegistry.getConnection(for: chainAsset.chain.chainId), + let runtimeRegistry = chainRegistry.getRuntimeProvider(for: chainAsset.chain.chainId), + let currencyManager = CurrencyManager.shared else { + return nil + } + + let extrinsicServiceFactory = ExtrinsicServiceFactory( + runtimeRegistry: runtimeRegistry, + engine: connection, + operationManager: OperationManagerFacade.sharedManager, + userStorageFacade: UserDataStorageFacade.shared + ) + + let accountProviderFactory = AccountProviderFactory( + storageFacade: UserDataStorageFacade.shared, + operationManager: OperationManagerFacade.sharedManager, + logger: Logger.shared + ) + + return StakingSetupProxyInteractor( + runtimeService: runtimeRegistry, + stakingLocalSubscriptionFactory: state.localSubscriptionFactory, + walletLocalSubscriptionFactory: WalletLocalSubscriptionFactory.shared, + accountProviderFactory: accountProviderFactory, + priceLocalSubscriptionFactory: PriceProviderFactory.shared, + callFactory: SubstrateCallFactory(), + feeProxy: ExtrinsicFeeProxy(), + extrinsicServiceFactory: extrinsicServiceFactory, + selectedAccount: selectedAccount, + chainAsset: chainAsset, + currencyManager: currencyManager, + operationQueue: OperationManagerFacade.sharedDefaultQueue + ) + } } diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewLayout.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewLayout.swift index c632a9fc76..9a804872d5 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewLayout.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewLayout.swift @@ -26,7 +26,7 @@ final class StakingSetupProxyViewLayout: ScrollableContainerLayoutView { } } - let proxyView: ProxyDepositView = .create { + let proxyDepositView: ProxyDepositView = .create { $0.imageView.image = R.image.iconLock()!.withTintColor(R.color.colorIconSecondary()!) $0.contentInsets = .zero } @@ -57,7 +57,7 @@ final class StakingSetupProxyViewLayout: ScrollableContainerLayoutView { addArrangedSubview(titleStackView, spacingAfter: 0) addArrangedSubview(accountInputView, spacingAfter: 40) - addArrangedSubview(proxyView, spacingAfter: 0) + addArrangedSubview(proxyDepositView, spacingAfter: 0) addArrangedSubview(feeView) } } From 4ed20faca95f5a856b31a019a574c3a2793f6db8 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Mon, 15 Jan 2024 11:36:27 +0300 Subject: [PATCH 07/60] fix coding --- .../Calls/Common/SubstrateCallFactory.swift | 8 ++++---- .../Common/Substrate/Calls/Proxy/Proxy+Call.swift | 12 ++++++++++++ .../Base/StakingProxyBaseInteractor.swift | 3 +-- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/novawallet/Common/Substrate/Calls/Common/SubstrateCallFactory.swift b/novawallet/Common/Substrate/Calls/Common/SubstrateCallFactory.swift index 10798c0296..613a2c399e 100644 --- a/novawallet/Common/Substrate/Calls/Common/SubstrateCallFactory.swift +++ b/novawallet/Common/Substrate/Calls/Common/SubstrateCallFactory.swift @@ -62,7 +62,7 @@ protocol SubstrateCallFactoryProtocol { amount: BigUInt ) -> RuntimeCall - func addProxy(accountId: AccountId, type: Proxy.ProxyType) -> RuntimeCall + func addProxy(accountId: AccountId, type: Proxy.ProxyType) -> RuntimeCall } final class SubstrateCallFactory: SubstrateCallFactoryProtocol { @@ -224,9 +224,9 @@ final class SubstrateCallFactory: SubstrateCallFactoryProtocol { }) ?? rebagCall.defaultRuntimeCall } - func addProxy(accountId: AccountId, type: Proxy.ProxyType) -> RuntimeCall { - let proxyCall = Proxy.ProxyDefinition( - proxy: accountId, + func addProxy(accountId: AccountId, type: Proxy.ProxyType) -> RuntimeCall { + let proxyCall = Proxy.AddProxyCall( + proxy: .accoundId(accountId), proxyType: type, delay: 0 ) diff --git a/novawallet/Common/Substrate/Calls/Proxy/Proxy+Call.swift b/novawallet/Common/Substrate/Calls/Proxy/Proxy+Call.swift index 42632652e1..6bc94e077a 100644 --- a/novawallet/Common/Substrate/Calls/Proxy/Proxy+Call.swift +++ b/novawallet/Common/Substrate/Calls/Proxy/Proxy+Call.swift @@ -17,4 +17,16 @@ extension Proxy { RuntimeCall(moduleName: Proxy.name, callName: "proxy", args: self) } } + + struct AddProxyCall: Codable { + enum CodingKeys: String, CodingKey { + case proxy = "delegate" + case proxyType = "proxy_type" + case delay + } + + let proxy: MultiAddress + let proxyType: ProxyType + @StringCodable var delay: BlockNumber + } } diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseInteractor.swift b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseInteractor.swift index 0c845cdea4..f142cdf394 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseInteractor.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseInteractor.swift @@ -161,7 +161,6 @@ extension StakingProxyBaseInteractor: StakingProxyBaseInteractorInputProtocol { func estimateFee() { guard - let stashAccountId = try? stashItem?.stash.toAccountId(), let extrinsicService = self.extrinsicService, let amount = StakingConstants.feeEstimation.toSubstrateAmount( precision: chainAsset.assetDisplayInfo.assetPrecision @@ -170,7 +169,7 @@ extension StakingProxyBaseInteractor: StakingProxyBaseInteractorInputProtocol { } let call = callFactory.addProxy( - accountId: stashAccountId, + accountId: AccountId.empty, type: .staking ) From e92ccceca6b161c1b3d14e61f63504590af18dd1 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Mon, 15 Jan 2024 12:13:40 +0300 Subject: [PATCH 08/60] fix accountId --- .../StakingSetupProxy/Base/StakingProxyBaseInteractor.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseInteractor.swift b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseInteractor.swift index f142cdf394..67dba94c5e 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseInteractor.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseInteractor.swift @@ -169,7 +169,7 @@ extension StakingProxyBaseInteractor: StakingProxyBaseInteractorInputProtocol { } let call = callFactory.addProxy( - accountId: AccountId.empty, + accountId: AccountId.zeroAccountId(of: chainAsset.chain.accountIdSize), type: .staking ) From 58c9e77edc6db668e180b665eda7d20be21caec8 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Mon, 15 Jan 2024 15:26:41 +0300 Subject: [PATCH 09/60] PR fixes --- ...yListLocalStorageSubscriptionHandler.swift | 10 ++ .../ProxyListLocalSubscriptionFactory.swift | 68 ++++++++++++- .../Proxy/ProxyLocalStorageSubscriber.swift | 54 +++++++++++ .../StakingLocalStorageSubscriber.swift | 52 ---------- .../StakingLocalSubscriptionHandler.swift | 12 --- .../Common/Services/Proxy/ProxyModels.swift | 6 +- .../RelaychainStakingSharedState.swift | 4 + .../StakingSharedStateFactory.swift | 5 +- ...ingRelaychainInteractor+Subscription.swift | 8 +- .../StakingRelaychainInteractor.swift | 4 + novawalletTests/Mocks/CommonMocks.swift | 50 +++++----- .../StakingLocalSubscriptionFactoryStub.swift | 28 +++++- novawalletTests/Mocks/DefaultStub.swift | 2 +- novawalletTests/Mocks/ModuleMocks.swift | 96 +++++++++++++++++++ .../DApps/DAppList/DAppListTests.swift | 8 +- .../Modules/Settings/SettingsTests.swift | 8 +- 16 files changed, 316 insertions(+), 99 deletions(-) diff --git a/novawallet/Common/DataProvider/Subscription/Proxy/ProxyListLocalStorageSubscriptionHandler.swift b/novawallet/Common/DataProvider/Subscription/Proxy/ProxyListLocalStorageSubscriptionHandler.swift index 44360d792a..6533a935c7 100644 --- a/novawallet/Common/DataProvider/Subscription/Proxy/ProxyListLocalStorageSubscriptionHandler.swift +++ b/novawallet/Common/DataProvider/Subscription/Proxy/ProxyListLocalStorageSubscriptionHandler.swift @@ -3,8 +3,18 @@ import RobinHood protocol ProxyListLocalSubscriptionHandler { func handleAllProxies(result: Result<[DataProviderChange], Error>) + func handleProxies( + result: Result, + accountId: AccountId, + chainId: ChainModel.Id + ) } extension ProxyListLocalSubscriptionHandler { func handleAllProxies(result _: Result<[DataProviderChange], Error>) {} + func handleProxies( + result _: Result, + accountId _: AccountId, + chainId _: ChainModel.Id + ) {} } diff --git a/novawallet/Common/DataProvider/Subscription/Proxy/ProxyListLocalSubscriptionFactory.swift b/novawallet/Common/DataProvider/Subscription/Proxy/ProxyListLocalSubscriptionFactory.swift index cabcc08b3a..fe6ad9eae6 100644 --- a/novawallet/Common/DataProvider/Subscription/Proxy/ProxyListLocalSubscriptionFactory.swift +++ b/novawallet/Common/DataProvider/Subscription/Proxy/ProxyListLocalSubscriptionFactory.swift @@ -2,24 +2,40 @@ import RobinHood protocol ProxyListLocalSubscriptionFactoryProtocol { func getProxyListProvider() throws -> StreamableProvider + func getProxyListProvider( + for accountId: AccountId, + chainId: ChainModel.Id + ) throws -> AnyDataProvider } final class ProxyListLocalSubscriptionFactory: BaseLocalSubscriptionFactory { static let shared = ProxyListLocalSubscriptionFactory( + chainRegistry: ChainRegistryFacade.sharedRegistry, + streamableProviderFactory: SubstrateDataProviderFactory( + facade: SubstrateDataStorageFacade.shared, + operationManager: OperationManagerFacade.sharedManager, + logger: Logger.shared + ), storageFacade: UserDataStorageFacade.shared, - operationManager: OperationManager(operationQueue: OperationManagerFacade.sharedDefaultQueue), + operationManager: OperationManagerFacade.sharedManager, logger: Logger.shared ) + let chainRegistry: ChainRegistryProtocol + let streamableProviderFactory: SubstrateDataProviderFactoryProtocol let storageFacade: StorageFacadeProtocol let operationManager: OperationManagerProtocol let logger: LoggerProtocol init( + chainRegistry: ChainRegistryProtocol, + streamableProviderFactory: SubstrateDataProviderFactoryProtocol, storageFacade: StorageFacadeProtocol, operationManager: OperationManagerProtocol, logger: LoggerProtocol ) { + self.chainRegistry = chainRegistry + self.streamableProviderFactory = streamableProviderFactory self.storageFacade = storageFacade self.operationManager = operationManager self.logger = logger @@ -64,4 +80,54 @@ extension ProxyListLocalSubscriptionFactory: ProxyListLocalSubscriptionFactoryPr return provider } + + func getProxyListProvider( + for accountId: AccountId, + chainId: ChainModel.Id + ) throws -> AnyDataProvider { + clearIfNeeded() + + let codingPath = Proxy.proxyList + let localKey = try LocalStorageKeyFactory().createFromStoragePath( + codingPath, + accountId: accountId, + chainId: chainId + ) + + if let dataProvider = getProvider(for: localKey) as? DataProvider { + return AnyDataProvider(dataProvider) + } + + guard let runtimeCodingProvider = chainRegistry.getRuntimeProvider(for: chainId) else { + throw ChainRegistryError.runtimeMetadaUnavailable + } + + let repository = InMemoryDataProviderRepository() + + let streamableProvider = streamableProviderFactory.createStorageProvider(for: localKey) + let fallback = StorageProviderSourceFallback.init( + usesRuntimeFallback: false, + missingEntryStrategy: .defaultValue(nil) + ) + let trigger = DataProviderProxyTrigger() + let source: StorageProviderSource = StorageProviderSource( + itemIdentifier: localKey, + possibleCodingPaths: [codingPath], + runtimeService: runtimeCodingProvider, + provider: streamableProvider, + trigger: trigger, + fallback: fallback, + operationManager: operationManager + ) + + let dataProvider = DataProvider( + source: AnyDataProviderSource(source), + repository: AnyDataProviderRepository(repository), + updateTrigger: trigger + ) + + saveProvider(dataProvider, for: localKey) + + return AnyDataProvider(dataProvider) + } } diff --git a/novawallet/Common/DataProvider/Subscription/Proxy/ProxyLocalStorageSubscriber.swift b/novawallet/Common/DataProvider/Subscription/Proxy/ProxyLocalStorageSubscriber.swift index d9c5e7cff0..b7a91ff8f7 100644 --- a/novawallet/Common/DataProvider/Subscription/Proxy/ProxyLocalStorageSubscriber.swift +++ b/novawallet/Common/DataProvider/Subscription/Proxy/ProxyLocalStorageSubscriber.swift @@ -7,6 +7,12 @@ protocol ProxyListLocalStorageSubscriber where Self: AnyObject { var proxyListLocalSubscriptionHandler: ProxyListLocalSubscriptionHandler { get } func subscribeAllProxies() -> StreamableProvider? + + func subscribeProxies( + for accountId: AccountId, + chainId: ChainModel.Id, + modifyInternalList: @escaping (ProxyDefinition) -> ProxyDefinition + ) -> AnyDataProvider? } extension ProxyListLocalStorageSubscriber { @@ -42,6 +48,54 @@ extension ProxyListLocalStorageSubscriber { return provider } + + func subscribeProxies( + for accountId: AccountId, + chainId: ChainModel.Id, + modifyInternalList: @escaping (ProxyDefinition) -> ProxyDefinition + ) -> AnyDataProvider? { + guard let provider = try? proxyListLocalSubscriptionFactory.getProxyListProvider( + for: accountId, + chainId: chainId + ) else { + return nil + } + + let updateClosure = { [weak self] (changes: [DataProviderChange]) in + let proxies = changes.reduceToLastChange()?.item.map { modifyInternalList($0) } ?? nil + + self?.proxyListLocalSubscriptionHandler.handleProxies( + result: .success(proxies), + accountId: accountId, + chainId: chainId + ) + return + } + + let failureClosure = { [weak self] (error: Error) in + self?.proxyListLocalSubscriptionHandler.handleProxies( + result: .failure(error), + accountId: accountId, + chainId: chainId + ) + return + } + + let options = DataProviderObserverOptions( + alwaysNotifyOnRefresh: false, + waitsInProgressSyncOnAdd: false + ) + + provider.addObserver( + self, + deliverOn: .main, + executing: updateClosure, + failing: failureClosure, + options: options + ) + + return provider + } } extension ProxyListLocalStorageSubscriber where Self: ProxyListLocalSubscriptionHandler { diff --git a/novawallet/Common/DataProvider/Subscription/StakingLocalStorageSubscriber.swift b/novawallet/Common/DataProvider/Subscription/StakingLocalStorageSubscriber.swift index 0a813754ec..b05647f888 100644 --- a/novawallet/Common/DataProvider/Subscription/StakingLocalStorageSubscriber.swift +++ b/novawallet/Common/DataProvider/Subscription/StakingLocalStorageSubscriber.swift @@ -50,11 +50,6 @@ protocol StakingLocalStorageSubscriber where Self: AnyObject { api: LocalChainExternalApi, assetPrecision: Int16 ) -> AnySingleValueProvider? - - func subscribeProxies( - for accountId: AccountId, - chainId: ChainModel.Id - ) -> AnyDataProvider? } extension StakingLocalStorageSubscriber { @@ -653,53 +648,6 @@ extension StakingLocalStorageSubscriber { return provider } - - func subscribeProxies( - for accountId: AccountId, - chainId: ChainModel.Id - ) -> AnyDataProvider? { - guard let provider = try? stakingLocalSubscriptionFactory.getProxyListProvider( - for: accountId, - chainId: chainId - ) else { - return nil - } - - let updateClosure = { [weak self] (changes: [DataProviderChange]) in - let proxies = changes.reduceToLastChange()?.item?.filterStakingProxy() - - self?.stakingLocalSubscriptionHandler.handleProxies( - result: .success(proxies), - accountId: accountId, - chainId: chainId - ) - return - } - - let failureClosure = { [weak self] (error: Error) in - self?.stakingLocalSubscriptionHandler.handleProxies( - result: .failure(error), - accountId: accountId, - chainId: chainId - ) - return - } - - let options = DataProviderObserverOptions( - alwaysNotifyOnRefresh: false, - waitsInProgressSyncOnAdd: false - ) - - provider.addObserver( - self, - deliverOn: .main, - executing: updateClosure, - failing: failureClosure, - options: options - ) - - return provider - } } extension StakingLocalStorageSubscriber where Self: StakingLocalSubscriptionHandler { diff --git a/novawallet/Common/DataProvider/Subscription/StakingLocalSubscriptionHandler.swift b/novawallet/Common/DataProvider/Subscription/StakingLocalSubscriptionHandler.swift index a5ac5d4ac4..45a6aca6bf 100644 --- a/novawallet/Common/DataProvider/Subscription/StakingLocalSubscriptionHandler.swift +++ b/novawallet/Common/DataProvider/Subscription/StakingLocalSubscriptionHandler.swift @@ -49,12 +49,6 @@ protocol StakingLocalSubscriptionHandler { func handleActiveEra(result: Result, chainId: ChainModel.Id) func handleCurrentEra(result: Result, chainId: ChainModel.Id) - - func handleProxies( - result: Result, - accountId: AccountId, - chainId: ChainModel.Id - ) } extension StakingLocalSubscriptionHandler { @@ -109,10 +103,4 @@ extension StakingLocalSubscriptionHandler { func handleActiveEra(result _: Result, chainId _: ChainModel.Id) {} func handleCurrentEra(result _: Result, chainId _: ChainModel.Id) {} - - func handleProxies( - result _: Result, - accountId _: AccountId, - chainId _: ChainModel.Id - ) {} } diff --git a/novawallet/Common/Services/Proxy/ProxyModels.swift b/novawallet/Common/Services/Proxy/ProxyModels.swift index c19a074768..951041f7ba 100644 --- a/novawallet/Common/Services/Proxy/ProxyModels.swift +++ b/novawallet/Common/Services/Proxy/ProxyModels.swift @@ -44,8 +44,8 @@ struct ProxyDefinition: Decodable, Equatable { } } -extension ProxyDefinition { - func filterStakingProxy() -> ProxyDefinition { - .init(definition: definition.filter { $0.proxyType.allowStaking }) +enum ProxyFilter { + static func filteredStakingProxy(from proxy: ProxyDefinition) -> ProxyDefinition { + ProxyDefinition(definition: proxy.definition.filter { $0.proxyType.allowStaking }) } } diff --git a/novawallet/Modules/Staking/Model/StakingSharedState/RelaychainStakingSharedState.swift b/novawallet/Modules/Staking/Model/StakingSharedState/RelaychainStakingSharedState.swift index 504b08d1e6..93c842ce3b 100644 --- a/novawallet/Modules/Staking/Model/StakingSharedState/RelaychainStakingSharedState.swift +++ b/novawallet/Modules/Staking/Model/StakingSharedState/RelaychainStakingSharedState.swift @@ -7,6 +7,7 @@ protocol RelaychainStakingSharedStateProtocol: AnyObject { var stakingOption: Multistaking.ChainAssetOption { get } var globalRemoteSubscriptionService: StakingRemoteSubscriptionServiceProtocol { get } var accountRemoteSubscriptionService: StakingAccountUpdatingServiceProtocol { get } + var proxyLocalSubscriptionFactory: ProxyListLocalSubscriptionFactoryProtocol { get } var localSubscriptionFactory: StakingLocalSubscriptionFactoryProtocol { get } var eraValidatorService: EraValidatorServiceProtocol { get } var rewardCalculatorService: RewardCalculatorServiceProtocol { get } @@ -29,6 +30,7 @@ final class RelaychainStakingSharedState: RelaychainStakingSharedStateProtocol { let globalRemoteSubscriptionService: StakingRemoteSubscriptionServiceProtocol let accountRemoteSubscriptionService: StakingAccountUpdatingServiceProtocol let localSubscriptionFactory: StakingLocalSubscriptionFactoryProtocol + let proxyLocalSubscriptionFactory: ProxyListLocalSubscriptionFactoryProtocol let eraValidatorService: EraValidatorServiceProtocol let rewardCalculatorService: RewardCalculatorServiceProtocol let logger: LoggerProtocol @@ -45,6 +47,7 @@ final class RelaychainStakingSharedState: RelaychainStakingSharedStateProtocol { globalRemoteSubscriptionService: StakingRemoteSubscriptionServiceProtocol, accountRemoteSubscriptionService: StakingAccountUpdatingServiceProtocol, localSubscriptionFactory: StakingLocalSubscriptionFactoryProtocol, + proxyLocalSubscriptionFactory: ProxyListLocalSubscriptionFactoryProtocol, eraValidatorService: EraValidatorServiceProtocol, rewardCalculatorService: RewardCalculatorServiceProtocol, timeModel: StakingTimeModel, @@ -55,6 +58,7 @@ final class RelaychainStakingSharedState: RelaychainStakingSharedStateProtocol { self.globalRemoteSubscriptionService = globalRemoteSubscriptionService self.accountRemoteSubscriptionService = accountRemoteSubscriptionService self.localSubscriptionFactory = localSubscriptionFactory + self.proxyLocalSubscriptionFactory = proxyLocalSubscriptionFactory self.eraValidatorService = eraValidatorService self.rewardCalculatorService = rewardCalculatorService self.timeModel = timeModel diff --git a/novawallet/Modules/Staking/Model/StakingSharedState/StakingSharedStateFactory.swift b/novawallet/Modules/Staking/Model/StakingSharedState/StakingSharedStateFactory.swift index f9a50a6832..783870da6c 100644 --- a/novawallet/Modules/Staking/Model/StakingSharedState/StakingSharedStateFactory.swift +++ b/novawallet/Modules/Staking/Model/StakingSharedState/StakingSharedStateFactory.swift @@ -43,6 +43,7 @@ final class StakingSharedStateFactory { let rewardCalculatorService: RewardCalculatorServiceProtocol let timeModel: StakingTimeModel let localSubscriptionFactory: StakingLocalSubscriptionFactoryProtocol + let proxySubscriptionFactory: ProxyListLocalSubscriptionFactoryProtocol } struct NominationPoolsServices { @@ -166,7 +167,8 @@ final class StakingSharedStateFactory { eraValidatorService: globalServices.eraValidatorService, rewardCalculatorService: globalServices.rewardCalculatorService, timeModel: globalServices.timeModel, - localSubscriptionFactory: globalServices.localSubscriptionFactory + localSubscriptionFactory: globalServices.localSubscriptionFactory, + proxySubscriptionFactory: ProxyListLocalSubscriptionFactory.shared ) } @@ -260,6 +262,7 @@ extension StakingSharedStateFactory: StakingSharedStateFactoryProtocol { globalRemoteSubscriptionService: services.globalRemoteSubscriptionService, accountRemoteSubscriptionService: services.accountRemoteSubscriptionService, localSubscriptionFactory: services.localSubscriptionFactory, + proxyLocalSubscriptionFactory: services.proxySubscriptionFactory, eraValidatorService: services.eraValidatorService, rewardCalculatorService: services.rewardCalculatorService, timeModel: services.timeModel, diff --git a/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainInteractor+Subscription.swift b/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainInteractor+Subscription.swift index 3445da6078..0202de8bde 100644 --- a/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainInteractor+Subscription.swift +++ b/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainInteractor+Subscription.swift @@ -26,7 +26,11 @@ extension StakingRelaychainInteractor { nominatorProvider = subscribeNomination(for: stashAccountId, chainId: chainId) validatorProvider = subscribeValidator(for: stashAccountId, chainId: chainId) payeeProvider = subscribePayee(for: stashAccountId, chainId: chainId) - proxyProvider = subscribeProxies(for: stashAccountId, chainId: chainId) + proxyProvider = subscribeProxies( + for: stashAccountId, + chainId: chainId, + modifyInternalList: ProxyFilter.filteredStakingProxy + ) performTotalRewardSubscription() @@ -262,7 +266,9 @@ extension StakingRelaychainInteractor: StakingLocalStorageSubscriber, StakingLoc presenter?.didReceiveBagListScoreFactor(result: .failure(error)) } } +} +extension StakingRelaychainInteractor: ProxyListLocalStorageSubscriber, ProxyListLocalSubscriptionHandler { func handleProxies(result: Result, accountId _: AccountId, chainId _: ChainModel.Id) { presenter?.didReceiveProxy(result: result) } diff --git a/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainInteractor.swift b/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainInteractor.swift index b726174b2f..30109a5dca 100644 --- a/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainInteractor.swift +++ b/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainInteractor.swift @@ -10,6 +10,10 @@ final class StakingRelaychainInteractor: RuntimeConstantFetching, AnyCancellable sharedState.localSubscriptionFactory } + var proxyListLocalSubscriptionFactory: ProxyListLocalSubscriptionFactoryProtocol { + sharedState.proxyLocalSubscriptionFactory + } + var stakingOption: Multistaking.ChainAssetOption { sharedState.stakingOption } let chainRegistry: ChainRegistryProtocol diff --git a/novawalletTests/Mocks/CommonMocks.swift b/novawalletTests/Mocks/CommonMocks.swift index 68ae1ef55f..24c25a437d 100644 --- a/novawalletTests/Mocks/CommonMocks.swift +++ b/novawalletTests/Mocks/CommonMocks.swift @@ -5760,16 +5760,16 @@ import RobinHood - func setupSubscription(for accountId: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat) throws { + func setupSubscription(for accountId: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat, chainHasProxy: Bool) throws { - return try cuckoo_manager.callThrows("setupSubscription(for: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat) throws", - parameters: (accountId, chainId, chainFormat), - escapingParameters: (accountId, chainId, chainFormat), + return try cuckoo_manager.callThrows("setupSubscription(for: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat, chainHasProxy: Bool) throws", + parameters: (accountId, chainId, chainFormat, chainHasProxy), + escapingParameters: (accountId, chainId, chainFormat, chainHasProxy), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.setupSubscription(for: accountId, chainId: chainId, chainFormat: chainFormat)) + defaultCall: __defaultImplStub!.setupSubscription(for: accountId, chainId: chainId, chainFormat: chainFormat, chainHasProxy: chainHasProxy)) } @@ -5797,9 +5797,9 @@ import RobinHood } - func setupSubscription(for accountId: M1, chainId: M2, chainFormat: M3) -> Cuckoo.ProtocolStubNoReturnThrowingFunction<(AccountId, ChainModel.Id, ChainFormat)> where M1.MatchedType == AccountId, M2.MatchedType == ChainModel.Id, M3.MatchedType == ChainFormat { - let matchers: [Cuckoo.ParameterMatcher<(AccountId, ChainModel.Id, ChainFormat)>] = [wrap(matchable: accountId) { $0.0 }, wrap(matchable: chainId) { $0.1 }, wrap(matchable: chainFormat) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingAccountUpdatingServiceProtocol.self, method: "setupSubscription(for: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat) throws", parameterMatchers: matchers)) + func setupSubscription(for accountId: M1, chainId: M2, chainFormat: M3, chainHasProxy: M4) -> Cuckoo.ProtocolStubNoReturnThrowingFunction<(AccountId, ChainModel.Id, ChainFormat, Bool)> where M1.MatchedType == AccountId, M2.MatchedType == ChainModel.Id, M3.MatchedType == ChainFormat, M4.MatchedType == Bool { + let matchers: [Cuckoo.ParameterMatcher<(AccountId, ChainModel.Id, ChainFormat, Bool)>] = [wrap(matchable: accountId) { $0.0 }, wrap(matchable: chainId) { $0.1 }, wrap(matchable: chainFormat) { $0.2 }, wrap(matchable: chainHasProxy) { $0.3 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingAccountUpdatingServiceProtocol.self, method: "setupSubscription(for: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat, chainHasProxy: Bool) throws", parameterMatchers: matchers)) } func clearSubscription() -> Cuckoo.ProtocolStubNoReturnFunction<()> { @@ -5824,9 +5824,9 @@ import RobinHood @discardableResult - func setupSubscription(for accountId: M1, chainId: M2, chainFormat: M3) -> Cuckoo.__DoNotUse<(AccountId, ChainModel.Id, ChainFormat), Void> where M1.MatchedType == AccountId, M2.MatchedType == ChainModel.Id, M3.MatchedType == ChainFormat { - let matchers: [Cuckoo.ParameterMatcher<(AccountId, ChainModel.Id, ChainFormat)>] = [wrap(matchable: accountId) { $0.0 }, wrap(matchable: chainId) { $0.1 }, wrap(matchable: chainFormat) { $0.2 }] - return cuckoo_manager.verify("setupSubscription(for: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat) throws", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func setupSubscription(for accountId: M1, chainId: M2, chainFormat: M3, chainHasProxy: M4) -> Cuckoo.__DoNotUse<(AccountId, ChainModel.Id, ChainFormat, Bool), Void> where M1.MatchedType == AccountId, M2.MatchedType == ChainModel.Id, M3.MatchedType == ChainFormat, M4.MatchedType == Bool { + let matchers: [Cuckoo.ParameterMatcher<(AccountId, ChainModel.Id, ChainFormat, Bool)>] = [wrap(matchable: accountId) { $0.0 }, wrap(matchable: chainId) { $0.1 }, wrap(matchable: chainFormat) { $0.2 }, wrap(matchable: chainHasProxy) { $0.3 }] + return cuckoo_manager.verify("setupSubscription(for: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat, chainHasProxy: Bool) throws", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult @@ -5846,7 +5846,7 @@ import RobinHood - func setupSubscription(for accountId: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat) throws { + func setupSubscription(for accountId: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat, chainHasProxy: Bool) throws { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -5885,16 +5885,16 @@ import RobinHood - override func setupSubscription(for accountId: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat) throws { + override func setupSubscription(for accountId: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat, chainHasProxy: Bool) throws { - return try cuckoo_manager.callThrows("setupSubscription(for: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat) throws", - parameters: (accountId, chainId, chainFormat), - escapingParameters: (accountId, chainId, chainFormat), + return try cuckoo_manager.callThrows("setupSubscription(for: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat, chainHasProxy: Bool) throws", + parameters: (accountId, chainId, chainFormat, chainHasProxy), + escapingParameters: (accountId, chainId, chainFormat, chainHasProxy), superclassCall: - super.setupSubscription(for: accountId, chainId: chainId, chainFormat: chainFormat) + super.setupSubscription(for: accountId, chainId: chainId, chainFormat: chainFormat, chainHasProxy: chainHasProxy) , - defaultCall: __defaultImplStub!.setupSubscription(for: accountId, chainId: chainId, chainFormat: chainFormat)) + defaultCall: __defaultImplStub!.setupSubscription(for: accountId, chainId: chainId, chainFormat: chainFormat, chainHasProxy: chainHasProxy)) } @@ -5922,9 +5922,9 @@ import RobinHood } - func setupSubscription(for accountId: M1, chainId: M2, chainFormat: M3) -> Cuckoo.ClassStubNoReturnThrowingFunction<(AccountId, ChainModel.Id, ChainFormat)> where M1.MatchedType == AccountId, M2.MatchedType == ChainModel.Id, M3.MatchedType == ChainFormat { - let matchers: [Cuckoo.ParameterMatcher<(AccountId, ChainModel.Id, ChainFormat)>] = [wrap(matchable: accountId) { $0.0 }, wrap(matchable: chainId) { $0.1 }, wrap(matchable: chainFormat) { $0.2 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingAccountUpdatingService.self, method: "setupSubscription(for: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat) throws", parameterMatchers: matchers)) + func setupSubscription(for accountId: M1, chainId: M2, chainFormat: M3, chainHasProxy: M4) -> Cuckoo.ClassStubNoReturnThrowingFunction<(AccountId, ChainModel.Id, ChainFormat, Bool)> where M1.MatchedType == AccountId, M2.MatchedType == ChainModel.Id, M3.MatchedType == ChainFormat, M4.MatchedType == Bool { + let matchers: [Cuckoo.ParameterMatcher<(AccountId, ChainModel.Id, ChainFormat, Bool)>] = [wrap(matchable: accountId) { $0.0 }, wrap(matchable: chainId) { $0.1 }, wrap(matchable: chainFormat) { $0.2 }, wrap(matchable: chainHasProxy) { $0.3 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingAccountUpdatingService.self, method: "setupSubscription(for: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat, chainHasProxy: Bool) throws", parameterMatchers: matchers)) } func clearSubscription() -> Cuckoo.ClassStubNoReturnFunction<()> { @@ -5949,9 +5949,9 @@ import RobinHood @discardableResult - func setupSubscription(for accountId: M1, chainId: M2, chainFormat: M3) -> Cuckoo.__DoNotUse<(AccountId, ChainModel.Id, ChainFormat), Void> where M1.MatchedType == AccountId, M2.MatchedType == ChainModel.Id, M3.MatchedType == ChainFormat { - let matchers: [Cuckoo.ParameterMatcher<(AccountId, ChainModel.Id, ChainFormat)>] = [wrap(matchable: accountId) { $0.0 }, wrap(matchable: chainId) { $0.1 }, wrap(matchable: chainFormat) { $0.2 }] - return cuckoo_manager.verify("setupSubscription(for: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat) throws", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func setupSubscription(for accountId: M1, chainId: M2, chainFormat: M3, chainHasProxy: M4) -> Cuckoo.__DoNotUse<(AccountId, ChainModel.Id, ChainFormat, Bool), Void> where M1.MatchedType == AccountId, M2.MatchedType == ChainModel.Id, M3.MatchedType == ChainFormat, M4.MatchedType == Bool { + let matchers: [Cuckoo.ParameterMatcher<(AccountId, ChainModel.Id, ChainFormat, Bool)>] = [wrap(matchable: accountId) { $0.0 }, wrap(matchable: chainId) { $0.1 }, wrap(matchable: chainFormat) { $0.2 }, wrap(matchable: chainHasProxy) { $0.3 }] + return cuckoo_manager.verify("setupSubscription(for: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat, chainHasProxy: Bool) throws", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult @@ -5971,7 +5971,7 @@ import RobinHood - override func setupSubscription(for accountId: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat) throws { + override func setupSubscription(for accountId: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat, chainHasProxy: Bool) throws { return DefaultValueRegistry.defaultValue(for: (Void).self) } diff --git a/novawalletTests/Mocks/DataProviders/StakingLocalSubscriptionFactoryStub.swift b/novawalletTests/Mocks/DataProviders/StakingLocalSubscriptionFactoryStub.swift index ec4f05b6d5..af403be051 100644 --- a/novawalletTests/Mocks/DataProviders/StakingLocalSubscriptionFactoryStub.swift +++ b/novawalletTests/Mocks/DataProviders/StakingLocalSubscriptionFactoryStub.swift @@ -20,7 +20,8 @@ final class StakingLocalSubscriptionFactoryStub: StakingLocalSubscriptionFactory let totalIssuance: BigUInt? let stashItem: StashItem? let storageFacade: StorageFacadeProtocol - + let proxy: ProxyDefinition? + init( minNominatorBond: BigUInt? = nil, counterForNominators: UInt32? = nil, @@ -36,6 +37,7 @@ final class StakingLocalSubscriptionFactoryStub: StakingLocalSubscriptionFactory totalIssuance: BigUInt? = nil, totalReward: TotalRewardItem? = nil, stashItem: StashItem? = nil, + proxy: ProxyDefinition? = nil, storageFacade: StorageFacadeProtocol = SubstrateStorageTestFacade() ) { self.minNominatorBond = minNominatorBond @@ -52,6 +54,7 @@ final class StakingLocalSubscriptionFactoryStub: StakingLocalSubscriptionFactory self.totalReward = totalReward self.totalIssuance = totalIssuance self.stashItem = stashItem + self.proxy = proxy self.storageFacade = storageFacade } @@ -332,6 +335,29 @@ final class StakingLocalSubscriptionFactoryStub: StakingLocalSubscriptionFactory return provider } + + func getProxyListProvider( + for accountId: AccountId, + chainId: ChainModel.Id + ) throws -> AnyDataProvider { + let localIdentifierFactory = LocalStorageKeyFactory() + + let proxyModel: DecodedProxyDefinition = try { + let localKey = try localIdentifierFactory.createFromStoragePath( + Proxy.proxyList, + accountId: accountId, + chainId: chainId + ) + + if let proxy = proxy { + return DecodedProxyDefinition(identifier: localKey, item: proxy) + } else { + return DecodedProxyDefinition(identifier: localKey, item: nil) + } + }() + + return AnyDataProvider(DataProviderStub(models: [proxyModel])) + } private func getDataProviderStub( for value: T?, diff --git a/novawalletTests/Mocks/DefaultStub.swift b/novawalletTests/Mocks/DefaultStub.swift index 5677bf70df..713c3a2571 100644 --- a/novawalletTests/Mocks/DefaultStub.swift +++ b/novawalletTests/Mocks/DefaultStub.swift @@ -124,7 +124,7 @@ extension MockStakingRemoteSubscriptionServiceProtocol { extension MockStakingAccountUpdatingServiceProtocol { func applyDefault() -> MockStakingAccountUpdatingServiceProtocol { stub(self) { stub in - stub.setupSubscription(for: any(), chainId: any(), chainFormat: any()).thenDoNothing() + stub.setupSubscription(for: any(), chainId: any(), chainFormat: any(), chainHasProxy: any()).thenDoNothing() stub.clearSubscription().thenDoNothing() } diff --git a/novawalletTests/Mocks/ModuleMocks.swift b/novawalletTests/Mocks/ModuleMocks.swift index 167dbbdc98..8554481309 100644 --- a/novawalletTests/Mocks/ModuleMocks.swift +++ b/novawalletTests/Mocks/ModuleMocks.swift @@ -36176,6 +36176,21 @@ import Foundation } + + + func didReceiveProxy(result: Result) { + + return cuckoo_manager.call("didReceiveProxy(result: Result)", + parameters: (result), + escapingParameters: (result), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.didReceiveProxy(result: result)) + + } + struct __StubbingProxy_StakingRelaychainInteractorOutputProtocol: Cuckoo.StubbingProxy { private let cuckoo_manager: Cuckoo.MockManager @@ -36350,6 +36365,11 @@ import Foundation return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceiveAccount(_: MetaChainAccountResponse?, for: AccountId)", parameterMatchers: matchers)) } + func didReceiveProxy(result: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(Result)> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainInteractorOutputProtocol.self, method: "didReceiveProxy(result: Result)", parameterMatchers: matchers)) + } + } struct __VerificationProxy_StakingRelaychainInteractorOutputProtocol: Cuckoo.VerificationProxy { @@ -36564,6 +36584,12 @@ import Foundation return cuckoo_manager.verify("didReceiveAccount(_: MetaChainAccountResponse?, for: AccountId)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } + @discardableResult + func didReceiveProxy(result: M1) -> Cuckoo.__DoNotUse<(Result), Void> where M1.MatchedType == Result { + let matchers: [Cuckoo.ParameterMatcher<(Result)>] = [wrap(matchable: result) { $0 }] + return cuckoo_manager.verify("didReceiveProxy(result: Result)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + } } @@ -36771,6 +36797,12 @@ import Foundation return DefaultValueRegistry.defaultValue(for: (Void).self) } + + + func didReceiveProxy(result: Result) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + } @@ -36980,6 +37012,36 @@ import Foundation + func showAddProxy(from view: ControllerBackedProtocol?) { + + return cuckoo_manager.call("showAddProxy(from: ControllerBackedProtocol?)", + parameters: (view), + escapingParameters: (view), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.showAddProxy(from: view)) + + } + + + + func showEditProxies(from view: ControllerBackedProtocol?) { + + return cuckoo_manager.call("showEditProxies(from: ControllerBackedProtocol?)", + parameters: (view), + escapingParameters: (view), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.showEditProxies(from: view)) + + } + + + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { return cuckoo_manager.call("present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", @@ -37077,6 +37139,16 @@ import Foundation return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainWireframeProtocol.self, method: "showYourValidatorInfo(_: AccountAddress, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) } + func showAddProxy(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?)> where M1.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainWireframeProtocol.self, method: "showAddProxy(from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + } + + func showEditProxies(from view: M1) -> Cuckoo.ProtocolStubNoReturnFunction<(ControllerBackedProtocol?)> where M1.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainWireframeProtocol.self, method: "showEditProxies(from: ControllerBackedProtocol?)", parameterMatchers: matchers)) + } + func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.ProtocolStubNoReturnFunction<(String?, String?, String?, ControllerBackedProtocol?)> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] return .init(stub: cuckoo_manager.createStub(for: MockStakingRelaychainWireframeProtocol.self, method: "present(message: String?, title: String?, closeAction: String?, from: ControllerBackedProtocol?)", parameterMatchers: matchers)) @@ -37175,6 +37247,18 @@ import Foundation return cuckoo_manager.verify("showYourValidatorInfo(_: AccountAddress, from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } + @discardableResult + func showAddProxy(from view: M1) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("showAddProxy(from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + + @discardableResult + func showEditProxies(from view: M1) -> Cuckoo.__DoNotUse<(ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == ControllerBackedProtocol { + let matchers: [Cuckoo.ParameterMatcher<(ControllerBackedProtocol?)>] = [wrap(matchable: view) { $0 }] + return cuckoo_manager.verify("showEditProxies(from: ControllerBackedProtocol?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + @discardableResult func present(message: M1, title: M2, closeAction: M3, from view: M4) -> Cuckoo.__DoNotUse<(String?, String?, String?, ControllerBackedProtocol?), Void> where M1.OptionalMatchedType == String, M2.OptionalMatchedType == String, M3.OptionalMatchedType == String, M4.OptionalMatchedType == ControllerBackedProtocol { let matchers: [Cuckoo.ParameterMatcher<(String?, String?, String?, ControllerBackedProtocol?)>] = [wrap(matchable: message) { $0.0 }, wrap(matchable: title) { $0.1 }, wrap(matchable: closeAction) { $0.2 }, wrap(matchable: view) { $0.3 }] @@ -37270,6 +37354,18 @@ import Foundation + func showAddProxy(from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + + func showEditProxies(from view: ControllerBackedProtocol?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + func present(message: String?, title: String?, closeAction: String?, from view: ControllerBackedProtocol?) { return DefaultValueRegistry.defaultValue(for: (Void).self) } diff --git a/novawalletTests/Modules/DApps/DAppList/DAppListTests.swift b/novawalletTests/Modules/DApps/DAppList/DAppListTests.swift index 73fe0b2e8c..73d3d295ef 100644 --- a/novawalletTests/Modules/DApps/DAppList/DAppListTests.swift +++ b/novawalletTests/Modules/DApps/DAppList/DAppListTests.swift @@ -39,10 +39,16 @@ class DAppListTests: XCTestCase { storageFacade: storageFacade, operationQueue: operationQueue ) - + let streamableProviderFactory = SubstrateDataProviderFactory( + facade: SubstrateStorageTestFacade(), + operationManager: OperationManagerFacade.sharedManager + ) + let mapper = DAppFavoriteMapper() let dappsFavoriteRepository = storageFacade.createRepository(mapper: AnyCoreDataMapper(mapper)) let proxyListLocalSubscriptionFactory = ProxyListLocalSubscriptionFactory( + chainRegistry: ChainRegistryProtocolStub(), + streamableProviderFactory: streamableProviderFactory, storageFacade: storageFacade, operationManager: OperationManagerFacade.sharedManager, logger: Logger.shared diff --git a/novawalletTests/Modules/Settings/SettingsTests.swift b/novawalletTests/Modules/Settings/SettingsTests.swift index 0f923b8b47..427afa2e98 100644 --- a/novawalletTests/Modules/Settings/SettingsTests.swift +++ b/novawalletTests/Modules/Settings/SettingsTests.swift @@ -47,9 +47,15 @@ final class SettingsTests: XCTestCase { let wireframe = MockSettingsWireframeProtocol() let eventCenter = MockEventCenterProtocol() - + let streamableProviderFactory = SubstrateDataProviderFactory( + facade: SubstrateStorageTestFacade(), + operationManager: OperationManagerFacade.sharedManager + ) + let walletConnect = MockWalletConnectDelegateInputProtocol() let proxyListLocalSubscriptionFactory = ProxyListLocalSubscriptionFactory( + chainRegistry: ChainRegistryProtocolStub(), + streamableProviderFactory: streamableProviderFactory, storageFacade: storageFacade, operationManager: OperationManagerFacade.sharedManager, logger: Logger.shared From a3582a6c43fc145257a8bf07648d8ce0adb0dfc4 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Mon, 15 Jan 2024 17:45:36 +0300 Subject: [PATCH 10/60] bugfix --- .../Subscription/StakingLocalStorageSubscriber.swift | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/novawallet/Common/DataProvider/Subscription/StakingLocalStorageSubscriber.swift b/novawallet/Common/DataProvider/Subscription/StakingLocalStorageSubscriber.swift index b05647f888..64eefef189 100644 --- a/novawallet/Common/DataProvider/Subscription/StakingLocalStorageSubscriber.swift +++ b/novawallet/Common/DataProvider/Subscription/StakingLocalStorageSubscriber.swift @@ -50,6 +50,11 @@ protocol StakingLocalStorageSubscriber where Self: AnyObject { api: LocalChainExternalApi, assetPrecision: Int16 ) -> AnySingleValueProvider? + + func subscribeStashItemProvider( + for address: AccountAddress, + chainId: ChainModel.Id + ) -> StreamableProvider? } extension StakingLocalStorageSubscriber { From 05b49f26ff22ad7c5c895b9cdaf2cfba9e560f7a Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Tue, 16 Jan 2024 13:54:56 +0300 Subject: [PATCH 11/60] add yourwallets, w3name --- novawallet.xcodeproj/project.pbxproj | 24 ++ novawallet/Common/Model/AssetBalance.swift | 9 + .../Protocols/YourWalletsPresentable.swift | 38 +++ .../Common/Services/Proxy/ProxyModels.swift | 4 + .../Base/StakingProxyBaseInteractor.swift | 56 +++-- .../Base/StakingProxyBasePresenter.swift | 154 ++++++++++++ .../Base/StakingProxyBaseProtocols.swift | 12 + .../StakingSetupProxyInteractor.swift | 97 +++++++- .../StakingSetupProxyPresenter.swift | 235 +++++++++++++----- .../StakingSetupProxyProtocols.swift | 39 ++- .../StakingSetupProxyViewController.swift | 57 +++++ .../StakingSetupProxyViewFactory.swift | 56 ++++- .../StakingSetupProxyViewLayout.swift | 5 +- .../StakingSetupProxyWireframe.swift | 6 +- .../ProxyDataValidatorFactory.swift | 164 ++++++++++++ .../Validation/ProxyErrorPresentable.swift | 103 ++++++++ .../Model/TransferSetupRecipientAccount.swift | 4 +- .../TransferSetupProtocols.swift | 11 +- .../TransferSetupWireframe.swift | 25 -- novawallet/en.lproj/Localizable.strings | 8 + novawallet/ru.lproj/Localizable.strings | 8 + 21 files changed, 980 insertions(+), 135 deletions(-) create mode 100644 novawallet/Common/Protocols/YourWalletsPresentable.swift create mode 100644 novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift create mode 100644 novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyDataValidatorFactory.swift create mode 100644 novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyErrorPresentable.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index eb8b24bfe1..231c4e2abd 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -812,6 +812,9 @@ 772AD8E62AC5A87200B0C41A /* MinStakeCrossedParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = 772AD8E52AC5A87200B0C41A /* MinStakeCrossedParams.swift */; }; 772AD8E82AC5E30000B0C41A /* StakingBaseErrorPresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 772AD8E72AC5E30000B0C41A /* StakingBaseErrorPresentable.swift */; }; 772B1C7D2A93837800A19061 /* StartStakingCustomValidatorListWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 772B1C7C2A93837800A19061 /* StartStakingCustomValidatorListWireframe.swift */; }; + 7730904F2B557F46002577AE /* StakingProxyBasePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7730904E2B557F46002577AE /* StakingProxyBasePresenter.swift */; }; + 773090512B559196002577AE /* ProxyDataValidatorFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 773090502B559196002577AE /* ProxyDataValidatorFactory.swift */; }; + 773090532B5591A1002577AE /* ProxyErrorPresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 773090522B5591A1002577AE /* ProxyErrorPresentable.swift */; }; 7731E9C42A14DA3F0085B5FF /* BorderedActionControlView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7731E9C32A14DA3F0085B5FF /* BorderedActionControlView.swift */; }; 7738FB6A2A4C5D1A00797439 /* StartStakingRelaychainInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7738FB692A4C5D1A00797439 /* StartStakingRelaychainInteractor.swift */; }; 773A37542B398CEB006AC4AA /* WalletNotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 773A37532B398CEB006AC4AA /* WalletNotificationService.swift */; }; @@ -920,6 +923,7 @@ 77AB55592AA244BB0058814E /* OperationPoolRewardOrSlashModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77AB55582AA244BB0058814E /* OperationPoolRewardOrSlashModel.swift */; }; 77AB555B2AA246CA0058814E /* OperationPoolRewardOrSlashViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77AB555A2AA246CA0058814E /* OperationPoolRewardOrSlashViewModel.swift */; }; 77AB555D2AA24BA90058814E /* OperationDetailsPoolRewardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77AB555C2AA24BA90058814E /* OperationDetailsPoolRewardView.swift */; }; + 77C35CE52B568ED100308F16 /* YourWalletsPresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C35CE42B568ED100308F16 /* YourWalletsPresentable.swift */; }; 77C976202AF36A170049272C /* SwapModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C9761F2AF36A170049272C /* SwapModels.swift */; }; 77C976222AF39F180049272C /* TokenOperationTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C976212AF39F180049272C /* TokenOperationTableViewCell.swift */; }; 77C976242AF3A5280049272C /* SwapViewModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C976232AF3A5280049272C /* SwapViewModels.swift */; }; @@ -5022,6 +5026,9 @@ 772AD8E52AC5A87200B0C41A /* MinStakeCrossedParams.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MinStakeCrossedParams.swift; sourceTree = ""; }; 772AD8E72AC5E30000B0C41A /* StakingBaseErrorPresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingBaseErrorPresentable.swift; sourceTree = ""; }; 772B1C7C2A93837800A19061 /* StartStakingCustomValidatorListWireframe.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StartStakingCustomValidatorListWireframe.swift; sourceTree = ""; }; + 7730904E2B557F46002577AE /* StakingProxyBasePresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingProxyBasePresenter.swift; sourceTree = ""; }; + 773090502B559196002577AE /* ProxyDataValidatorFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProxyDataValidatorFactory.swift; sourceTree = ""; }; + 773090522B5591A1002577AE /* ProxyErrorPresentable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProxyErrorPresentable.swift; sourceTree = ""; }; 7731E9C32A14DA3F0085B5FF /* BorderedActionControlView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BorderedActionControlView.swift; sourceTree = ""; }; 7738FB692A4C5D1A00797439 /* StartStakingRelaychainInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartStakingRelaychainInteractor.swift; sourceTree = ""; }; 773A37532B398CEB006AC4AA /* WalletNotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletNotificationService.swift; sourceTree = ""; }; @@ -5131,6 +5138,7 @@ 77AB55582AA244BB0058814E /* OperationPoolRewardOrSlashModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OperationPoolRewardOrSlashModel.swift; sourceTree = ""; }; 77AB555A2AA246CA0058814E /* OperationPoolRewardOrSlashViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OperationPoolRewardOrSlashViewModel.swift; sourceTree = ""; }; 77AB555C2AA24BA90058814E /* OperationDetailsPoolRewardView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OperationDetailsPoolRewardView.swift; sourceTree = ""; }; + 77C35CE42B568ED100308F16 /* YourWalletsPresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YourWalletsPresentable.swift; sourceTree = ""; }; 77C9761F2AF36A170049272C /* SwapModels.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwapModels.swift; sourceTree = ""; }; 77C976212AF39F180049272C /* TokenOperationTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokenOperationTableViewCell.swift; sourceTree = ""; }; 77C976232AF3A5280049272C /* SwapViewModels.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwapViewModels.swift; sourceTree = ""; }; @@ -10190,6 +10198,15 @@ path = ParaStkStakeSetup; sourceTree = ""; }; + 773090542B5591AC002577AE /* Validation */ = { + isa = PBXGroup; + children = ( + 773090522B5591A1002577AE /* ProxyErrorPresentable.swift */, + 773090502B559196002577AE /* ProxyDataValidatorFactory.swift */, + ); + path = Validation; + sourceTree = ""; + }; 7738FB5B2A4C5C2000797439 /* ParachainStaking */ = { isa = PBXGroup; children = ( @@ -10272,6 +10289,7 @@ 7754BD522B501E330099C13E /* StakingProxyBaseInteractor.swift */, 7754BD552B5021C30099C13E /* StakingProxyBaseProtocols.swift */, 7754BD572B50232C0099C13E /* ProxyDepositCalculator.swift */, + 7730904E2B557F46002577AE /* StakingProxyBasePresenter.swift */, ); path = Base; sourceTree = ""; @@ -14058,6 +14076,7 @@ 772540372AC45D22002B3FD4 /* PurchasePresentable.swift */, 7719019A2AE670AE00D9C918 /* ShortTextInfoPresentable.swift */, 0C259EA72B46C55C00CB86E4 /* ExtrinsicSigningErrorHandling.swift */, + 77C35CE42B568ED100308F16 /* YourWalletsPresentable.swift */, ); path = Protocols; sourceTree = ""; @@ -18126,6 +18145,7 @@ A4542BFD7BBCF6B05FB2D3E4 /* StakingSetupProxy */ = { isa = PBXGroup; children = ( + 773090542B5591AC002577AE /* Validation */, 7754BD542B501E3C0099C13E /* Base */, 173BB84A4695492A77AE206D /* StakingSetupProxyProtocols.swift */, 1399884D5F4905DA0BD1E5C3 /* StakingSetupProxyWireframe.swift */, @@ -20370,6 +20390,7 @@ 774091F92ACB1F4B00172516 /* SwapAmountInputView.swift in Sources */, 7728E5912A1324A2007901E0 /* ReferendumsSearchManager.swift in Sources */, 843C49DB24DF373000B71DDA /* AccountImportRequest.swift in Sources */, + 7730904F2B557F46002577AE /* StakingProxyBasePresenter.swift in Sources */, 843910C1253F36F300E3C217 /* BaseStorageChildSubscription.swift in Sources */, 88FB7DC829505DC300784E08 /* AssetDetailsContainerViewFactory.swift in Sources */, 846B749528B422C800C39B93 /* ChainAccountAddViewModel.swift in Sources */, @@ -21052,6 +21073,7 @@ 840DFF5128940D0C001B11EA /* ChainAddressDetailsViewModel.swift in Sources */, 84CFF1F226526FBC00DB7CF7 /* StakingBondMoreConfirmationVC.swift in Sources */, 8446F5F82819235B00B7A86C /* AssetIconView+Style.swift in Sources */, + 77C35CE52B568ED100308F16 /* YourWalletsPresentable.swift in Sources */, 840882B02514024800177E20 /* SelectedConnectionChanged.swift in Sources */, 84FD3DB72540EF0700A234E3 /* TransactionSubscription.swift in Sources */, 8482F628280C49940006C3A0 /* DAppsAuthViewModelFactory.swift in Sources */, @@ -21120,6 +21142,7 @@ 8402CC9C275B92AC00E5BF30 /* ControlView.swift in Sources */, 0C66102B2A73816000E44634 /* StakingSharedStateFactory.swift in Sources */, 77DC54862B1FE5C100C7E45A /* ProxySyncService.swift in Sources */, + 773090532B5591A1002577AE /* ProxyErrorPresentable.swift in Sources */, 2AB7A7FF25CD0E8000767D87 /* GitHubPhishingAPIService.swift in Sources */, 77F033972A8142D1006BC67E /* StakingSetupAmountStyles.swift in Sources */, AEF507F72625A3280098574D /* ValidatorState+Status.swift in Sources */, @@ -23449,6 +23472,7 @@ 1B1402BB29CFF6D9FB944B2D /* CreateWatchOnlyViewLayout.swift in Sources */, 88E74E8C29538C36008031A3 /* QRCodeInfo.swift in Sources */, 777BD86229F97322004969A2 /* ReferendumsFilter.swift in Sources */, + 773090512B559196002577AE /* ProxyDataValidatorFactory.swift in Sources */, 77FF02692B21ECB900B655BC /* ProxyTableViewCell.swift in Sources */, 84282288289AC80600163031 /* MultiValueView+Factory.swift in Sources */, 0C13DFDD2AFA82BA00E5F355 /* AmountInputViewModel+Slippage.swift in Sources */, diff --git a/novawallet/Common/Model/AssetBalance.swift b/novawallet/Common/Model/AssetBalance.swift index 3f1838430d..1da2a955ef 100644 --- a/novawallet/Common/Model/AssetBalance.swift +++ b/novawallet/Common/Model/AssetBalance.swift @@ -45,6 +45,15 @@ struct AssetBalance: Equatable { ) } + func regularTransferrableBalance() -> BigUInt { + Self.transferrableBalance( + from: freeInPlank, + frozen: frozenInPlank, + reserved: reservedInPlank, + mode: .regular + ) + } + static func transferrableBalance( from free: BigUInt, frozen: BigUInt, diff --git a/novawallet/Common/Protocols/YourWalletsPresentable.swift b/novawallet/Common/Protocols/YourWalletsPresentable.swift new file mode 100644 index 0000000000..f13d7910be --- /dev/null +++ b/novawallet/Common/Protocols/YourWalletsPresentable.swift @@ -0,0 +1,38 @@ +import SoraUI + +protocol YourWalletsPresentable { + func showYourWallets( + from view: ControllerBackedProtocol?, + accounts: [MetaAccountChainResponse], + address: AccountAddress?, + delegate: YourWalletsDelegate + ) + func hideYourWallets(from view: ControllerBackedProtocol?) +} + +extension YourWalletsPresentable { + func showYourWallets( + from view: ControllerBackedProtocol?, + accounts: [MetaAccountChainResponse], + address: AccountAddress?, + delegate: YourWalletsDelegate + ) { + guard let viewController = YourWalletsViewFactory.createView( + metaAccounts: accounts, + address: address, + delegate: delegate + ) else { + return + } + + let factory = ModalSheetPresentationFactory(configuration: ModalSheetPresentationConfiguration.nova) + viewController.controller.modalTransitioningFactory = factory + viewController.controller.modalPresentationStyle = .custom + + view?.controller.present(viewController.controller, animated: true) + } + + func hideYourWallets(from view: ControllerBackedProtocol?) { + view?.controller.dismiss(animated: true) + } +} diff --git a/novawallet/Common/Services/Proxy/ProxyModels.swift b/novawallet/Common/Services/Proxy/ProxyModels.swift index 951041f7ba..f7a61ad7d7 100644 --- a/novawallet/Common/Services/Proxy/ProxyModels.swift +++ b/novawallet/Common/Services/Proxy/ProxyModels.swift @@ -48,4 +48,8 @@ enum ProxyFilter { static func filteredStakingProxy(from proxy: ProxyDefinition) -> ProxyDefinition { ProxyDefinition(definition: proxy.definition.filter { $0.proxyType.allowStaking }) } + + static func allProxies(from proxy: ProxyDefinition) -> ProxyDefinition { + proxy + } } diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseInteractor.swift b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseInteractor.swift index 67dba94c5e..868f8386fa 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseInteractor.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseInteractor.swift @@ -2,24 +2,23 @@ import UIKit import BigInt import RobinHood -class StakingProxyBaseInteractor: RuntimeConstantFetching { +class StakingProxyBaseInteractor: RuntimeConstantFetching, StakingProxyBaseInteractorInputProtocol { weak var basePresenter: StakingProxyBaseInteractorOutputProtocol? let runtimeService: RuntimeCodingServiceProtocol let selectedAccount: ChainAccountResponse let chainAsset: ChainAsset - let stakingLocalSubscriptionFactory: StakingLocalSubscriptionFactoryProtocol let walletLocalSubscriptionFactory: WalletLocalSubscriptionFactoryProtocol let accountProviderFactory: AccountProviderFactoryProtocol let priceLocalSubscriptionFactory: PriceProviderFactoryProtocol let callFactory: SubstrateCallFactoryProtocol let feeProxy: ExtrinsicFeeProxyProtocol let extrinsicServiceFactory: ExtrinsicServiceFactoryProtocol + let sharedState: RelaychainStakingSharedStateProtocol private lazy var operationManager = OperationManager(operationQueue: operationQueue) private var calculator = ProxyDepositCalculator() private var proxyProvider: AnyDataProvider? private let operationQueue: OperationQueue - private var balanceProvider: StreamableProvider? private var extrinsicService: ExtrinsicServiceProtocol? private var controllerAccountProvider: StreamableProvider? @@ -28,9 +27,17 @@ class StakingProxyBaseInteractor: RuntimeConstantFetching { private var stashItemProvider: StreamableProvider? private var stashItem: StashItem? + var stakingLocalSubscriptionFactory: StakingLocalSubscriptionFactoryProtocol { + sharedState.localSubscriptionFactory + } + + var proxyListLocalSubscriptionFactory: ProxyListLocalSubscriptionFactoryProtocol { + sharedState.proxyLocalSubscriptionFactory + } + init( runtimeService: RuntimeCodingServiceProtocol, - stakingLocalSubscriptionFactory: StakingLocalSubscriptionFactoryProtocol, + sharedState: RelaychainStakingSharedStateProtocol, walletLocalSubscriptionFactory: WalletLocalSubscriptionFactoryProtocol, accountProviderFactory: AccountProviderFactoryProtocol, priceLocalSubscriptionFactory: PriceProviderFactoryProtocol, @@ -43,7 +50,7 @@ class StakingProxyBaseInteractor: RuntimeConstantFetching { operationQueue: OperationQueue ) { self.runtimeService = runtimeService - self.stakingLocalSubscriptionFactory = stakingLocalSubscriptionFactory + self.sharedState = sharedState self.walletLocalSubscriptionFactory = walletLocalSubscriptionFactory self.accountProviderFactory = accountProviderFactory self.priceLocalSubscriptionFactory = priceLocalSubscriptionFactory @@ -106,7 +113,11 @@ class StakingProxyBaseInteractor: RuntimeConstantFetching { let stashItem = stashItem, let stashAccountId = try? stashItem.stash.toAccountId() { let chainId = chainAsset.chain.chainId - proxyProvider = subscribeProxies(for: stashAccountId, chainId: chainId) + proxyProvider = subscribeProxies( + for: stashAccountId, + chainId: chainId, + modifyInternalList: ProxyFilter.allProxies + ) balanceProvider = subscribeToAssetBalanceProvider( for: stashAccountId, chainId: chainAsset.chain.chainId, @@ -145,9 +156,9 @@ class StakingProxyBaseInteractor: RuntimeConstantFetching { stashAccountProvider = subscribeForAccountId(accountId, chain: chain) } -} -extension StakingProxyBaseInteractor: StakingProxyBaseInteractorInputProtocol { + // MARK: - StakingProxyBaseInteractorInputProtocol + func setup() { if let address = selectedAccount.toAddress() { stashItemProvider = subscribeStashItemProvider(for: address, chainId: chainAsset.chain.chainId) @@ -161,10 +172,7 @@ extension StakingProxyBaseInteractor: StakingProxyBaseInteractorInputProtocol { func estimateFee() { guard - let extrinsicService = self.extrinsicService, - let amount = StakingConstants.feeEstimation.toSubstrateAmount( - precision: chainAsset.assetDisplayInfo.assetPrecision - ) else { + let extrinsicService = self.extrinsicService else { return } @@ -189,17 +197,6 @@ extension StakingProxyBaseInteractor: StakingLocalStorageSubscriber, StakingLoca basePresenter?.didReceive(baseError: .stashItem(error)) } } - - func handleProxies(result: Result, accountId _: AccountId, chainId _: ChainModel.Id) { - switch result { - case let .success(proxy): - let proxyCount = proxy?.definition.count ?? 0 - calculator.proxyCount = proxyCount - updateProxyDeposit() - case let .failure(error): - basePresenter?.didReceive(baseError: .handleProxies(error)) - } - } } extension StakingProxyBaseInteractor: PriceLocalStorageSubscriber, PriceLocalSubscriptionHandler { @@ -277,3 +274,16 @@ extension StakingProxyBaseInteractor: AccountLocalSubscriptionHandler, AccountLo } } } + +extension StakingProxyBaseInteractor: ProxyListLocalSubscriptionHandler, ProxyListLocalStorageSubscriber { + func handleProxies(result: Result, accountId _: AccountId, chainId _: ChainModel.Id) { + switch result { + case let .success(proxy): + let proxyCount = proxy?.definition.count ?? 0 + calculator.proxyCount = proxyCount + updateProxyDeposit() + case let .failure(error): + basePresenter?.didReceive(baseError: .handleProxies(error)) + } + } +} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift new file mode 100644 index 0000000000..a5572a8f7b --- /dev/null +++ b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift @@ -0,0 +1,154 @@ +import Foundation +import BigInt +import SoraFoundation + +class StakingProxyBasePresenter: StakingSetupProxyBasePresenterProtocol { + weak var baseView: StakingSetupProxyViewProtocol? + let balanceViewModelFactory: BalanceViewModelFactoryProtocol + let chainAsset: ChainAsset + let dataValidatingFactory: ProxyDataValidatorFactoryProtocol + + private let interactor: StakingProxyBaseInteractorInputProtocol + private let wireframe: StakingSetupProxyBaseWireframeProtocol + private var assetBalance: AssetBalance? + private var proxyDeposit: BigUInt? + private var priceData: PriceData? + private var fee: ExtrinsicFeeProtocol? + private var proxyAddress: String? + private var currentDeposit: BigUInt? + private var deposit: BigUInt? + private var existensialDeposit: BigUInt? + private var maxProxies: Int? + private var proxy: ProxyDefinition? + + init( + chainAsset: ChainAsset, + interactor: StakingProxyBaseInteractorInputProtocol, + wireframe: StakingSetupProxyBaseWireframeProtocol, + balanceViewModelFactory: BalanceViewModelFactoryProtocol, + dataValidatingFactory: ProxyDataValidatorFactoryProtocol, + localizationManager: LocalizationManagerProtocol + ) { + self.chainAsset = chainAsset + self.interactor = interactor + self.wireframe = wireframe + self.balanceViewModelFactory = balanceViewModelFactory + self.dataValidatingFactory = dataValidatingFactory + self.localizationManager = localizationManager + } + + func provideProxyDeposit() { + guard let amount = proxyDeposit?.decimal(precision: chainAsset.asset.precision) else { + baseView?.didReceiveProxyDeposit(viewModel: .loading) + return + } + let proxyDepositViewModel = balanceViewModelFactory.balanceFromPrice( + amount, + priceData: priceData + ).value(for: selectedLocale) + baseView?.didReceiveProxyDeposit(viewModel: .loaded(value: .init( + isEditable: false, + balanceViewModel: proxyDepositViewModel + ))) + } + + func provideFee() { + guard let fee = fee?.amount.decimal(precision: chainAsset.asset.precision) else { + baseView?.didReceiveFee(viewModel: nil) + return + } + let feeViewModel = balanceViewModelFactory.balanceFromPrice( + fee, + priceData: priceData + ).value(for: selectedLocale) + baseView?.didReceiveFee(viewModel: feeViewModel) + } + + func updateView() { + provideProxyDeposit() + provideFee() + } + + // MARK: - StakingSetupProxyPresenterProtocol + + func setup() { + interactor.setup() + } + + func showDepositInfo() {} + + func createCommonValidations() -> [DataValidating]? { + [ + dataValidatingFactory.has( + fee: fee, + locale: selectedLocale + ) { [weak self] in + self?.interactor.estimateFee() + }, + dataValidatingFactory.canPayFeeInPlank( + balance: assetBalance?.regularTransferrableBalance(), + fee: fee, + asset: chainAsset.assetDisplayInfo, + locale: selectedLocale + ), + dataValidatingFactory.proxyNotExists( + address: proxyAddress ?? "", + chain: chainAsset.chain, + proxyList: proxy, + locale: selectedLocale + ), + dataValidatingFactory.hasSufficientBalance( + available: (assetBalance?.regularTransferrableBalance() ?? 0) + (currentDeposit ?? 0), + deposit: deposit, + fee: fee?.amountForCurrentAccount, + asset: chainAsset.assetDisplayInfo, + locale: selectedLocale + ), + dataValidatingFactory.exsitentialDepositIsNotViolated( + spendingAmount: fee?.amountForCurrentAccount, + totalAmount: assetBalance?.freeInPlank, + minimumBalance: existensialDeposit, + locale: selectedLocale + ), + dataValidatingFactory.notReachedMaximimProxyCount( + proxy?.definition.count ?? 0, + limit: maxProxies ?? 32, + chain: chainAsset.chain, + locale: selectedLocale + ) + ] + } +} + +extension StakingProxyBasePresenter: StakingProxyBaseInteractorOutputProtocol { + func didReceive(baseError _: StakingProxyBaseError) {} + func didReceive(proxyDeposit: BigUInt?) { + self.proxyDeposit = proxyDeposit + provideProxyDeposit() + } + + func didReceive(assetBalance: AssetBalance?) { + self.assetBalance = assetBalance + } + + func didReceive(fee: ExtrinsicFeeProtocol?) { + self.fee = fee + provideFee() + } + + func didReceive(price: PriceData?) { + priceData = price + provideProxyDeposit() + provideFee() + } + + func didReceiveAccount(_: MetaChainAccountResponse?, for _: AccountId) {} +} + +extension StakingProxyBasePresenter: Localizable { + func applyLocalization() { + if baseView?.isSetup == true { + updateView() + } + } +} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseProtocols.swift b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseProtocols.swift index 47a701d429..306e336271 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseProtocols.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseProtocols.swift @@ -23,3 +23,15 @@ protocol StakingProxyBaseInteractorInputProtocol: AnyObject { func setup() func estimateFee() } + +protocol StakingSetupProxyBaseViewProtocol: ControllerBackedProtocol { + func didReceiveProxyDeposit(viewModel: LoadableViewModelState) + func didReceiveFee(viewModel: BalanceViewModelProtocol?) +} + +protocol StakingSetupProxyBasePresenterProtocol: AnyObject { + func setup() + func showDepositInfo() +} + +protocol StakingSetupProxyBaseWireframeProtocol: AnyObject {} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyInteractor.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyInteractor.swift index ecd4ed8898..0890ce6be5 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyInteractor.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyInteractor.swift @@ -1,9 +1,102 @@ import UIKit +import RobinHood -final class StakingSetupProxyInteractor: StakingProxyBaseInteractor { +final class StakingSetupProxyInteractor: StakingProxyBaseInteractor, AccountFetching { weak var presenter: StakingSetupProxyInteractorOutputProtocol? { basePresenter as? StakingSetupProxyInteractorOutputProtocol } + + let web3NamesService: Web3NameServiceProtocol? + let accountRepository: AnyDataProviderRepository + let operationManager: OperationManagerProtocol + + init( + web3NamesService: Web3NameServiceProtocol?, + accountRepository: AnyDataProviderRepository, + runtimeService: RuntimeCodingServiceProtocol, + sharedState: RelaychainStakingSharedStateProtocol, + walletLocalSubscriptionFactory: WalletLocalSubscriptionFactoryProtocol, + accountProviderFactory: AccountProviderFactoryProtocol, + priceLocalSubscriptionFactory: PriceProviderFactoryProtocol, + callFactory: SubstrateCallFactoryProtocol, + feeProxy: ExtrinsicFeeProxyProtocol, + extrinsicServiceFactory: ExtrinsicServiceFactoryProtocol, + selectedAccount: ChainAccountResponse, + chainAsset: ChainAsset, + currencyManager: CurrencyManagerProtocol, + operationQueue: OperationQueue + ) { + self.web3NamesService = web3NamesService + self.accountRepository = accountRepository + operationManager = OperationManager(operationQueue: operationQueue) + super.init( + runtimeService: runtimeService, + sharedState: sharedState, + walletLocalSubscriptionFactory: walletLocalSubscriptionFactory, + accountProviderFactory: accountProviderFactory, + priceLocalSubscriptionFactory: priceLocalSubscriptionFactory, + callFactory: callFactory, + feeProxy: feeProxy, + extrinsicServiceFactory: extrinsicServiceFactory, + selectedAccount: selectedAccount, + chainAsset: chainAsset, + currencyManager: currencyManager, + operationQueue: operationQueue + ) + } + + override func setup() { + super.setup() + web3NamesService?.setup() + fetchAccounts() + } + + private func fetchAccounts() { + fetchAllMetaAccountChainResponses( + for: chainAsset.chain.accountRequest(), + repository: accountRepository, + operationManager: operationManager + ) { [weak self] result in + DispatchQueue.main.async { + self?.handleFetchAccountsResult(result) + } + } + } + + private func handleFetchAccountsResult(_ result: Result<[MetaAccountChainResponse], Error>) { + switch result { + case let .failure(error): + presenter?.didReceive(error: .fetchMetaAccounts(error)) + presenter?.didReceive(metaChainAccountResponses: []) + case let .success(accounts): + let excludedWalletTypes: [MetaAccountModelType] = [ /* .watchOnly, */ .proxied] + let filteredAccounts = accounts.filter { !excludedWalletTypes.contains($0.metaAccount.type) } + presenter?.didReceive(metaChainAccountResponses: filteredAccounts) + } + } } -extension StakingSetupProxyInteractor: StakingSetupProxyInteractorInputProtocol {} +extension StakingSetupProxyInteractor: StakingSetupProxyInteractorInputProtocol { + func search(web3Name: String) { + guard let web3NamesService = web3NamesService else { + let error = Web3NameServiceError.serviceNotFound(web3Name, chainAsset.chain.name) + presenter?.didReceive(error: .web3NamesService(error)) + return + } + + web3NamesService.cancel() + web3NamesService.search( + name: web3Name, + destinationChainAsset: chainAsset + ) { result in + DispatchQueue.main.async { + switch result { + case let .success(recipients): + self.presenter?.didReceive(recipients: recipients, for: web3Name) + case let .failure(error): + self.presenter?.didReceive(error: .web3NamesService(error)) + } + } + } + } +} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyPresenter.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyPresenter.swift index 1b4e08a041..be4e478ee3 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyPresenter.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyPresenter.swift @@ -2,103 +2,218 @@ import Foundation import BigInt import SoraFoundation -final class StakingSetupProxyPresenter { - weak var view: StakingSetupProxyViewProtocol? +final class StakingSetupProxyPresenter: StakingProxyBasePresenter { + weak var view: StakingSetupProxyViewProtocol? { + baseView as? StakingSetupProxyViewProtocol + } + let wireframe: StakingSetupProxyWireframeProtocol let interactor: StakingSetupProxyInteractorInputProtocol - let balanceViewModelFactory: BalanceViewModelFactoryProtocol - let chainAsset: ChainAsset - private var assetBalance: AssetBalance? - private var proxyDeposit: BigUInt? - private var priceData: PriceData? - private var fee: ExtrinsicFeeProtocol? + let web3NameViewModelFactory: Web3NameViewModelFactoryProtocol + private(set) var recipientAddress: SetupRecipientAccount? { + didSet { + switch recipientAddress { + case .none, .address: + view?.didReceiveWeb3NameAuthority(viewModel: .loaded(value: nil)) + case let .external(externalAccount): + let isLoading = externalAccount.recipient.isLoading == true + view?.didReceiveWeb3NameAuthority(viewModel: isLoading ? .loading : + .loaded(value: externalAccount.recipient.value??.displayTitle)) + } + } + } + + private var yourWallets: [MetaAccountChainResponse] = [] init( chainAsset: ChainAsset, interactor: StakingSetupProxyInteractorInputProtocol, wireframe: StakingSetupProxyWireframeProtocol, balanceViewModelFactory: BalanceViewModelFactoryProtocol, + dataValidatingFactory: ProxyDataValidatorFactoryProtocol, + web3NameViewModelFactory: Web3NameViewModelFactoryProtocol, localizationManager: LocalizationManagerProtocol ) { - self.chainAsset = chainAsset self.interactor = interactor self.wireframe = wireframe - self.balanceViewModelFactory = balanceViewModelFactory - self.localizationManager = localizationManager + self.web3NameViewModelFactory = web3NameViewModelFactory + + super.init( + chainAsset: chainAsset, + interactor: interactor, + wireframe: wireframe, + balanceViewModelFactory: balanceViewModelFactory, + dataValidatingFactory: dataValidatingFactory, + localizationManager: localizationManager + ) + } + + override func setup() { + view?.didReceive(token: chainAsset.assetDisplayInfo.symbol) + interactor.setup() + provideInputViewModel() } - private func provideProxyDeposit() { - guard let amount = proxyDeposit?.decimal(precision: chainAsset.asset.precision) else { - view?.didReceiveProxyDeposit(viewModel: .loading) + private func showWeb3NameAddressList(recipients: [Web3TransferRecipient], for name: String) { + guard let view = view else { return } - let proxyDepositViewModel = balanceViewModelFactory.balanceFromPrice( - amount, - priceData: priceData - ).value(for: selectedLocale) - view?.didReceiveProxyDeposit(viewModel: .loaded(value: .init( - isEditable: false, - balanceViewModel: proxyDepositViewModel - ))) - } - - private func provideFee() { - guard let fee = fee?.amount.decimal(precision: chainAsset.asset.precision) else { - view?.didReceiveFee(viewModel: nil) + + let chain = chainAsset.chain + view.didReceiveWeb3NameAuthority(viewModel: .cached(value: nil)) + + let viewModel = web3NameViewModelFactory.recipientListViewModel( + recipients: recipients, + for: name, + chain: chain, + selectedAddress: recipientAddress?.address + ) + + wireframe.presentWeb3NameAddressListPicker(from: view, viewModel: viewModel, delegate: self) + } + + private func provideWeb3NameViewModel(_ authority: Web3TransferRecipient?, name: String) { + guard let authority = authority else { + if recipientAddress?.isExternal == true { + recipientAddress = .external(.init(name: name, recipient: .loaded(value: nil))) + view?.didReceiveAuthorityInputState(focused: true, empty: true) + } return } - let feeViewModel = balanceViewModelFactory.balanceFromPrice( - fee, - priceData: priceData - ).value(for: selectedLocale) - view?.didReceiveFee(viewModel: feeViewModel) + + let chain = chainAsset.chain + + if let account = authority.normalizedAddress(for: chain.chainFormat) { + let authorityViewModel = SetupRecipientAccount.ExternalAccountValue( + address: account, + description: authority.description + ) + recipientAddress = .external(.init(name: name, recipient: .loaded(value: authorityViewModel))) + view?.didReceiveAuthorityInputState(focused: false, empty: nil) + } else { + recipientAddress = .external(.init(name: name, recipient: .loaded(value: nil))) + didReceive(error: .web3NameInvalidAddress(chainName: chain.name)) + } + } + + private func provideInputViewModel() { + let value = recipientAddress?.address ?? "" + + let inputViewModel = InputViewModel.createAccountInputViewModel(for: value) + + view?.didReceiveAccountInput(viewModel: inputViewModel) + } + + private func updateRecepientAddress(_ newAddress: String) { + guard recipientAddress?.address != newAddress else { + return + } + + recipientAddress = .address(newAddress) + + // let optAccountId = getRecepientAccountId() + // interactor.change(recepient: optAccountId) } - private func updateView() { - provideProxyDeposit() - provideFee() + func updateYourWalletsButton() { + let isShowYourWallets = yourWallets.contains { $0.chainAccountResponse != nil } + view?.didReceiveYourWallets(state: isShowYourWallets ? .inactive : .hidden) } } extension StakingSetupProxyPresenter: StakingSetupProxyPresenterProtocol { - func setup() { - view?.didReceive(token: chainAsset.assetDisplayInfo.symbol) - interactor.setup() + func complete(authority: String) { + guard !wireframe.checkDismissing(view: view) else { + return + } + + guard let web3Name = KiltW3n.web3Name(nameWithScheme: authority) else { + return + } + recipientAddress = .external(.init( + name: KiltW3n.fullName(for: web3Name), + recipient: .loading + )) + interactor.search(web3Name: web3Name) } - func complete(authority _: String) {} - func showDepositInfo() {} -} + func updateAuthority(partialAddress: String) { + if let w3n = KiltW3n.web3Name(nameWithScheme: partialAddress) { + recipientAddress = .external(.init( + name: KiltW3n.fullName(for: w3n), + recipient: .cached(value: nil) + )) + } else { + recipientAddress = .address(partialAddress) + } -extension StakingSetupProxyPresenter: StakingSetupProxyInteractorOutputProtocol { - func didReceive(baseError _: StakingProxyBaseError) {} - func didReceive(proxyDeposit: BigUInt?) { - self.proxyDeposit = proxyDeposit - provideProxyDeposit() + view?.didReceiveWeb3NameAuthority(viewModel: .loaded(value: nil)) } - func didReceive(assetBalance: AssetBalance?) { - self.assetBalance = assetBalance + func showWeb3NameAuthority() { + guard let view = view, let address = recipientAddress?.address else { + return + } + + wireframe.presentAccountOptions( + from: view, + address: address, + chain: chainAsset.chain, + locale: selectedLocale + ) } - func didReceive(fee: ExtrinsicFeeProtocol?) { - self.fee = fee - provideFee() + func didTapOnYourWallets() { + wireframe.showYourWallets( + from: view, + accounts: yourWallets, + address: recipientAddress?.address, + delegate: self + ) } +} + +extension StakingSetupProxyPresenter: StakingSetupProxyInteractorOutputProtocol { + func didReceive(error _: StakingSetupProxyError) {} - func didReceive(price: PriceData?) { - priceData = price - provideProxyDeposit() - provideFee() + func didReceive(recipients: [Web3TransferRecipient], for name: String) { + if recipients.count > 1 { + showWeb3NameAddressList(recipients: recipients, for: name) + } else { + provideWeb3NameViewModel(recipients.first, name: name) + } } - func didReceiveAccount(_: MetaChainAccountResponse?, for _: AccountId) {} + func didReceive(metaChainAccountResponses: [MetaAccountChainResponse]) { + let excludingWalletTypes: [MetaAccountModelType] = [.proxied, .watchOnly] + yourWallets = metaChainAccountResponses.filter { + !excludingWalletTypes.contains($0.metaAccount.type) + } + updateYourWalletsButton() + } } -extension StakingSetupProxyPresenter: Localizable { - func applyLocalization() { - if view?.isSetup == true { - updateView() +extension StakingSetupProxyPresenter: ModalPickerViewControllerDelegate { + func modalPickerDidSelectModelAtIndex(_ index: Int, context: AnyObject?) { + if let selectionState = context as? Web3NameAddressesSelectionState { + let selectedAccount = selectionState.accounts[index] + provideWeb3NameViewModel(selectedAccount, name: selectionState.name) } } + + func modalPickerDidCancel(context _: AnyObject?) { + view?.didReceiveAuthorityInputState(focused: true, empty: nil) + } +} + +extension StakingSetupProxyPresenter: YourWalletsDelegate { + func didSelectYourWallet(address: AccountAddress) { + wireframe.hideYourWallets(from: view) + view?.didReceiveYourWallets(state: .inactive) + recipientAddress = .address(address) + } + + func didCloseYourWalletSelection() { + view?.didReceiveYourWallets(state: .inactive) + } } diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyProtocols.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyProtocols.swift index f225fb998b..bfd63dad86 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyProtocols.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyProtocols.swift @@ -1,17 +1,38 @@ -protocol StakingSetupProxyViewProtocol: ControllerBackedProtocol { - func didReceiveProxyDeposit(viewModel: LoadableViewModelState) - func didReceiveFee(viewModel: BalanceViewModelProtocol?) +import SoraFoundation + +protocol StakingSetupProxyViewProtocol: StakingSetupProxyBaseViewProtocol { func didReceive(token: String) + func didReceiveAuthorityInputState(focused: Bool, empty: Bool?) + func didReceiveAccountInput(viewModel: InputViewModelProtocol) + func didReceiveWeb3NameAuthority(viewModel: LoadableViewModelState) + func didReceiveYourWallets(state: YourWalletsControl.State) } -protocol StakingSetupProxyPresenterProtocol: AnyObject { - func setup() +protocol StakingSetupProxyPresenterProtocol: StakingSetupProxyBasePresenterProtocol { func complete(authority: String) - func showDepositInfo() + func updateAuthority(partialAddress: String) + func showWeb3NameAuthority() + func didTapOnYourWallets() +} + +protocol StakingSetupProxyInteractorInputProtocol: StakingProxyBaseInteractorInputProtocol { + func search(web3Name: String) } -protocol StakingSetupProxyInteractorInputProtocol: StakingProxyBaseInteractorInputProtocol {} +protocol StakingSetupProxyInteractorOutputProtocol: StakingProxyBaseInteractorOutputProtocol { + func didReceive(error: StakingSetupProxyError) + func didReceive(recipients: [Web3TransferRecipient], for name: String) + func didReceive(metaChainAccountResponses: [MetaAccountChainResponse]) +} -protocol StakingSetupProxyInteractorOutputProtocol: StakingProxyBaseInteractorOutputProtocol {} +protocol StakingSetupProxyWireframeProtocol: StakingSetupProxyBaseWireframeProtocol, + ProxyErrorPresentable, AlertPresentable, CommonRetryable, ErrorPresentable, + Web3NameAddressListPresentable, AddressOptionsPresentable, YourWalletsPresentable { + func checkDismissing(view: ControllerBackedProtocol?) -> Bool +} -protocol StakingSetupProxyWireframeProtocol: AnyObject {} +enum StakingSetupProxyError: Error { + case web3NamesService(Error) + case web3NameInvalidAddress(chainName: String) + case fetchMetaAccounts(Error) +} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewController.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewController.swift index 45b35f27d9..a7c4f70688 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewController.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewController.swift @@ -60,6 +60,17 @@ final class StakingSetupProxyViewController: UIViewController, ViewHolder { action: #selector(proxyInfoAction), for: .touchUpInside ) + rootView.accountInputView.addTarget( + self, + action: #selector(actionAddressChange), + for: .editingChanged + ) + rootView.yourWalletsControl.addTarget( + self, + action: #selector(actionYourWallets), + for: .touchUpInside + ) + rootView.web3NameReceipientView.delegate = self rootView.accountInputView.delegate = self } @@ -67,6 +78,19 @@ final class StakingSetupProxyViewController: UIViewController, ViewHolder { private func proxyInfoAction() { presenter.showDepositInfo() } + + @objc private func actionAddressChange() { + let partialAddress = rootView.accountInputView.textField.text ?? "" + presenter.updateAuthority(partialAddress: partialAddress) + + updateActionButtonState() + } + + @objc func actionYourWallets() { + presenter.didTapOnYourWallets() + } + + func updateActionButtonState() {} } extension StakingSetupProxyViewController: StakingSetupProxyViewProtocol { @@ -85,6 +109,31 @@ extension StakingSetupProxyViewController: StakingSetupProxyViewProtocol { preferredLanguages: selectedLocale.rLanguages ) } + + func didReceiveAccountInput(viewModel: InputViewModelProtocol) { + rootView.accountInputView.bind(inputViewModel: viewModel) + + updateActionButtonState() + } + + func didReceiveAuthorityInputState(focused: Bool, empty: Bool?) { + if focused { + rootView.accountInputView.textField.becomeFirstResponder() + } else { + rootView.accountInputView.textField.resignFirstResponder() + } + if empty == true { + rootView.accountInputView.actionClear() + } + } + + func didReceiveWeb3NameAuthority(viewModel: LoadableViewModelState) { + rootView.web3NameReceipientView.bind(viewModel: viewModel) + } + + func didReceiveYourWallets(state: YourWalletsControl.State) { + rootView.yourWalletsControl.apply(state: state) + } } extension StakingSetupProxyViewController: Localizable { @@ -113,3 +162,11 @@ extension StakingSetupProxyViewController: AccountInputViewDelegate { } } } + +extension StakingSetupProxyViewController: Web3NameReceipientViewDelegate { + func didTapOnAccountList() {} + + func didTapOnAccount() { + presenter.showWeb3NameAuthority() + } +} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewFactory.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewFactory.swift index 416c1930a5..e7ff5f9912 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewFactory.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewFactory.swift @@ -17,12 +17,21 @@ struct StakingSetupProxyViewFactory { targetAssetInfo: chainAsset.assetDisplayInfo, priceAssetInfoFactory: priceAssetInfoFactory ) - + let dataValidatingFactory = ProxyDataValidatorFactory( + presentable: wireframe, + balanceViewModelFactoryFacade: BalanceViewModelFactoryFacade( + priceAssetInfoFactory: priceAssetInfoFactory + ) + ) let presenter = StakingSetupProxyPresenter( chainAsset: chainAsset, interactor: interactor, wireframe: wireframe, balanceViewModelFactory: balanceViewModelFactory, + dataValidatingFactory: dataValidatingFactory, + web3NameViewModelFactory: Web3NameViewModelFactory( + displayAddressViewModelFactory: DisplayAddressViewModelFactory() + ), localizationManager: LocalizationManager.shared ) @@ -31,7 +40,7 @@ struct StakingSetupProxyViewFactory { localizationManager: LocalizationManager.shared ) - presenter.view = view + presenter.baseView = view interactor.basePresenter = presenter return view @@ -66,9 +75,18 @@ struct StakingSetupProxyViewFactory { logger: Logger.shared ) + let web3NamesService = createWeb3NameService() + let accountRepositoryFactory = AccountRepositoryFactory(storageFacade: UserDataStorageFacade.shared) + let accountRepository = accountRepositoryFactory.createMetaAccountRepository( + for: nil, + sortDescriptors: [NSSortDescriptor.accountsByOrder] + ) + return StakingSetupProxyInteractor( + web3NamesService: web3NamesService, + accountRepository: accountRepository, runtimeService: runtimeRegistry, - stakingLocalSubscriptionFactory: state.localSubscriptionFactory, + sharedState: state, walletLocalSubscriptionFactory: WalletLocalSubscriptionFactory.shared, accountProviderFactory: accountProviderFactory, priceLocalSubscriptionFactory: PriceProviderFactory.shared, @@ -81,4 +99,36 @@ struct StakingSetupProxyViewFactory { operationQueue: OperationManagerFacade.sharedDefaultQueue ) } + + private static func createWeb3NameService() -> Web3NameServiceProtocol? { + let kiltChainId = KnowChainId.kiltOnEnviroment + let chainRegistry = ChainRegistryFacade.sharedRegistry + + guard let kiltConnection = chainRegistry.getConnection(for: kiltChainId), + let kiltRuntimeService = chainRegistry.getRuntimeProvider(for: kiltChainId) else { + return nil + } + + let operationQueue = OperationManagerFacade.sharedDefaultQueue + let web3NamesOperationFactory = KiltWeb3NamesOperationFactory(operationQueue: operationQueue) + + let recipientRepositoryFactory = Web3TransferRecipientRepositoryFactory( + integrityVerifierFactory: Web3TransferRecipientIntegrityVerifierFactory() + ) + + let slip44CoinsUrl = ApplicationConfig.shared.slip44URL + let slip44CoinsProvider: AnySingleValueProvider = JsonDataProviderFactory.shared.getJson( + for: slip44CoinsUrl + ) + + return Web3NameService( + providerName: Web3NameProvider.kilt, + slip44CoinsProvider: slip44CoinsProvider, + web3NamesOperationFactory: web3NamesOperationFactory, + runtimeService: kiltRuntimeService, + connection: kiltConnection, + transferRecipientRepositoryFactory: recipientRepositoryFactory, + operationQueue: operationQueue + ) + } } diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewLayout.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewLayout.swift index 9a804872d5..e9920d1951 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewLayout.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewLayout.swift @@ -37,6 +37,8 @@ final class StakingSetupProxyViewLayout: ScrollableContainerLayoutView { return view }() + let web3NameReceipientView = Web3NameReceipientView() + override func setupLayout() { super.setupLayout() @@ -56,7 +58,8 @@ final class StakingSetupProxyViewLayout: ScrollableContainerLayoutView { ]) addArrangedSubview(titleStackView, spacingAfter: 0) - addArrangedSubview(accountInputView, spacingAfter: 40) + addArrangedSubview(accountInputView, spacingAfter: 8) + addArrangedSubview(web3NameReceipientView, spacingAfter: 40) addArrangedSubview(proxyDepositView, spacingAfter: 0) addArrangedSubview(feeView) } diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyWireframe.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyWireframe.swift index b825d239c6..bcf4c9e41c 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyWireframe.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyWireframe.swift @@ -1,3 +1,7 @@ import Foundation -final class StakingSetupProxyWireframe: StakingSetupProxyWireframeProtocol {} +final class StakingSetupProxyWireframe: StakingSetupProxyWireframeProtocol { + func checkDismissing(view: ControllerBackedProtocol?) -> Bool { + view?.controller.navigationController?.isBeingDismissed ?? true + } +} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyDataValidatorFactory.swift b/novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyDataValidatorFactory.swift new file mode 100644 index 0000000000..61ca981a63 --- /dev/null +++ b/novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyDataValidatorFactory.swift @@ -0,0 +1,164 @@ +import Foundation +import BigInt +import SoraFoundation + +protocol ProxyDataValidatorFactoryProtocol: BaseDataValidatingFactoryProtocol { + func hasSufficientBalance( + available: BigUInt?, + deposit: BigUInt?, + fee: BigUInt?, + asset: AssetBalanceDisplayInfo, + locale: Locale + ) -> DataValidating + + func validAddress( + _ address: String, + chain: ChainModel, + locale: Locale + ) -> DataValidating + + func notReachedMaximimProxyCount( + _ proxyCount: Int?, + limit: Int?, + chain: ChainModel, + locale: Locale + ) -> DataValidating + + func proxyNotExists( + address: String, + chain: ChainModel, + proxyList: ProxyDefinition?, + locale: Locale + ) -> DataValidating +} + +final class ProxyDataValidatorFactory: ProxyDataValidatorFactoryProtocol { + weak var view: ControllerBackedProtocol? + + var basePresentable: BaseErrorPresentable { presentable } + + let presentable: ProxyErrorPresentable + let balanceViewModelFactoryFacade: BalanceViewModelFactoryFacadeProtocol + + init( + presentable: ProxyErrorPresentable, + balanceViewModelFactoryFacade: BalanceViewModelFactoryFacadeProtocol + ) { + self.presentable = presentable + self.balanceViewModelFactoryFacade = balanceViewModelFactoryFacade + } + + func hasSufficientBalance( + available: BigUInt?, + deposit: BigUInt?, + fee: BigUInt?, + asset: AssetBalanceDisplayInfo, + locale: Locale + ) -> DataValidating { + ErrorConditionViolation(onError: { [weak self] in + guard + let view = self?.view, + let viewModelFactory = self?.balanceViewModelFactoryFacade else { + return + } + let balanceDecimal = available?.decimal(assetInfo: asset) + let depositDecimal = deposit?.decimal(assetInfo: asset) + + let balanceModel = viewModelFactory.amountFromValue( + targetAssetInfo: asset, + value: balanceDecimal ?? 0 + ).value(for: locale) + let depositModel = viewModelFactory.amountFromValue( + targetAssetInfo: asset, + value: depositDecimal ?? 0 + ).value(for: locale) + + self?.presentable.presentNotEnoughBalanceForDeposit( + from: view, + deposit: depositModel, + balance: balanceModel, + locale: locale + ) + }, preservesCondition: { + guard let deposit = deposit, + let fee = fee, + let available = available else { + return false + } + return available >= deposit + fee + }) + } + + func validAddress( + _ address: String, + chain: ChainModel, + locale: Locale + ) -> DataValidating { + ErrorConditionViolation(onError: { [weak self] in + guard let view = self?.view else { + return + } + self?.presentable.presentNotValidAddress( + from: view, + networkName: chain.name, + locale: locale + ) + }, preservesCondition: { + let accountId = try? address.toAccountId(using: chain.chainFormat) + return accountId != nil + }) + } + + func notReachedMaximimProxyCount( + _ proxyCount: Int?, + limit: Int?, + chain: ChainModel, + locale: Locale + ) -> DataValidating { + ErrorConditionViolation(onError: { [weak self] in + guard let view = self?.view else { + return + } + + let limitNumber = NSNumber(value: limit ?? 0) + let formatter = NumberFormatter.quantity + self?.presentable.presentMaximumProxyCount( + from: view, + limit: formatter.string(from: limitNumber) ?? "", + networkName: chain.name, + locale: locale + ) + }, preservesCondition: { + guard let proxyCount = proxyCount, + let limit = limit else { + return false + } + return proxyCount < limit + }) + } + + func proxyNotExists( + address: String, + chain: ChainModel, + proxyList: ProxyDefinition?, + locale: Locale + ) -> DataValidating { + ErrorConditionViolation(onError: { [weak self] in + guard let view = self?.view else { + return + } + let formatter = NumberFormatter.quantity + self?.presentable.presentProxyAlreadyAdded( + from: view, + account: address, + locale: locale + ) + }, preservesCondition: { + guard let proxyList = proxyList else { + return false + } + let accountId = try? address.toAccountId(using: chain.chainFormat) + return proxyList.definition.contains(where: { $0.proxy == accountId }) == false + }) + } +} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyErrorPresentable.swift b/novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyErrorPresentable.swift new file mode 100644 index 0000000000..09397aa150 --- /dev/null +++ b/novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyErrorPresentable.swift @@ -0,0 +1,103 @@ +import Foundation + +protocol ProxyErrorPresentable: BaseErrorPresentable { + func presentNotEnoughBalanceForDeposit( + from view: ControllerBackedProtocol, + deposit: String, + balance: String, + locale: Locale? + ) + + func presentNotValidAddress( + from view: ControllerBackedProtocol, + networkName: String, + locale: Locale? + ) + + func presentMaximumProxyCount( + from view: ControllerBackedProtocol?, + limit: String, + networkName: String, + locale: Locale + ) + + func presentProxyAlreadyAdded( + from view: ControllerBackedProtocol?, + account: String, + locale: Locale + ) +} + +extension ProxyErrorPresentable where Self: AlertPresentable & ErrorPresentable { + func presentNotEnoughBalanceForDeposit( + from view: ControllerBackedProtocol, + deposit: String, + balance: String, + locale: Locale? + ) { + let title = R.string.localizable.stakingSetupProxyErrorInsufficientBalanceTitle( + preferredLanguages: locale?.rLanguages) + let message = R.string.localizable.stakingSetupProxyErrorInsufficientBalanceMessage( + deposit, + balance, + preferredLanguages: locale?.rLanguages + ) + let closeAction = R.string.localizable.commonClose( + preferredLanguages: locale?.rLanguages) + + present(message: message, title: title, closeAction: closeAction, from: view) + } + + func presentNotValidAddress( + from view: ControllerBackedProtocol, + networkName: String, + locale: Locale? + ) { + let title = R.string.localizable.stakingSetupProxyErrorInvalidAddressTitle( + preferredLanguages: locale?.rLanguages) + let message = R.string.localizable.stakingSetupProxyErrorInvalidAddressMessage( + networkName, + preferredLanguages: locale?.rLanguages + ) + let closeAction = R.string.localizable.commonClose( + preferredLanguages: locale?.rLanguages) + + present(message: message, title: title, closeAction: closeAction, from: view) + } + + func presentMaximumProxyCount( + from view: ControllerBackedProtocol?, + limit: String, + networkName: String, + locale: Locale + ) { + let title = R.string.localizable.stakingSetupProxyErrorInvalidMaximumProxiesTitle( + preferredLanguages: locale.rLanguages) + let message = R.string.localizable.stakingSetupProxyErrorInvalidMaximumProxiesMessage( + limit, + networkName, + preferredLanguages: locale.rLanguages + ) + let closeAction = R.string.localizable.commonClose( + preferredLanguages: locale.rLanguages) + + present(message: message, title: title, closeAction: closeAction, from: view) + } + + func presentProxyAlreadyAdded( + from view: ControllerBackedProtocol?, + account: String, + locale: Locale + ) { + let title = R.string.localizable.stakingSetupProxyErrorProxyAlreadyExistsTitle( + preferredLanguages: locale.rLanguages) + let message = R.string.localizable.stakingSetupProxyErrorProxyAlreadyExistsMessage( + account, + preferredLanguages: locale.rLanguages + ) + let closeAction = R.string.localizable.commonClose( + preferredLanguages: locale.rLanguages) + + present(message: message, title: title, closeAction: closeAction, from: view) + } +} diff --git a/novawallet/Modules/Transfer/TransferSetup/Model/TransferSetupRecipientAccount.swift b/novawallet/Modules/Transfer/TransferSetup/Model/TransferSetupRecipientAccount.swift index 19695deca1..09fe153ad5 100644 --- a/novawallet/Modules/Transfer/TransferSetup/Model/TransferSetupRecipientAccount.swift +++ b/novawallet/Modules/Transfer/TransferSetup/Model/TransferSetupRecipientAccount.swift @@ -1,4 +1,6 @@ -enum TransferSetupRecipientAccount { +typealias TransferSetupRecipientAccount = SetupRecipientAccount + +enum SetupRecipientAccount { case address(AccountAddress?) case external(ExternalAccount) diff --git a/novawallet/Modules/Transfer/TransferSetup/TransferSetupProtocols.swift b/novawallet/Modules/Transfer/TransferSetup/TransferSetupProtocols.swift index b1864fb0ff..81d9ed020c 100644 --- a/novawallet/Modules/Transfer/TransferSetup/TransferSetupProtocols.swift +++ b/novawallet/Modules/Transfer/TransferSetup/TransferSetupProtocols.swift @@ -61,7 +61,7 @@ protocol TransferSetupInteractorOutputProtocol: AnyObject { } protocol TransferSetupWireframeProtocol: AlertPresentable, ErrorPresentable, AddressOptionsPresentable, - Web3NameAddressListPresentable { + Web3NameAddressListPresentable, YourWalletsPresentable { func showDestinationChainSelection( from view: TransferSetupViewProtocol?, selectionState: CrossChainDestinationSelectionState, @@ -79,14 +79,5 @@ protocol TransferSetupWireframeProtocol: AlertPresentable, ErrorPresentable, Add func hideRecepientScan(from view: TransferSetupViewProtocol?) - func showYourWallets( - from view: TransferSetupViewProtocol?, - accounts: [MetaAccountChainResponse], - address: AccountAddress?, - delegate: YourWalletsDelegate - ) - - func hideYourWallets(from view: TransferSetupViewProtocol?) - func checkDismissing(view: TransferSetupViewProtocol?) -> Bool } diff --git a/novawallet/Modules/Transfer/TransferSetup/TransferSetupWireframe.swift b/novawallet/Modules/Transfer/TransferSetup/TransferSetupWireframe.swift index 14271f7eb3..e80156e8ce 100644 --- a/novawallet/Modules/Transfer/TransferSetup/TransferSetupWireframe.swift +++ b/novawallet/Modules/Transfer/TransferSetup/TransferSetupWireframe.swift @@ -56,31 +56,6 @@ class TransferSetupWireframe: TransferSetupWireframeProtocol { view?.controller.dismiss(animated: true) } - func showYourWallets( - from view: TransferSetupViewProtocol?, - accounts: [MetaAccountChainResponse], - address: AccountAddress?, - delegate: YourWalletsDelegate - ) { - guard let viewController = YourWalletsViewFactory.createView( - metaAccounts: accounts, - address: address, - delegate: delegate - ) else { - return - } - - let factory = ModalSheetPresentationFactory(configuration: ModalSheetPresentationConfiguration.nova) - viewController.controller.modalTransitioningFactory = factory - viewController.controller.modalPresentationStyle = .custom - - view?.controller.present(viewController.controller, animated: true) - } - - func hideYourWallets(from view: TransferSetupViewProtocol?) { - view?.controller.dismiss(animated: true) - } - func checkDismissing(view: TransferSetupViewProtocol?) -> Bool { view?.controller.navigationController?.isBeingDismissed ?? true } diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index 9212b2488e..15d8f0efb4 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -1378,6 +1378,14 @@ "staking.setup.proxy.deposit.details" = "The deposit stays reserved on your account until the proxy is removed."; "staking.setup.your.proxies" = "Your delegations"; "staking.setup.add.your.proxy" = "Add delegated authority (Proxy)"; +"staking.setup.proxy.error.insufficient.balance.title" = "Not enough tokens"; +"staking.setup.proxy.error.insufficient.balance.message" = "You don’t have enough balance for proxy deposit of %@. Available balance: %@"; +"staking.setup.proxy.error.invalid.address.title" = "Invalid proxy address"; +"staking.setup.proxy.error.invalid.address.message" = "Proxy address should be a valid %@ address"; +"staking.setup.proxy.error.invalid.maximum.proxies.title" = "Maximum number of proxies has been reached"; +"staking.setup.proxy.error.invalid.maximum.proxies.message" = "You have reached the limit of %@ added proxies in %@. Remove proxies to add new ones."; +"staking.setup.proxy.error.proxy.already.exists.title" = "Delegation already exists"; +"staking.setup.proxy.error.proxy.already.exists.message" = "You are already delegating to this account: %@"; "common.time.in" = "in"; "common.and" = " and "; "common.time.period.after" = "after"; diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index 86fff8b2d8..19a3978aed 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1378,6 +1378,14 @@ "staking.setup.proxy.deposit.details" = "Депозит остается зарезервированным на вашем счете до тех пор, пока прокси не будет удален."; "staking.setup.your.proxies" = "Ваши делегации"; "staking.setup.add.your.proxy" = "Добавить делегацию (Прокси)"; +"staking.setup.proxy.error.insufficient.balance.title" = "Недостаточно токенов"; +"staking.setup.proxy.error.insufficient.balance.message" = "У вас недостаточно средств для депозита прокси %@. Доступный баланс: %@"; +"staking.setup.proxy.error.invalid.address.title" = "Некорректный адрес прокси"; +"staking.setup.proxy.error.invalid.address.message" = "Адрес прокси должен быть допустимым адресом в сети %@"; +"staking.setup.proxy.error.invalid.maximum.proxies.title" = "Достигнуто максимальное количество прокси"; +"staking.setup.proxy.error.invalid.maximum.proxies.message" = "Вы достигли лимита добавленных прокси (%@) в %@. Чтобы добавить новые, удалите существующие."; +"staking.setup.proxy.error.proxy.already.exists.title" = "Прокси уже добавлен"; +"staking.setup.proxy.error.proxy.already.exists.message" = "Вы уже делегируете этой учетной записи: %@"; "common.time.in" = "через"; "common.and" = " и "; "common.time.period.after" = "через"; From 279b9b03d7f54f77af039ee60a1985e692010b63 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Tue, 16 Jan 2024 19:05:11 +0300 Subject: [PATCH 12/60] add error handling, add constants --- novawallet.xcodeproj/project.pbxproj | 4 + .../Protocols/ScanAddressPresentable.swift | 32 ++++++ .../Types/Proxy/Proxy+CodingPath.swift | 4 + .../Base/ProxyDepositCalculator.swift | 16 ++- .../Base/StakingProxyBaseInteractor.swift | 41 ++++++- .../Base/StakingProxyBasePresenter.swift | 54 +++++++--- .../Base/StakingProxyBaseProtocols.swift | 12 ++- .../StakingSetupProxyInteractor.swift | 16 ++- .../StakingSetupProxyPresenter.swift | 100 ++++++++++++++++-- .../StakingSetupProxyProtocols.swift | 18 ++-- .../StakingSetupProxyViewController.swift | 47 +++++++- .../StakingSetupProxyWireframe.swift | 7 ++ .../ShortTextInfoPresentableExtensions.swift | 14 +++ .../TransferSetupPresenter.swift | 4 +- .../TransferSetupProtocols.swift | 6 +- .../TransferSetupWireframe.swift | 20 ---- 16 files changed, 324 insertions(+), 71 deletions(-) create mode 100644 novawallet/Common/Protocols/ScanAddressPresentable.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 231c4e2abd..79c5e8ae55 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -924,6 +924,7 @@ 77AB555B2AA246CA0058814E /* OperationPoolRewardOrSlashViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77AB555A2AA246CA0058814E /* OperationPoolRewardOrSlashViewModel.swift */; }; 77AB555D2AA24BA90058814E /* OperationDetailsPoolRewardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77AB555C2AA24BA90058814E /* OperationDetailsPoolRewardView.swift */; }; 77C35CE52B568ED100308F16 /* YourWalletsPresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C35CE42B568ED100308F16 /* YourWalletsPresentable.swift */; }; + 77C35CE72B56D07300308F16 /* ScanAddressPresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C35CE62B56D07300308F16 /* ScanAddressPresentable.swift */; }; 77C976202AF36A170049272C /* SwapModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C9761F2AF36A170049272C /* SwapModels.swift */; }; 77C976222AF39F180049272C /* TokenOperationTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C976212AF39F180049272C /* TokenOperationTableViewCell.swift */; }; 77C976242AF3A5280049272C /* SwapViewModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C976232AF3A5280049272C /* SwapViewModels.swift */; }; @@ -5139,6 +5140,7 @@ 77AB555A2AA246CA0058814E /* OperationPoolRewardOrSlashViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OperationPoolRewardOrSlashViewModel.swift; sourceTree = ""; }; 77AB555C2AA24BA90058814E /* OperationDetailsPoolRewardView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OperationDetailsPoolRewardView.swift; sourceTree = ""; }; 77C35CE42B568ED100308F16 /* YourWalletsPresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YourWalletsPresentable.swift; sourceTree = ""; }; + 77C35CE62B56D07300308F16 /* ScanAddressPresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanAddressPresentable.swift; sourceTree = ""; }; 77C9761F2AF36A170049272C /* SwapModels.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwapModels.swift; sourceTree = ""; }; 77C976212AF39F180049272C /* TokenOperationTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokenOperationTableViewCell.swift; sourceTree = ""; }; 77C976232AF3A5280049272C /* SwapViewModels.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwapViewModels.swift; sourceTree = ""; }; @@ -14077,6 +14079,7 @@ 7719019A2AE670AE00D9C918 /* ShortTextInfoPresentable.swift */, 0C259EA72B46C55C00CB86E4 /* ExtrinsicSigningErrorHandling.swift */, 77C35CE42B568ED100308F16 /* YourWalletsPresentable.swift */, + 77C35CE62B56D07300308F16 /* ScanAddressPresentable.swift */, ); path = Protocols; sourceTree = ""; @@ -23537,6 +23540,7 @@ ECD4EB7314609007CE35461E /* ParitySignerAddConfirmProtocols.swift in Sources */, 6D622CD4A83EEC1F135B66A8 /* ParitySignerAddConfirmWireframe.swift in Sources */, 41FA237A4AA56AC99322A040 /* ParitySignerAddConfirmPresenter.swift in Sources */, + 77C35CE72B56D07300308F16 /* ScanAddressPresentable.swift in Sources */, 663DB041307C59E939BF0BE2 /* ParitySignerAddConfirmInteractor.swift in Sources */, 13CF38563E1849EAF1B4E4B6 /* ParitySignerAddConfirmViewFactory.swift in Sources */, 0C9C64382A8D6949004DC078 /* NPoolsStakingSharedState.swift in Sources */, diff --git a/novawallet/Common/Protocols/ScanAddressPresentable.swift b/novawallet/Common/Protocols/ScanAddressPresentable.swift new file mode 100644 index 0000000000..3b662ac500 --- /dev/null +++ b/novawallet/Common/Protocols/ScanAddressPresentable.swift @@ -0,0 +1,32 @@ +protocol ScanAddressPresentable { + func showAddressScan( + from view: ControllerBackedProtocol?, + delegate: AddressScanDelegate + ) + func hideAddressScan(from view: ControllerBackedProtocol?) +} + +extension ScanAddressPresentable { + func showAddressScan( + from view: ControllerBackedProtocol?, + delegate: AddressScanDelegate + ) { + guard + let scanView = AddressScanViewFactory.createTransferRecipientScan( + for: delegate, + context: nil + ) else { + return + } + + let navigationController = NovaNavigationController( + rootViewController: scanView.controller + ) + + view?.controller.present(navigationController, animated: true, completion: nil) + } + + func hideAddressScan(from view: ControllerBackedProtocol?) { + view?.controller.dismiss(animated: true) + } +} diff --git a/novawallet/Common/Substrate/Types/Proxy/Proxy+CodingPath.swift b/novawallet/Common/Substrate/Types/Proxy/Proxy+CodingPath.swift index f27576b00b..cfa6a5a96c 100644 --- a/novawallet/Common/Substrate/Types/Proxy/Proxy+CodingPath.swift +++ b/novawallet/Common/Substrate/Types/Proxy/Proxy+CodingPath.swift @@ -14,4 +14,8 @@ extension Proxy { static var depositFactor: ConstantCodingPath { .init(moduleName: Proxy.name, constantName: "ProxyDepositFactor") } + + static var maxProxyCount: ConstantCodingPath { + .init(moduleName: Proxy.name, constantName: "MaxProxies") + } } diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Base/ProxyDepositCalculator.swift b/novawallet/Modules/Staking/StakingSetupProxy/Base/ProxyDepositCalculator.swift index 1b8daf5485..1768186395 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/Base/ProxyDepositCalculator.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/Base/ProxyDepositCalculator.swift @@ -5,7 +5,7 @@ struct ProxyDepositCalculator { var factor: BigUInt? var proxyCount: Int? - func calculate() -> BigUInt? { + func calculate() -> ProxyDeposit? { guard let base = self.base, let factor = self.factor, let proxyCount = self.proxyCount else { return nil } @@ -13,6 +13,18 @@ struct ProxyDepositCalculator { let currentDeposit = base + BigUInt(proxyCount) * factor let newDeposit = base + BigUInt(proxyCount + 1) * factor - return newDeposit - currentDeposit + return .init( + current: currentDeposit, + new: newDeposit + ) + } +} + +struct ProxyDeposit { + let current: BigUInt + let new: BigUInt + + var diff: BigUInt { + new - current } } diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseInteractor.swift b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseInteractor.swift index 868f8386fa..17d24ded7a 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseInteractor.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseInteractor.swift @@ -89,6 +89,32 @@ class StakingProxyBaseInteractor: RuntimeConstantFetching, StakingProxyBaseInter self?.basePresenter?.didReceive(baseError: .fetchDepositFactor(error)) } } + + fetchConstant( + for: Proxy.maxProxyCount, + runtimeCodingService: runtimeService, + operationManager: operationManager + ) { [weak self] (result: Result) in + switch result { + case let .success(maxCount): + self?.basePresenter?.didReceive(maxProxies: maxCount) + case let .failure(error): + self?.basePresenter?.didReceive(baseError: .fetchMaxProxyCount(error)) + } + } + + fetchConstant( + for: .existentialDeposit, + runtimeCodingService: runtimeService, + operationManager: operationManager + ) { [weak self] (result: Result) in + switch result { + case let .success(existensialDeposit): + self?.basePresenter?.didReceive(existensialDeposit: existensialDeposit) + case let .failure(error): + self?.basePresenter?.didReceive(baseError: .fetchED(error)) + } + } } private func performPriceSubscription() { @@ -185,6 +211,16 @@ class StakingProxyBaseInteractor: RuntimeConstantFetching, StakingProxyBaseInter try builder.adding(call: call) } } + + func refetchConstants() { + fetchConstants() + } + + func remakeSubscriptions() { + if let stashItem = stashItem { + handle(stashItem: stashItem) + } + } } extension StakingProxyBaseInteractor: StakingLocalStorageSubscriber, StakingLocalSubscriptionHandler, @@ -253,7 +289,7 @@ extension StakingProxyBaseInteractor: SelectedCurrencyDepending { extension StakingProxyBaseInteractor: AccountLocalSubscriptionHandler, AccountLocalStorageSubscriber { func handleAccountResponse( result: Result, - accountId: AccountId, + accountId _: AccountId, chain _: ChainModel ) { switch result { @@ -265,12 +301,9 @@ extension StakingProxyBaseInteractor: AccountLocalSubscriptionHandler, AccountLo ) estimateFee() } - - basePresenter?.didReceiveAccount(optAccount, for: accountId) case .failure: extrinsicService = nil estimateFee() - basePresenter?.didReceiveAccount(nil, for: accountId) } } } diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift index a5572a8f7b..f76e2628e7 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift @@ -11,12 +11,10 @@ class StakingProxyBasePresenter: StakingSetupProxyBasePresenterProtocol { private let interactor: StakingProxyBaseInteractorInputProtocol private let wireframe: StakingSetupProxyBaseWireframeProtocol private var assetBalance: AssetBalance? - private var proxyDeposit: BigUInt? + private var proxyDeposit: ProxyDeposit? private var priceData: PriceData? private var fee: ExtrinsicFeeProtocol? private var proxyAddress: String? - private var currentDeposit: BigUInt? - private var deposit: BigUInt? private var existensialDeposit: BigUInt? private var maxProxies: Int? private var proxy: ProxyDefinition? @@ -38,7 +36,7 @@ class StakingProxyBasePresenter: StakingSetupProxyBasePresenterProtocol { } func provideProxyDeposit() { - guard let amount = proxyDeposit?.decimal(precision: chainAsset.asset.precision) else { + guard let amount = proxyDeposit?.diff.decimal(precision: chainAsset.asset.precision) else { baseView?.didReceiveProxyDeposit(viewModel: .loading) return } @@ -75,9 +73,11 @@ class StakingProxyBasePresenter: StakingSetupProxyBasePresenterProtocol { interactor.setup() } - func showDepositInfo() {} + func showDepositInfo() { + wireframe.showProxyDepositInfo(from: baseView) + } - func createCommonValidations() -> [DataValidating]? { + func createCommonValidations() -> [DataValidating] { [ dataValidatingFactory.has( fee: fee, @@ -98,8 +98,8 @@ class StakingProxyBasePresenter: StakingSetupProxyBasePresenterProtocol { locale: selectedLocale ), dataValidatingFactory.hasSufficientBalance( - available: (assetBalance?.regularTransferrableBalance() ?? 0) + (currentDeposit ?? 0), - deposit: deposit, + available: (assetBalance?.regularTransferrableBalance() ?? 0) + (proxyDeposit?.current ?? 0), + deposit: proxyDeposit?.new, fee: fee?.amountForCurrentAccount, asset: chainAsset.assetDisplayInfo, locale: selectedLocale @@ -121,8 +121,28 @@ class StakingProxyBasePresenter: StakingSetupProxyBasePresenterProtocol { } extension StakingProxyBasePresenter: StakingProxyBaseInteractorOutputProtocol { - func didReceive(baseError _: StakingProxyBaseError) {} - func didReceive(proxyDeposit: BigUInt?) { + func didReceive(baseError: StakingProxyBaseError) { + switch baseError { + case .fetchDepositBase, .fetchDepositFactor, .fetchED, .fetchMaxProxyCount: + wireframe.presentRequestStatus(on: baseView, locale: selectedLocale) { [weak self] in + self?.interactor.refetchConstants() + } + case .handleProxies, .balance: + wireframe.presentRequestStatus(on: baseView, locale: selectedLocale) { [weak self] in + self?.interactor.refetchConstants() + } + case .stashItem, .price: + wireframe.presentRequestStatus(on: baseView, locale: selectedLocale) { [weak self] in + self?.interactor.setup() + } + case .fee: + wireframe.presentRequestStatus(on: baseView, locale: selectedLocale) { [weak self] in + self?.interactor.estimateFee() + } + } + } + + func didReceive(proxyDeposit: ProxyDeposit?) { self.proxyDeposit = proxyDeposit provideProxyDeposit() } @@ -136,13 +156,23 @@ extension StakingProxyBasePresenter: StakingProxyBaseInteractorOutputProtocol { provideFee() } + func didReceive(maxProxies: Int?) { + self.maxProxies = maxProxies + } + + func didReceive(existensialDeposit: BigUInt?) { + self.existensialDeposit = existensialDeposit + } + + func didReceive(proxy: ProxyDefinition?) { + self.proxy = proxy + } + func didReceive(price: PriceData?) { priceData = price provideProxyDeposit() provideFee() } - - func didReceiveAccount(_: MetaChainAccountResponse?, for _: AccountId) {} } extension StakingProxyBasePresenter: Localizable { diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseProtocols.swift b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseProtocols.swift index 306e336271..9f4065affd 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseProtocols.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseProtocols.swift @@ -2,11 +2,13 @@ import BigInt protocol StakingProxyBaseInteractorOutputProtocol: AnyObject { func didReceive(baseError: StakingProxyBaseError) - func didReceive(proxyDeposit: BigUInt?) + func didReceive(proxyDeposit: ProxyDeposit?) func didReceive(assetBalance: AssetBalance?) func didReceive(fee: ExtrinsicFeeProtocol?) + func didReceive(maxProxies: Int?) + func didReceive(existensialDeposit: BigUInt?) + func didReceive(proxy: ProxyDefinition?) func didReceive(price: PriceData?) - func didReceiveAccount(_ account: MetaChainAccountResponse?, for accountId: AccountId) } enum StakingProxyBaseError: Error { @@ -17,11 +19,15 @@ enum StakingProxyBaseError: Error { case price(Error) case stashItem(Error) case fee(Error) + case fetchMaxProxyCount(Error) + case fetchED(Error) } protocol StakingProxyBaseInteractorInputProtocol: AnyObject { func setup() func estimateFee() + func refetchConstants() + func remakeSubscriptions() } protocol StakingSetupProxyBaseViewProtocol: ControllerBackedProtocol { @@ -34,4 +40,4 @@ protocol StakingSetupProxyBasePresenterProtocol: AnyObject { func showDepositInfo() } -protocol StakingSetupProxyBaseWireframeProtocol: AnyObject {} +protocol StakingSetupProxyBaseWireframeProtocol: ShortTextInfoPresentable, AlertPresentable, ErrorPresentable, CommonRetryable {} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyInteractor.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyInteractor.swift index 0890ce6be5..ccd325f891 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyInteractor.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyInteractor.swift @@ -67,11 +67,13 @@ final class StakingSetupProxyInteractor: StakingProxyBaseInteractor, AccountFetc switch result { case let .failure(error): presenter?.didReceive(error: .fetchMetaAccounts(error)) - presenter?.didReceive(metaChainAccountResponses: []) + presenter?.didReceive(yourWallets: []) case let .success(accounts): let excludedWalletTypes: [MetaAccountModelType] = [ /* .watchOnly, */ .proxied] - let filteredAccounts = accounts.filter { !excludedWalletTypes.contains($0.metaAccount.type) } - presenter?.didReceive(metaChainAccountResponses: filteredAccounts) + let filteredAccounts = accounts.filter { + !excludedWalletTypes.contains($0.metaAccount.type) && $0.chainAccountResponse != nil + } + presenter?.didReceive(yourWallets: filteredAccounts) } } } @@ -80,7 +82,7 @@ extension StakingSetupProxyInteractor: StakingSetupProxyInteractorInputProtocol func search(web3Name: String) { guard let web3NamesService = web3NamesService else { let error = Web3NameServiceError.serviceNotFound(web3Name, chainAsset.chain.name) - presenter?.didReceive(error: .web3NamesService(error)) + presenter?.didReceive(error: .web3Name(error)) return } @@ -94,9 +96,13 @@ extension StakingSetupProxyInteractor: StakingSetupProxyInteractorInputProtocol case let .success(recipients): self.presenter?.didReceive(recipients: recipients, for: web3Name) case let .failure(error): - self.presenter?.didReceive(error: .web3NamesService(error)) + self.presenter?.didReceive(error: .web3Name(error)) } } } } + + func refetchAccounts() { + fetchAccounts() + } } diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyPresenter.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyPresenter.swift index be4e478ee3..8a891848ff 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyPresenter.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyPresenter.swift @@ -92,7 +92,7 @@ final class StakingSetupProxyPresenter: StakingProxyBasePresenter { view?.didReceiveAuthorityInputState(focused: false, empty: nil) } else { recipientAddress = .external(.init(name: name, recipient: .loaded(value: nil))) - didReceive(error: .web3NameInvalidAddress(chainName: chain.name)) + didReceive(error: .web3Name(.invalidAddress(chain.name))) } } @@ -110,15 +110,42 @@ final class StakingSetupProxyPresenter: StakingProxyBasePresenter { } recipientAddress = .address(newAddress) - - // let optAccountId = getRecepientAccountId() - // interactor.change(recepient: optAccountId) } func updateYourWalletsButton() { let isShowYourWallets = yourWallets.contains { $0.chainAccountResponse != nil } view?.didReceiveYourWallets(state: isShowYourWallets ? .inactive : .hidden) } + + private func proceedWithExternal(account: SetupRecipientAccount.ExternalAccount) { + switch account.recipient { + case let .cached(value), let .loaded(value): + if value?.address == nil { + didReceive(error: .web3Name(.accountNotFound(account.name))) + } else { + proceedWithValidation() + } + case .loading: + // wait the result + break + } + } + + private func proceedWithValidation() { + let validations = createCommonValidations() + + DataValidationRunner(validators: validations).runValidation { [weak self] in + guard + let address = self?.recipientAddress?.address else { + return + } + + self?.wireframe.showConfirmation( + from: self?.view, + proxyAddress: address + ) + } + } } extension StakingSetupProxyPresenter: StakingSetupProxyPresenterProtocol { @@ -171,10 +198,45 @@ extension StakingSetupProxyPresenter: StakingSetupProxyPresenterProtocol { delegate: self ) } + + func scanAddressCode() { + wireframe.showAddressScan(from: view, delegate: self) + } + + func proceed() { + switch recipientAddress { + case .none, .address: + proceedWithValidation() + case let .external(externalAccount): + proceedWithExternal(account: externalAccount) + } + } } extension StakingSetupProxyPresenter: StakingSetupProxyInteractorOutputProtocol { - func didReceive(error _: StakingSetupProxyError) {} + func didReceive(error: StakingSetupProxyError) { + switch error { + case let .web3Name(error): + wireframe.present( + error: error, + from: view, + locale: selectedLocale + ) { [weak self] in + self?.view?.didReceiveAuthorityInputState(focused: true, empty: nil) + self?.recipientAddress = .external(.init( + name: self?.recipientAddress?.name ?? "", + recipient: .loaded(value: nil) + )) + } + case let .fetchMetaAccounts(error): + wireframe.presentRequestStatus( + on: view, + locale: selectedLocale + ) { [weak self] in + self?.interactor.refetchAccounts() + } + } + } func didReceive(recipients: [Web3TransferRecipient], for name: String) { if recipients.count > 1 { @@ -184,11 +246,8 @@ extension StakingSetupProxyPresenter: StakingSetupProxyInteractorOutputProtocol } } - func didReceive(metaChainAccountResponses: [MetaAccountChainResponse]) { - let excludingWalletTypes: [MetaAccountModelType] = [.proxied, .watchOnly] - yourWallets = metaChainAccountResponses.filter { - !excludingWalletTypes.contains($0.metaAccount.type) - } + func didReceive(yourWallets: [MetaAccountChainResponse]) { + self.yourWallets = yourWallets updateYourWalletsButton() } } @@ -210,10 +269,29 @@ extension StakingSetupProxyPresenter: YourWalletsDelegate { func didSelectYourWallet(address: AccountAddress) { wireframe.hideYourWallets(from: view) view?.didReceiveYourWallets(state: .inactive) - recipientAddress = .address(address) + updateRecepientAddress(address) + provideInputViewModel() } func didCloseYourWalletSelection() { view?.didReceiveYourWallets(state: .inactive) } } + +extension StakingSetupProxyPresenter: AddressScanDelegate { + func addressScanDidReceiveRecepient(address: AccountAddress, context _: AnyObject?) { + wireframe.hideAddressScan(from: view) + + updateRecepientAddress(address) + provideInputViewModel() + } +} + +struct ProxyConfirmInputState { + let delegatingAccount: AccountId + let proxyDeposit: BigUInt + let fee: BigUInt + let proxy: AccountAddress + let grantingAccess: Proxy.ProxyType + let chainAsset: ChainAsset +} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyProtocols.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyProtocols.swift index bfd63dad86..8402d13149 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyProtocols.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyProtocols.swift @@ -13,26 +13,32 @@ protocol StakingSetupProxyPresenterProtocol: StakingSetupProxyBasePresenterProto func updateAuthority(partialAddress: String) func showWeb3NameAuthority() func didTapOnYourWallets() + func proceed() + func scanAddressCode() } protocol StakingSetupProxyInteractorInputProtocol: StakingProxyBaseInteractorInputProtocol { func search(web3Name: String) + func refetchAccounts() } protocol StakingSetupProxyInteractorOutputProtocol: StakingProxyBaseInteractorOutputProtocol { func didReceive(error: StakingSetupProxyError) func didReceive(recipients: [Web3TransferRecipient], for name: String) - func didReceive(metaChainAccountResponses: [MetaAccountChainResponse]) + func didReceive(yourWallets: [MetaAccountChainResponse]) } -protocol StakingSetupProxyWireframeProtocol: StakingSetupProxyBaseWireframeProtocol, - ProxyErrorPresentable, AlertPresentable, CommonRetryable, ErrorPresentable, - Web3NameAddressListPresentable, AddressOptionsPresentable, YourWalletsPresentable { +protocol StakingSetupProxyWireframeProtocol: StakingSetupProxyBaseWireframeProtocol, ProxyErrorPresentable, AlertPresentable, + CommonRetryable, ErrorPresentable, Web3NameAddressListPresentable, AddressOptionsPresentable, + YourWalletsPresentable, ScanAddressPresentable { func checkDismissing(view: ControllerBackedProtocol?) -> Bool + func showConfirmation( + from: ControllerBackedProtocol?, + proxyAddress: AccountAddress + ) } enum StakingSetupProxyError: Error { - case web3NamesService(Error) - case web3NameInvalidAddress(chainName: String) + case web3Name(Web3NameServiceError) case fetchMetaAccounts(Error) } diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewController.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewController.swift index a7c4f70688..784e900e2e 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewController.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewController.swift @@ -70,6 +70,17 @@ final class StakingSetupProxyViewController: UIViewController, ViewHolder { action: #selector(actionYourWallets), for: .touchUpInside ) + rootView.actionButton.addTarget( + self, + action: #selector(actionProceed), + for: .touchUpInside + ) + rootView.accountInputView.scanButton.addTarget( + self, + action: #selector(actionAddressScan), + for: .touchUpInside + ) + rootView.web3NameReceipientView.delegate = self rootView.accountInputView.delegate = self } @@ -90,7 +101,41 @@ final class StakingSetupProxyViewController: UIViewController, ViewHolder { presenter.didTapOnYourWallets() } - func updateActionButtonState() {} + func updateActionButtonState() { + if !rootView.accountInputView.completed { + rootView.actionButton.applyDisabledStyle() + rootView.actionButton.isUserInteractionEnabled = false + + rootView.actionButton.imageWithTitleView?.title = R.string.localizable + .transferSetupEnterAddress(preferredLanguages: selectedLocale.rLanguages) + rootView.actionButton.invalidateLayout() + + return + } + + rootView.actionButton.applyEnabledStyle() + rootView.actionButton.isUserInteractionEnabled = true + + rootView.actionButton.imageWithTitleView?.title = R.string.localizable.commonContinue( + preferredLanguages: selectedLocale.rLanguages + ) + rootView.actionButton.invalidateLayout() + } + + @objc func actionAddressScan() { + presenter.scanAddressCode() + } + + @objc func actionProceed() { + if rootView.accountInputView.textField.isFirstResponder { + let partialAddress = rootView.accountInputView.textField.text ?? "" + presenter.complete(authority: partialAddress) + + rootView.accountInputView.textField.resignFirstResponder() + } + + presenter.proceed() + } } extension StakingSetupProxyViewController: StakingSetupProxyViewProtocol { diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyWireframe.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyWireframe.swift index bcf4c9e41c..d66b3da78e 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyWireframe.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyWireframe.swift @@ -4,4 +4,11 @@ final class StakingSetupProxyWireframe: StakingSetupProxyWireframeProtocol { func checkDismissing(view: ControllerBackedProtocol?) -> Bool { view?.controller.navigationController?.isBeingDismissed ?? true } + + func showConfirmation( + from _: ControllerBackedProtocol?, + proxyAddress _: AccountAddress + ) { + // TODO: Confirm screen + } } diff --git a/novawallet/Modules/Swaps/Base/ShortTextInfoPresentableExtensions.swift b/novawallet/Modules/Swaps/Base/ShortTextInfoPresentableExtensions.swift index e00895e039..6cafa0c548 100644 --- a/novawallet/Modules/Swaps/Base/ShortTextInfoPresentableExtensions.swift +++ b/novawallet/Modules/Swaps/Base/ShortTextInfoPresentableExtensions.swift @@ -50,4 +50,18 @@ extension ShortTextInfoPresentable { details: details ) } + + func showProxyDepositInfo(from view: ControllerBackedProtocol?) { + let title = LocalizableResource { + R.string.localizable.stakingSetupProxyDeposit(preferredLanguages: $0.rLanguages) + } + let details = LocalizableResource { + R.string.localizable.stakingSetupProxyDepositDetails(preferredLanguages: $0.rLanguages) + } + showInfo( + from: view, + title: title, + details: details + ) + } } diff --git a/novawallet/Modules/Transfer/TransferSetup/TransferSetupPresenter.swift b/novawallet/Modules/Transfer/TransferSetup/TransferSetupPresenter.swift index 5c990724d1..6401f7c52a 100644 --- a/novawallet/Modules/Transfer/TransferSetup/TransferSetupPresenter.swift +++ b/novawallet/Modules/Transfer/TransferSetup/TransferSetupPresenter.swift @@ -321,7 +321,7 @@ extension TransferSetupPresenter: TransferSetupPresenterProtocol { } func scanRecepientCode() { - wireframe.showRecepientScan(from: view, delegate: self) + wireframe.showAddressScan(from: view, delegate: self) } func applyMyselfRecepient() { @@ -485,7 +485,7 @@ extension TransferSetupPresenter: ModalPickerViewControllerDelegate { extension TransferSetupPresenter: AddressScanDelegate { func addressScanDidReceiveRecepient(address: AccountAddress, context _: AnyObject?) { - wireframe.hideRecepientScan(from: view) + wireframe.hideAddressScan(from: view) recipientAddress = .address(address) childPresenter?.changeRecepient(address: address) diff --git a/novawallet/Modules/Transfer/TransferSetup/TransferSetupProtocols.swift b/novawallet/Modules/Transfer/TransferSetup/TransferSetupProtocols.swift index 81d9ed020c..53dbfcd662 100644 --- a/novawallet/Modules/Transfer/TransferSetup/TransferSetupProtocols.swift +++ b/novawallet/Modules/Transfer/TransferSetup/TransferSetupProtocols.swift @@ -61,7 +61,7 @@ protocol TransferSetupInteractorOutputProtocol: AnyObject { } protocol TransferSetupWireframeProtocol: AlertPresentable, ErrorPresentable, AddressOptionsPresentable, - Web3NameAddressListPresentable, YourWalletsPresentable { + Web3NameAddressListPresentable, YourWalletsPresentable, ScanAddressPresentable { func showDestinationChainSelection( from view: TransferSetupViewProtocol?, selectionState: CrossChainDestinationSelectionState, @@ -75,9 +75,5 @@ protocol TransferSetupWireframeProtocol: AlertPresentable, ErrorPresentable, Add delegate: ModalPickerViewControllerDelegate ) - func showRecepientScan(from view: TransferSetupViewProtocol?, delegate: AddressScanDelegate) - - func hideRecepientScan(from view: TransferSetupViewProtocol?) - func checkDismissing(view: TransferSetupViewProtocol?) -> Bool } diff --git a/novawallet/Modules/Transfer/TransferSetup/TransferSetupWireframe.swift b/novawallet/Modules/Transfer/TransferSetup/TransferSetupWireframe.swift index e80156e8ce..aecf2e1227 100644 --- a/novawallet/Modules/Transfer/TransferSetup/TransferSetupWireframe.swift +++ b/novawallet/Modules/Transfer/TransferSetup/TransferSetupWireframe.swift @@ -36,26 +36,6 @@ class TransferSetupWireframe: TransferSetupWireframeProtocol { ) } - func showRecepientScan(from view: TransferSetupViewProtocol?, delegate: AddressScanDelegate) { - guard - let scanView = AddressScanViewFactory.createTransferRecipientScan( - for: delegate, - context: nil - ) else { - return - } - - let navigationController = NovaNavigationController( - rootViewController: scanView.controller - ) - - view?.controller.present(navigationController, animated: true, completion: nil) - } - - func hideRecepientScan(from view: TransferSetupViewProtocol?) { - view?.controller.dismiss(animated: true) - } - func checkDismissing(view: TransferSetupViewProtocol?) -> Bool { view?.controller.navigationController?.isBeingDismissed ?? true } From 4eef7e7647bdb63415a12c5a1faa48ff5fa85851 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Wed, 17 Jan 2024 00:18:58 +0300 Subject: [PATCH 13/60] cleanup --- .../Base/StakingProxyBaseInteractor.swift | 10 ++- .../Base/StakingProxyBasePresenter.swift | 6 +- .../Base/StakingProxyBaseProtocols.swift | 3 +- .../StakingSetupProxyPresenter.swift | 77 ++++++++----------- .../StakingSetupProxyProtocols.swift | 18 ++--- .../StakingSetupProxyViewController.swift | 26 +++---- .../StakingSetupProxyViewLayout.swift | 6 +- .../ProxyDataValidatorFactory.swift | 3 +- .../Model/TransferSetupRecipientAccount.swift | 1 + 9 files changed, 74 insertions(+), 76 deletions(-) diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseInteractor.swift b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseInteractor.swift index 17d24ded7a..d348b0d179 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseInteractor.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseInteractor.swift @@ -203,7 +203,7 @@ class StakingProxyBaseInteractor: RuntimeConstantFetching, StakingProxyBaseInter } let call = callFactory.addProxy( - accountId: AccountId.zeroAccountId(of: chainAsset.chain.accountIdSize), + accountId: proxyAccount(), type: .staking ) @@ -221,6 +221,10 @@ class StakingProxyBaseInteractor: RuntimeConstantFetching, StakingProxyBaseInter handle(stashItem: stashItem) } } + + func proxyAccount() -> AccountId { + AccountId.zeroAccountId(of: chainAsset.chain.accountIdSize) + } } extension StakingProxyBaseInteractor: StakingLocalStorageSubscriber, StakingLocalSubscriptionHandler, @@ -315,8 +319,12 @@ extension StakingProxyBaseInteractor: ProxyListLocalSubscriptionHandler, ProxyLi let proxyCount = proxy?.definition.count ?? 0 calculator.proxyCount = proxyCount updateProxyDeposit() + basePresenter?.didReceive(proxy: proxy) case let .failure(error): basePresenter?.didReceive(baseError: .handleProxies(error)) + calculator.proxyCount = nil + updateProxyDeposit() + basePresenter?.didReceive(proxy: nil) } } } diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift index f76e2628e7..3a0e6ad394 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift @@ -111,8 +111,8 @@ class StakingProxyBasePresenter: StakingSetupProxyBasePresenterProtocol { locale: selectedLocale ), dataValidatingFactory.notReachedMaximimProxyCount( - proxy?.definition.count ?? 0, - limit: maxProxies ?? 32, + proxy?.definition.count, + limit: maxProxies, chain: chainAsset.chain, locale: selectedLocale ) @@ -129,7 +129,7 @@ extension StakingProxyBasePresenter: StakingProxyBaseInteractorOutputProtocol { } case .handleProxies, .balance: wireframe.presentRequestStatus(on: baseView, locale: selectedLocale) { [weak self] in - self?.interactor.refetchConstants() + self?.interactor.remakeSubscriptions() } case .stashItem, .price: wireframe.presentRequestStatus(on: baseView, locale: selectedLocale) { [weak self] in diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseProtocols.swift b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseProtocols.swift index 9f4065affd..572bdbbd5b 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseProtocols.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseProtocols.swift @@ -40,4 +40,5 @@ protocol StakingSetupProxyBasePresenterProtocol: AnyObject { func showDepositInfo() } -protocol StakingSetupProxyBaseWireframeProtocol: ShortTextInfoPresentable, AlertPresentable, ErrorPresentable, CommonRetryable {} +protocol StakingSetupProxyBaseWireframeProtocol: ShortTextInfoPresentable, AlertPresentable, + ErrorPresentable, CommonRetryable {} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyPresenter.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyPresenter.swift index 8a891848ff..bd0df2715e 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyPresenter.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyPresenter.swift @@ -10,14 +10,14 @@ final class StakingSetupProxyPresenter: StakingProxyBasePresenter { let wireframe: StakingSetupProxyWireframeProtocol let interactor: StakingSetupProxyInteractorInputProtocol let web3NameViewModelFactory: Web3NameViewModelFactoryProtocol - private(set) var recipientAddress: SetupRecipientAccount? { + private(set) var proxyAddress: StakingSetupProxyAccount? { didSet { - switch recipientAddress { + switch proxyAddress { case .none, .address: - view?.didReceiveWeb3NameAuthority(viewModel: .loaded(value: nil)) + view?.didReceiveWeb3NameProxy(viewModel: .loaded(value: nil)) case let .external(externalAccount): let isLoading = externalAccount.recipient.isLoading == true - view?.didReceiveWeb3NameAuthority(viewModel: isLoading ? .loading : + view?.didReceiveWeb3NameProxy(viewModel: isLoading ? .loading : .loaded(value: externalAccount.recipient.value??.displayTitle)) } } @@ -60,13 +60,13 @@ final class StakingSetupProxyPresenter: StakingProxyBasePresenter { } let chain = chainAsset.chain - view.didReceiveWeb3NameAuthority(viewModel: .cached(value: nil)) + view.didReceiveWeb3NameProxy(viewModel: .cached(value: nil)) let viewModel = web3NameViewModelFactory.recipientListViewModel( recipients: recipients, for: name, chain: chain, - selectedAddress: recipientAddress?.address + selectedAddress: proxyAddress?.address ) wireframe.presentWeb3NameAddressListPicker(from: view, viewModel: viewModel, delegate: self) @@ -74,9 +74,9 @@ final class StakingSetupProxyPresenter: StakingProxyBasePresenter { private func provideWeb3NameViewModel(_ authority: Web3TransferRecipient?, name: String) { guard let authority = authority else { - if recipientAddress?.isExternal == true { - recipientAddress = .external(.init(name: name, recipient: .loaded(value: nil))) - view?.didReceiveAuthorityInputState(focused: true, empty: true) + if proxyAddress?.isExternal == true { + proxyAddress = .external(.init(name: name, recipient: .loaded(value: nil))) + view?.didReceiveProxyInputState(focused: true, empty: true) } return } @@ -84,32 +84,32 @@ final class StakingSetupProxyPresenter: StakingProxyBasePresenter { let chain = chainAsset.chain if let account = authority.normalizedAddress(for: chain.chainFormat) { - let authorityViewModel = SetupRecipientAccount.ExternalAccountValue( + let authorityViewModel = StakingSetupProxyAccount.ExternalAccountValue( address: account, description: authority.description ) - recipientAddress = .external(.init(name: name, recipient: .loaded(value: authorityViewModel))) - view?.didReceiveAuthorityInputState(focused: false, empty: nil) + proxyAddress = .external(.init(name: name, recipient: .loaded(value: authorityViewModel))) + view?.didReceiveProxyInputState(focused: false, empty: nil) } else { - recipientAddress = .external(.init(name: name, recipient: .loaded(value: nil))) + proxyAddress = .external(.init(name: name, recipient: .loaded(value: nil))) didReceive(error: .web3Name(.invalidAddress(chain.name))) } } private func provideInputViewModel() { - let value = recipientAddress?.address ?? "" + let value = proxyAddress?.address ?? "" let inputViewModel = InputViewModel.createAccountInputViewModel(for: value) - view?.didReceiveAccountInput(viewModel: inputViewModel) + view?.didReceiveProxyAccountInput(viewModel: inputViewModel) } private func updateRecepientAddress(_ newAddress: String) { - guard recipientAddress?.address != newAddress else { + guard proxyAddress?.address != newAddress else { return } - recipientAddress = .address(newAddress) + proxyAddress = .address(newAddress) } func updateYourWalletsButton() { @@ -117,7 +117,7 @@ final class StakingSetupProxyPresenter: StakingProxyBasePresenter { view?.didReceiveYourWallets(state: isShowYourWallets ? .inactive : .hidden) } - private func proceedWithExternal(account: SetupRecipientAccount.ExternalAccount) { + private func proceedWithExternal(account: StakingSetupProxyAccount.ExternalAccount) { switch account.recipient { case let .cached(value), let .loaded(value): if value?.address == nil { @@ -136,7 +136,7 @@ final class StakingSetupProxyPresenter: StakingProxyBasePresenter { DataValidationRunner(validators: validations).runValidation { [weak self] in guard - let address = self?.recipientAddress?.address else { + let address = self?.proxyAddress?.address else { return } @@ -149,36 +149,36 @@ final class StakingSetupProxyPresenter: StakingProxyBasePresenter { } extension StakingSetupProxyPresenter: StakingSetupProxyPresenterProtocol { - func complete(authority: String) { + func complete(proxyInput: String) { guard !wireframe.checkDismissing(view: view) else { return } - guard let web3Name = KiltW3n.web3Name(nameWithScheme: authority) else { + guard let web3Name = KiltW3n.web3Name(nameWithScheme: proxyInput) else { return } - recipientAddress = .external(.init( + proxyAddress = .external(.init( name: KiltW3n.fullName(for: web3Name), recipient: .loading )) interactor.search(web3Name: web3Name) } - func updateAuthority(partialAddress: String) { + func updateProxy(partialAddress: String) { if let w3n = KiltW3n.web3Name(nameWithScheme: partialAddress) { - recipientAddress = .external(.init( + proxyAddress = .external(.init( name: KiltW3n.fullName(for: w3n), recipient: .cached(value: nil) )) } else { - recipientAddress = .address(partialAddress) + proxyAddress = .address(partialAddress) } - view?.didReceiveWeb3NameAuthority(viewModel: .loaded(value: nil)) + view?.didReceiveWeb3NameProxy(viewModel: .loaded(value: nil)) } - func showWeb3NameAuthority() { - guard let view = view, let address = recipientAddress?.address else { + func showWeb3NameProxy() { + guard let view = view, let address = proxyAddress?.address else { return } @@ -194,7 +194,7 @@ extension StakingSetupProxyPresenter: StakingSetupProxyPresenterProtocol { wireframe.showYourWallets( from: view, accounts: yourWallets, - address: recipientAddress?.address, + address: proxyAddress?.address, delegate: self ) } @@ -204,7 +204,7 @@ extension StakingSetupProxyPresenter: StakingSetupProxyPresenterProtocol { } func proceed() { - switch recipientAddress { + switch proxyAddress { case .none, .address: proceedWithValidation() case let .external(externalAccount): @@ -222,9 +222,9 @@ extension StakingSetupProxyPresenter: StakingSetupProxyInteractorOutputProtocol from: view, locale: selectedLocale ) { [weak self] in - self?.view?.didReceiveAuthorityInputState(focused: true, empty: nil) - self?.recipientAddress = .external(.init( - name: self?.recipientAddress?.name ?? "", + self?.view?.didReceiveProxyInputState(focused: true, empty: nil) + self?.proxyAddress = .external(.init( + name: self?.proxyAddress?.name ?? "", recipient: .loaded(value: nil) )) } @@ -261,7 +261,7 @@ extension StakingSetupProxyPresenter: ModalPickerViewControllerDelegate { } func modalPickerDidCancel(context _: AnyObject?) { - view?.didReceiveAuthorityInputState(focused: true, empty: nil) + view?.didReceiveProxyInputState(focused: true, empty: nil) } } @@ -286,12 +286,3 @@ extension StakingSetupProxyPresenter: AddressScanDelegate { provideInputViewModel() } } - -struct ProxyConfirmInputState { - let delegatingAccount: AccountId - let proxyDeposit: BigUInt - let fee: BigUInt - let proxy: AccountAddress - let grantingAccess: Proxy.ProxyType - let chainAsset: ChainAsset -} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyProtocols.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyProtocols.swift index 8402d13149..cdfa61d68a 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyProtocols.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyProtocols.swift @@ -2,16 +2,16 @@ import SoraFoundation protocol StakingSetupProxyViewProtocol: StakingSetupProxyBaseViewProtocol { func didReceive(token: String) - func didReceiveAuthorityInputState(focused: Bool, empty: Bool?) - func didReceiveAccountInput(viewModel: InputViewModelProtocol) - func didReceiveWeb3NameAuthority(viewModel: LoadableViewModelState) + func didReceiveProxyInputState(focused: Bool, empty: Bool?) + func didReceiveProxyAccountInput(viewModel: InputViewModelProtocol) + func didReceiveWeb3NameProxy(viewModel: LoadableViewModelState) func didReceiveYourWallets(state: YourWalletsControl.State) } protocol StakingSetupProxyPresenterProtocol: StakingSetupProxyBasePresenterProtocol { - func complete(authority: String) - func updateAuthority(partialAddress: String) - func showWeb3NameAuthority() + func complete(proxyInput: String) + func updateProxy(partialAddress: String) + func showWeb3NameProxy() func didTapOnYourWallets() func proceed() func scanAddressCode() @@ -28,9 +28,9 @@ protocol StakingSetupProxyInteractorOutputProtocol: StakingProxyBaseInteractorOu func didReceive(yourWallets: [MetaAccountChainResponse]) } -protocol StakingSetupProxyWireframeProtocol: StakingSetupProxyBaseWireframeProtocol, ProxyErrorPresentable, AlertPresentable, - CommonRetryable, ErrorPresentable, Web3NameAddressListPresentable, AddressOptionsPresentable, - YourWalletsPresentable, ScanAddressPresentable { +protocol StakingSetupProxyWireframeProtocol: StakingSetupProxyBaseWireframeProtocol, ProxyErrorPresentable, + AlertPresentable, CommonRetryable, ErrorPresentable, Web3NameAddressListPresentable, + AddressOptionsPresentable, YourWalletsPresentable, ScanAddressPresentable { func checkDismissing(view: ControllerBackedProtocol?) -> Bool func showConfirmation( from: ControllerBackedProtocol?, diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewController.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewController.swift index 784e900e2e..f78f4d4e0a 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewController.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewController.swift @@ -27,11 +27,10 @@ final class StakingSetupProxyViewController: UIViewController, ViewHolder { override func viewDidLoad() { super.viewDidLoad() - - presenter.setup() - setupLocalization() setupHandlers() + + presenter.setup() } private func setupLocalization() { @@ -39,7 +38,7 @@ final class StakingSetupProxyViewController: UIViewController, ViewHolder { let strings = R.string.localizable.self rootView.titleLabel.text = strings.stakingSetupProxyTitle(token, preferredLanguages: languages) - rootView.authorityLabel.text = strings.stakingSetupProxyAuthority(preferredLanguages: languages) + rootView.proxyTitleLabel.text = strings.stakingSetupProxyAuthority(preferredLanguages: languages) let selectYourWalletTitle = strings.assetsSelectSendYourWallets(preferredLanguages: languages) rootView.yourWalletsControl.bind(model: .init( @@ -85,14 +84,13 @@ final class StakingSetupProxyViewController: UIViewController, ViewHolder { rootView.accountInputView.delegate = self } - @objc - private func proxyInfoAction() { + @objc private func proxyInfoAction() { presenter.showDepositInfo() } @objc private func actionAddressChange() { let partialAddress = rootView.accountInputView.textField.text ?? "" - presenter.updateAuthority(partialAddress: partialAddress) + presenter.updateProxy(partialAddress: partialAddress) updateActionButtonState() } @@ -129,7 +127,7 @@ final class StakingSetupProxyViewController: UIViewController, ViewHolder { @objc func actionProceed() { if rootView.accountInputView.textField.isFirstResponder { let partialAddress = rootView.accountInputView.textField.text ?? "" - presenter.complete(authority: partialAddress) + presenter.complete(proxyInput: partialAddress) rootView.accountInputView.textField.resignFirstResponder() } @@ -155,13 +153,13 @@ extension StakingSetupProxyViewController: StakingSetupProxyViewProtocol { ) } - func didReceiveAccountInput(viewModel: InputViewModelProtocol) { + func didReceiveProxyAccountInput(viewModel: InputViewModelProtocol) { rootView.accountInputView.bind(inputViewModel: viewModel) updateActionButtonState() } - func didReceiveAuthorityInputState(focused: Bool, empty: Bool?) { + func didReceiveProxyInputState(focused: Bool, empty: Bool?) { if focused { rootView.accountInputView.textField.becomeFirstResponder() } else { @@ -172,7 +170,7 @@ extension StakingSetupProxyViewController: StakingSetupProxyViewProtocol { } } - func didReceiveWeb3NameAuthority(viewModel: LoadableViewModelState) { + func didReceiveWeb3NameProxy(viewModel: LoadableViewModelState) { rootView.web3NameReceipientView.bind(viewModel: viewModel) } @@ -193,7 +191,7 @@ extension StakingSetupProxyViewController: AccountInputViewDelegate { func accountInputViewWillStartEditing(_: AccountInputView) {} func accountInputViewDidEndEditing(_ inputView: AccountInputView) { - presenter.complete(authority: inputView.textField.text ?? "") + presenter.complete(proxyInput: inputView.textField.text ?? "") } func accountInputViewShouldReturn(_ inputView: AccountInputView) -> Bool { @@ -203,7 +201,7 @@ extension StakingSetupProxyViewController: AccountInputViewDelegate { func accountInputViewDidPaste(_ inputView: AccountInputView) { if !inputView.textField.isFirstResponder { - presenter.complete(authority: inputView.textField.text ?? "") + presenter.complete(proxyInput: inputView.textField.text ?? "") } } } @@ -212,6 +210,6 @@ extension StakingSetupProxyViewController: Web3NameReceipientViewDelegate { func didTapOnAccountList() {} func didTapOnAccount() { - presenter.showWeb3NameAuthority() + presenter.showWeb3NameProxy() } } diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewLayout.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewLayout.swift index e9920d1951..6fab1e7890 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewLayout.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewLayout.swift @@ -10,7 +10,7 @@ final class StakingSetupProxyViewLayout: ScrollableContainerLayoutView { $0.apply(style: .boldTitle2Primary) } - let authorityLabel: UILabel = .create { + let proxyTitleLabel: UILabel = .create { $0.apply(style: .footnoteSecondary) } @@ -52,14 +52,14 @@ final class StakingSetupProxyViewLayout: ScrollableContainerLayoutView { addArrangedSubview(titleLabel, spacingAfter: 8) let titleStackView = UIStackView(arrangedSubviews: [ - authorityLabel, + proxyTitleLabel, FlexibleSpaceView(), yourWalletsControl ]) addArrangedSubview(titleStackView, spacingAfter: 0) addArrangedSubview(accountInputView, spacingAfter: 8) - addArrangedSubview(web3NameReceipientView, spacingAfter: 40) + addArrangedSubview(web3NameReceipientView, spacingAfter: 16) addArrangedSubview(proxyDepositView, spacingAfter: 0) addArrangedSubview(feeView) } diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyDataValidatorFactory.swift b/novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyDataValidatorFactory.swift index 61ca981a63..9bb1fff220 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyDataValidatorFactory.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyDataValidatorFactory.swift @@ -147,7 +147,6 @@ final class ProxyDataValidatorFactory: ProxyDataValidatorFactoryProtocol { guard let view = self?.view else { return } - let formatter = NumberFormatter.quantity self?.presentable.presentProxyAlreadyAdded( from: view, account: address, @@ -155,7 +154,7 @@ final class ProxyDataValidatorFactory: ProxyDataValidatorFactoryProtocol { ) }, preservesCondition: { guard let proxyList = proxyList else { - return false + return true } let accountId = try? address.toAccountId(using: chain.chainFormat) return proxyList.definition.contains(where: { $0.proxy == accountId }) == false diff --git a/novawallet/Modules/Transfer/TransferSetup/Model/TransferSetupRecipientAccount.swift b/novawallet/Modules/Transfer/TransferSetup/Model/TransferSetupRecipientAccount.swift index 09fe153ad5..56ba554fad 100644 --- a/novawallet/Modules/Transfer/TransferSetup/Model/TransferSetupRecipientAccount.swift +++ b/novawallet/Modules/Transfer/TransferSetup/Model/TransferSetupRecipientAccount.swift @@ -1,4 +1,5 @@ typealias TransferSetupRecipientAccount = SetupRecipientAccount +typealias StakingSetupProxyAccount = SetupRecipientAccount enum SetupRecipientAccount { case address(AccountAddress?) From 32b11424c70a790ace52191d06e98bf0248a22e7 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Wed, 17 Jan 2024 00:48:01 +0300 Subject: [PATCH 14/60] bugfix --- .../Base/StakingProxyBasePresenter.swift | 34 ++++++++++++------- .../StakingSetupProxyPresenter.swift | 4 +++ .../StakingSetupProxyViewFactory.swift | 1 + 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift index 3a0e6ad394..6bb7d55627 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift @@ -14,7 +14,6 @@ class StakingProxyBasePresenter: StakingSetupProxyBasePresenterProtocol { private var proxyDeposit: ProxyDeposit? private var priceData: PriceData? private var fee: ExtrinsicFeeProtocol? - private var proxyAddress: String? private var existensialDeposit: BigUInt? private var maxProxies: Int? private var proxy: ProxyDefinition? @@ -79,6 +78,23 @@ class StakingProxyBasePresenter: StakingSetupProxyBasePresenterProtocol { func createCommonValidations() -> [DataValidating] { [ + dataValidatingFactory.validAddress( + getProxyAddress(), + chain: chainAsset.chain, + locale: selectedLocale + ), + dataValidatingFactory.proxyNotExists( + address: getProxyAddress(), + chain: chainAsset.chain, + proxyList: proxy, + locale: selectedLocale + ), + dataValidatingFactory.notReachedMaximimProxyCount( + proxy?.definition.count, + limit: maxProxies, + chain: chainAsset.chain, + locale: selectedLocale + ), dataValidatingFactory.has( fee: fee, locale: selectedLocale @@ -91,12 +107,6 @@ class StakingProxyBasePresenter: StakingSetupProxyBasePresenterProtocol { asset: chainAsset.assetDisplayInfo, locale: selectedLocale ), - dataValidatingFactory.proxyNotExists( - address: proxyAddress ?? "", - chain: chainAsset.chain, - proxyList: proxy, - locale: selectedLocale - ), dataValidatingFactory.hasSufficientBalance( available: (assetBalance?.regularTransferrableBalance() ?? 0) + (proxyDeposit?.current ?? 0), deposit: proxyDeposit?.new, @@ -109,15 +119,13 @@ class StakingProxyBasePresenter: StakingSetupProxyBasePresenterProtocol { totalAmount: assetBalance?.freeInPlank, minimumBalance: existensialDeposit, locale: selectedLocale - ), - dataValidatingFactory.notReachedMaximimProxyCount( - proxy?.definition.count, - limit: maxProxies, - chain: chainAsset.chain, - locale: selectedLocale ) ] } + + func getProxyAddress() -> AccountAddress { + fatalError("This function should be overriden") + } } extension StakingProxyBasePresenter: StakingProxyBaseInteractorOutputProtocol { diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyPresenter.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyPresenter.swift index bd0df2715e..fc30e5d2d4 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyPresenter.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyPresenter.swift @@ -146,6 +146,10 @@ final class StakingSetupProxyPresenter: StakingProxyBasePresenter { ) } } + + override func getProxyAddress() -> AccountAddress { + proxyAddress?.address ?? "" + } } extension StakingSetupProxyPresenter: StakingSetupProxyPresenterProtocol { diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewFactory.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewFactory.swift index e7ff5f9912..7c36ba7386 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewFactory.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewFactory.swift @@ -42,6 +42,7 @@ struct StakingSetupProxyViewFactory { presenter.baseView = view interactor.basePresenter = presenter + dataValidatingFactory.view = view return view } From 4876dc5444c11605c8988d68d1f3f8d0a55727e0 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Wed, 17 Jan 2024 09:02:05 +0300 Subject: [PATCH 15/60] bugfixes, fix address icon --- .../Base/ProxyDepositCalculator.swift | 8 ++++++-- .../Base/StakingProxyBasePresenter.swift | 8 ++++---- .../StakingSetupProxyPresenter.swift | 19 +++++++++++++++++++ .../StakingSetupProxyProtocols.swift | 1 + .../StakingSetupProxyViewController.swift | 4 ++++ .../ProxyDataValidatorFactory.swift | 8 ++++---- 6 files changed, 38 insertions(+), 10 deletions(-) diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Base/ProxyDepositCalculator.swift b/novawallet/Modules/Staking/StakingSetupProxy/Base/ProxyDepositCalculator.swift index 1768186395..709109fa9f 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/Base/ProxyDepositCalculator.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/Base/ProxyDepositCalculator.swift @@ -10,14 +10,18 @@ struct ProxyDepositCalculator { return nil } - let currentDeposit = base + BigUInt(proxyCount) * factor - let newDeposit = base + BigUInt(proxyCount + 1) * factor + let currentDeposit = proxyCount > 0 ? calculate(base: base, factor: factor, proxyCount: proxyCount) : 0 + let newDeposit = calculate(base: base, factor: factor, proxyCount: proxyCount + 1) return .init( current: currentDeposit, new: newDeposit ) } + + func calculate(base: BigUInt, factor: BigUInt, proxyCount: Int) -> BigUInt { + base + BigUInt(proxyCount) * factor + } } struct ProxyDeposit { diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift index 6bb7d55627..24e2d0b9cb 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift @@ -16,7 +16,7 @@ class StakingProxyBasePresenter: StakingSetupProxyBasePresenterProtocol { private var fee: ExtrinsicFeeProtocol? private var existensialDeposit: BigUInt? private var maxProxies: Int? - private var proxy: ProxyDefinition? + private var proxy: UncertainStorage = .undefined init( chainAsset: ChainAsset, @@ -86,11 +86,11 @@ class StakingProxyBasePresenter: StakingSetupProxyBasePresenterProtocol { dataValidatingFactory.proxyNotExists( address: getProxyAddress(), chain: chainAsset.chain, - proxyList: proxy, + proxyList: proxy.map { $0?.definition ?? [] }.value, locale: selectedLocale ), dataValidatingFactory.notReachedMaximimProxyCount( - proxy?.definition.count, + proxy.map { $0?.definition.count ?? 0 }.value, limit: maxProxies, chain: chainAsset.chain, locale: selectedLocale @@ -173,7 +173,7 @@ extension StakingProxyBasePresenter: StakingProxyBaseInteractorOutputProtocol { } func didReceive(proxy: ProxyDefinition?) { - self.proxy = proxy + self.proxy = .defined(proxy) } func didReceive(price: PriceData?) { diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyPresenter.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyPresenter.swift index fc30e5d2d4..f1118ed9b6 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyPresenter.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyPresenter.swift @@ -1,6 +1,7 @@ import Foundation import BigInt import SoraFoundation +import SubstrateSdk final class StakingSetupProxyPresenter: StakingProxyBasePresenter { weak var view: StakingSetupProxyViewProtocol? { @@ -12,6 +13,9 @@ final class StakingSetupProxyPresenter: StakingProxyBasePresenter { let web3NameViewModelFactory: Web3NameViewModelFactoryProtocol private(set) var proxyAddress: StakingSetupProxyAccount? { didSet { + guard view?.isSetup == true else { + return + } switch proxyAddress { case .none, .address: view?.didReceiveWeb3NameProxy(viewModel: .loaded(value: nil)) @@ -20,10 +24,12 @@ final class StakingSetupProxyPresenter: StakingProxyBasePresenter { view?.didReceiveWeb3NameProxy(viewModel: isLoading ? .loading : .loaded(value: externalAccount.recipient.value??.displayTitle)) } + provideAccountFieldStateViewModel() } } private var yourWallets: [MetaAccountChainResponse] = [] + private(set) lazy var iconGenerator = PolkadotIconGenerator() init( chainAsset: ChainAsset, @@ -150,6 +156,19 @@ final class StakingSetupProxyPresenter: StakingProxyBasePresenter { override func getProxyAddress() -> AccountAddress { proxyAddress?.address ?? "" } + + private func provideAccountFieldStateViewModel() { + if + let accountId = try? getProxyAddress().toAccountId(using: chainAsset.chain.chainFormat), + let icon = try? iconGenerator.generateFromAccountId(accountId) { + let iconViewModel = DrawableIconViewModel(icon: icon) + let viewModel = AccountFieldStateViewModel(icon: iconViewModel) + view?.didReceiveAccountState(viewModel: viewModel) + } else { + let viewModel = AccountFieldStateViewModel(icon: nil) + view?.didReceiveAccountState(viewModel: viewModel) + } + } } extension StakingSetupProxyPresenter: StakingSetupProxyPresenterProtocol { diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyProtocols.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyProtocols.swift index cdfa61d68a..87f49d677e 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyProtocols.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyProtocols.swift @@ -6,6 +6,7 @@ protocol StakingSetupProxyViewProtocol: StakingSetupProxyBaseViewProtocol { func didReceiveProxyAccountInput(viewModel: InputViewModelProtocol) func didReceiveWeb3NameProxy(viewModel: LoadableViewModelState) func didReceiveYourWallets(state: YourWalletsControl.State) + func didReceiveAccountState(viewModel: AccountFieldStateViewModel) } protocol StakingSetupProxyPresenterProtocol: StakingSetupProxyBasePresenterProtocol { diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewController.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewController.swift index f78f4d4e0a..450df0efc8 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewController.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewController.swift @@ -177,6 +177,10 @@ extension StakingSetupProxyViewController: StakingSetupProxyViewProtocol { func didReceiveYourWallets(state: YourWalletsControl.State) { rootView.yourWalletsControl.apply(state: state) } + + func didReceiveAccountState(viewModel: AccountFieldStateViewModel) { + rootView.accountInputView.bind(fieldStateViewModel: viewModel) + } } extension StakingSetupProxyViewController: Localizable { diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyDataValidatorFactory.swift b/novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyDataValidatorFactory.swift index 9bb1fff220..157f597a8b 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyDataValidatorFactory.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyDataValidatorFactory.swift @@ -27,7 +27,7 @@ protocol ProxyDataValidatorFactoryProtocol: BaseDataValidatingFactoryProtocol { func proxyNotExists( address: String, chain: ChainModel, - proxyList: ProxyDefinition?, + proxyList: [Proxy.ProxyDefinition]?, locale: Locale ) -> DataValidating } @@ -140,7 +140,7 @@ final class ProxyDataValidatorFactory: ProxyDataValidatorFactoryProtocol { func proxyNotExists( address: String, chain: ChainModel, - proxyList: ProxyDefinition?, + proxyList: [Proxy.ProxyDefinition]?, locale: Locale ) -> DataValidating { ErrorConditionViolation(onError: { [weak self] in @@ -154,10 +154,10 @@ final class ProxyDataValidatorFactory: ProxyDataValidatorFactoryProtocol { ) }, preservesCondition: { guard let proxyList = proxyList else { - return true + return false } let accountId = try? address.toAccountId(using: chain.chainFormat) - return proxyList.definition.contains(where: { $0.proxy == accountId }) == false + return proxyList.contains(where: { $0.proxy == accountId }) == false }) } } From ec647b5b4f391e65225689a00a9f30facd1c5a07 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Wed, 17 Jan 2024 09:18:53 +0300 Subject: [PATCH 16/60] add watchonly in filter --- .../Staking/StakingSetupProxy/StakingSetupProxyInteractor.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyInteractor.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyInteractor.swift index ccd325f891..0a0297897b 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyInteractor.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyInteractor.swift @@ -69,7 +69,7 @@ final class StakingSetupProxyInteractor: StakingProxyBaseInteractor, AccountFetc presenter?.didReceive(error: .fetchMetaAccounts(error)) presenter?.didReceive(yourWallets: []) case let .success(accounts): - let excludedWalletTypes: [MetaAccountModelType] = [ /* .watchOnly, */ .proxied] + let excludedWalletTypes: [MetaAccountModelType] = [.watchOnly, .proxied] let filteredAccounts = accounts.filter { !excludedWalletTypes.contains($0.metaAccount.type) && $0.chainAccountResponse != nil } From e7ff5c10e6fbb530f3c2834391baf88f7254cecb Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Wed, 17 Jan 2024 19:42:46 +0300 Subject: [PATCH 17/60] init --- novawallet.xcodeproj/project.pbxproj | 48 ++++++ .../Base/StakingProxyBaseInteractor.swift | 24 ++- .../Base/StakingProxyBasePresenter.swift | 2 +- .../Base/StakingProxyBaseProtocols.swift | 4 +- .../StakingSetupProxy/ProxyDepositView.swift | 2 +- .../StakingConfirmProxyInteractor.swift | 96 ++++++++++++ .../StakingConfirmProxyPresenter.swift | 134 ++++++++++++++++ .../StakingConfirmProxyProtocols.swift | 29 ++++ .../StakingConfirmProxyViewController.swift | 146 ++++++++++++++++++ .../StakingConfirmProxyViewFactory.swift | 106 +++++++++++++ .../StakingConfirmProxyViewLayout.swift | 65 ++++++++ .../StakingConfirmProxyWireframe.swift | 3 + .../StakingSetupProxyProtocols.swift | 3 +- .../StakingSetupProxyViewFactory.swift | 2 +- .../StakingSetupProxyWireframe.swift | 19 ++- novawallet/en.lproj/Localizable.strings | 5 + novawallet/ru.lproj/Localizable.strings | 5 + .../StakingConfirmProxyTests.swift | 16 ++ 18 files changed, 691 insertions(+), 18 deletions(-) create mode 100644 novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyInteractor.swift create mode 100644 novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyPresenter.swift create mode 100644 novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyProtocols.swift create mode 100644 novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewController.swift create mode 100644 novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewFactory.swift create mode 100644 novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewLayout.swift create mode 100644 novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyWireframe.swift create mode 100644 novawalletTests/Modules/StakingConfirmProxy/StakingConfirmProxyTests.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 79c5e8ae55..afecf1e94d 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -434,6 +434,7 @@ 1F45D221E855D5340572C243 /* GovernanceUnavailableTracksProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 59BED0E6DBC4C21D9625740C /* GovernanceUnavailableTracksProtocols.swift */; }; 1F496969FEE3E160BABDAC66 /* ReferendumVoteSetupProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5159EA2661A6CBE123CCF891 /* ReferendumVoteSetupProtocols.swift */; }; 1F88F3DBFA0BD6D0FDF558F3 /* SelectValidatorsConfirmViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 975DECE71DE70DFD866B8E23 /* SelectValidatorsConfirmViewFactory.swift */; }; + 2003738C399EFA9A61343EDD /* StakingConfirmProxyInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49AEF66A11C7B27F947CEA5C /* StakingConfirmProxyInteractor.swift */; }; 20B1463FB1F2431A0C913DCE /* StakingMoreOptionsViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC767DE76479F70A8FA3292A /* StakingMoreOptionsViewLayout.swift */; }; 20B2942A4241F6713A1C70D9 /* StakingRewardDetailsViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2377F8FB07B47637346249F5 /* StakingRewardDetailsViewFactory.swift */; }; 211725E26764530359F53A38 /* ParitySignerTxQrInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7859654B7C1FAC269CA61E71 /* ParitySignerTxQrInteractor.swift */; }; @@ -484,6 +485,7 @@ 2AD0A19025D3D1E100312428 /* GitHubPhishingServiceFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AD0A18F25D3D1E100312428 /* GitHubPhishingServiceFactory.swift */; }; 2AD0A19525D3D3EC00312428 /* GitHubOperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AD0A19425D3D3EC00312428 /* GitHubOperationFactory.swift */; }; 2AF8204F274FD2120092E3E7 /* BaseAccountCreatePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AF8204E274FD2110092E3E7 /* BaseAccountCreatePresenter.swift */; }; + 2AFCF6923D31691A53BEC762 /* StakingConfirmProxyViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E52C5919A1DA8A18297325B /* StakingConfirmProxyViewFactory.swift */; }; 2AFF4BA0274D1E4D00D790B4 /* UsernameSetupViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AFF4B9F274D1E4D00D790B4 /* UsernameSetupViewController.swift */; }; 2AFF4BA2274D1E5C00D790B4 /* UsernameSetupViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AFF4BA1274D1E5C00D790B4 /* UsernameSetupViewLayout.swift */; }; 2B0FC94B4AE9AFE9532F493F /* ReferralCrowdloanViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71285CF636B32ACD8EB5519E /* ReferralCrowdloanViewFactory.swift */; }; @@ -544,6 +546,7 @@ 37FB290D01ADAA67155C9755 /* StakingSelectPoolPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 060D52F9BFFB646BF9FCC968 /* StakingSelectPoolPresenter.swift */; }; 37FF873F9B2358FA137658D8 /* StakingMoreOptionsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77F3F175AFC554763696CB2A /* StakingMoreOptionsPresenter.swift */; }; 384653967D27BD0F39F09255 /* GovernanceUnavailableTracksViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3526D1FB18C2615BE28E15C /* GovernanceUnavailableTracksViewLayout.swift */; }; + 387EA6361B625F9FF4E25F71 /* StakingConfirmProxyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84250F242666D7764E41DBC1 /* StakingConfirmProxyTests.swift */; }; 38D0977931828C7894579968 /* GovernanceUnlockSetupInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = CFA54AB88E24A2053F289D74 /* GovernanceUnlockSetupInteractor.swift */; }; 39218CF5AA701518BD3B0103 /* ExportMnemonicInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 200C6B2C85846AED8CA9451A /* ExportMnemonicInteractor.swift */; }; 39373DDCEE7CB9D04C310BC9 /* GovernanceRevokeDelegationConfirmProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C3F5511D2E7AC283FF021E8 /* GovernanceRevokeDelegationConfirmProtocols.swift */; }; @@ -3642,11 +3645,13 @@ A44CA3E6BB506841948AB2D1 /* ReferendumsFiltersWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 215C03EE9C9EE024F952CB1C /* ReferendumsFiltersWireframe.swift */; }; A5153C322938579FA145742A /* DAppWalletAuthViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5B675B6727754E3727CBC7BE /* DAppWalletAuthViewController.swift */; }; A5880E3789BC9E30835BDCC7 /* TransferSetupViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8202B83B2DF36439CB6449C6 /* TransferSetupViewFactory.swift */; }; + A63C2F992CDBB115E9495624 /* StakingConfirmProxyProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42787EE71C10AD13B8584EFC /* StakingConfirmProxyProtocols.swift */; }; A6E762549FF85393D1B69007 /* GovernanceSelectTracksPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 984A42A14D86FC79DA777833 /* GovernanceSelectTracksPresenter.swift */; }; A714CEAF7A86292E8D679056 /* ParaStkStakeSetupViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37C7955BBDC93BC07D069B8F /* ParaStkStakeSetupViewFactory.swift */; }; A748D64F6048192E16E5BE44 /* ParaStkUnstakeConfirmViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CD36AD8C414F8973CDA8A0F /* ParaStkUnstakeConfirmViewLayout.swift */; }; A8115BE0BFA6558B46CEA101 /* ParaStkCollatorInfoPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4C96F37D7166820D6C9CC62 /* ParaStkCollatorInfoPresenter.swift */; }; A83ED3518F2FD1C7B1C48D9E /* StartStakingInfoViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9D4A8C06D94C748124E6AA5 /* StartStakingInfoViewLayout.swift */; }; + A84E2721D839DA22BF907566 /* StakingConfirmProxyPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = E193257ED2B3E3960849204A /* StakingConfirmProxyPresenter.swift */; }; A8515273213D048B0F9AFD15 /* StakingSetupProxyProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 173BB84A4695492A77AE206D /* StakingSetupProxyProtocols.swift */; }; A871B6ABACAE8A811010F792 /* StakingPayoutConfirmationWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5ACCFD31E14AF4D30955288 /* StakingPayoutConfirmationWireframe.swift */; }; A8F69AC9D7294E7DCBA50470 /* SelectValidatorsStartPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B6244A9538B39AFCD3A6F3A /* SelectValidatorsStartPresenter.swift */; }; @@ -3839,6 +3844,7 @@ BF31A2900BA28194047D2219 /* NPoolsUnstakeSetupViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2864B5E1A5AFC6A8C1B4B9E5 /* NPoolsUnstakeSetupViewController.swift */; }; BFC8C5A2C95D6EDF97D73732 /* ParaStkCollatorsSearchPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18EBB92677F15F1E41762DE4 /* ParaStkCollatorsSearchPresenter.swift */; }; C01C5F1C8CB67B0D5CBE9FB1 /* StakingMainPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 502D42F4A480889BA226CAD3 /* StakingMainPresenter.swift */; }; + C044A73D956CAFB926D4BEC1 /* StakingConfirmProxyViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4E64E1B99253D7F875C637C /* StakingConfirmProxyViewController.swift */; }; C0A7710415B9C9BA496320E7 /* ParaStkYieldBoostSetupProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C2437D345C3D9B12AEE1E28 /* ParaStkYieldBoostSetupProtocols.swift */; }; C0B0DDF638915E8259B1CD67 /* StakingRedeemPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAB2478DE3AF0885A3ED7ED8 /* StakingRedeemPresenter.swift */; }; C102544345E604976BF7AFFC /* LedgerNetworkSelectionWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 935B5118367A118FC86B66C8 /* LedgerNetworkSelectionWireframe.swift */; }; @@ -3928,6 +3934,7 @@ D76DC92333E4D689934D47EB /* TokensAddSelectNetworkViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38BBECA4E3F54769D95DD21E /* TokensAddSelectNetworkViewController.swift */; }; D7B4AE688B93EC562F452F4E /* ParaStkUnstakeInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 76AA6A6232B1CF2D5AF74D0D /* ParaStkUnstakeInteractor.swift */; }; D7D91A2CACE6FE12AE634BEF /* DAppWalletAuthViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16A05911AC400226DD29AE20 /* DAppWalletAuthViewLayout.swift */; }; + D82FA7D0E27C366741AFC1B1 /* StakingConfirmProxyWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96BD67826AED0B073E044D10 /* StakingConfirmProxyWireframe.swift */; }; D83B47B07C0D40A327AC44F7 /* CustomValidatorListViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = F52B8815D6AF5E69B145D245 /* CustomValidatorListViewFactory.swift */; }; D840B64C33EF47E723905378 /* OperationDetailsViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5F05632A6635A54A9CDA7FC /* OperationDetailsViewFactory.swift */; }; D886425A55425810AD070AB5 /* ControllerAccountConfirmationWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = C96C3B5ABF4A8124848EFD17 /* ControllerAccountConfirmationWireframe.swift */; }; @@ -3942,6 +3949,7 @@ D9D163642744F60D00681C1F /* ExternalContribution.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9D163632744F60D00681C1F /* ExternalContribution.swift */; }; D9D163662744F9BF00681C1F /* ExternalContributionSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9D163652744F9BF00681C1F /* ExternalContributionSource.swift */; }; D9ECCCCF1449EFAFD0FA886E /* ParaStkStakeSetupViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44DDD9500E4A1040D863BC1E /* ParaStkStakeSetupViewLayout.swift */; }; + DA33289649E281A2D6378C1C /* StakingConfirmProxyViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3543AE2CAA63AC0A20D532B6 /* StakingConfirmProxyViewLayout.swift */; }; DA53192887DFEEE42B658286 /* TokensManageAddViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8A5632D4768BC5039EE8276 /* TokensManageAddViewLayout.swift */; }; DAB29F2A9C864D7FCF1AF934 /* UsernameSetupProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD098B40697FD6CC08F9A6AC /* UsernameSetupProtocols.swift */; }; DAD0C626F7AA97E4974486AD /* AccountConfirmViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = FFF3E2C8682E9BCCB0A6872D /* AccountConfirmViewController.xib */; }; @@ -4587,6 +4595,7 @@ 0D6E67AD564867E121601F18 /* WalletsListPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = WalletsListPresenter.swift; sourceTree = ""; }; 0D9C85AB0C9D53B522DCF3C5 /* CreateWatchOnlyInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CreateWatchOnlyInteractor.swift; sourceTree = ""; }; 0E4D3F275296975CA39280D5 /* StartStakingInfoBasePresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StartStakingInfoBasePresenter.swift; sourceTree = ""; }; + 0E52C5919A1DA8A18297325B /* StakingConfirmProxyViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingConfirmProxyViewFactory.swift; sourceTree = ""; }; 0EC18369BDAF9076681B6E3F /* InAppUpdatesWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = InAppUpdatesWireframe.swift; sourceTree = ""; }; 0FA94E5B74194AABA482F2FD /* WalletConnectSessionDetailsProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = WalletConnectSessionDetailsProtocols.swift; sourceTree = ""; }; 1039AA3654461114FBB86844 /* DAppTxDetailsPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppTxDetailsPresenter.swift; sourceTree = ""; }; @@ -4743,6 +4752,7 @@ 33DFAA0EEEA7F99C6D1CF4B1 /* ReferendumFullDetailsPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumFullDetailsPresenter.swift; sourceTree = ""; }; 340D78F99A4FCDC04C012ED3 /* StakingRebagConfirmInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingRebagConfirmInteractor.swift; sourceTree = ""; }; 3531B386DEF40108C34E7232 /* ReferendumVoteConfirmViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumVoteConfirmViewLayout.swift; sourceTree = ""; }; + 3543AE2CAA63AC0A20D532B6 /* StakingConfirmProxyViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingConfirmProxyViewLayout.swift; sourceTree = ""; }; 3558BD7D1B8CA1409BE74879 /* AccountManagementInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AccountManagementInteractor.swift; sourceTree = ""; }; 3574BADE9CF77599048C7010 /* CrowdloanContributionSetupWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CrowdloanContributionSetupWireframe.swift; sourceTree = ""; }; 358E87C8E90981E6D9515745 /* GovernanceUnlockConfirmViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = GovernanceUnlockConfirmViewFactory.swift; sourceTree = ""; }; @@ -4805,6 +4815,7 @@ 40B1EE1E66B8325C47D8A404 /* GovernanceDelegateSearchProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = GovernanceDelegateSearchProtocols.swift; sourceTree = ""; }; 4191E0055768541F6A3D8A61 /* StakingRewardPayoutsInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingRewardPayoutsInteractor.swift; sourceTree = ""; }; 41DFB2757D029FB5DF3CEBC2 /* WalletHistoryFilterProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = WalletHistoryFilterProtocols.swift; sourceTree = ""; }; + 42787EE71C10AD13B8584EFC /* StakingConfirmProxyProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingConfirmProxyProtocols.swift; sourceTree = ""; }; 43AC83139115B51457C9961F /* GovernanceDelegateInfoProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = GovernanceDelegateInfoProtocols.swift; sourceTree = ""; }; 43AE3AE09F98E37C15BA87A1 /* LedgerInstructionsWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = LedgerInstructionsWireframe.swift; sourceTree = ""; }; 43FBC2EA83A121CEBD25549D /* DAppOperationConfirmViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppOperationConfirmViewController.swift; sourceTree = ""; }; @@ -4828,6 +4839,7 @@ 48CECA2C5A0EFEBFDBB3C90C /* DAppOperationConfirmWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppOperationConfirmWireframe.swift; sourceTree = ""; }; 48E5BB1EB494B5DB92FC3053 /* Pods-novawalletAll-novawalletIntegrationTests.dev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-novawalletAll-novawalletIntegrationTests.dev.xcconfig"; path = "Target Support Files/Pods-novawalletAll-novawalletIntegrationTests/Pods-novawalletAll-novawalletIntegrationTests.dev.xcconfig"; sourceTree = ""; }; 48E6BE303472080271AAC917 /* SwapConfirmPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SwapConfirmPresenter.swift; sourceTree = ""; }; + 49AEF66A11C7B27F947CEA5C /* StakingConfirmProxyInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingConfirmProxyInteractor.swift; sourceTree = ""; }; 4A191B92AD171FDDDD8C30E2 /* DAppSearchWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppSearchWireframe.swift; sourceTree = ""; }; 4B243F6751E2277D9FC14481 /* AdvancedWalletViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AdvancedWalletViewFactory.swift; sourceTree = ""; }; 4B6060CE86A7EA49AD05329C /* ParaStkUnstakeConfirmViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkUnstakeConfirmViewController.swift; sourceTree = ""; }; @@ -5498,6 +5510,7 @@ 84243094265B1888003E07EC /* CrowdloanMetadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdloanMetadata.swift; sourceTree = ""; }; 8424A8C6262EC0E50091BFB1 /* PayoutInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PayoutInfo.swift; sourceTree = ""; }; 8424DB0A26B8466A008C834F /* ValidatorOperationFactoryProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValidatorOperationFactoryProtocol.swift; sourceTree = ""; }; + 84250F242666D7764E41DBC1 /* StakingConfirmProxyTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingConfirmProxyTests.swift; sourceTree = ""; }; 8425D0DF28FE738D003B782A /* ReferendumVoteSetupInteractorError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumVoteSetupInteractorError.swift; sourceTree = ""; }; 8425D0E228FE766B003B782A /* ReferendumVoteProtocols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumVoteProtocols.swift; sourceTree = ""; }; 8425D0E528FE82CB003B782A /* ReferendumVoteInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumVoteInteractor.swift; sourceTree = ""; }; @@ -7850,6 +7863,7 @@ 9622C6C3102EF12BEE78D63D /* AssetSelectionViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AssetSelectionViewFactory.swift; sourceTree = ""; }; 96340EDDE0EAA7F9B6D33E96 /* LedgerWalletConfirmInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = LedgerWalletConfirmInteractor.swift; sourceTree = ""; }; 9638E6EDBA41A5772E0033AE /* GovernanceUnlockConfirmInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = GovernanceUnlockConfirmInteractor.swift; sourceTree = ""; }; + 96BD67826AED0B073E044D10 /* StakingConfirmProxyWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingConfirmProxyWireframe.swift; sourceTree = ""; }; 96BE36DA0A2310660A43FF5B /* DAppAddFavoriteInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppAddFavoriteInteractor.swift; sourceTree = ""; }; 96D540DFC00C25D8F73CFDC3 /* CustomValidatorListWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CustomValidatorListWireframe.swift; sourceTree = ""; }; 975DECE71DE70DFD866B8E23 /* SelectValidatorsConfirmViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SelectValidatorsConfirmViewFactory.swift; sourceTree = ""; }; @@ -8074,6 +8088,7 @@ B3CC9CAB00B604CD1AC5B4D8 /* NftDetailsViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = NftDetailsViewFactory.swift; sourceTree = ""; }; B48994B2FA6FEE45A718252C /* DAppAuthConfirmViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppAuthConfirmViewFactory.swift; sourceTree = ""; }; B4B15579DAD0DD84AEDA7D01 /* ParaStkYieldBoostStopPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkYieldBoostStopPresenter.swift; sourceTree = ""; }; + B4E64E1B99253D7F875C637C /* StakingConfirmProxyViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingConfirmProxyViewController.swift; sourceTree = ""; }; B50ACC876575577A9D477A77 /* StakingTypeProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingTypeProtocols.swift; sourceTree = ""; }; B56202207DF8BB6684C6EF6C /* AdvancedWalletPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AdvancedWalletPresenter.swift; sourceTree = ""; }; B5BC1402B34E341312ABB378 /* LedgerWalletConfirmPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = LedgerWalletConfirmPresenter.swift; sourceTree = ""; }; @@ -8233,6 +8248,7 @@ E12E4AA5C56575FD3ABA7693 /* NPoolsClaimRewardsProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = NPoolsClaimRewardsProtocols.swift; sourceTree = ""; }; E13BDB2E7FF04670131408DB /* StakingMoreOptionsWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingMoreOptionsWireframe.swift; sourceTree = ""; }; E18B94164B49123E62FA60B7 /* AccountManagementViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AccountManagementViewFactory.swift; sourceTree = ""; }; + E193257ED2B3E3960849204A /* StakingConfirmProxyPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingConfirmProxyPresenter.swift; sourceTree = ""; }; E1E60EF37AC0A7646ED8FE64 /* AccountImportViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AccountImportViewFactory.swift; sourceTree = ""; }; E20124142C4011901EF55AAA /* ParitySignerAddressesViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParitySignerAddressesViewLayout.swift; sourceTree = ""; }; E29DAC8F2DB0F7BF909812FA /* DAppTxDetailsViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppTxDetailsViewLayout.swift; sourceTree = ""; }; @@ -10014,6 +10030,20 @@ path = StakingRewardFilters; sourceTree = ""; }; + 600A0B1B13D9E0897BC4FDA9 /* StakingConfirmProxy */ = { + isa = PBXGroup; + children = ( + 42787EE71C10AD13B8584EFC /* StakingConfirmProxyProtocols.swift */, + 96BD67826AED0B073E044D10 /* StakingConfirmProxyWireframe.swift */, + E193257ED2B3E3960849204A /* StakingConfirmProxyPresenter.swift */, + 49AEF66A11C7B27F947CEA5C /* StakingConfirmProxyInteractor.swift */, + B4E64E1B99253D7F875C637C /* StakingConfirmProxyViewController.swift */, + 3543AE2CAA63AC0A20D532B6 /* StakingConfirmProxyViewLayout.swift */, + 0E52C5919A1DA8A18297325B /* StakingConfirmProxyViewFactory.swift */, + ); + path = StakingConfirmProxy; + sourceTree = ""; + }; 6B9FCD7484C894D77EE13328 /* DelegateSearch */ = { isa = PBXGroup; children = ( @@ -15364,6 +15394,7 @@ 84B7C705289BFA79001A3566 /* AccountManagement */, 84B7C708289BFA79001A3566 /* WalletList */, 84B7C70A289BFA79001A3566 /* ControllerAccount */, + ECEE9BB6AC9E9F1ECD5BAA7D /* StakingConfirmProxy */, ); path = Modules; sourceTree = ""; @@ -18148,6 +18179,7 @@ A4542BFD7BBCF6B05FB2D3E4 /* StakingSetupProxy */ = { isa = PBXGroup; children = ( + 600A0B1B13D9E0897BC4FDA9 /* StakingConfirmProxy */, 773090542B5591AC002577AE /* Validation */, 7754BD542B501E3C0099C13E /* Base */, 173BB84A4695492A77AE206D /* StakingSetupProxyProtocols.swift */, @@ -19302,6 +19334,14 @@ path = AssetReceive; sourceTree = ""; }; + ECEE9BB6AC9E9F1ECD5BAA7D /* StakingConfirmProxy */ = { + isa = PBXGroup; + children = ( + 84250F242666D7764E41DBC1 /* StakingConfirmProxyTests.swift */, + ); + path = StakingConfirmProxy; + sourceTree = ""; + }; F14E378DE1BCBB4C8D39AB4C /* ParaStkYieldBoostStop */ = { isa = PBXGroup; children = ( @@ -24179,6 +24219,13 @@ 9AA018D4BDEEECF00018F049 /* ProxySignValidationPresenter.swift in Sources */, 4DBCCC36F7CD1876D6E77ECC /* ProxySignValidationInteractor.swift in Sources */, 84272585149E6A422690779C /* ProxySignValidationViewFactory.swift in Sources */, + A63C2F992CDBB115E9495624 /* StakingConfirmProxyProtocols.swift in Sources */, + D82FA7D0E27C366741AFC1B1 /* StakingConfirmProxyWireframe.swift in Sources */, + A84E2721D839DA22BF907566 /* StakingConfirmProxyPresenter.swift in Sources */, + 2003738C399EFA9A61343EDD /* StakingConfirmProxyInteractor.swift in Sources */, + C044A73D956CAFB926D4BEC1 /* StakingConfirmProxyViewController.swift in Sources */, + DA33289649E281A2D6378C1C /* StakingConfirmProxyViewLayout.swift in Sources */, + 2AFCF6923D31691A53BEC762 /* StakingConfirmProxyViewFactory.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -24342,6 +24389,7 @@ 84B7C748289BFA79001A3566 /* WalletListTests.swift in Sources */, 84B7C720289BFA79001A3566 /* ReferralCrowdloanTests.swift in Sources */, F4897BB126AED13D0075F291 /* EraCountdownOperationFactoryStub.swift in Sources */, + 387EA6361B625F9FF4E25F71 /* StakingConfirmProxyTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseInteractor.swift b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseInteractor.swift index d348b0d179..80133aac45 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseInteractor.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseInteractor.swift @@ -20,7 +20,7 @@ class StakingProxyBaseInteractor: RuntimeConstantFetching, StakingProxyBaseInter private var proxyProvider: AnyDataProvider? private let operationQueue: OperationQueue private var balanceProvider: StreamableProvider? - private var extrinsicService: ExtrinsicServiceProtocol? + private(set) var extrinsicService: ExtrinsicServiceProtocol? private var controllerAccountProvider: StreamableProvider? private var stashAccountProvider: StreamableProvider? private var priceProvider: StreamableProvider? @@ -225,6 +225,19 @@ class StakingProxyBaseInteractor: RuntimeConstantFetching, StakingProxyBaseInter func proxyAccount() -> AccountId { AccountId.zeroAccountId(of: chainAsset.chain.accountIdSize) } + + func handleStashItemChainAccountResponse(_ response: MetaChainAccountResponse?) { + if let response = response { + extrinsicService = extrinsicServiceFactory.createService( + account: response.chainAccount, + chain: chainAsset.chain + ) + estimateFee() + } else { + extrinsicService = nil + estimateFee() + } + } } extension StakingProxyBaseInteractor: StakingLocalStorageSubscriber, StakingLocalSubscriptionHandler, @@ -299,15 +312,10 @@ extension StakingProxyBaseInteractor: AccountLocalSubscriptionHandler, AccountLo switch result { case let .success(optAccount): if let account = optAccount { - extrinsicService = extrinsicServiceFactory.createService( - account: account.chainAccount, - chain: chainAsset.chain - ) - estimateFee() + handleStashItemChainAccountResponse(optAccount) } case .failure: - extrinsicService = nil - estimateFee() + handleStashItemChainAccountResponse(nil) } } } diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift index 24e2d0b9cb..a1e11a8109 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift @@ -3,7 +3,7 @@ import BigInt import SoraFoundation class StakingProxyBasePresenter: StakingSetupProxyBasePresenterProtocol { - weak var baseView: StakingSetupProxyViewProtocol? + weak var baseView: StakingSetupProxyBaseViewProtocol? let balanceViewModelFactory: BalanceViewModelFactoryProtocol let chainAsset: ChainAsset let dataValidatingFactory: ProxyDataValidatorFactoryProtocol diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseProtocols.swift b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseProtocols.swift index 572bdbbd5b..65b347fe9b 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseProtocols.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseProtocols.swift @@ -40,5 +40,5 @@ protocol StakingSetupProxyBasePresenterProtocol: AnyObject { func showDepositInfo() } -protocol StakingSetupProxyBaseWireframeProtocol: ShortTextInfoPresentable, AlertPresentable, - ErrorPresentable, CommonRetryable {} +protocol StakingSetupProxyBaseWireframeProtocol: ShortTextInfoPresentable, ProxyErrorPresentable, + AlertPresentable, CommonRetryable, ErrorPresentable {} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/ProxyDepositView.swift b/novawallet/Modules/Staking/StakingSetupProxy/ProxyDepositView.swift index 064ed9c480..800e1d9c8c 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/ProxyDepositView.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/ProxyDepositView.swift @@ -1,6 +1,6 @@ import SoraUI -final class ProxyDepositView: RowView> { +final class ProxyDepositView: RowView>, StackTableViewCellProtocol { var imageView: UIImageView { rowContentView.imageView } var titleButton: RoundedButton { rowContentView.detailsView.titleButton } var valueTopButton: RoundedButton { rowContentView.detailsView.valueTopButton } diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyInteractor.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyInteractor.swift new file mode 100644 index 0000000000..833b58be2a --- /dev/null +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyInteractor.swift @@ -0,0 +1,96 @@ +import UIKit + +final class StakingConfirmProxyInteractor: StakingProxyBaseInteractor { + weak var presenter: StakingConfirmProxyInteractorOutputProtocol? { + basePresenter as? StakingConfirmProxyInteractorOutputProtocol + } + + let proxyAccount: AccountAddress + let signingWrapperFactory: SigningWrapperFactoryProtocol + + private var signingWrapper: SigningWrapperProtocol? + + init( + proxyAccount: AccountAddress, + signingWrapperFactory: SigningWrapperFactoryProtocol, + runtimeService: RuntimeCodingServiceProtocol, + sharedState: RelaychainStakingSharedStateProtocol, + walletLocalSubscriptionFactory: WalletLocalSubscriptionFactoryProtocol, + accountProviderFactory: AccountProviderFactoryProtocol, + priceLocalSubscriptionFactory: PriceProviderFactoryProtocol, + callFactory: SubstrateCallFactoryProtocol, + feeProxy: ExtrinsicFeeProxyProtocol, + extrinsicServiceFactory: ExtrinsicServiceFactoryProtocol, + selectedAccount: ChainAccountResponse, + chainAsset: ChainAsset, + currencyManager: CurrencyManagerProtocol, + operationQueue: OperationQueue + ) { + self.proxyAccount = proxyAccount + self.signingWrapperFactory = signingWrapperFactory + + super.init( + runtimeService: runtimeService, + sharedState: sharedState, + walletLocalSubscriptionFactory: walletLocalSubscriptionFactory, + accountProviderFactory: accountProviderFactory, + priceLocalSubscriptionFactory: priceLocalSubscriptionFactory, + callFactory: callFactory, + feeProxy: feeProxy, + extrinsicServiceFactory: extrinsicServiceFactory, + selectedAccount: selectedAccount, + chainAsset: chainAsset, + currencyManager: currencyManager, + operationQueue: operationQueue + ) + } + + override func handleStashItemChainAccountResponse( + _ response: MetaChainAccountResponse? + ) { + super.handleStashItemChainAccountResponse(response) + + if let response = response { + signingWrapper = signingWrapperFactory.createSigningWrapper( + for: response.metaId, + accountResponse: response.chainAccount + ) + } else { + signingWrapper = nil + } + } +} + +extension StakingConfirmProxyInteractor: StakingConfirmProxyInteractorInputProtocol { + func submit() { + guard let extrinsicService = extrinsicService, + let signingWrapper = signingWrapper, + let proxyAccountId = try? proxyAccount.toAccountId( + using: chainAsset.chain.chainFormat + ) else { + presenter?.didReceive(error: .submit(CommonError.undefined)) + return + } + + let call = callFactory.addProxy( + accountId: proxyAccountId, + type: .staking + ) + + extrinsicService.submit( + { builder in + try builder.adding(call: call) + }, + signer: signingWrapper, + runningIn: .main, + completion: { [weak self] result in + switch result { + case .success: + self?.presenter?.didSubmit() + case let .failure(error): + self?.presenter?.didReceive(error: .submit(error)) + } + } + ) + } +} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyPresenter.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyPresenter.swift new file mode 100644 index 0000000000..8d472817e2 --- /dev/null +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyPresenter.swift @@ -0,0 +1,134 @@ +import Foundation +import SoraFoundation +import SubstrateSdk + +final class StakingConfirmProxyPresenter: StakingProxyBasePresenter { + weak var view: StakingConfirmProxyViewProtocol? { + baseView as? StakingConfirmProxyViewProtocol + } + + let wireframe: StakingConfirmProxyWireframeProtocol + let interactor: StakingConfirmProxyInteractorInputProtocol + let proxyAddress: AccountAddress + let wallet: MetaAccountModel + let displayAddressViewModelFactory: DisplayAddressViewModelFactoryProtocol + let networkViewModelFactory: NetworkViewModelFactoryProtocol + + private lazy var walletIconGenerator = NovaIconGenerator() + + init( + chainAsset: ChainAsset, + wallet: MetaAccountModel, + proxyAddress: AccountAddress, + interactor: StakingConfirmProxyInteractorInputProtocol, + wireframe: StakingConfirmProxyWireframeProtocol, + balanceViewModelFactory: BalanceViewModelFactoryProtocol, + dataValidatingFactory: ProxyDataValidatorFactoryProtocol, + displayAddressViewModelFactory: DisplayAddressViewModelFactoryProtocol, + networkViewModelFactory: NetworkViewModelFactoryProtocol, + localizationManager: LocalizationManagerProtocol + ) { + self.proxyAddress = proxyAddress + self.wallet = wallet + self.interactor = interactor + self.wireframe = wireframe + self.displayAddressViewModelFactory = displayAddressViewModelFactory + self.networkViewModelFactory = networkViewModelFactory + + super.init( + chainAsset: chainAsset, + interactor: interactor, + wireframe: wireframe, + balanceViewModelFactory: balanceViewModelFactory, + dataValidatingFactory: dataValidatingFactory, + localizationManager: localizationManager + ) + } + + override func setup() { + super.setup() + + provideNetworkViewModel() + provideProxiedWalletViewModel() + provideProxiedAddressViewModel() + provideProxyAddressViewModel() + } + + private func provideNetworkViewModel() { + let viewModel = networkViewModelFactory.createViewModel(from: chainAsset.chain) + view?.didReceiveNetwork(viewModel: viewModel) + } + + private func provideProxiedWalletViewModel() { + let name = wallet.name + + let icon = wallet.walletIdenticonData().flatMap { try? walletIconGenerator.generateFromAccountId($0) } + let iconViewModel = icon.map { DrawableIconViewModel(icon: $0) } + let viewModel = StackCellViewModel(details: name, imageViewModel: iconViewModel) + view?.didReceiveWallet(viewModel: viewModel) + } + + private func provideProxiedAddressViewModel() { + guard let address = wallet.fetch(for: chainAsset.chain.accountRequest())?.toAddress() else { + return + } + + let displayAddress = DisplayAddress(address: address, username: "") + let viewModel = displayAddressViewModelFactory.createViewModel(from: displayAddress) + view?.didReceiveProxiedAddress(viewModel: viewModel) + } + + private func provideProxyAddressViewModel() { + let displayAddress = DisplayAddress(address: proxyAddress, username: "") + let viewModel = displayAddressViewModelFactory.createViewModel(from: displayAddress) + view?.didReceiveProxyAddress(viewModel: viewModel) + } +} + +extension StakingConfirmProxyPresenter: StakingConfirmProxyPresenterProtocol { + func showProxiedAddressOptions() { + guard let view = view else { + return + } + wireframe.presentAccountOptions( + from: view, + address: "", + chain: chainAsset.chain, + locale: selectedLocale + ) + } + + func showProxyAddressOptions() { + guard let view = view else { + return + } + wireframe.presentAccountOptions( + from: view, + address: proxyAddress, + chain: chainAsset.chain, + locale: selectedLocale + ) + } + + func confirm() { + view?.didStartLoading() + interactor.submit() + } +} + +extension StakingConfirmProxyPresenter: StakingConfirmProxyInteractorOutputProtocol { + func didSubmit() { + view?.didStopLoading() + } + + func didReceive(error: StakingConfirmProxyError) { + view?.didStopLoading() + + switch error { + case .submit: + wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in + self?.confirm() + } + } + } +} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyProtocols.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyProtocols.swift new file mode 100644 index 0000000000..e46adac5e1 --- /dev/null +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyProtocols.swift @@ -0,0 +1,29 @@ +protocol StakingConfirmProxyViewProtocol: StakingSetupProxyBaseViewProtocol { + func didReceiveNetwork(viewModel: NetworkViewModel) + func didReceiveWallet(viewModel: StackCellViewModel) + func didReceiveProxiedAddress(viewModel: DisplayAddressViewModel) + func didReceiveProxyAddress(viewModel: DisplayAddressViewModel) + func didStartLoading() + func didStopLoading() +} + +protocol StakingConfirmProxyPresenterProtocol: StakingSetupProxyBasePresenterProtocol { + func showProxiedAddressOptions() + func showProxyAddressOptions() + func confirm() +} + +protocol StakingConfirmProxyInteractorInputProtocol: StakingProxyBaseInteractorInputProtocol { + func submit() +} + +protocol StakingConfirmProxyInteractorOutputProtocol: StakingProxyBaseInteractorOutputProtocol { + func didSubmit() + func didReceive(error: StakingConfirmProxyError) +} + +protocol StakingConfirmProxyWireframeProtocol: StakingSetupProxyBaseWireframeProtocol, AddressOptionsPresentable {} + +enum StakingConfirmProxyError: Error { + case submit(Error) +} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewController.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewController.swift new file mode 100644 index 0000000000..091192f0be --- /dev/null +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewController.swift @@ -0,0 +1,146 @@ +import UIKit +import SoraFoundation + +final class StakingConfirmProxyViewController: UIViewController, ViewHolder { + typealias RootViewType = StakingConfirmProxyViewLayout + + let presenter: StakingConfirmProxyPresenterProtocol + + init( + presenter: StakingConfirmProxyPresenterProtocol, + localizationManager: LocalizationManagerProtocol + ) { + self.presenter = presenter + super.init(nibName: nil, bundle: nil) + + self.localizationManager = localizationManager + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func loadView() { + view = StakingConfirmProxyViewLayout() + } + + override func viewDidLoad() { + super.viewDidLoad() + + setupLocalization() + setupHandlers() + presenter.setup() + } + + private func setupLocalization() { + let languages = selectedLocale.rLanguages + + rootView.networkCell.titleLabel.text = R.string.localizable.commonNetwork( + preferredLanguages: languages + ) + rootView.proxiedWalletCell.titleLabel.text = R.string.localizable.stakingConfirmProxyWallet( + preferredLanguages: languages + ) + rootView.proxiedAddressCell.titleLabel.text = R.string.localizable.stakingConfirmProxyAccountProxied( + preferredLanguages: languages + ) + rootView.proxyDepositView.titleButton.imageWithTitleView?.title = R.string.localizable.stakingSetupProxyDeposit( + preferredLanguages: languages + ) + rootView.feeCell.rowContentView.locale = selectedLocale + rootView.proxyTypeCell.titleLabel.text = R.string.localizable.stakingConfirmProxyTypeTitle( + preferredLanguages: languages + ) + rootView.proxyTypeCell.detailsLabel.text = R.string.localizable.stakingConfirmProxyTypeSubtitle( + preferredLanguages: languages + ) + rootView.proxyAddressCell.titleLabel.text = R.string.localizable.stakingConfirmProxyAccountProxy( + preferredLanguages: languages + ) + title = R.string.localizable.delegationsAddTitle( + preferredLanguages: languages + ) + } + + private func setupHandlers() { + rootView.proxiedAddressCell.addTarget( + self, + action: #selector(proxiedAddressAction), + for: .touchUpInside + ) + rootView.proxyAddressCell.addTarget( + self, + action: #selector(proxyAddressAction), + for: .touchUpInside + ) + rootView.proxyDepositView.addTarget( + self, + action: #selector(depositInfoAction), + for: .touchUpInside + ) + rootView.actionButton.actionButton.addTarget( + self, + action: #selector(confirmAction), + for: .touchUpInside + ) + } + + @objc private func proxiedAddressAction() { + presenter.showProxiedAddressOptions() + } + + @objc private func proxyAddressAction() { + presenter.showProxyAddressOptions() + } + + @objc private func depositInfoAction() { + presenter.showDepositInfo() + } + + @objc private func confirmAction() { + presenter.confirm() + } +} + +extension StakingConfirmProxyViewController: StakingConfirmProxyViewProtocol { + func didReceiveProxyDeposit(viewModel: LoadableViewModelState) { + rootView.proxyDepositView.bind(loadableViewModel: viewModel) + } + + func didReceiveFee(viewModel: BalanceViewModelProtocol?) { + rootView.feeCell.rowContentView.bind(viewModel: viewModel) + } + + func didReceiveNetwork(viewModel: NetworkViewModel) { + rootView.networkCell.bind(viewModel: viewModel) + } + + func didReceiveWallet(viewModel: StackCellViewModel) { + rootView.proxiedWalletCell.bind(viewModel: viewModel) + } + + func didReceiveProxiedAddress(viewModel: DisplayAddressViewModel) { + rootView.proxiedAddressCell.bind(viewModel: viewModel.cellViewModel) + } + + func didReceiveProxyAddress(viewModel: DisplayAddressViewModel) { + rootView.proxyAddressCell.bind(viewModel: viewModel.cellViewModel) + } + + func didStartLoading() { + rootView.actionButton.startLoading() + } + + func didStopLoading() { + rootView.actionButton.stopLoading() + } +} + +extension StakingConfirmProxyViewController: Localizable { + func applyLocalization() { + if isViewLoaded { + applyLocalization() + } + } +} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewFactory.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewFactory.swift new file mode 100644 index 0000000000..fbf9a2eb29 --- /dev/null +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewFactory.swift @@ -0,0 +1,106 @@ +import Foundation +import SoraFoundation + +struct StakingConfirmProxyViewFactory { + static func createView( + state: RelaychainStakingSharedStateProtocol, + proxyAddress: AccountAddress + ) -> StakingConfirmProxyViewProtocol? { + guard let currencyManager = CurrencyManager.shared, + let wallet = SelectedWalletSettings.shared.value, + let interactor = createInteractor( + state: state, + proxyAddress: proxyAddress + ) else { + return nil + } + + let wireframe = StakingConfirmProxyWireframe() + + let chainAsset = state.stakingOption.chainAsset + + let priceAssetInfoFactory = PriceAssetInfoFactory(currencyManager: currencyManager) + let balanceViewModelFactory = BalanceViewModelFactory( + targetAssetInfo: chainAsset.assetDisplayInfo, + priceAssetInfoFactory: priceAssetInfoFactory + ) + let dataValidatingFactory = ProxyDataValidatorFactory( + presentable: wireframe, + balanceViewModelFactoryFacade: BalanceViewModelFactoryFacade( + priceAssetInfoFactory: priceAssetInfoFactory + ) + ) + + let presenter = StakingConfirmProxyPresenter( + chainAsset: chainAsset, + wallet: wallet, + proxyAddress: proxyAddress, + interactor: interactor, + wireframe: wireframe, + balanceViewModelFactory: balanceViewModelFactory, + dataValidatingFactory: dataValidatingFactory, + displayAddressViewModelFactory: DisplayAddressViewModelFactory(), + networkViewModelFactory: NetworkViewModelFactory(), + localizationManager: LocalizationManager.shared + ) + + let view = StakingConfirmProxyViewController( + presenter: presenter, + localizationManager: LocalizationManager.shared + ) + + presenter.baseView = view + interactor.basePresenter = presenter + dataValidatingFactory.view = view + + return view + } + + private static func createInteractor( + state: RelaychainStakingSharedStateProtocol, + proxyAddress: AccountAddress + ) -> StakingConfirmProxyInteractor? { + let chainRegistry = ChainRegistryFacade.sharedRegistry + let chainAsset = state.stakingOption.chainAsset + + guard + let selectedAccount = SelectedWalletSettings.shared.value.fetch( + for: chainAsset.chain.accountRequest() + ), + let connection = chainRegistry.getConnection(for: chainAsset.chain.chainId), + let runtimeRegistry = chainRegistry.getRuntimeProvider(for: chainAsset.chain.chainId), + let currencyManager = CurrencyManager.shared else { + return nil + } + + let extrinsicServiceFactory = ExtrinsicServiceFactory( + runtimeRegistry: runtimeRegistry, + engine: connection, + operationManager: OperationManagerFacade.sharedManager, + userStorageFacade: UserDataStorageFacade.shared + ) + + let accountProviderFactory = AccountProviderFactory( + storageFacade: UserDataStorageFacade.shared, + operationManager: OperationManagerFacade.sharedManager, + logger: Logger.shared + ) + + return StakingConfirmProxyInteractor( + proxyAccount: proxyAddress, + signingWrapperFactory: SigningWrapperFactory(), + runtimeService: runtimeRegistry, + sharedState: state, + walletLocalSubscriptionFactory: WalletLocalSubscriptionFactory.shared, + accountProviderFactory: accountProviderFactory, + priceLocalSubscriptionFactory: PriceProviderFactory.shared, + callFactory: SubstrateCallFactory(), + feeProxy: ExtrinsicFeeProxy(), + extrinsicServiceFactory: extrinsicServiceFactory, + selectedAccount: selectedAccount, + chainAsset: chainAsset, + currencyManager: currencyManager, + operationQueue: OperationManagerFacade.sharedDefaultQueue + ) + } +} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewLayout.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewLayout.swift new file mode 100644 index 0000000000..e9d6d163b5 --- /dev/null +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewLayout.swift @@ -0,0 +1,65 @@ +import UIKit + +final class StakingConfirmProxyViewLayout: ScrollableContainerLayoutView { + let detailsTableView: StackTableView = .create { + $0.cellHeight = 44 + $0.hasSeparators = true + $0.contentInsets = UIEdgeInsets(top: 0, left: 16, bottom: 4, right: 16) + } + + let networkCell = StackNetworkCell() + + let proxiedWalletCell = StackTableCell() + + let proxiedAddressCell: StackInfoTableCell = .create { + $0.detailsLabel.lineBreakMode = .byTruncatingMiddle + } + + let proxyDepositView: ProxyDepositView = .create { + $0.imageView.image = R.image.iconLock()!.withTintColor(R.color.colorIconSecondary()!) + $0.contentInsets = .zero + } + + let feeCell = StackNetworkFeeCell() + + let proxyTableView: StackTableView = .create { + $0.cellHeight = 44 + $0.hasSeparators = true + $0.contentInsets = UIEdgeInsets(top: 0, left: 16, bottom: 8, right: 16) + } + + let proxyTypeCell = StackTableCell() + + let proxyAddressCell: StackInfoTableCell = .create { + $0.detailsLabel.lineBreakMode = .byTruncatingMiddle + } + + let actionButton: LoadableActionView = .create { + $0.actionButton.applyDefaultStyle() + } + + override func setupLayout() { + super.setupLayout() + + addSubview(actionButton) + actionButton.snp.makeConstraints { make in + make.leading.trailing.equalToSuperview().inset(UIConstants.horizontalInset) + make.bottom.equalTo(safeAreaLayoutGuide).inset(UIConstants.actionBottomInset) + make.height.equalTo(UIConstants.actionHeight) + } + + stackView.layoutMargins = UIEdgeInsets(top: 16, left: 16, bottom: 0, right: 16) + + addArrangedSubview(detailsTableView, spacingAfter: 8) + addArrangedSubview(proxyTableView) + + detailsTableView.addArrangedSubview(networkCell) + detailsTableView.addArrangedSubview(proxiedWalletCell) + detailsTableView.addArrangedSubview(proxiedAddressCell) + detailsTableView.addArrangedSubview(proxyDepositView) + detailsTableView.addArrangedSubview(feeCell) + + proxyTableView.addArrangedSubview(proxyTypeCell) + proxyTableView.addArrangedSubview(proxyAddressCell) + } +} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyWireframe.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyWireframe.swift new file mode 100644 index 0000000000..4f3e7735b0 --- /dev/null +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyWireframe.swift @@ -0,0 +1,3 @@ +import Foundation + +final class StakingConfirmProxyWireframe: StakingConfirmProxyWireframeProtocol {} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyProtocols.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyProtocols.swift index 87f49d677e..b52071aba7 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyProtocols.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyProtocols.swift @@ -29,8 +29,7 @@ protocol StakingSetupProxyInteractorOutputProtocol: StakingProxyBaseInteractorOu func didReceive(yourWallets: [MetaAccountChainResponse]) } -protocol StakingSetupProxyWireframeProtocol: StakingSetupProxyBaseWireframeProtocol, ProxyErrorPresentable, - AlertPresentable, CommonRetryable, ErrorPresentable, Web3NameAddressListPresentable, +protocol StakingSetupProxyWireframeProtocol: StakingSetupProxyBaseWireframeProtocol, Web3NameAddressListPresentable, AddressOptionsPresentable, YourWalletsPresentable, ScanAddressPresentable { func checkDismissing(view: ControllerBackedProtocol?) -> Bool func showConfirmation( diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewFactory.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewFactory.swift index 7c36ba7386..a6010ef661 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewFactory.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewFactory.swift @@ -9,7 +9,7 @@ struct StakingSetupProxyViewFactory { guard let interactor = createInteractor(state: state) else { return nil } - let wireframe = StakingSetupProxyWireframe() + let wireframe = StakingSetupProxyWireframe(state: state) let chainAsset = state.stakingOption.chainAsset let priceAssetInfoFactory = PriceAssetInfoFactory(currencyManager: currencyManager) diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyWireframe.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyWireframe.swift index d66b3da78e..a245049401 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyWireframe.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyWireframe.swift @@ -1,14 +1,27 @@ import Foundation final class StakingSetupProxyWireframe: StakingSetupProxyWireframeProtocol { + let state: RelaychainStakingSharedStateProtocol + + init(state: RelaychainStakingSharedStateProtocol) { + self.state = state + } + func checkDismissing(view: ControllerBackedProtocol?) -> Bool { view?.controller.navigationController?.isBeingDismissed ?? true } func showConfirmation( - from _: ControllerBackedProtocol?, - proxyAddress _: AccountAddress + from view: ControllerBackedProtocol?, + proxyAddress: AccountAddress ) { - // TODO: Confirm screen + guard let confirmView = StakingConfirmProxyViewFactory.createView( + state: state, + proxyAddress: proxyAddress + ) else { + return + } + + view?.controller.navigationController?.pushViewController(confirmView.controller, animated: true) } } diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index 15d8f0efb4..3c476e5694 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -1386,6 +1386,11 @@ "staking.setup.proxy.error.invalid.maximum.proxies.message" = "You have reached the limit of %@ added proxies in %@. Remove proxies to add new ones."; "staking.setup.proxy.error.proxy.already.exists.title" = "Delegation already exists"; "staking.setup.proxy.error.proxy.already.exists.message" = "You are already delegating to this account: %@"; +"staking.confirm.proxy.wallet" = "Delegating wallet"; +"staking.confirm.proxy.account.proxied" = "Delegating account"; +"staking.confirm.proxy.type.title" = "Grant access type"; +"staking.confirm.proxy.type.subtitle" = "Staking operations"; +"staking.confirm.proxy.account.proxy" = "Delegate to"; "common.time.in" = "in"; "common.and" = " and "; "common.time.period.after" = "after"; diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index 19a3978aed..91f3e26344 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1387,6 +1387,11 @@ "staking.setup.proxy.error.proxy.already.exists.title" = "Прокси уже добавлен"; "staking.setup.proxy.error.proxy.already.exists.message" = "Вы уже делегируете этой учетной записи: %@"; "common.time.in" = "через"; +"staking.confirm.proxy.wallet" = "Делегирующий кошелек"; +"staking.confirm.proxy.account.proxied" = "Делегирующий аккаунт"; +"staking.confirm.proxy.type.title" = "Выданный тип доступа"; +"staking.confirm.proxy.type.subtitle" = "Операции стекинга"; +"staking.confirm.proxy.account.proxy" = "Делегировать"; "common.and" = " и "; "common.time.period.after" = "через"; "common.time.period.every" = "раз в"; diff --git a/novawalletTests/Modules/StakingConfirmProxy/StakingConfirmProxyTests.swift b/novawalletTests/Modules/StakingConfirmProxy/StakingConfirmProxyTests.swift new file mode 100644 index 0000000000..365d773bd1 --- /dev/null +++ b/novawalletTests/Modules/StakingConfirmProxy/StakingConfirmProxyTests.swift @@ -0,0 +1,16 @@ +import XCTest + +class StakingConfirmProxyTests: XCTestCase { + + override func setUp() { + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } + + func testExample() { + XCTFail("Did you forget to add tests?") + } +} From 4c6b562674b845cf0d4665520738f392dd248292 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Wed, 17 Jan 2024 21:20:57 +0300 Subject: [PATCH 18/60] bugfixes --- .../StakingConfirmProxyPresenter.swift | 2 ++ .../StakingConfirmProxyProtocols.swift | 4 +++- .../StakingConfirmProxyViewController.swift | 3 +++ .../StakingConfirmProxyWireframe.swift | 10 +++++++++- 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyPresenter.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyPresenter.swift index 8d472817e2..8b27da5c9d 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyPresenter.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyPresenter.swift @@ -119,6 +119,8 @@ extension StakingConfirmProxyPresenter: StakingConfirmProxyPresenterProtocol { extension StakingConfirmProxyPresenter: StakingConfirmProxyInteractorOutputProtocol { func didSubmit() { view?.didStopLoading() + + wireframe.complete(from: view) } func didReceive(error: StakingConfirmProxyError) { diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyProtocols.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyProtocols.swift index e46adac5e1..eb408f12c2 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyProtocols.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyProtocols.swift @@ -22,7 +22,9 @@ protocol StakingConfirmProxyInteractorOutputProtocol: StakingProxyBaseInteractor func didReceive(error: StakingConfirmProxyError) } -protocol StakingConfirmProxyWireframeProtocol: StakingSetupProxyBaseWireframeProtocol, AddressOptionsPresentable {} +protocol StakingConfirmProxyWireframeProtocol: StakingSetupProxyBaseWireframeProtocol, AddressOptionsPresentable { + func complete(from view: ControllerBackedProtocol?) +} enum StakingConfirmProxyError: Error { case submit(Error) diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewController.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewController.swift index 091192f0be..d537412196 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewController.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewController.swift @@ -58,6 +58,9 @@ final class StakingConfirmProxyViewController: UIViewController, ViewHolder { rootView.proxyAddressCell.titleLabel.text = R.string.localizable.stakingConfirmProxyAccountProxy( preferredLanguages: languages ) + rootView.actionButton.actionButton.imageWithTitleView?.title = R.string.localizable.commonConfirm( + preferredLanguages: languages + ) title = R.string.localizable.delegationsAddTitle( preferredLanguages: languages ) diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyWireframe.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyWireframe.swift index 4f3e7735b0..88da161e08 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyWireframe.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyWireframe.swift @@ -1,3 +1,11 @@ import Foundation -final class StakingConfirmProxyWireframe: StakingConfirmProxyWireframeProtocol {} +final class StakingConfirmProxyWireframe: StakingConfirmProxyWireframeProtocol { + func complete(from view: StakingRebagConfirmViewProtocol?) { + let presenter = view?.controller.navigationController?.presentingViewController + + presenter?.dismiss(animated: true) { + self.presentSuccessNotification("", from: presenter, completion: nil) + } + } +} From 0f1b5cce2daf4ad1aceef0f6ce12514b0b2cbffc Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Wed, 17 Jan 2024 21:28:35 +0300 Subject: [PATCH 19/60] buildfix --- .../StakingConfirmProxy/StakingConfirmProxyPresenter.swift | 2 +- .../StakingConfirmProxy/StakingConfirmProxyWireframe.swift | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyPresenter.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyPresenter.swift index 8b27da5c9d..af23147093 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyPresenter.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyPresenter.swift @@ -119,7 +119,7 @@ extension StakingConfirmProxyPresenter: StakingConfirmProxyPresenterProtocol { extension StakingConfirmProxyPresenter: StakingConfirmProxyInteractorOutputProtocol { func didSubmit() { view?.didStopLoading() - + wireframe.complete(from: view) } diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyWireframe.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyWireframe.swift index 88da161e08..981cc1bec7 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyWireframe.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyWireframe.swift @@ -1,7 +1,7 @@ import Foundation -final class StakingConfirmProxyWireframe: StakingConfirmProxyWireframeProtocol { - func complete(from view: StakingRebagConfirmViewProtocol?) { +final class StakingConfirmProxyWireframe: StakingConfirmProxyWireframeProtocol, ModalAlertPresenting { + func complete(from view: ControllerBackedProtocol?) { let presenter = view?.controller.navigationController?.presentingViewController presenter?.dismiss(animated: true) { From d48dbb0e1c0ceaae1021709cf8065c2f058856d9 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Wed, 17 Jan 2024 21:46:49 +0300 Subject: [PATCH 20/60] remove tests --- novawallet.xcodeproj/project.pbxproj | 12 ------------ .../StakingConfirmProxyTests.swift | 16 ---------------- 2 files changed, 28 deletions(-) delete mode 100644 novawalletTests/Modules/StakingConfirmProxy/StakingConfirmProxyTests.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index afecf1e94d..f3840b6c48 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -546,7 +546,6 @@ 37FB290D01ADAA67155C9755 /* StakingSelectPoolPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 060D52F9BFFB646BF9FCC968 /* StakingSelectPoolPresenter.swift */; }; 37FF873F9B2358FA137658D8 /* StakingMoreOptionsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77F3F175AFC554763696CB2A /* StakingMoreOptionsPresenter.swift */; }; 384653967D27BD0F39F09255 /* GovernanceUnavailableTracksViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3526D1FB18C2615BE28E15C /* GovernanceUnavailableTracksViewLayout.swift */; }; - 387EA6361B625F9FF4E25F71 /* StakingConfirmProxyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84250F242666D7764E41DBC1 /* StakingConfirmProxyTests.swift */; }; 38D0977931828C7894579968 /* GovernanceUnlockSetupInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = CFA54AB88E24A2053F289D74 /* GovernanceUnlockSetupInteractor.swift */; }; 39218CF5AA701518BD3B0103 /* ExportMnemonicInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 200C6B2C85846AED8CA9451A /* ExportMnemonicInteractor.swift */; }; 39373DDCEE7CB9D04C310BC9 /* GovernanceRevokeDelegationConfirmProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C3F5511D2E7AC283FF021E8 /* GovernanceRevokeDelegationConfirmProtocols.swift */; }; @@ -5510,7 +5509,6 @@ 84243094265B1888003E07EC /* CrowdloanMetadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrowdloanMetadata.swift; sourceTree = ""; }; 8424A8C6262EC0E50091BFB1 /* PayoutInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PayoutInfo.swift; sourceTree = ""; }; 8424DB0A26B8466A008C834F /* ValidatorOperationFactoryProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValidatorOperationFactoryProtocol.swift; sourceTree = ""; }; - 84250F242666D7764E41DBC1 /* StakingConfirmProxyTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingConfirmProxyTests.swift; sourceTree = ""; }; 8425D0DF28FE738D003B782A /* ReferendumVoteSetupInteractorError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumVoteSetupInteractorError.swift; sourceTree = ""; }; 8425D0E228FE766B003B782A /* ReferendumVoteProtocols.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumVoteProtocols.swift; sourceTree = ""; }; 8425D0E528FE82CB003B782A /* ReferendumVoteInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumVoteInteractor.swift; sourceTree = ""; }; @@ -15394,7 +15392,6 @@ 84B7C705289BFA79001A3566 /* AccountManagement */, 84B7C708289BFA79001A3566 /* WalletList */, 84B7C70A289BFA79001A3566 /* ControllerAccount */, - ECEE9BB6AC9E9F1ECD5BAA7D /* StakingConfirmProxy */, ); path = Modules; sourceTree = ""; @@ -19334,14 +19331,6 @@ path = AssetReceive; sourceTree = ""; }; - ECEE9BB6AC9E9F1ECD5BAA7D /* StakingConfirmProxy */ = { - isa = PBXGroup; - children = ( - 84250F242666D7764E41DBC1 /* StakingConfirmProxyTests.swift */, - ); - path = StakingConfirmProxy; - sourceTree = ""; - }; F14E378DE1BCBB4C8D39AB4C /* ParaStkYieldBoostStop */ = { isa = PBXGroup; children = ( @@ -24389,7 +24378,6 @@ 84B7C748289BFA79001A3566 /* WalletListTests.swift in Sources */, 84B7C720289BFA79001A3566 /* ReferralCrowdloanTests.swift in Sources */, F4897BB126AED13D0075F291 /* EraCountdownOperationFactoryStub.swift in Sources */, - 387EA6361B625F9FF4E25F71 /* StakingConfirmProxyTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/novawalletTests/Modules/StakingConfirmProxy/StakingConfirmProxyTests.swift b/novawalletTests/Modules/StakingConfirmProxy/StakingConfirmProxyTests.swift deleted file mode 100644 index 365d773bd1..0000000000 --- a/novawalletTests/Modules/StakingConfirmProxy/StakingConfirmProxyTests.swift +++ /dev/null @@ -1,16 +0,0 @@ -import XCTest - -class StakingConfirmProxyTests: XCTestCase { - - override func setUp() { - // Put setup code here. This method is called before the invocation of each test method in the class. - } - - override func tearDown() { - // Put teardown code here. This method is called after the invocation of each test method in the class. - } - - func testExample() { - XCTFail("Did you forget to add tests?") - } -} From 00b531a5388f9fe27224c2365528cf24336f0ada Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Thu, 18 Jan 2024 22:25:18 +0300 Subject: [PATCH 21/60] init --- novawallet.xcodeproj/project.pbxproj | 48 +++++++ .../iconDelete.imageset/Contents.json | 12 ++ .../iconDelete.imageset/delete.pdf | Bin 0 -> 2494 bytes .../Protocols/AddressOptionsPresentable.swift | 89 +++++++++++- .../StakingRelaychainWireframe.swift | 9 +- .../StakingProxyManagementInteractor.swift | 93 ++++++++++++ .../StakingProxyManagementPresenter.swift | 135 ++++++++++++++++++ .../StakingProxyManagementProtocols.swift | 34 +++++ ...StakingProxyManagementViewController.swift | 118 +++++++++++++++ .../StakingProxyManagementViewFactory.swift | 53 +++++++ .../StakingProxyManagementViewLayout.swift | 49 +++++++ .../StakingProxyManagementWireframe.swift | 23 +++ novawallet/en.lproj/Localizable.strings | 2 + novawallet/ru.lproj/Localizable.strings | 2 + 14 files changed, 660 insertions(+), 7 deletions(-) create mode 100644 novawallet/Assets.xcassets/iconDelete.imageset/Contents.json create mode 100644 novawallet/Assets.xcassets/iconDelete.imageset/delete.pdf create mode 100644 novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementInteractor.swift create mode 100644 novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementPresenter.swift create mode 100644 novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementProtocols.swift create mode 100644 novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementViewController.swift create mode 100644 novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementViewFactory.swift create mode 100644 novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementViewLayout.swift create mode 100644 novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementWireframe.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index f3840b6c48..330da7280c 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -674,6 +674,7 @@ 59A0AF440ABAAA459EF7D993 /* GovernanceYourDelegationsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E4462DCD832DB73AA78D44C /* GovernanceYourDelegationsViewController.swift */; }; 59D03D8CB4AE60DE53130729 /* NPoolsRedeemViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 23EF6FA61F2B7E3B2ADD3200 /* NPoolsRedeemViewLayout.swift */; }; 5AC2A8AD94278DFA4B68A718 /* NominationPoolSearchInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44AA632DE49B746BC38B959F /* NominationPoolSearchInteractor.swift */; }; + 5AEA54E0691BD6DC6B570ACF /* StakingProxyManagementPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C6A61D7A529DB2412430DA1C /* StakingProxyManagementPresenter.swift */; }; 5B02D050E6E067906A05B46B /* SwapSetupWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7F910E56C2CC7AA5224BD21 /* SwapSetupWireframe.swift */; }; 5B54978244C37502DD592486 /* NftListPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A092ADC09DA0429548EBC08 /* NftListPresenter.swift */; }; 5B652F1E0040F68F835A2F1D /* AssetDetailsViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = DEE05ECCFE3DD11A2EAAF495 /* AssetDetailsViewLayout.swift */; }; @@ -705,6 +706,7 @@ 62B2298F132DB0CE0794DD7A /* MarkdownDescriptionWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57E6825E525785A1A12C62E7 /* MarkdownDescriptionWireframe.swift */; }; 62D28F231DED3F39B2C53F1F /* StakingSetupAmountProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = B73F89021BEE1F4576128305 /* StakingSetupAmountProtocols.swift */; }; 63185C6D67EAEB2867069AB9 /* ParitySignerWelcomeProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8CBB8745F8C36BB107625E8F /* ParitySignerWelcomeProtocols.swift */; }; + 6362476898582D2118E96447 /* StakingProxyManagementInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 211CEE2D931F177676D280DC /* StakingProxyManagementInteractor.swift */; }; 640A79BD1335394818E70366 /* WalletHistoryFilterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6884DFC1AA1B995C21C274C /* WalletHistoryFilterViewController.swift */; }; 641D7CF89F37B1890516015E /* ParitySignerTxScanProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F10F130391C4B3652FE8F59 /* ParitySignerTxScanProtocols.swift */; }; 642B0B0294604907D8070EC1 /* DAppSettingsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C52D6675524DB913210F0459 /* DAppSettingsPresenter.swift */; }; @@ -1021,6 +1023,7 @@ 78D63EC7EC5F7427335A025E /* NPoolsClaimRewardsViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6A7302440137F083F7AEC64E /* NPoolsClaimRewardsViewLayout.swift */; }; 78D94A761EFECED60F38232D /* CustomValidatorListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 270B309EC85D8897A4ADD98A /* CustomValidatorListViewController.swift */; }; 78E0B6963A8D0A07E742232C /* GovernanceEditDelegationTracksWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC3B84FA1F22CC12B16C79AE /* GovernanceEditDelegationTracksWireframe.swift */; }; + 78E67009E5A7D4564172FD0B /* StakingProxyManagementViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBADD72EE1AFA6E549D779FB /* StakingProxyManagementViewLayout.swift */; }; 790129F3CB6AEA611639E886 /* ParaStkUnstakeViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5467B9B6AEDB33F565D130A1 /* ParaStkUnstakeViewFactory.swift */; }; 7A47B0731BC8B411CC01C3D1 /* TransferNetworkSelectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D6106D11494F979A46F7B4C /* TransferNetworkSelectionViewController.swift */; }; 7BD09D3022967C4D90AB4693 /* DAppOperationConfirmViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 859E0EF774DF0D498FEF8FCB /* DAppOperationConfirmViewLayout.swift */; }; @@ -3623,6 +3626,7 @@ 9E15912C35D50C6D738FD04C /* AccountConfirmProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5002B8FA2695F470587677D2 /* AccountConfirmProtocols.swift */; }; 9E40464B7687006B1EE75C72 /* LocksProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4F9944B0577EFF25A0643FE /* LocksProtocols.swift */; }; 9E4E458C92D12B24D5EAD893 /* ControllerAccountInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 748E0AF1A286016CB220155C /* ControllerAccountInteractor.swift */; }; + 9E9F61EA4C716C3768469845 /* StakingProxyManagementViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7DDEB59CB3BDF9BDAAC4E3C5 /* StakingProxyManagementViewFactory.swift */; }; 9ECB28EA7E1D2C79869ED54F /* TokenManageSinglePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48182DE3A1302757558031FD /* TokenManageSinglePresenter.swift */; }; 9F3E2D64D77BF89B474BF1E3 /* DAppOperationConfirmViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43FBC2EA83A121CEBD25549D /* DAppOperationConfirmViewController.swift */; }; 9F4A48B1BE3A1110A0CF9F36 /* ReferralCrowdloanViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7DDDB2B35CD3299F50613141 /* ReferralCrowdloanViewController.swift */; }; @@ -3665,6 +3669,7 @@ ABA3D873BBECB7F4BD670872 /* ExportSeedPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EFB278373745C20822442686 /* ExportSeedPresenter.swift */; }; AC904E313DC15AE40C927946 /* DAppAddFavoriteInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96BE36DA0A2310660A43FF5B /* DAppAddFavoriteInteractor.swift */; }; ACE725ECAB92169CC13E788D /* NominationPoolBondMoreConfirmInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73D6B3F74819B5D45324F714 /* NominationPoolBondMoreConfirmInteractor.swift */; }; + ACF27885E3B3D01B6C3BBB4B /* StakingProxyManagementViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 466D36DE48F51DC3023E3C5E /* StakingProxyManagementViewController.swift */; }; AD1920A8DE1C9A4D6502473F /* GovernanceRemoveVotesConfirmViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6606F6FCB40D5EDA2CDFA84F /* GovernanceRemoveVotesConfirmViewController.swift */; }; AD36A601830C69DA003B3B01 /* StakingSelectPoolProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5A2FE372A88ECF23B620D2 /* StakingSelectPoolProtocols.swift */; }; AD3D8EA1D79D3E5E5B625CF7 /* StakingTypeWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D99FECD7EDCFE3A23E1AEAF /* StakingTypeWireframe.swift */; }; @@ -3864,6 +3869,7 @@ C39CB534B2EE7ABD6D6085BA /* TransactionHistoryViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = A937F85FE35340EDA131C2EC /* TransactionHistoryViewFactory.swift */; }; C49AC521056CBDB5451B1CDC /* NominationPoolBondMoreBaseInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84033496FC259BCA5420D52B /* NominationPoolBondMoreBaseInteractor.swift */; }; C4A4D40A08DAB4A71C21C1A8 /* StakingRedeemInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 560C48D7A83F51F001622D71 /* StakingRedeemInteractor.swift */; }; + C4D962BDC211A38CA3536425 /* StakingProxyManagementProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = DE5C4D40180946CA35A0E2F8 /* StakingProxyManagementProtocols.swift */; }; C5B07E59C0B00CAD1D0D2DFD /* ReferendumSearchWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72EF3BEC3EA07548C10A87FD /* ReferendumSearchWireframe.swift */; }; C5B6C00F8B0E3D89CBF1A8DB /* ParaStkSelectCollatorsViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2336E4CAF4A1F627C39093FF /* ParaStkSelectCollatorsViewFactory.swift */; }; C5B833588833888A8AC2B8EE /* TransactionHistoryInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8511A3B5C31B73CDC794F63 /* TransactionHistoryInteractor.swift */; }; @@ -3924,6 +3930,7 @@ D567BAAF620EDB9F4975C800 /* DAppAuthConfirmProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75CFAA1D2D04553B10421C69 /* DAppAuthConfirmProtocols.swift */; }; D591F555544FB6329BFA835C /* GovernanceDelegateInfoPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB1A69B90DCA16C219BF087 /* GovernanceDelegateInfoPresenter.swift */; }; D5BB3A36DB9ADD25EE43109F /* GovernanceUnlockConfirmViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 358E87C8E90981E6D9515745 /* GovernanceUnlockConfirmViewFactory.swift */; }; + D5F1C910930BA08E5F7681B2 /* StakingProxyManagementWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = A313F1654986753E341D7D39 /* StakingProxyManagementWireframe.swift */; }; D600448CB75095E6873E542F /* DAppTxDetailsProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D383344BEDAEDC76A6BE2CE /* DAppTxDetailsProtocols.swift */; }; D6511F7C3E55197F82AB552C /* RecommendedValidatorListViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE4AF0849E32E5B9C72E2ABB /* RecommendedValidatorListViewFactory.swift */; }; D6A2790F5C9E2AAA137E52CC /* InAppUpdatesPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DFDA05E0E68FE6D85E647C9 /* InAppUpdatesPresenter.swift */; }; @@ -3988,6 +3995,7 @@ E36D8899C003C0AFA5BE290F /* AssetsSettingsProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90681A889A40F7163CBE9B6B /* AssetsSettingsProtocols.swift */; }; E3765FB9E68018936E951FBD /* TokensManageViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9B778B6EC447C0B55110638 /* TokensManageViewLayout.swift */; }; E37BB7A393FFEFC350B4EA3D /* AdvancedWalletProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0043E77B2DBB3546A9E54C4B /* AdvancedWalletProtocols.swift */; }; + E3FD20535969DA8919BD8FB6 /* StakingProxyManagementTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09297ADB427400DABA56CE5E /* StakingProxyManagementTests.swift */; }; E4021A6E90432CC5C797A647 /* ReferendumVotersWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9FBF368FBB46AD4DE606DB1 /* ReferendumVotersWireframe.swift */; }; E477B09B47A3021EF1CE66F0 /* ParaStkRedeemViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2D3F02FD57B4C28BA09C5F8 /* ParaStkRedeemViewLayout.swift */; }; E488F3E052650FF525D41D63 /* LedgerTxConfirmInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 313B89948DC631DE61E01007 /* LedgerTxConfirmInteractor.swift */; }; @@ -4249,6 +4257,7 @@ 0816F2A4A5CC1F111E626188 /* SwapSlippagePresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SwapSlippagePresenter.swift; sourceTree = ""; }; 088C765E5A0F81B96ADE72D8 /* SwapSlippageWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SwapSlippageWireframe.swift; sourceTree = ""; }; 0912F5E8BA170342D52F7D38 /* TransferConfirmViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TransferConfirmViewController.swift; sourceTree = ""; }; + 09297ADB427400DABA56CE5E /* StakingProxyManagementTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingProxyManagementTests.swift; sourceTree = ""; }; 0988D8EC0768B03BA7C55612 /* ParaStkYieldBoostStartInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkYieldBoostStartInteractor.swift; sourceTree = ""; }; 09E4E9A052F9F04A92F158D6 /* GovernanceDelegateSetupWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = GovernanceDelegateSetupWireframe.swift; sourceTree = ""; }; 0A42FD5E0D98EFE83883EC56 /* AssetDetailsViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AssetDetailsViewFactory.swift; sourceTree = ""; }; @@ -4656,6 +4665,7 @@ 20878E303E9332322655F008 /* ParaStkSelectCollatorsProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkSelectCollatorsProtocols.swift; sourceTree = ""; }; 20BB15F2A86E47DE30AE8107 /* GovernanceRemoveVotesConfirmProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = GovernanceRemoveVotesConfirmProtocols.swift; sourceTree = ""; }; 20E4FF68D8A9AD54E4F089BC /* GovernanceDelegateInfoViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = GovernanceDelegateInfoViewLayout.swift; sourceTree = ""; }; + 211CEE2D931F177676D280DC /* StakingProxyManagementInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingProxyManagementInteractor.swift; sourceTree = ""; }; 215C03EE9C9EE024F952CB1C /* ReferendumsFiltersWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumsFiltersWireframe.swift; sourceTree = ""; }; 21621DCC39234CC4B0A1433B /* GovernanceYourDelegationsPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = GovernanceYourDelegationsPresenter.swift; sourceTree = ""; }; 219B9B1D97460F022D40D63E /* DAppTxDetailsWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppTxDetailsWireframe.swift; sourceTree = ""; }; @@ -4825,6 +4835,7 @@ 45C0B1C175A2470AAA50DAC5 /* DAppSettingsViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppSettingsViewController.swift; sourceTree = ""; }; 461A9E7672D247C9CCF0B45D /* GovernanceRevokeDelegationTracksWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = GovernanceRevokeDelegationTracksWireframe.swift; sourceTree = ""; }; 461B7FAD84690F82070E4431 /* StakingRebagConfirmPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingRebagConfirmPresenter.swift; sourceTree = ""; }; + 466D36DE48F51DC3023E3C5E /* StakingProxyManagementViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingProxyManagementViewController.swift; sourceTree = ""; }; 46BDF9947BE6366712E454DD /* LedgerDiscoverWalletCreateWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = LedgerDiscoverWalletCreateWireframe.swift; sourceTree = ""; }; 47042BBA5082B1EC1D017B56 /* AssetReceiveProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AssetReceiveProtocols.swift; sourceTree = ""; }; 470B64C45E547C25FCCCFC33 /* StakingMainProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingMainProtocols.swift; sourceTree = ""; }; @@ -5270,6 +5281,7 @@ 7CD1FBC9C063951E2520265D /* SwapConfirmWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SwapConfirmWireframe.swift; sourceTree = ""; }; 7D8A9948F319AD0D154D1EC4 /* DelegationListViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DelegationListViewFactory.swift; sourceTree = ""; }; 7DDDB2B35CD3299F50613141 /* ReferralCrowdloanViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferralCrowdloanViewController.swift; sourceTree = ""; }; + 7DDEB59CB3BDF9BDAAC4E3C5 /* StakingProxyManagementViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingProxyManagementViewFactory.swift; sourceTree = ""; }; 7DEDFCF115BB1015C928F3B2 /* ParitySignerWelcomeViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParitySignerWelcomeViewLayout.swift; sourceTree = ""; }; 7E2F6581450E9DB4C18C4984 /* ParaStkRedeemPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkRedeemPresenter.swift; sourceTree = ""; }; 7E62CD2831DCF0A2D5DBB08F /* SelectValidatorsStartViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SelectValidatorsStartViewController.swift; sourceTree = ""; }; @@ -7909,6 +7921,7 @@ A2E14458DEC3317602A17527 /* GovernanceUnlockSetupViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = GovernanceUnlockSetupViewLayout.swift; sourceTree = ""; }; A2FCBFC59ED9D7E6F046D2A1 /* GovernanceYourDelegationsProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = GovernanceYourDelegationsProtocols.swift; sourceTree = ""; }; A3104ABC4BECF08B0BA836AA /* AccountConfirmViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AccountConfirmViewController.swift; sourceTree = ""; }; + A313F1654986753E341D7D39 /* StakingProxyManagementWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingProxyManagementWireframe.swift; sourceTree = ""; }; A31780E84948D7FE632ECB02 /* YourValidatorListProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = YourValidatorListProtocols.swift; sourceTree = ""; }; A31B8F292DA050D1D19B9F5F /* NominationPoolSearchProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = NominationPoolSearchProtocols.swift; sourceTree = ""; }; A3BACB7E24BC87F9218DBBC4 /* StakingPayoutConfirmationViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingPayoutConfirmationViewController.swift; sourceTree = ""; }; @@ -8143,6 +8156,7 @@ C52D6675524DB913210F0459 /* DAppSettingsPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppSettingsPresenter.swift; sourceTree = ""; }; C585109AC3A2580AB1253C31 /* SwapSetupInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SwapSetupInteractor.swift; sourceTree = ""; }; C5E9D289393AA2CC1E34C2F4 /* AssetDetailsWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AssetDetailsWireframe.swift; sourceTree = ""; }; + C6A61D7A529DB2412430DA1C /* StakingProxyManagementPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingProxyManagementPresenter.swift; sourceTree = ""; }; C74A2166B054240BD5D925B6 /* UsernameSetupViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = UsernameSetupViewFactory.swift; sourceTree = ""; }; C7F910E56C2CC7AA5224BD21 /* SwapSetupWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SwapSetupWireframe.swift; sourceTree = ""; }; C80D934D47929D2331111AD7 /* ReferendumFullDetailsWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumFullDetailsWireframe.swift; sourceTree = ""; }; @@ -8226,6 +8240,7 @@ DB9AB4A7C57057ECFA1DA03E /* StartStakingConfirmViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StartStakingConfirmViewLayout.swift; sourceTree = ""; }; DBA49A762B2FBB66FD6A55FC /* ControllerAccountConfirmationProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ControllerAccountConfirmationProtocols.swift; sourceTree = ""; }; DBAD69608028E9FAE0F8E58D /* StakingDashboardViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingDashboardViewController.swift; sourceTree = ""; }; + DBADD72EE1AFA6E549D779FB /* StakingProxyManagementViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingProxyManagementViewLayout.swift; sourceTree = ""; }; DBD0DBD280596DBBC5CE5A8F /* ParaStkYieldBoostStopProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkYieldBoostStopProtocols.swift; sourceTree = ""; }; DBF9C192200F9B998724FC6C /* DAppSearchViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppSearchViewFactory.swift; sourceTree = ""; }; DBFC5052A062548D20D232DA /* AssetsSettingsWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AssetsSettingsWireframe.swift; sourceTree = ""; }; @@ -8236,6 +8251,7 @@ DD71DD9CFF2B4BECCDEAF8C0 /* StakingSetupAmountViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingSetupAmountViewFactory.swift; sourceTree = ""; }; DDB1A69B90DCA16C219BF087 /* GovernanceDelegateInfoPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = GovernanceDelegateInfoPresenter.swift; sourceTree = ""; }; DDF3C1CFECE4340E82837FC4 /* ReferendumOnChainVotersViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumOnChainVotersViewFactory.swift; sourceTree = ""; }; + DE5C4D40180946CA35A0E2F8 /* StakingProxyManagementProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingProxyManagementProtocols.swift; sourceTree = ""; }; DE767858B6CF5F6F7C7B418E /* ReferendumVoteConfirmProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ReferendumVoteConfirmProtocols.swift; sourceTree = ""; }; DEE05ECCFE3DD11A2EAAF495 /* AssetDetailsViewLayout.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AssetDetailsViewLayout.swift; sourceTree = ""; }; DF715CEF29477B59119520F1 /* ParitySignerAddressesInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParitySignerAddressesInteractor.swift; sourceTree = ""; }; @@ -15392,6 +15408,7 @@ 84B7C705289BFA79001A3566 /* AccountManagement */, 84B7C708289BFA79001A3566 /* WalletList */, 84B7C70A289BFA79001A3566 /* ControllerAccount */, + D5086D85D3AF98C11D77588D /* StakingProxyManagement */, ); path = Modules; sourceTree = ""; @@ -17186,6 +17203,7 @@ 17432B4B5D8D9DC5C22CA238 /* StakingType */, 92CDAD21CEED554306CAF5D8 /* StartStakingConfirm */, A4542BFD7BBCF6B05FB2D3E4 /* StakingSetupProxy */, + 8AE87694A810D25060A567E1 /* StakingProxyManagement */, ); path = Staking; sourceTree = ""; @@ -18057,6 +18075,20 @@ path = "CAIP-2"; sourceTree = ""; }; + 8AE87694A810D25060A567E1 /* StakingProxyManagement */ = { + isa = PBXGroup; + children = ( + DE5C4D40180946CA35A0E2F8 /* StakingProxyManagementProtocols.swift */, + A313F1654986753E341D7D39 /* StakingProxyManagementWireframe.swift */, + C6A61D7A529DB2412430DA1C /* StakingProxyManagementPresenter.swift */, + 211CEE2D931F177676D280DC /* StakingProxyManagementInteractor.swift */, + 466D36DE48F51DC3023E3C5E /* StakingProxyManagementViewController.swift */, + DBADD72EE1AFA6E549D779FB /* StakingProxyManagementViewLayout.swift */, + 7DDEB59CB3BDF9BDAAC4E3C5 /* StakingProxyManagementViewFactory.swift */, + ); + path = StakingProxyManagement; + sourceTree = ""; + }; 8C1DCF40C8BE3290D4BB9843 /* ParaStkStakeConfirm */ = { isa = PBXGroup; children = ( @@ -19112,6 +19144,14 @@ path = TransactionScan; sourceTree = ""; }; + D5086D85D3AF98C11D77588D /* StakingProxyManagement */ = { + isa = PBXGroup; + children = ( + 09297ADB427400DABA56CE5E /* StakingProxyManagementTests.swift */, + ); + path = StakingProxyManagement; + sourceTree = ""; + }; D9BFD42DC43BEF657BE541DC /* NftDetails */ = { isa = PBXGroup; children = ( @@ -24215,6 +24255,13 @@ C044A73D956CAFB926D4BEC1 /* StakingConfirmProxyViewController.swift in Sources */, DA33289649E281A2D6378C1C /* StakingConfirmProxyViewLayout.swift in Sources */, 2AFCF6923D31691A53BEC762 /* StakingConfirmProxyViewFactory.swift in Sources */, + C4D962BDC211A38CA3536425 /* StakingProxyManagementProtocols.swift in Sources */, + D5F1C910930BA08E5F7681B2 /* StakingProxyManagementWireframe.swift in Sources */, + 5AEA54E0691BD6DC6B570ACF /* StakingProxyManagementPresenter.swift in Sources */, + 6362476898582D2118E96447 /* StakingProxyManagementInteractor.swift in Sources */, + ACF27885E3B3D01B6C3BBB4B /* StakingProxyManagementViewController.swift in Sources */, + 78E67009E5A7D4564172FD0B /* StakingProxyManagementViewLayout.swift in Sources */, + 9E9F61EA4C716C3768469845 /* StakingProxyManagementViewFactory.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -24378,6 +24425,7 @@ 84B7C748289BFA79001A3566 /* WalletListTests.swift in Sources */, 84B7C720289BFA79001A3566 /* ReferralCrowdloanTests.swift in Sources */, F4897BB126AED13D0075F291 /* EraCountdownOperationFactoryStub.swift in Sources */, + E3FD20535969DA8919BD8FB6 /* StakingProxyManagementTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/novawallet/Assets.xcassets/iconDelete.imageset/Contents.json b/novawallet/Assets.xcassets/iconDelete.imageset/Contents.json new file mode 100644 index 0000000000..e6fe9f0fcb --- /dev/null +++ b/novawallet/Assets.xcassets/iconDelete.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "delete.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/novawallet/Assets.xcassets/iconDelete.imageset/delete.pdf b/novawallet/Assets.xcassets/iconDelete.imageset/delete.pdf new file mode 100644 index 0000000000000000000000000000000000000000..7083974fb319fab6e48c2e3a5af319ebf445501f GIT binary patch literal 2494 zcmZuzO>f*b5WVwP@M0h-5H5$`1cCsK?F2LL+a}8=G`k&Q3#S+_J8~-q8)_xIy&?56*y{MqlMRw-#b^39v+ zM|7tLHWTK;{-^HrIDV2A;1(OjFrK^Jli1vJ{~Y$+_WfIVeZT&1KZw7@=9c8+AV@I- zIP|=D)mH7Do8Q@av42`D+qSkC_9p?GWP(YOqRKf3ALWyd7oFO*xLjjCXKjgnE-0&-2&F@i3tHp{E7vAuj{v4B zd1Jwdh$#Dj9Jq1?gHNLzw3}=y3ZDxam2*yK!%S;5dLjaoQO0Vou}Z5vGDT~_-mv}u zwd_%R5=h#54Hv7h(EbY=FsBKnK>!Y2kV60$gE2WS(gL=IM5v2>OP1Nt43tc)eMFEJ zbHim$2)NdYa`6jPQ;ZSHDU0SpD;;5HnI?3>rZrWNIskWYe0!Q&JFnN}E8J|+@cK4@3^u0l9C zFgy{{-Ap3}%90Q0wWM;yDUf7PI5r4}0JzJ>3?aCc@USA4!x@0+16Fi_kgS1TGY6YG zq#7g2y%!myY`L;d5jZg28Dz%#3&dDd+|PD=j-aV11T->A8*H@Pn?Xf%21cj)XRQ#r z)j${j0YsWC@2ZSmC5!&%JtZ#o&u$ZsaSeYWDoD$**;OeF>>>ofDCt=cpr);6Pup(jKcDyA zAo;6cTispvr?ESMk+1q0yxX0DNn8{K!c{-#z|itR@#EnEp-RqRD`%eT{xfXpoA?JH zD^KCV6DK${!X@$R-MBmUkC&#;=kB9GABpJ}OUMxV;427NgU0jjaO}>4tM|hV + let icon: UIImage? + let indicator: ChainAddressDetailsIndicator + let onSelection: () -> Void +} + protocol AddressOptionsPresentable { func presentAccountOptions( from view: ControllerBackedProtocol, @@ -9,6 +16,14 @@ protocol AddressOptionsPresentable { chain: ChainModel, locale: Locale ) + + func presentExtendedAccountOptions( + from view: ControllerBackedProtocol, + address: String, + chain: ChainModel, + option: AccountAdditionalOption, + locale: Locale + ) } extension AddressOptionsPresentable { @@ -64,6 +79,32 @@ extension AddressOptionsPresentable { view.controller.present(controller, animated: true, completion: nil) } + + func presentExtendedAccountOptions( + from view: ControllerBackedProtocol, + address: String, + chain: ChainModel, + option: AccountAdditionalOption, + locale: Locale + ) { + let copyClosure = { copyAddress(from: view, address: address, locale: locale) } + + let urlClosure = { (url: URL) in + present(from: view, url: url) + } + + guard let controller = AddressOptionsPresentableFactory.createAccountOptionsController( + address: address, + chain: chain, + copyClosure: copyClosure, + urlClosure: urlClosure, + option: option + ) else { + return + } + + view.controller.present(controller, animated: true, completion: nil) + } } enum AddressOptionsPresentableFactory { @@ -73,6 +114,48 @@ enum AddressOptionsPresentableFactory { copyClosure: @escaping () -> Void, urlClosure: @escaping (URL) -> Void ) -> UIViewController? { + let builder = createAccountOptionsBuilder( + address: address, + chain: chain, + copyClosure: copyClosure, + urlClosure: urlClosure + ) + let model = builder.build() + return ChainAddressDetailsPresentableFactory.createChainAddressDetails( + for: model + )?.controller + } + + static func createAccountOptionsController( + address: String, + chain: ChainModel, + copyClosure: @escaping () -> Void, + urlClosure: @escaping (URL) -> Void, + option: AccountAdditionalOption + ) -> UIViewController? { + let builder = createAccountOptionsBuilder( + address: address, + chain: chain, + copyClosure: copyClosure, + urlClosure: urlClosure + ).addAction( + for: option.title, + icon: option.icon, + indicator: option.indicator, + onSelection: option.onSelection + ) + let model = builder.build() + return ChainAddressDetailsPresentableFactory.createChainAddressDetails( + for: model + )?.controller + } + + static func createAccountOptionsBuilder( + address: String, + chain: ChainModel, + copyClosure: @escaping () -> Void, + urlClosure: @escaping (URL) -> Void + ) -> ChainAddressDetailsModelBuilder { let copyTitle = LocalizableResource { locale in R.string.localizable.commonCopyAddress(preferredLanguages: locale.rLanguages) } @@ -111,10 +194,6 @@ enum AddressOptionsPresentableFactory { ) } - let model = builder.build() - - return ChainAddressDetailsPresentableFactory.createChainAddressDetails( - for: model - )?.controller + return builder } } diff --git a/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainWireframe.swift b/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainWireframe.swift index 0d12c3252a..9d11f98fec 100644 --- a/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainWireframe.swift +++ b/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainWireframe.swift @@ -160,7 +160,12 @@ extension StakingRelaychainWireframe: StakingRelaychainWireframeProtocol { view?.controller.present(navigationController, animated: true, completion: nil) } - func showEditProxies(from _: ControllerBackedProtocol?) { - // TODO: Proxy List + func showEditProxies(from view: ControllerBackedProtocol?) { + guard let managmentView = StakingProxyManagementViewFactory.createView(state: state) else { + return + } + + let navigationController = NovaNavigationController(rootViewController: managmentView.controller) + view?.controller.present(navigationController, animated: true, completion: nil) } } diff --git a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementInteractor.swift b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementInteractor.swift new file mode 100644 index 0000000000..30252ef48d --- /dev/null +++ b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementInteractor.swift @@ -0,0 +1,93 @@ +import UIKit +import SubstrateSdk +import RobinHood + +final class StakingProxyManagementInteractor: AnyProviderAutoCleaning { + weak var presenter: StakingProxyManagementInteractorOutputProtocol? + + let sharedState: RelaychainStakingSharedStateProtocol + let identityOperationFactory: IdentityOperationFactoryProtocol + let connection: JSONRPCEngine + let runtimeProvider: RuntimeCodingServiceProtocol + let selectedAccount: MetaChainAccountResponse + private var chainAsset: ChainAsset { sharedState.stakingOption.chainAsset } + private let operationQueue: OperationQueue + + var proxyListLocalSubscriptionFactory: ProxyListLocalSubscriptionFactoryProtocol { + sharedState.proxyLocalSubscriptionFactory + } + + private var proxyProvider: AnyDataProvider? + + init( + selectedAccount: MetaChainAccountResponse, + sharedState: RelaychainStakingSharedStateProtocol, + identityOperationFactory: IdentityOperationFactoryProtocol, + connection: JSONRPCEngine, + runtimeProvider: RuntimeCodingServiceProtocol, + operationQueue: OperationQueue + ) { + self.selectedAccount = selectedAccount + self.sharedState = sharedState + self.identityOperationFactory = identityOperationFactory + self.connection = connection + self.runtimeProvider = runtimeProvider + self.operationQueue = operationQueue + } + + private func performProxySubscription() { + clear(dataProvider: &proxyProvider) + + proxyProvider = subscribeProxies( + for: selectedAccount.chainAccount.accountId, + chainId: chainAsset.chain.chainId, + modifyInternalList: ProxyFilter.filteredStakingProxy + ) + } + + private func fetchIdentities(proxyDefifnition: ProxyDefinition?) { + guard let proxyDefifnition = proxyDefifnition, !proxyDefifnition.definition.isEmpty else { + return + } + + let identityWrapper = identityOperationFactory.createIdentityWrapperByAccountId( + for: { + proxyDefifnition.definition.map(\.proxy) + }, + engine: connection, + runtimeService: runtimeProvider, + chainFormat: chainAsset.chain.chainFormat + ) + + execute( + wrapper: identityWrapper, + inOperationQueue: operationQueue, + runningCallbackIn: .main + ) { [weak self] in + switch $0 { + case let .success(identities): + self?.presenter?.didReceive(identities: identities) + case let .failure(error): + self?.presenter?.didReceive(error: .identities(error)) + } + } + } +} + +extension StakingProxyManagementInteractor: StakingProxyManagementInteractorInputProtocol { + func setup() { + performProxySubscription() + } +} + +extension StakingProxyManagementInteractor: ProxyListLocalSubscriptionHandler, ProxyListLocalStorageSubscriber { + func handleProxies(result: Result, accountId _: AccountId, chainId _: ChainModel.Id) { + switch result { + case let .success(proxy): + presenter?.didReceive(proxyDefinition: proxy) + fetchIdentities(proxyDefifnition: proxy) + case let .failure(error): + presenter?.didReceive(error: .proxyDefifnition(error)) + } + } +} diff --git a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementPresenter.swift b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementPresenter.swift new file mode 100644 index 0000000000..db3ed4018e --- /dev/null +++ b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementPresenter.swift @@ -0,0 +1,135 @@ +import Foundation +import SubstrateSdk +import SoraFoundation + +final class StakingProxyManagementPresenter { + weak var view: StakingProxyManagementViewProtocol? + let wireframe: StakingProxyManagementWireframeProtocol + let interactor: StakingProxyManagementInteractorInputProtocol + let chainAsset: ChainAsset + + private lazy var novaIconGenerator = NovaIconGenerator() + private lazy var polkadotIconGenerator = PolkadotIconGenerator() + private var identities: [AccountId: AccountIdentity] = [:] + private var proxyDefinition: ProxyDefinition? + private let localizationManager: LocalizationManagerProtocol + + init( + chainAsset: ChainAsset, + interactor: StakingProxyManagementInteractorInputProtocol, + wireframe: StakingProxyManagementWireframeProtocol, + localizationManager: LocalizationManagerProtocol + ) { + self.chainAsset = chainAsset + self.interactor = interactor + self.wireframe = wireframe + self.localizationManager = localizationManager + } + + private func imageViewModel(from icon: DrawableIcon?, accountId: AccountId) -> IdentifiableDrawableIconViewModel? { + guard let icon = icon else { + return nil + } + let imageViewModel = DrawableIconViewModel(icon: icon) + return .init(imageViewModel, identifier: accountId.toHexString()) + } + + private func provideViewModel() { + guard let proxyDefinition = proxyDefinition else { + return + } + + let viewModels = proxyDefinition.definition.map { definition in + let walletInfo: WalletView.ViewModel.WalletInfo + + if let name = identities[definition.proxy]?.displayName { + let icon = try? self.novaIconGenerator.generateFromAccountId(definition.proxy) + let imageViewModel = self.imageViewModel(from: icon, accountId: definition.proxy) + walletInfo = .init( + icon: imageViewModel, + name: name + ) + } else { + let icon = try? self.polkadotIconGenerator.generateFromAccountId(definition.proxy) + let imageViewModel = self.imageViewModel(from: icon, accountId: definition.proxy) + let address = try? definition.proxy.toAddress(using: chainAsset.chain.chainFormat) ?? "" + walletInfo = .init( + icon: imageViewModel, + name: address ?? "" + ) + } + + let proxyInfo = WalletView.ViewModel.ProxyInfo( + networkIcon: RemoteImageViewModel(url: self.chainAsset.chain.icon), + proxyType: "", + proxyIcon: nil, + proxyName: nil, + isNew: false + ) + + let info = WalletView.ViewModel(wallet: walletInfo, type: .proxy(proxyInfo)) + + return StakingProxyManagementViewModel( + info: info, + accountId: definition.proxy + ) + } + + view?.didReceive(viewModels: viewModels) + } + + private func showAddressOptions(address: AccountAddress) { + guard let view = view else { + return + } + let revokeAccess = AccountAdditionalOption( + title: .init { + R.string.localizable.stakingProxyManagementRevokeAccess( + preferredLanguages: $0.rLanguages + ) + }, + icon: R.image.iconDelete(), + indicator: .navigation + ) { [weak self] in + self?.wireframe.showRevokeProxyAccess(from: self?.view) + } + + wireframe.presentExtendedAccountOptions( + from: view, + address: address, + chain: chainAsset.chain, + option: revokeAccess, + locale: localizationManager.selectedLocale + ) + } +} + +extension StakingProxyManagementPresenter: StakingProxyManagementPresenterProtocol { + func setup() { + interactor.setup() + } + + func addProxy() { + wireframe.showAddProxy(from: view) + } + + func showOptions(accountId: AccountId) { + if let address = try? accountId.toAddress(using: chainAsset.chain.chainFormat) { + showAddressOptions(address: address) + } + } +} + +extension StakingProxyManagementPresenter: StakingProxyManagementInteractorOutputProtocol { + func didReceive(identities: [AccountId: AccountIdentity]) { + self.identities = identities + provideViewModel() + } + + func didReceive(proxyDefinition: ProxyDefinition?) { + self.proxyDefinition = proxyDefinition + provideViewModel() + } + + func didReceive(error _: StakingProxyManagementError) {} +} diff --git a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementProtocols.swift b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementProtocols.swift new file mode 100644 index 0000000000..aaf090ae55 --- /dev/null +++ b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementProtocols.swift @@ -0,0 +1,34 @@ +protocol StakingProxyManagementViewProtocol: ControllerBackedProtocol { + func didReceive(viewModels: [StakingProxyManagementViewModel]) +} + +protocol StakingProxyManagementPresenterProtocol: AnyObject { + func setup() + func addProxy() + func showOptions(accountId: AccountId) +} + +protocol StakingProxyManagementInteractorInputProtocol: AnyObject { + func setup() +} + +protocol StakingProxyManagementInteractorOutputProtocol: AnyObject { + func didReceive(identities: [AccountId: AccountIdentity]) + func didReceive(proxyDefinition: ProxyDefinition?) + func didReceive(error: StakingProxyManagementError) +} + +protocol StakingProxyManagementWireframeProtocol: AnyObject, AddressOptionsPresentable { + func showAddProxy(from view: ControllerBackedProtocol?) + func showRevokeProxyAccess(from view: ControllerBackedProtocol?) +} + +enum StakingProxyManagementError: Error { + case identities(Error) + case proxyDefifnition(Error) +} + +struct StakingProxyManagementViewModel: Hashable { + let info: WalletView.ViewModel + let accountId: AccountId +} diff --git a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementViewController.swift b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementViewController.swift new file mode 100644 index 0000000000..1bb19c5b24 --- /dev/null +++ b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementViewController.swift @@ -0,0 +1,118 @@ +import UIKit +import SoraFoundation + +final class StakingProxyManagementViewController: UIViewController, ViewHolder { + typealias RootViewType = StakingProxyManagementViewLayout + typealias DataSource = UITableViewDiffableDataSource + typealias Snapshot = NSDiffableDataSourceSnapshot + + let presenter: StakingProxyManagementPresenterProtocol + private lazy var dataSource = makeDataSource() + + init( + presenter: StakingProxyManagementPresenterProtocol, + localizationManager: LocalizationManagerProtocol + ) { + self.presenter = presenter + super.init(nibName: nil, bundle: nil) + self.localizationManager = localizationManager + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func loadView() { + view = StakingProxyManagementViewLayout() + } + + override func viewDidLoad() { + super.viewDidLoad() + + setupTableView() + setupLocalization() + setupHandlers() + presenter.setup() + } + + private func setupTableView() { + rootView.tableView.rowHeight = 48 + rootView.tableView.registerClassForCell(WalletsListTableViewCell.self) + rootView.tableView.registerHeaderFooterView(withClass: SectionTextHeaderView.self) + rootView.tableView.delegate = self + } + + private func setupLocalization() { + title = R.string.localizable.stakingProxyManagementTitle( + preferredLanguages: selectedLocale.rLanguages + ) + + rootView.addButton.imageWithTitleView?.title = R.string.localizable.delegationsAddTitle( + preferredLanguages: selectedLocale.rLanguages + ) + } + + private func makeDataSource() -> DataSource { + .init(tableView: rootView.tableView) { [weak self] tableView, _, viewModel in + let cell = tableView.dequeueReusableCellWithType(WalletsListTableViewCell.self) + cell?.contentDisplayView.valueView.image = R.image.iconMore()?.withTintColor(R.color.colorIconSecondary()!) + cell?.infoView.bind(viewModel: viewModel.info) + return cell + } + } + + private func setupHandlers() { + rootView.addButton.addTarget( + self, + action: #selector(actionAddProxy), + for: .touchUpInside + ) + } + + @objc private func actionAddProxy() { + presenter.addProxy() + } +} + +extension StakingProxyManagementViewController: StakingProxyManagementViewProtocol { + func didReceive(viewModels: [StakingProxyManagementViewModel]) { + var snapshot = Snapshot() + snapshot.appendSections([.main]) + snapshot.appendItems(viewModels) + + dataSource.apply(snapshot, animatingDifferences: false) + } +} + +extension StakingProxyManagementViewController: UITableViewDelegate { + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + tableView.deselectRow(at: indexPath, animated: true) + + if let model = dataSource.itemIdentifier(for: indexPath) { + presenter.showOptions(accountId: model.accountId) + } + } + + func tableView(_: UITableView, heightForHeaderInSection _: Int) -> CGFloat { + 41 + } + + func tableView(_ tableView: UITableView, viewForHeaderInSection _: Int) -> UIView? { + let header: SectionTextHeaderView = tableView.dequeueReusableHeaderFooterView() + let text = R.string.localizable.stakingProxyManagementTitle( + preferredLanguages: selectedLocale.rLanguages + ) + header.bind(text: text) + return header + } +} + +extension StakingProxyManagementViewController: Localizable { + func applyLocalization() { + if isViewLoaded { + setupLocalization() + rootView.tableView.reloadData() + } + } +} diff --git a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementViewFactory.swift b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementViewFactory.swift new file mode 100644 index 0000000000..d55ddc8ae6 --- /dev/null +++ b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementViewFactory.swift @@ -0,0 +1,53 @@ +import Foundation +import SoraFoundation +import SubstrateSdk + +struct StakingProxyManagementViewFactory { + static func createView(state: RelaychainStakingSharedStateProtocol) -> StakingProxyManagementViewProtocol? { + let chainRegistry = ChainRegistryFacade.sharedRegistry + let chainAsset = state.stakingOption.chainAsset + + guard + let selectedAccount = SelectedWalletSettings.shared.value?.fetchMetaChainAccount( + for: chainAsset.chain.accountRequest() + ), + let connection = chainRegistry.getConnection(for: chainAsset.chain.chainId), + let runtimeRegistry = chainRegistry.getRuntimeProvider(for: chainAsset.chain.chainId) else { + return nil + } + + let requestFactory = StorageRequestFactory( + remoteFactory: StorageKeyFactory(), + operationManager: OperationManagerFacade.sharedManager + ) + let identityOperationFactory = IdentityOperationFactory(requestFactory: requestFactory) + + let interactor = StakingProxyManagementInteractor( + selectedAccount: selectedAccount, + sharedState: state, + identityOperationFactory: identityOperationFactory, + connection: connection, + runtimeProvider: runtimeRegistry, + operationQueue: OperationManagerFacade.sharedDefaultQueue + ) + + let wireframe = StakingProxyManagementWireframe(state: state) + + let presenter = StakingProxyManagementPresenter( + chainAsset: chainAsset, + interactor: interactor, + wireframe: wireframe, + localizationManager: LocalizationManager.shared + ) + + let view = StakingProxyManagementViewController( + presenter: presenter, + localizationManager: LocalizationManager.shared + ) + + presenter.view = view + interactor.presenter = presenter + + return view + } +} diff --git a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementViewLayout.swift b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementViewLayout.swift new file mode 100644 index 0000000000..cc5e9e2a14 --- /dev/null +++ b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementViewLayout.swift @@ -0,0 +1,49 @@ +import UIKit + +final class StakingProxyManagementViewLayout: UIView { + lazy var tableView: UITableView = { + let view = UITableView(frame: .zero, style: .grouped) + view.separatorStyle = .none + view.backgroundColor = .clear + view.contentInset = .zero + view.rowHeight = UITableView.automaticDimension + view.showsVerticalScrollIndicator = false + view.contentInsetAdjustmentBehavior = .never + view.tableHeaderView = .init(frame: .init(x: 0, y: 0, width: 0, height: CGFloat.leastNonzeroMagnitude)) + view.sectionFooterHeight = 0 + return view + }() + + let addButton: TriangularedButton = .create { + $0.applyDefaultStyle() + } + + override init(frame: CGRect) { + super.init(frame: frame) + + backgroundColor = R.color.colorSecondaryScreenBackground() + + setupLayout() + } + + @available(*, unavailable) + required init?(coder _: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setupLayout() { + addSubview(tableView) + tableView.snp.makeConstraints { + $0.top.equalTo(safeAreaLayoutGuide).offset(8) + $0.leading.trailing.equalToSuperview() + } + + addSubview(addButton) + addButton.snp.makeConstraints { + $0.top.equalTo(tableView.snp.bottom) + $0.height.equalTo(UIConstants.actionHeight) + $0.leading.trailing.equalToSuperview().inset(UIConstants.horizontalInset) + $0.bottom.equalTo(safeAreaLayoutGuide).inset(UIConstants.actionBottomInset) + } + } +} diff --git a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementWireframe.swift b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementWireframe.swift new file mode 100644 index 0000000000..4dd82ee780 --- /dev/null +++ b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementWireframe.swift @@ -0,0 +1,23 @@ +import Foundation + +final class StakingProxyManagementWireframe: StakingProxyManagementWireframeProtocol { + let state: RelaychainStakingSharedStateProtocol + + init(state: RelaychainStakingSharedStateProtocol) { + self.state = state + } + + func showAddProxy(from view: ControllerBackedProtocol?) { + guard let setupProxyView = StakingSetupProxyViewFactory.createView(state: state) else { + return + } + view?.controller.navigationController?.pushViewController( + setupProxyView.controller, + animated: true + ) + } + + func showRevokeProxyAccess(from _: ControllerBackedProtocol?) { + // TODO: + } +} diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index 3c476e5694..aa1845c115 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -1391,6 +1391,8 @@ "staking.confirm.proxy.type.title" = "Grant access type"; "staking.confirm.proxy.type.subtitle" = "Staking operations"; "staking.confirm.proxy.account.proxy" = "Delegate to"; +"staking.proxy.management.title" = "Delegated authorities (proxy)"; +"staking.proxy.management.revoke.access" = "Revoke access"; "common.time.in" = "in"; "common.and" = " and "; "common.time.period.after" = "after"; diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index 91f3e26344..01e95dbf34 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1392,6 +1392,8 @@ "staking.confirm.proxy.type.title" = "Выданный тип доступа"; "staking.confirm.proxy.type.subtitle" = "Операции стекинга"; "staking.confirm.proxy.account.proxy" = "Делегировать"; +"staking.proxy.management.title" = "Делегированные полномочия (прокси)"; +"staking.proxy.management.revoke.access" = "Отозвать доступ"; "common.and" = " и "; "common.time.period.after" = "через"; "common.time.period.every" = "раз в"; From 220a8303767b7b40d437944d42ba581a7171629f Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Thu, 18 Jan 2024 22:25:32 +0300 Subject: [PATCH 22/60] remove tests --- novawallet.xcodeproj/project.pbxproj | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 330da7280c..87d5c892c6 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -3995,7 +3995,6 @@ E36D8899C003C0AFA5BE290F /* AssetsSettingsProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 90681A889A40F7163CBE9B6B /* AssetsSettingsProtocols.swift */; }; E3765FB9E68018936E951FBD /* TokensManageViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9B778B6EC447C0B55110638 /* TokensManageViewLayout.swift */; }; E37BB7A393FFEFC350B4EA3D /* AdvancedWalletProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0043E77B2DBB3546A9E54C4B /* AdvancedWalletProtocols.swift */; }; - E3FD20535969DA8919BD8FB6 /* StakingProxyManagementTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09297ADB427400DABA56CE5E /* StakingProxyManagementTests.swift */; }; E4021A6E90432CC5C797A647 /* ReferendumVotersWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9FBF368FBB46AD4DE606DB1 /* ReferendumVotersWireframe.swift */; }; E477B09B47A3021EF1CE66F0 /* ParaStkRedeemViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = B2D3F02FD57B4C28BA09C5F8 /* ParaStkRedeemViewLayout.swift */; }; E488F3E052650FF525D41D63 /* LedgerTxConfirmInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 313B89948DC631DE61E01007 /* LedgerTxConfirmInteractor.swift */; }; @@ -4257,7 +4256,6 @@ 0816F2A4A5CC1F111E626188 /* SwapSlippagePresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SwapSlippagePresenter.swift; sourceTree = ""; }; 088C765E5A0F81B96ADE72D8 /* SwapSlippageWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SwapSlippageWireframe.swift; sourceTree = ""; }; 0912F5E8BA170342D52F7D38 /* TransferConfirmViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TransferConfirmViewController.swift; sourceTree = ""; }; - 09297ADB427400DABA56CE5E /* StakingProxyManagementTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = StakingProxyManagementTests.swift; sourceTree = ""; }; 0988D8EC0768B03BA7C55612 /* ParaStkYieldBoostStartInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkYieldBoostStartInteractor.swift; sourceTree = ""; }; 09E4E9A052F9F04A92F158D6 /* GovernanceDelegateSetupWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = GovernanceDelegateSetupWireframe.swift; sourceTree = ""; }; 0A42FD5E0D98EFE83883EC56 /* AssetDetailsViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AssetDetailsViewFactory.swift; sourceTree = ""; }; @@ -15408,7 +15406,6 @@ 84B7C705289BFA79001A3566 /* AccountManagement */, 84B7C708289BFA79001A3566 /* WalletList */, 84B7C70A289BFA79001A3566 /* ControllerAccount */, - D5086D85D3AF98C11D77588D /* StakingProxyManagement */, ); path = Modules; sourceTree = ""; @@ -19144,14 +19141,6 @@ path = TransactionScan; sourceTree = ""; }; - D5086D85D3AF98C11D77588D /* StakingProxyManagement */ = { - isa = PBXGroup; - children = ( - 09297ADB427400DABA56CE5E /* StakingProxyManagementTests.swift */, - ); - path = StakingProxyManagement; - sourceTree = ""; - }; D9BFD42DC43BEF657BE541DC /* NftDetails */ = { isa = PBXGroup; children = ( @@ -24425,7 +24414,6 @@ 84B7C748289BFA79001A3566 /* WalletListTests.swift in Sources */, 84B7C720289BFA79001A3566 /* ReferralCrowdloanTests.swift in Sources */, F4897BB126AED13D0075F291 /* EraCountdownOperationFactoryStub.swift in Sources */, - E3FD20535969DA8919BD8FB6 /* StakingProxyManagementTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; From 1b091bc1278265218bb56ff3e9ee006b735b0b56 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Thu, 18 Jan 2024 22:41:16 +0300 Subject: [PATCH 23/60] add error handling --- .../StakingProxyManagementPresenter.swift | 19 +++++++++++++++++-- .../StakingProxyManagementProtocols.swift | 3 ++- .../StakingProxyManagementViewFactory.swift | 3 ++- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementPresenter.swift b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementPresenter.swift index db3ed4018e..3b17f8a7ec 100644 --- a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementPresenter.swift +++ b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementPresenter.swift @@ -7,6 +7,7 @@ final class StakingProxyManagementPresenter { let wireframe: StakingProxyManagementWireframeProtocol let interactor: StakingProxyManagementInteractorInputProtocol let chainAsset: ChainAsset + let logger: LoggerProtocol private lazy var novaIconGenerator = NovaIconGenerator() private lazy var polkadotIconGenerator = PolkadotIconGenerator() @@ -18,12 +19,14 @@ final class StakingProxyManagementPresenter { chainAsset: ChainAsset, interactor: StakingProxyManagementInteractorInputProtocol, wireframe: StakingProxyManagementWireframeProtocol, - localizationManager: LocalizationManagerProtocol + localizationManager: LocalizationManagerProtocol, + logger: LoggerProtocol ) { self.chainAsset = chainAsset self.interactor = interactor self.wireframe = wireframe self.localizationManager = localizationManager + self.logger = logger } private func imageViewModel(from icon: DrawableIcon?, accountId: AccountId) -> IdentifiableDrawableIconViewModel? { @@ -131,5 +134,17 @@ extension StakingProxyManagementPresenter: StakingProxyManagementInteractorOutpu provideViewModel() } - func didReceive(error _: StakingProxyManagementError) {} + func didReceive(error: StakingProxyManagementError) { + switch error { + case let .identities(error): + logger.error("Error occured while fetching identities: \(error.localizedDescription)") + case let .proxyDefifnition(error): + wireframe.presentRequestStatus( + on: view, + locale: localizationManager.selectedLocale + ) { [weak self] in + self?.interactor.setup() + } + } + } } diff --git a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementProtocols.swift b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementProtocols.swift index aaf090ae55..1b192dbb7d 100644 --- a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementProtocols.swift +++ b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementProtocols.swift @@ -18,7 +18,8 @@ protocol StakingProxyManagementInteractorOutputProtocol: AnyObject { func didReceive(error: StakingProxyManagementError) } -protocol StakingProxyManagementWireframeProtocol: AnyObject, AddressOptionsPresentable { +protocol StakingProxyManagementWireframeProtocol: AnyObject, AddressOptionsPresentable, + AlertPresentable, CommonRetryable, ErrorPresentable { func showAddProxy(from view: ControllerBackedProtocol?) func showRevokeProxyAccess(from view: ControllerBackedProtocol?) } diff --git a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementViewFactory.swift b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementViewFactory.swift index d55ddc8ae6..b73482fc97 100644 --- a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementViewFactory.swift +++ b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementViewFactory.swift @@ -37,7 +37,8 @@ struct StakingProxyManagementViewFactory { chainAsset: chainAsset, interactor: interactor, wireframe: wireframe, - localizationManager: LocalizationManager.shared + localizationManager: LocalizationManager.shared, + logger: Logger.shared ) let view = StakingProxyManagementViewController( From 65e2b1f9adc41566494620dba81d9bf8a1dc8073 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Fri, 19 Jan 2024 09:55:32 +0300 Subject: [PATCH 24/60] fix warning --- .../StakingProxyManagementPresenter.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementPresenter.swift b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementPresenter.swift index 3b17f8a7ec..f54388b298 100644 --- a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementPresenter.swift +++ b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementPresenter.swift @@ -138,7 +138,7 @@ extension StakingProxyManagementPresenter: StakingProxyManagementInteractorOutpu switch error { case let .identities(error): logger.error("Error occured while fetching identities: \(error.localizedDescription)") - case let .proxyDefifnition(error): + case let .proxyDefifnition: wireframe.presentRequestStatus( on: view, locale: localizationManager.selectedLocale From 7206dade3a4c389e5939fc35bc6ffa0c9dd1451b Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Fri, 19 Jan 2024 13:08:26 +0300 Subject: [PATCH 25/60] PR fixes --- .../Base/ProxyDepositCalculator.swift | 5 +- .../Base/StakingProxyBaseInteractor.swift | 129 ++++-------------- .../Base/StakingProxyBasePresenter.swift | 6 +- .../Base/StakingProxyBaseProtocols.swift | 1 - .../StakingSetupProxyInteractor.swift | 6 +- .../StakingSetupProxyViewFactory.swift | 7 +- 6 files changed, 35 insertions(+), 119 deletions(-) diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Base/ProxyDepositCalculator.swift b/novawallet/Modules/Staking/StakingSetupProxy/Base/ProxyDepositCalculator.swift index 709109fa9f..0ef9ec30ad 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/Base/ProxyDepositCalculator.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/Base/ProxyDepositCalculator.swift @@ -29,6 +29,9 @@ struct ProxyDeposit { let new: BigUInt var diff: BigUInt { - new - current + guard new > current else { + return 0 + } + return new - current } } diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseInteractor.swift b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseInteractor.swift index d348b0d179..a2739cadf9 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseInteractor.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseInteractor.swift @@ -2,34 +2,28 @@ import UIKit import BigInt import RobinHood -class StakingProxyBaseInteractor: RuntimeConstantFetching, StakingProxyBaseInteractorInputProtocol { +class StakingProxyBaseInteractor: RuntimeConstantFetching, + StakingProxyBaseInteractorInputProtocol, AnyProviderAutoCleaning { weak var basePresenter: StakingProxyBaseInteractorOutputProtocol? let runtimeService: RuntimeCodingServiceProtocol let selectedAccount: ChainAccountResponse - let chainAsset: ChainAsset let walletLocalSubscriptionFactory: WalletLocalSubscriptionFactoryProtocol let accountProviderFactory: AccountProviderFactoryProtocol let priceLocalSubscriptionFactory: PriceProviderFactoryProtocol let callFactory: SubstrateCallFactoryProtocol let feeProxy: ExtrinsicFeeProxyProtocol - let extrinsicServiceFactory: ExtrinsicServiceFactoryProtocol let sharedState: RelaychainStakingSharedStateProtocol + let extrinsicService: ExtrinsicServiceProtocol + var chainAsset: ChainAsset { + sharedState.stakingOption.chainAsset + } private lazy var operationManager = OperationManager(operationQueue: operationQueue) private var calculator = ProxyDepositCalculator() private var proxyProvider: AnyDataProvider? private let operationQueue: OperationQueue private var balanceProvider: StreamableProvider? - private var extrinsicService: ExtrinsicServiceProtocol? - private var controllerAccountProvider: StreamableProvider? - private var stashAccountProvider: StreamableProvider? private var priceProvider: StreamableProvider? - private var stashItemProvider: StreamableProvider? - private var stashItem: StashItem? - - var stakingLocalSubscriptionFactory: StakingLocalSubscriptionFactoryProtocol { - sharedState.localSubscriptionFactory - } var proxyListLocalSubscriptionFactory: ProxyListLocalSubscriptionFactoryProtocol { sharedState.proxyLocalSubscriptionFactory @@ -43,21 +37,19 @@ class StakingProxyBaseInteractor: RuntimeConstantFetching, StakingProxyBaseInter priceLocalSubscriptionFactory: PriceProviderFactoryProtocol, callFactory: SubstrateCallFactoryProtocol, feeProxy: ExtrinsicFeeProxyProtocol, - extrinsicServiceFactory: ExtrinsicServiceFactoryProtocol, + extrinsicService: ExtrinsicServiceProtocol, selectedAccount: ChainAccountResponse, - chainAsset: ChainAsset, currencyManager: CurrencyManagerProtocol, operationQueue: OperationQueue ) { self.runtimeService = runtimeService + self.extrinsicService = extrinsicService self.sharedState = sharedState self.walletLocalSubscriptionFactory = walletLocalSubscriptionFactory self.accountProviderFactory = accountProviderFactory self.priceLocalSubscriptionFactory = priceLocalSubscriptionFactory - self.extrinsicServiceFactory = extrinsicServiceFactory self.callFactory = callFactory self.feeProxy = feeProxy - self.chainAsset = chainAsset self.selectedAccount = selectedAccount self.operationQueue = operationQueue self.currencyManager = currencyManager @@ -128,36 +120,26 @@ class StakingProxyBaseInteractor: RuntimeConstantFetching, StakingProxyBaseInter priceProvider = subscribeToPrice(for: priceId, currency: selectedCurrency) } - func handle(stashItem: StashItem?) { - self.stashItem = stashItem - + func performAccountSubscriptions() { clear(streamableProvider: &balanceProvider) - clear(streamableProvider: &stashAccountProvider) clear(dataProvider: &proxyProvider) - if - let stashItem = stashItem, - let stashAccountId = try? stashItem.stash.toAccountId() { - let chainId = chainAsset.chain.chainId - proxyProvider = subscribeProxies( - for: stashAccountId, - chainId: chainId, - modifyInternalList: ProxyFilter.allProxies - ) - balanceProvider = subscribeToAssetBalanceProvider( - for: stashAccountId, - chainId: chainAsset.chain.chainId, - assetId: chainAsset.asset.assetId - ) + let chainId = chainAsset.chain.chainId + let accountId = selectedAccount.accountId - subscribeToControllerAccount(address: stashItem.controller, chain: chainAsset.chain) + proxyProvider = subscribeProxies( + for: accountId, + chainId: chainId, + modifyInternalList: ProxyFilter.allProxies + ) - if stashItem.controller != stashItem.stash { - subscribeToStashAccount(address: stashItem.stash, chain: chainAsset.chain) - } + balanceProvider = subscribeToAssetBalanceProvider( + for: accountId, + chainId: chainAsset.chain.chainId, + assetId: chainAsset.asset.assetId + ) - estimateFee() - } + estimateFee() } private func updateProxyDeposit() { @@ -165,43 +147,17 @@ class StakingProxyBaseInteractor: RuntimeConstantFetching, StakingProxyBaseInter basePresenter?.didReceive(proxyDeposit: deposit) } - private func subscribeToControllerAccount(address: AccountAddress, chain: ChainModel) { - clear(streamableProvider: &controllerAccountProvider) - guard controllerAccountProvider == nil, let accountId = try? address.toAccountId() else { - return - } - - controllerAccountProvider = subscribeForAccountId(accountId, chain: chain) - } - - private func subscribeToStashAccount(address: AccountAddress, chain: ChainModel) { - clear(streamableProvider: &stashAccountProvider) - guard stashAccountProvider == nil, let accountId = try? address.toAccountId() else { - return - } - - stashAccountProvider = subscribeForAccountId(accountId, chain: chain) - } - // MARK: - StakingProxyBaseInteractorInputProtocol func setup() { - if let address = selectedAccount.toAddress() { - stashItemProvider = subscribeStashItemProvider(for: address, chainId: chainAsset.chain.chainId) - } - feeProxy.delegate = self fetchConstants() performPriceSubscription() + performAccountSubscriptions() } func estimateFee() { - guard - let extrinsicService = self.extrinsicService else { - return - } - let call = callFactory.addProxy( accountId: proxyAccount(), type: .staking @@ -217,9 +173,8 @@ class StakingProxyBaseInteractor: RuntimeConstantFetching, StakingProxyBaseInter } func remakeSubscriptions() { - if let stashItem = stashItem { - handle(stashItem: stashItem) - } + performPriceSubscription() + performAccountSubscriptions() } func proxyAccount() -> AccountId { @@ -227,18 +182,6 @@ class StakingProxyBaseInteractor: RuntimeConstantFetching, StakingProxyBaseInter } } -extension StakingProxyBaseInteractor: StakingLocalStorageSubscriber, StakingLocalSubscriptionHandler, - AnyProviderAutoCleaning { - func handleStashItem(result: Result, for _: AccountAddress) { - switch result { - case let .success(stashItem): - handle(stashItem: stashItem) - case let .failure(error): - basePresenter?.didReceive(baseError: .stashItem(error)) - } - } -} - extension StakingProxyBaseInteractor: PriceLocalStorageSubscriber, PriceLocalSubscriptionHandler { func handlePrice(result: Result, priceId: AssetModel.PriceId) { if chainAsset.asset.priceId == priceId { @@ -290,28 +233,6 @@ extension StakingProxyBaseInteractor: SelectedCurrencyDepending { } } -extension StakingProxyBaseInteractor: AccountLocalSubscriptionHandler, AccountLocalStorageSubscriber { - func handleAccountResponse( - result: Result, - accountId _: AccountId, - chain _: ChainModel - ) { - switch result { - case let .success(optAccount): - if let account = optAccount { - extrinsicService = extrinsicServiceFactory.createService( - account: account.chainAccount, - chain: chainAsset.chain - ) - estimateFee() - } - case .failure: - extrinsicService = nil - estimateFee() - } - } -} - extension StakingProxyBaseInteractor: ProxyListLocalSubscriptionHandler, ProxyListLocalStorageSubscriber { func handleProxies(result: Result, accountId _: AccountId, chainId _: ChainModel.Id) { switch result { diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift index 24e2d0b9cb..200d0f8b93 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift @@ -135,14 +135,10 @@ extension StakingProxyBasePresenter: StakingProxyBaseInteractorOutputProtocol { wireframe.presentRequestStatus(on: baseView, locale: selectedLocale) { [weak self] in self?.interactor.refetchConstants() } - case .handleProxies, .balance: + case .handleProxies, .balance, .price: wireframe.presentRequestStatus(on: baseView, locale: selectedLocale) { [weak self] in self?.interactor.remakeSubscriptions() } - case .stashItem, .price: - wireframe.presentRequestStatus(on: baseView, locale: selectedLocale) { [weak self] in - self?.interactor.setup() - } case .fee: wireframe.presentRequestStatus(on: baseView, locale: selectedLocale) { [weak self] in self?.interactor.estimateFee() diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseProtocols.swift b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseProtocols.swift index 572bdbbd5b..bd2aeb0e13 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseProtocols.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseProtocols.swift @@ -17,7 +17,6 @@ enum StakingProxyBaseError: Error { case handleProxies(Error) case balance(Error) case price(Error) - case stashItem(Error) case fee(Error) case fetchMaxProxyCount(Error) case fetchED(Error) diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyInteractor.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyInteractor.swift index 0a0297897b..70e5ecc6b7 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyInteractor.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyInteractor.swift @@ -20,9 +20,8 @@ final class StakingSetupProxyInteractor: StakingProxyBaseInteractor, AccountFetc priceLocalSubscriptionFactory: PriceProviderFactoryProtocol, callFactory: SubstrateCallFactoryProtocol, feeProxy: ExtrinsicFeeProxyProtocol, - extrinsicServiceFactory: ExtrinsicServiceFactoryProtocol, + extrinsicService: ExtrinsicServiceProtocol, selectedAccount: ChainAccountResponse, - chainAsset: ChainAsset, currencyManager: CurrencyManagerProtocol, operationQueue: OperationQueue ) { @@ -37,9 +36,8 @@ final class StakingSetupProxyInteractor: StakingProxyBaseInteractor, AccountFetc priceLocalSubscriptionFactory: priceLocalSubscriptionFactory, callFactory: callFactory, feeProxy: feeProxy, - extrinsicServiceFactory: extrinsicServiceFactory, + extrinsicService: extrinsicService, selectedAccount: selectedAccount, - chainAsset: chainAsset, currencyManager: currencyManager, operationQueue: operationQueue ) diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewFactory.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewFactory.swift index 7c36ba7386..b617673e15 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewFactory.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewFactory.swift @@ -63,12 +63,12 @@ struct StakingSetupProxyViewFactory { return nil } - let extrinsicServiceFactory = ExtrinsicServiceFactory( + let extrinsicService = ExtrinsicServiceFactory( runtimeRegistry: runtimeRegistry, engine: connection, operationManager: OperationManagerFacade.sharedManager, userStorageFacade: UserDataStorageFacade.shared - ) + ).createService(account: selectedAccount, chain: chainAsset.chain) let accountProviderFactory = AccountProviderFactory( storageFacade: UserDataStorageFacade.shared, @@ -93,9 +93,8 @@ struct StakingSetupProxyViewFactory { priceLocalSubscriptionFactory: PriceProviderFactory.shared, callFactory: SubstrateCallFactory(), feeProxy: ExtrinsicFeeProxy(), - extrinsicServiceFactory: extrinsicServiceFactory, + extrinsicService: extrinsicService, selectedAccount: selectedAccount, - chainAsset: chainAsset, currencyManager: currencyManager, operationQueue: OperationManagerFacade.sharedDefaultQueue ) From 8a5aa0cc0a8dad4e353f5c6a58a3517db0b7dce0 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Fri, 19 Jan 2024 14:13:43 +0300 Subject: [PATCH 26/60] PR fixes --- novawallet.xcodeproj/project.pbxproj | 4 ++ .../Protocols/BaseErrorPresentable.swift | 23 +++++++++ .../Web3Name/Web3NameServiceFactory.swift | 49 +++++++++++++++++++ .../Validators/BaseDataValidatorFactory.swift | 26 ++++++++++ .../Base/StakingProxyBasePresenter.swift | 2 +- .../StakingSetupProxyViewFactory.swift | 13 +++-- .../ProxyDataValidatorFactory.swift | 37 ++------------ .../Validation/ProxyErrorPresentable.swift | 23 --------- .../TransferSetupViewFactory.swift | 35 +------------ novawallet/en.lproj/Localizable.strings | 4 +- novawallet/ru.lproj/Localizable.strings | 4 +- 11 files changed, 122 insertions(+), 98 deletions(-) create mode 100644 novawallet/Common/Services/Web3Name/Web3NameServiceFactory.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 79c5e8ae55..3f7ccdcdec 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -925,6 +925,7 @@ 77AB555D2AA24BA90058814E /* OperationDetailsPoolRewardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77AB555C2AA24BA90058814E /* OperationDetailsPoolRewardView.swift */; }; 77C35CE52B568ED100308F16 /* YourWalletsPresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C35CE42B568ED100308F16 /* YourWalletsPresentable.swift */; }; 77C35CE72B56D07300308F16 /* ScanAddressPresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C35CE62B56D07300308F16 /* ScanAddressPresentable.swift */; }; + 77C35CE92B5A890500308F16 /* Web3NameServiceFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C35CE82B5A890500308F16 /* Web3NameServiceFactory.swift */; }; 77C976202AF36A170049272C /* SwapModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C9761F2AF36A170049272C /* SwapModels.swift */; }; 77C976222AF39F180049272C /* TokenOperationTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C976212AF39F180049272C /* TokenOperationTableViewCell.swift */; }; 77C976242AF3A5280049272C /* SwapViewModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C976232AF3A5280049272C /* SwapViewModels.swift */; }; @@ -5141,6 +5142,7 @@ 77AB555C2AA24BA90058814E /* OperationDetailsPoolRewardView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OperationDetailsPoolRewardView.swift; sourceTree = ""; }; 77C35CE42B568ED100308F16 /* YourWalletsPresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YourWalletsPresentable.swift; sourceTree = ""; }; 77C35CE62B56D07300308F16 /* ScanAddressPresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanAddressPresentable.swift; sourceTree = ""; }; + 77C35CE82B5A890500308F16 /* Web3NameServiceFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Web3NameServiceFactory.swift; sourceTree = ""; }; 77C9761F2AF36A170049272C /* SwapModels.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwapModels.swift; sourceTree = ""; }; 77C976212AF39F180049272C /* TokenOperationTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokenOperationTableViewCell.swift; sourceTree = ""; }; 77C976232AF3A5280049272C /* SwapViewModels.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwapViewModels.swift; sourceTree = ""; }; @@ -17689,6 +17691,7 @@ 8886020A29D101B000C6344C /* Web3NameServiceError.swift */, 84C1E7C829EE990800D37668 /* Web3NameProvider.swift */, 77A6F5CE2A31C4D4004AFD1A /* Web3TransferRecipientRepositoryFactory.swift */, + 77C35CE82B5A890500308F16 /* Web3NameServiceFactory.swift */, ); path = Web3Name; sourceTree = ""; @@ -20379,6 +20382,7 @@ 88DA0CD0295F345E0009F70F /* WKWebView+VewportScript.swift in Sources */, 84DA3B1224C6D29100B5E27F /* RuntimeVersion.swift in Sources */, 0C962F882AA85C7F00C0B551 /* TransactionHistoryAccountPrefixFilter.swift in Sources */, + 77C35CE92B5A890500308F16 /* Web3NameServiceFactory.swift in Sources */, 840E59BD2A188B7B00BA6ADD /* UIImage+Filter.swift in Sources */, 0CB06E752A68139C00C7EC99 /* StakingDashboardNominationPoolMapper.swift in Sources */, 8476D3A127F4598D004D9A7A /* DAppBrowserPhishingDetectedState.swift in Sources */, diff --git a/novawallet/Common/Protocols/BaseErrorPresentable.swift b/novawallet/Common/Protocols/BaseErrorPresentable.swift index 9c59bb0c07..ffa6f6b443 100644 --- a/novawallet/Common/Protocols/BaseErrorPresentable.swift +++ b/novawallet/Common/Protocols/BaseErrorPresentable.swift @@ -21,6 +21,12 @@ protocol BaseErrorPresentable { ) func presentMinBalanceViolated(from view: ControllerBackedProtocol, locale: Locale?) + + func presentNotValidAddress( + from view: ControllerBackedProtocol, + networkName: String, + locale: Locale? + ) } extension BaseErrorPresentable where Self: AlertPresentable & ErrorPresentable { @@ -170,4 +176,21 @@ extension BaseErrorPresentable where Self: AlertPresentable & ErrorPresentable { present(message: message, title: title, closeAction: closeAction, from: view) } + + func presentNotValidAddress( + from view: ControllerBackedProtocol, + networkName: String, + locale: Locale? + ) { + let title = R.string.localizable.commonErrorInvalidAddressTitle( + preferredLanguages: locale?.rLanguages) + let message = R.string.localizable.commonErrorInvalidAddressMessage( + networkName, + preferredLanguages: locale?.rLanguages + ) + let closeAction = R.string.localizable.commonClose( + preferredLanguages: locale?.rLanguages) + + present(message: message, title: title, closeAction: closeAction, from: view) + } } diff --git a/novawallet/Common/Services/Web3Name/Web3NameServiceFactory.swift b/novawallet/Common/Services/Web3Name/Web3NameServiceFactory.swift new file mode 100644 index 0000000000..7847ae9073 --- /dev/null +++ b/novawallet/Common/Services/Web3Name/Web3NameServiceFactory.swift @@ -0,0 +1,49 @@ +import Foundation + +protocol Web3NameServiceFactoryProtocol { + func createService() -> Web3NameServiceProtocol? +} + +final class Web3NameServiceFactory: Web3NameServiceFactoryProtocol { + let chainRegistry: ChainRegistryProtocol + let operationQueue: OperationQueue + + init( + chainRegistry: ChainRegistryProtocol = ChainRegistryFacade.sharedRegistry, + operationQueue: OperationQueue + ) { + self.chainRegistry = chainRegistry + self.operationQueue = operationQueue + } + + func createService() -> Web3NameServiceProtocol? { + let kiltChainId = KnowChainId.kiltOnEnviroment + let chainRegistry = ChainRegistryFacade.sharedRegistry + + guard let kiltConnection = chainRegistry.getConnection(for: kiltChainId), + let kiltRuntimeService = chainRegistry.getRuntimeProvider(for: kiltChainId) else { + return nil + } + + let web3NamesOperationFactory = KiltWeb3NamesOperationFactory(operationQueue: operationQueue) + + let recipientRepositoryFactory = Web3TransferRecipientRepositoryFactory( + integrityVerifierFactory: Web3TransferRecipientIntegrityVerifierFactory() + ) + + let slip44CoinsUrl = ApplicationConfig.shared.slip44URL + let slip44CoinsProvider: AnySingleValueProvider = JsonDataProviderFactory.shared.getJson( + for: slip44CoinsUrl + ) + + return Web3NameService( + providerName: Web3NameProvider.kilt, + slip44CoinsProvider: slip44CoinsProvider, + web3NamesOperationFactory: web3NamesOperationFactory, + runtimeService: kiltRuntimeService, + connection: kiltConnection, + transferRecipientRepositoryFactory: recipientRepositoryFactory, + operationQueue: operationQueue + ) + } +} diff --git a/novawallet/Common/Validation/Validators/BaseDataValidatorFactory.swift b/novawallet/Common/Validation/Validators/BaseDataValidatorFactory.swift index 3413db7a4f..2c4f53b86d 100644 --- a/novawallet/Common/Validation/Validators/BaseDataValidatorFactory.swift +++ b/novawallet/Common/Validation/Validators/BaseDataValidatorFactory.swift @@ -37,6 +37,12 @@ protocol BaseDataValidatingFactoryProtocol: AnyObject { minBalance: BigUInt?, locale: Locale ) -> DataValidating + + func validAddress( + _ address: String, + chain: ChainModel, + locale: Locale + ) -> DataValidating } extension BaseDataValidatingFactoryProtocol { @@ -263,4 +269,24 @@ extension BaseDataValidatingFactoryProtocol { } }) } + + func validAddress( + _ address: String, + chain: ChainModel, + locale: Locale + ) -> DataValidating { + ErrorConditionViolation(onError: { [weak self] in + guard let view = self?.view else { + return + } + self?.basePresentable.presentNotValidAddress( + from: view, + networkName: chain.name, + locale: locale + ) + }, preservesCondition: { + let accountId = try? address.toAccountId(using: chain.chainFormat) + return accountId != nil + }) + } } diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift index 200d0f8b93..e012f3f77f 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift @@ -90,7 +90,7 @@ class StakingProxyBasePresenter: StakingSetupProxyBasePresenterProtocol { locale: selectedLocale ), dataValidatingFactory.notReachedMaximimProxyCount( - proxy.map { $0?.definition.count ?? 0 }.value, + proxy.map { $0?.definition.count ?? 0 }.value.map { $0 + 1 }, limit: maxProxies, chain: chainAsset.chain, locale: selectedLocale diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewFactory.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewFactory.swift index b617673e15..63ef1f02d7 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewFactory.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewFactory.swift @@ -1,5 +1,6 @@ import Foundation import SoraFoundation +import RobinHood struct StakingSetupProxyViewFactory { static func createView(state: RelaychainStakingSharedStateProtocol) -> StakingSetupProxyViewProtocol? { @@ -52,7 +53,6 @@ struct StakingSetupProxyViewFactory { ) -> StakingSetupProxyInteractor? { let chainRegistry = ChainRegistryFacade.sharedRegistry let chainAsset = state.stakingOption.chainAsset - guard let selectedAccount = SelectedWalletSettings.shared.value.fetch( for: chainAsset.chain.accountRequest() @@ -63,20 +63,23 @@ struct StakingSetupProxyViewFactory { return nil } + let operationQueue = OperationManagerFacade.sharedDefaultQueue + let operationManager = OperationManager(operationQueue: operationQueue) + let extrinsicService = ExtrinsicServiceFactory( runtimeRegistry: runtimeRegistry, engine: connection, - operationManager: OperationManagerFacade.sharedManager, + operationManager: operationManager, userStorageFacade: UserDataStorageFacade.shared ).createService(account: selectedAccount, chain: chainAsset.chain) let accountProviderFactory = AccountProviderFactory( storageFacade: UserDataStorageFacade.shared, - operationManager: OperationManagerFacade.sharedManager, + operationManager: operationManager, logger: Logger.shared ) - let web3NamesService = createWeb3NameService() + let web3NamesService = Web3NameServiceFactory(operationQueue: operationQueue).createService() let accountRepositoryFactory = AccountRepositoryFactory(storageFacade: UserDataStorageFacade.shared) let accountRepository = accountRepositoryFactory.createMetaAccountRepository( for: nil, @@ -96,7 +99,7 @@ struct StakingSetupProxyViewFactory { extrinsicService: extrinsicService, selectedAccount: selectedAccount, currencyManager: currencyManager, - operationQueue: OperationManagerFacade.sharedDefaultQueue + operationQueue: operationQueue ) } diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyDataValidatorFactory.swift b/novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyDataValidatorFactory.swift index 157f597a8b..49e7f75570 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyDataValidatorFactory.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyDataValidatorFactory.swift @@ -4,19 +4,13 @@ import SoraFoundation protocol ProxyDataValidatorFactoryProtocol: BaseDataValidatingFactoryProtocol { func hasSufficientBalance( - available: BigUInt?, + available: BigUInt, deposit: BigUInt?, fee: BigUInt?, asset: AssetBalanceDisplayInfo, locale: Locale ) -> DataValidating - func validAddress( - _ address: String, - chain: ChainModel, - locale: Locale - ) -> DataValidating - func notReachedMaximimProxyCount( _ proxyCount: Int?, limit: Int?, @@ -49,7 +43,7 @@ final class ProxyDataValidatorFactory: ProxyDataValidatorFactoryProtocol { } func hasSufficientBalance( - available: BigUInt?, + available: BigUInt, deposit: BigUInt?, fee: BigUInt?, asset: AssetBalanceDisplayInfo, @@ -61,7 +55,7 @@ final class ProxyDataValidatorFactory: ProxyDataValidatorFactoryProtocol { let viewModelFactory = self?.balanceViewModelFactoryFacade else { return } - let balanceDecimal = available?.decimal(assetInfo: asset) + let balanceDecimal = available.decimal(assetInfo: asset) let depositDecimal = deposit?.decimal(assetInfo: asset) let balanceModel = viewModelFactory.amountFromValue( @@ -81,34 +75,13 @@ final class ProxyDataValidatorFactory: ProxyDataValidatorFactoryProtocol { ) }, preservesCondition: { guard let deposit = deposit, - let fee = fee, - let available = available else { + let fee = fee else { return false } return available >= deposit + fee }) } - func validAddress( - _ address: String, - chain: ChainModel, - locale: Locale - ) -> DataValidating { - ErrorConditionViolation(onError: { [weak self] in - guard let view = self?.view else { - return - } - self?.presentable.presentNotValidAddress( - from: view, - networkName: chain.name, - locale: locale - ) - }, preservesCondition: { - let accountId = try? address.toAccountId(using: chain.chainFormat) - return accountId != nil - }) - } - func notReachedMaximimProxyCount( _ proxyCount: Int?, limit: Int?, @@ -133,7 +106,7 @@ final class ProxyDataValidatorFactory: ProxyDataValidatorFactoryProtocol { let limit = limit else { return false } - return proxyCount < limit + return proxyCount <= limit }) } diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyErrorPresentable.swift b/novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyErrorPresentable.swift index 09397aa150..fda8a70262 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyErrorPresentable.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyErrorPresentable.swift @@ -8,12 +8,6 @@ protocol ProxyErrorPresentable: BaseErrorPresentable { locale: Locale? ) - func presentNotValidAddress( - from view: ControllerBackedProtocol, - networkName: String, - locale: Locale? - ) - func presentMaximumProxyCount( from view: ControllerBackedProtocol?, limit: String, @@ -48,23 +42,6 @@ extension ProxyErrorPresentable where Self: AlertPresentable & ErrorPresentable present(message: message, title: title, closeAction: closeAction, from: view) } - func presentNotValidAddress( - from view: ControllerBackedProtocol, - networkName: String, - locale: Locale? - ) { - let title = R.string.localizable.stakingSetupProxyErrorInvalidAddressTitle( - preferredLanguages: locale?.rLanguages) - let message = R.string.localizable.stakingSetupProxyErrorInvalidAddressMessage( - networkName, - preferredLanguages: locale?.rLanguages - ) - let closeAction = R.string.localizable.commonClose( - preferredLanguages: locale?.rLanguages) - - present(message: message, title: title, closeAction: closeAction, from: view) - } - func presentMaximumProxyCount( from view: ControllerBackedProtocol?, limit: String, diff --git a/novawallet/Modules/Transfer/TransferSetup/TransferSetupViewFactory.swift b/novawallet/Modules/Transfer/TransferSetup/TransferSetupViewFactory.swift index a7a781ab46..243d8643fc 100644 --- a/novawallet/Modules/Transfer/TransferSetup/TransferSetupViewFactory.swift +++ b/novawallet/Modules/Transfer/TransferSetup/TransferSetupViewFactory.swift @@ -163,8 +163,9 @@ enum TransferSetupViewFactory { for: nil, sortDescriptors: [NSSortDescriptor.accountsByOrder] ) + let operationQueue = OperationManagerFacade.sharedDefaultQueue - let web3NameService = createWeb3NameService() + let web3NameService = Web3NameServiceFactory(operationQueue: operationQueue).createService() return TransferSetupInteractor( chainAsset: params.chainAsset, @@ -177,36 +178,4 @@ enum TransferSetupViewFactory { operationManager: OperationManager() ) } - - private static func createWeb3NameService() -> Web3NameServiceProtocol? { - let kiltChainId = KnowChainId.kiltOnEnviroment - let chainRegistry = ChainRegistryFacade.sharedRegistry - - guard let kiltConnection = chainRegistry.getConnection(for: kiltChainId), - let kiltRuntimeService = chainRegistry.getRuntimeProvider(for: kiltChainId) else { - return nil - } - - let operationQueue = OperationManagerFacade.sharedDefaultQueue - let web3NamesOperationFactory = KiltWeb3NamesOperationFactory(operationQueue: operationQueue) - - let recipientRepositoryFactory = Web3TransferRecipientRepositoryFactory( - integrityVerifierFactory: Web3TransferRecipientIntegrityVerifierFactory() - ) - - let slip44CoinsUrl = ApplicationConfig.shared.slip44URL - let slip44CoinsProvider: AnySingleValueProvider = JsonDataProviderFactory.shared.getJson( - for: slip44CoinsUrl - ) - - return Web3NameService( - providerName: Web3NameProvider.kilt, - slip44CoinsProvider: slip44CoinsProvider, - web3NamesOperationFactory: web3NamesOperationFactory, - runtimeService: kiltRuntimeService, - connection: kiltConnection, - transferRecipientRepositoryFactory: recipientRepositoryFactory, - operationQueue: operationQueue - ) - } } diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index 15d8f0efb4..dd263304bd 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -1380,8 +1380,8 @@ "staking.setup.add.your.proxy" = "Add delegated authority (Proxy)"; "staking.setup.proxy.error.insufficient.balance.title" = "Not enough tokens"; "staking.setup.proxy.error.insufficient.balance.message" = "You don’t have enough balance for proxy deposit of %@. Available balance: %@"; -"staking.setup.proxy.error.invalid.address.title" = "Invalid proxy address"; -"staking.setup.proxy.error.invalid.address.message" = "Proxy address should be a valid %@ address"; +"common.error.invalid.address.title" = "Invalid address"; +"common.error.invalid.address.message" = "Address should be a valid %@ address"; "staking.setup.proxy.error.invalid.maximum.proxies.title" = "Maximum number of proxies has been reached"; "staking.setup.proxy.error.invalid.maximum.proxies.message" = "You have reached the limit of %@ added proxies in %@. Remove proxies to add new ones."; "staking.setup.proxy.error.proxy.already.exists.title" = "Delegation already exists"; diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index 19a3978aed..096db6584a 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1380,8 +1380,8 @@ "staking.setup.add.your.proxy" = "Добавить делегацию (Прокси)"; "staking.setup.proxy.error.insufficient.balance.title" = "Недостаточно токенов"; "staking.setup.proxy.error.insufficient.balance.message" = "У вас недостаточно средств для депозита прокси %@. Доступный баланс: %@"; -"staking.setup.proxy.error.invalid.address.title" = "Некорректный адрес прокси"; -"staking.setup.proxy.error.invalid.address.message" = "Адрес прокси должен быть допустимым адресом в сети %@"; +"common.error.invalid.address.title" = "Некорректный адрес"; +"common.error.invalid.address.message" = "Адрес должен быть допустимым адресом в сети %@"; "staking.setup.proxy.error.invalid.maximum.proxies.title" = "Достигнуто максимальное количество прокси"; "staking.setup.proxy.error.invalid.maximum.proxies.message" = "Вы достигли лимита добавленных прокси (%@) в %@. Чтобы добавить новые, удалите существующие."; "staking.setup.proxy.error.proxy.already.exists.title" = "Прокси уже добавлен"; From bb6bcb5e9cbc168b05b6b76fa6ededec0d9e1273 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Fri, 19 Jan 2024 15:53:29 +0300 Subject: [PATCH 27/60] rollback validation --- .../Protocols/BaseErrorPresentable.swift | 23 ---------------- .../Validators/BaseDataValidatorFactory.swift | 26 ------------------- .../ProxyDataValidatorFactory.swift | 26 +++++++++++++++++++ .../Validation/ProxyErrorPresentable.swift | 23 ++++++++++++++++ novawallet/en.lproj/Localizable.strings | 4 +-- novawallet/ru.lproj/Localizable.strings | 4 +-- 6 files changed, 53 insertions(+), 53 deletions(-) diff --git a/novawallet/Common/Protocols/BaseErrorPresentable.swift b/novawallet/Common/Protocols/BaseErrorPresentable.swift index ffa6f6b443..9c59bb0c07 100644 --- a/novawallet/Common/Protocols/BaseErrorPresentable.swift +++ b/novawallet/Common/Protocols/BaseErrorPresentable.swift @@ -21,12 +21,6 @@ protocol BaseErrorPresentable { ) func presentMinBalanceViolated(from view: ControllerBackedProtocol, locale: Locale?) - - func presentNotValidAddress( - from view: ControllerBackedProtocol, - networkName: String, - locale: Locale? - ) } extension BaseErrorPresentable where Self: AlertPresentable & ErrorPresentable { @@ -176,21 +170,4 @@ extension BaseErrorPresentable where Self: AlertPresentable & ErrorPresentable { present(message: message, title: title, closeAction: closeAction, from: view) } - - func presentNotValidAddress( - from view: ControllerBackedProtocol, - networkName: String, - locale: Locale? - ) { - let title = R.string.localizable.commonErrorInvalidAddressTitle( - preferredLanguages: locale?.rLanguages) - let message = R.string.localizable.commonErrorInvalidAddressMessage( - networkName, - preferredLanguages: locale?.rLanguages - ) - let closeAction = R.string.localizable.commonClose( - preferredLanguages: locale?.rLanguages) - - present(message: message, title: title, closeAction: closeAction, from: view) - } } diff --git a/novawallet/Common/Validation/Validators/BaseDataValidatorFactory.swift b/novawallet/Common/Validation/Validators/BaseDataValidatorFactory.swift index 2c4f53b86d..3413db7a4f 100644 --- a/novawallet/Common/Validation/Validators/BaseDataValidatorFactory.swift +++ b/novawallet/Common/Validation/Validators/BaseDataValidatorFactory.swift @@ -37,12 +37,6 @@ protocol BaseDataValidatingFactoryProtocol: AnyObject { minBalance: BigUInt?, locale: Locale ) -> DataValidating - - func validAddress( - _ address: String, - chain: ChainModel, - locale: Locale - ) -> DataValidating } extension BaseDataValidatingFactoryProtocol { @@ -269,24 +263,4 @@ extension BaseDataValidatingFactoryProtocol { } }) } - - func validAddress( - _ address: String, - chain: ChainModel, - locale: Locale - ) -> DataValidating { - ErrorConditionViolation(onError: { [weak self] in - guard let view = self?.view else { - return - } - self?.basePresentable.presentNotValidAddress( - from: view, - networkName: chain.name, - locale: locale - ) - }, preservesCondition: { - let accountId = try? address.toAccountId(using: chain.chainFormat) - return accountId != nil - }) - } } diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyDataValidatorFactory.swift b/novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyDataValidatorFactory.swift index 49e7f75570..3aaccfb823 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyDataValidatorFactory.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyDataValidatorFactory.swift @@ -24,6 +24,12 @@ protocol ProxyDataValidatorFactoryProtocol: BaseDataValidatingFactoryProtocol { proxyList: [Proxy.ProxyDefinition]?, locale: Locale ) -> DataValidating + + func validAddress( + _ address: String, + chain: ChainModel, + locale: Locale + ) -> DataValidating } final class ProxyDataValidatorFactory: ProxyDataValidatorFactoryProtocol { @@ -133,4 +139,24 @@ final class ProxyDataValidatorFactory: ProxyDataValidatorFactoryProtocol { return proxyList.contains(where: { $0.proxy == accountId }) == false }) } + + func validAddress( + _ address: String, + chain: ChainModel, + locale: Locale + ) -> DataValidating { + ErrorConditionViolation(onError: { [weak self] in + guard let view = self?.view else { + return + } + self?.presentable.presentNotValidAddress( + from: view, + networkName: chain.name, + locale: locale + ) + }, preservesCondition: { + let accountId = try? address.toAccountId(using: chain.chainFormat) + return accountId != nil + }) + } } diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyErrorPresentable.swift b/novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyErrorPresentable.swift index fda8a70262..08d3fa7b95 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyErrorPresentable.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyErrorPresentable.swift @@ -20,6 +20,12 @@ protocol ProxyErrorPresentable: BaseErrorPresentable { account: String, locale: Locale ) + + func presentNotValidAddress( + from view: ControllerBackedProtocol, + networkName: String, + locale: Locale? + ) } extension ProxyErrorPresentable where Self: AlertPresentable & ErrorPresentable { @@ -77,4 +83,21 @@ extension ProxyErrorPresentable where Self: AlertPresentable & ErrorPresentable present(message: message, title: title, closeAction: closeAction, from: view) } + + func presentNotValidAddress( + from view: ControllerBackedProtocol, + networkName: String, + locale: Locale? + ) { + let title = R.string.localizable.stakingSetupProxyErrorInvalidAddressTitle( + preferredLanguages: locale?.rLanguages) + let message = R.string.localizable.stakingSetupProxyErrorInvalidAddressMessage( + networkName, + preferredLanguages: locale?.rLanguages + ) + let closeAction = R.string.localizable.commonClose( + preferredLanguages: locale?.rLanguages) + + present(message: message, title: title, closeAction: closeAction, from: view) + } } diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index dd263304bd..15d8f0efb4 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -1380,8 +1380,8 @@ "staking.setup.add.your.proxy" = "Add delegated authority (Proxy)"; "staking.setup.proxy.error.insufficient.balance.title" = "Not enough tokens"; "staking.setup.proxy.error.insufficient.balance.message" = "You don’t have enough balance for proxy deposit of %@. Available balance: %@"; -"common.error.invalid.address.title" = "Invalid address"; -"common.error.invalid.address.message" = "Address should be a valid %@ address"; +"staking.setup.proxy.error.invalid.address.title" = "Invalid proxy address"; +"staking.setup.proxy.error.invalid.address.message" = "Proxy address should be a valid %@ address"; "staking.setup.proxy.error.invalid.maximum.proxies.title" = "Maximum number of proxies has been reached"; "staking.setup.proxy.error.invalid.maximum.proxies.message" = "You have reached the limit of %@ added proxies in %@. Remove proxies to add new ones."; "staking.setup.proxy.error.proxy.already.exists.title" = "Delegation already exists"; diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index 096db6584a..19a3978aed 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1380,8 +1380,8 @@ "staking.setup.add.your.proxy" = "Добавить делегацию (Прокси)"; "staking.setup.proxy.error.insufficient.balance.title" = "Недостаточно токенов"; "staking.setup.proxy.error.insufficient.balance.message" = "У вас недостаточно средств для депозита прокси %@. Доступный баланс: %@"; -"common.error.invalid.address.title" = "Некорректный адрес"; -"common.error.invalid.address.message" = "Адрес должен быть допустимым адресом в сети %@"; +"staking.setup.proxy.error.invalid.address.title" = "Некорректный адрес прокси"; +"staking.setup.proxy.error.invalid.address.message" = "Адрес прокси должен быть допустимым адресом в сети %@"; "staking.setup.proxy.error.invalid.maximum.proxies.title" = "Достигнуто максимальное количество прокси"; "staking.setup.proxy.error.invalid.maximum.proxies.message" = "Вы достигли лимита добавленных прокси (%@) в %@. Чтобы добавить новые, удалите существующие."; "staking.setup.proxy.error.proxy.already.exists.title" = "Прокси уже добавлен"; From 088b2aca65d09d864569cf78cbb467183efd8d84 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Fri, 19 Jan 2024 16:16:39 +0300 Subject: [PATCH 28/60] PR fixes --- .../StakingConfirmProxyPresenter.swift | 24 ++++++++++++++----- .../StakingConfirmProxyProtocols.swift | 6 ++--- .../StakingConfirmProxyWireframe.swift | 10 +------- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyPresenter.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyPresenter.swift index af23147093..66c2704750 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyPresenter.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyPresenter.swift @@ -112,7 +112,11 @@ extension StakingConfirmProxyPresenter: StakingConfirmProxyPresenterProtocol { func confirm() { view?.didStartLoading() - interactor.submit() + let validations = createCommonValidations() + + DataValidationRunner(validators: validations).runValidation { [weak self] in + self?.interactor.submit() + } } } @@ -120,17 +124,25 @@ extension StakingConfirmProxyPresenter: StakingConfirmProxyInteractorOutputProto func didSubmit() { view?.didStopLoading() - wireframe.complete(from: view) + wireframe.presentExtrinsicSubmission( + from: view, + completionAction: .dismiss, + locale: selectedLocale + ) } func didReceive(error: StakingConfirmProxyError) { view?.didStopLoading() switch error { - case .submit: - wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in - self?.confirm() - } + case let .submit(error): + wireframe.handleExtrinsicSigningErrorPresentationElseDefault( + error, + view: view, + closeAction: .dismiss, + locale: selectedLocale, + completionClosure: nil + ) } } } diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyProtocols.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyProtocols.swift index eb408f12c2..6ed1f3c313 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyProtocols.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyProtocols.swift @@ -22,9 +22,9 @@ protocol StakingConfirmProxyInteractorOutputProtocol: StakingProxyBaseInteractor func didReceive(error: StakingConfirmProxyError) } -protocol StakingConfirmProxyWireframeProtocol: StakingSetupProxyBaseWireframeProtocol, AddressOptionsPresentable { - func complete(from view: ControllerBackedProtocol?) -} +protocol StakingConfirmProxyWireframeProtocol: StakingSetupProxyBaseWireframeProtocol, + AddressOptionsPresentable, ExtrinsicSubmissionPresenting, ModalAlertPresenting, + ExtrinsicSigningErrorHandling, MessageSheetPresentable, ErrorPresentable {} enum StakingConfirmProxyError: Error { case submit(Error) diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyWireframe.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyWireframe.swift index 981cc1bec7..4f3e7735b0 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyWireframe.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyWireframe.swift @@ -1,11 +1,3 @@ import Foundation -final class StakingConfirmProxyWireframe: StakingConfirmProxyWireframeProtocol, ModalAlertPresenting { - func complete(from view: ControllerBackedProtocol?) { - let presenter = view?.controller.navigationController?.presentingViewController - - presenter?.dismiss(animated: true) { - self.presentSuccessNotification("", from: presenter, completion: nil) - } - } -} +final class StakingConfirmProxyWireframe: StakingConfirmProxyWireframeProtocol {} From 12b92358ee19a1b96b0b34837dcd58d59b2cefdf Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Fri, 19 Jan 2024 18:31:51 +0300 Subject: [PATCH 29/60] init --- novawallet.xcodeproj/project.pbxproj | 4 ++ .../Calls/Common/SubstrateCallFactory.swift | 17 +++++++ .../Substrate/Calls/Proxy/Proxy+Call.swift | 2 + .../StakingProxyManagementPresenter.swift | 2 +- .../StakingProxyManagementProtocols.swift | 2 +- .../StakingProxyManagementWireframe.swift | 15 +++++- .../StakingConfirmProxyInteractor.swift | 15 +++--- .../StakingConfirmProxyViewController.swift | 9 ++-- .../StakingConfirmProxyViewFactory.swift | 13 +++-- .../StakingProxyConfirmOperation.swift | 48 +++++++++++++++++++ .../StakingSetupProxyWireframe.swift | 3 +- 11 files changed, 109 insertions(+), 21 deletions(-) create mode 100644 novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingProxyConfirmOperation.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index b13b92e668..673bbdef23 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -927,6 +927,7 @@ 77AB55592AA244BB0058814E /* OperationPoolRewardOrSlashModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77AB55582AA244BB0058814E /* OperationPoolRewardOrSlashModel.swift */; }; 77AB555B2AA246CA0058814E /* OperationPoolRewardOrSlashViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77AB555A2AA246CA0058814E /* OperationPoolRewardOrSlashViewModel.swift */; }; 77AB555D2AA24BA90058814E /* OperationDetailsPoolRewardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77AB555C2AA24BA90058814E /* OperationDetailsPoolRewardView.swift */; }; + 77B00A202B5AC6F200EAAEBE /* StakingProxyConfirmOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77B00A1F2B5AC6F200EAAEBE /* StakingProxyConfirmOperation.swift */; }; 77C35CE52B568ED100308F16 /* YourWalletsPresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C35CE42B568ED100308F16 /* YourWalletsPresentable.swift */; }; 77C35CE72B56D07300308F16 /* ScanAddressPresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C35CE62B56D07300308F16 /* ScanAddressPresentable.swift */; }; 77C35CE92B5A890500308F16 /* Web3NameServiceFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C35CE82B5A890500308F16 /* Web3NameServiceFactory.swift */; }; @@ -5160,6 +5161,7 @@ 77AB55582AA244BB0058814E /* OperationPoolRewardOrSlashModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OperationPoolRewardOrSlashModel.swift; sourceTree = ""; }; 77AB555A2AA246CA0058814E /* OperationPoolRewardOrSlashViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OperationPoolRewardOrSlashViewModel.swift; sourceTree = ""; }; 77AB555C2AA24BA90058814E /* OperationDetailsPoolRewardView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OperationDetailsPoolRewardView.swift; sourceTree = ""; }; + 77B00A1F2B5AC6F200EAAEBE /* StakingProxyConfirmOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingProxyConfirmOperation.swift; sourceTree = ""; }; 77C35CE42B568ED100308F16 /* YourWalletsPresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YourWalletsPresentable.swift; sourceTree = ""; }; 77C35CE62B56D07300308F16 /* ScanAddressPresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanAddressPresentable.swift; sourceTree = ""; }; 77C35CE82B5A890500308F16 /* Web3NameServiceFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Web3NameServiceFactory.swift; sourceTree = ""; }; @@ -10054,6 +10056,7 @@ B4E64E1B99253D7F875C637C /* StakingConfirmProxyViewController.swift */, 3543AE2CAA63AC0A20D532B6 /* StakingConfirmProxyViewLayout.swift */, 0E52C5919A1DA8A18297325B /* StakingConfirmProxyViewFactory.swift */, + 77B00A1F2B5AC6F200EAAEBE /* StakingProxyConfirmOperation.swift */, ); path = StakingConfirmProxy; sourceTree = ""; @@ -22888,6 +22891,7 @@ 88FB7DD12950720800784E08 /* ContainerProtocols.swift in Sources */, 840AE2E529C9AF9C008FF665 /* EtherscanWalletHistoryDecodable.swift in Sources */, 772B1C7D2A93837800A19061 /* StartStakingCustomValidatorListWireframe.swift in Sources */, + 77B00A202B5AC6F200EAAEBE /* StakingProxyConfirmOperation.swift in Sources */, 77AAE2202AFB00CB006872CC /* OperationSwapModel.swift in Sources */, 8465DA35298EC5FB00C7CFF1 /* TitleDetailsSheetLayout.swift in Sources */, AEE5FB1C264A610C002B8FDC /* StakingRewardDestSetupLayout.swift in Sources */, diff --git a/novawallet/Common/Substrate/Calls/Common/SubstrateCallFactory.swift b/novawallet/Common/Substrate/Calls/Common/SubstrateCallFactory.swift index 613a2c399e..1c1344d349 100644 --- a/novawallet/Common/Substrate/Calls/Common/SubstrateCallFactory.swift +++ b/novawallet/Common/Substrate/Calls/Common/SubstrateCallFactory.swift @@ -63,6 +63,11 @@ protocol SubstrateCallFactoryProtocol { ) -> RuntimeCall func addProxy(accountId: AccountId, type: Proxy.ProxyType) -> RuntimeCall + + func removeProxy( + accountId: AccountId, + type: Proxy.ProxyType + ) -> RuntimeCall } final class SubstrateCallFactory: SubstrateCallFactoryProtocol { @@ -232,6 +237,18 @@ final class SubstrateCallFactory: SubstrateCallFactoryProtocol { ) return RuntimeCall(moduleName: Proxy.name, callName: "add_proxy", args: proxyCall) } + + func removeProxy( + accountId: AccountId, + type: Proxy.ProxyType + ) -> RuntimeCall { + let proxyCall = Proxy.RemoveProxyCall( + proxy: .accoundId(accountId), + proxyType: type, + delay: 0 + ) + return RuntimeCall(moduleName: Proxy.name, callName: "remove_proxy", args: proxyCall) + } } extension SubstrateCallFactory { diff --git a/novawallet/Common/Substrate/Calls/Proxy/Proxy+Call.swift b/novawallet/Common/Substrate/Calls/Proxy/Proxy+Call.swift index 6bc94e077a..2c42e12e60 100644 --- a/novawallet/Common/Substrate/Calls/Proxy/Proxy+Call.swift +++ b/novawallet/Common/Substrate/Calls/Proxy/Proxy+Call.swift @@ -29,4 +29,6 @@ extension Proxy { let proxyType: ProxyType @StringCodable var delay: BlockNumber } + + typealias RemoveProxyCall = AddProxyCall } diff --git a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementPresenter.swift b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementPresenter.swift index f54388b298..592fa26ba2 100644 --- a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementPresenter.swift +++ b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementPresenter.swift @@ -94,7 +94,7 @@ final class StakingProxyManagementPresenter { icon: R.image.iconDelete(), indicator: .navigation ) { [weak self] in - self?.wireframe.showRevokeProxyAccess(from: self?.view) + self?.wireframe.showRevokeProxyAccess(from: self?.view, proxyAddress: address) } wireframe.presentExtendedAccountOptions( diff --git a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementProtocols.swift b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementProtocols.swift index 1b192dbb7d..757bcba2bc 100644 --- a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementProtocols.swift +++ b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementProtocols.swift @@ -21,7 +21,7 @@ protocol StakingProxyManagementInteractorOutputProtocol: AnyObject { protocol StakingProxyManagementWireframeProtocol: AnyObject, AddressOptionsPresentable, AlertPresentable, CommonRetryable, ErrorPresentable { func showAddProxy(from view: ControllerBackedProtocol?) - func showRevokeProxyAccess(from view: ControllerBackedProtocol?) + func showRevokeProxyAccess(from view: ControllerBackedProtocol?, proxyAddress: AccountAddress) } enum StakingProxyManagementError: Error { diff --git a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementWireframe.swift b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementWireframe.swift index 4dd82ee780..7445775aa2 100644 --- a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementWireframe.swift +++ b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementWireframe.swift @@ -17,7 +17,18 @@ final class StakingProxyManagementWireframe: StakingProxyManagementWireframeProt ) } - func showRevokeProxyAccess(from _: ControllerBackedProtocol?) { - // TODO: + func showRevokeProxyAccess(from view: ControllerBackedProtocol?, proxyAddress: AccountAddress) { + guard let confirmView = StakingConfirmProxyViewFactory.createView( + state: state, + proxyAddress: proxyAddress, + confirmOperation: .remove + ) else { + return + } + + view?.controller.navigationController?.pushViewController( + confirmView.controller, + animated: true + ) } } diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyInteractor.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyInteractor.swift index bce0717992..2118cdac13 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyInteractor.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyInteractor.swift @@ -7,6 +7,7 @@ final class StakingConfirmProxyInteractor: StakingProxyBaseInteractor { let proxyAccount: AccountAddress let signingWrapper: SigningWrapperProtocol + let operation: StakingProxyConfirmOperation init( proxyAccount: AccountAddress, @@ -21,10 +22,12 @@ final class StakingConfirmProxyInteractor: StakingProxyBaseInteractor { extrinsicService: ExtrinsicServiceProtocol, selectedAccount: ChainAccountResponse, currencyManager: CurrencyManagerProtocol, + operation: StakingProxyConfirmOperation, operationQueue: OperationQueue ) { self.proxyAccount = proxyAccount self.signingWrapper = signingWrapper + self.operation = operation super.init( runtimeService: runtimeService, @@ -51,15 +54,11 @@ extension StakingConfirmProxyInteractor: StakingConfirmProxyInteractorInputProto return } - let call = callFactory.addProxy( - accountId: proxyAccountId, - type: .staking - ) - extrinsicService.submit( - { builder in - try builder.adding(call: call) - }, + operation.builderClosure( + callFactory: callFactory, + accountId: proxyAccountId + ), signer: signingWrapper, runningIn: .main, completion: { [weak self] result in diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewController.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewController.swift index d537412196..2f6a4cdd37 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewController.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewController.swift @@ -5,12 +5,15 @@ final class StakingConfirmProxyViewController: UIViewController, ViewHolder { typealias RootViewType = StakingConfirmProxyViewLayout let presenter: StakingConfirmProxyPresenterProtocol + let localizableTitle: LocalizableResource init( presenter: StakingConfirmProxyPresenterProtocol, - localizationManager: LocalizationManagerProtocol + localizationManager: LocalizationManagerProtocol, + title: LocalizableResource ) { self.presenter = presenter + localizableTitle = title super.init(nibName: nil, bundle: nil) self.localizationManager = localizationManager @@ -61,9 +64,7 @@ final class StakingConfirmProxyViewController: UIViewController, ViewHolder { rootView.actionButton.actionButton.imageWithTitleView?.title = R.string.localizable.commonConfirm( preferredLanguages: languages ) - title = R.string.localizable.delegationsAddTitle( - preferredLanguages: languages - ) + title = localizableTitle.value(for: selectedLocale) } private func setupHandlers() { diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewFactory.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewFactory.swift index 4a4c576cff..71cb690ab5 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewFactory.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewFactory.swift @@ -4,14 +4,16 @@ import SoraFoundation struct StakingConfirmProxyViewFactory { static func createView( state: RelaychainStakingSharedStateProtocol, - proxyAddress: AccountAddress + proxyAddress: AccountAddress, + confirmOperation: StakingProxyConfirmOperation ) -> StakingConfirmProxyViewProtocol? { guard let currencyManager = CurrencyManager.shared, let wallet = SelectedWalletSettings.shared.value, let interactor = createInteractor( state: state, wallet: wallet, - proxyAddress: proxyAddress + proxyAddress: proxyAddress, + operation: confirmOperation ) else { return nil } @@ -47,7 +49,8 @@ struct StakingConfirmProxyViewFactory { let view = StakingConfirmProxyViewController( presenter: presenter, - localizationManager: LocalizationManager.shared + localizationManager: LocalizationManager.shared, + title: confirmOperation.title ) presenter.baseView = view @@ -60,7 +63,8 @@ struct StakingConfirmProxyViewFactory { private static func createInteractor( state: RelaychainStakingSharedStateProtocol, wallet: MetaAccountModel, - proxyAddress: AccountAddress + proxyAddress: AccountAddress, + operation: StakingProxyConfirmOperation ) -> StakingConfirmProxyInteractor? { let chainRegistry = ChainRegistryFacade.sharedRegistry let chainAsset = state.stakingOption.chainAsset @@ -106,6 +110,7 @@ struct StakingConfirmProxyViewFactory { extrinsicService: extrinsicService, selectedAccount: selectedAccount, currencyManager: currencyManager, + operation: operation, operationQueue: OperationManagerFacade.sharedDefaultQueue ) } diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingProxyConfirmOperation.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingProxyConfirmOperation.swift new file mode 100644 index 0000000000..b1b38a88ce --- /dev/null +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingProxyConfirmOperation.swift @@ -0,0 +1,48 @@ +import SubstrateSdk +import SoraFoundation + +enum StakingProxyConfirmOperation { + case add + case remove + + func builderClosure( + callFactory: SubstrateCallFactoryProtocol, + accountId: AccountId + ) -> ExtrinsicBuilderClosure { + switch self { + case .add: + let call = callFactory.addProxy( + accountId: accountId, + type: .staking + ) + return { builder in + try builder.adding(call: call) + } + case .remove: + let call = callFactory.removeProxy( + accountId: accountId, + type: .staking + ) + return { builder in + try builder.adding(call: call) + } + } + } + + var title: LocalizableResource { + switch self { + case .add: + return .init { + R.string.localizable.delegationsAddTitle( + preferredLanguages: $0.rLanguages + ) + } + case .remove: + return .init { + R.string.localizable.stakingProxyManagementRevokeAccess( + preferredLanguages: $0.rLanguages + ) + } + } + } +} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyWireframe.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyWireframe.swift index a245049401..36d426486e 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyWireframe.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyWireframe.swift @@ -17,7 +17,8 @@ final class StakingSetupProxyWireframe: StakingSetupProxyWireframeProtocol { ) { guard let confirmView = StakingConfirmProxyViewFactory.createView( state: state, - proxyAddress: proxyAddress + proxyAddress: proxyAddress, + confirmOperation: .add ) else { return } From 83df0e54e6a63125196df1e2de3b3c8384194d31 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Mon, 22 Jan 2024 11:57:53 +0300 Subject: [PATCH 30/60] add validations --- novawallet.xcodeproj/project.pbxproj | 12 ++++ .../Base/StakingProxyBasePresenter.swift | 16 +++--- .../StakingConfirmProxyPresenter.swift | 21 ++++++- .../StakingConfirmProxyViewFactory.swift | 1 + .../StakingProxyConfirmOperation.swift | 9 +++ .../StakingSetupProxyPresenter.swift | 2 +- .../AddProxyValidationsFactory.swift | 56 +++++++++++++++++++ ...oxyConfirmValidationsFactoryProtocol.swift | 18 ++++++ .../RemoveProxyValidationsFactory.swift | 31 ++++++++++ 9 files changed, 156 insertions(+), 10 deletions(-) create mode 100644 novawallet/Modules/Staking/StakingSetupProxy/Validation/AddProxyValidationsFactory.swift create mode 100644 novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyConfirmValidationsFactoryProtocol.swift create mode 100644 novawallet/Modules/Staking/StakingSetupProxy/Validation/RemoveProxyValidationsFactory.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 673bbdef23..0c7b86b831 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -931,6 +931,9 @@ 77C35CE52B568ED100308F16 /* YourWalletsPresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C35CE42B568ED100308F16 /* YourWalletsPresentable.swift */; }; 77C35CE72B56D07300308F16 /* ScanAddressPresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C35CE62B56D07300308F16 /* ScanAddressPresentable.swift */; }; 77C35CE92B5A890500308F16 /* Web3NameServiceFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C35CE82B5A890500308F16 /* Web3NameServiceFactory.swift */; }; + 77C3D7CF2B5E624C00997BA0 /* ProxyConfirmValidationsFactoryProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C3D7CE2B5E624C00997BA0 /* ProxyConfirmValidationsFactoryProtocol.swift */; }; + 77C3D7D12B5E626900997BA0 /* AddProxyValidationsFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C3D7D02B5E626900997BA0 /* AddProxyValidationsFactory.swift */; }; + 77C3D7D32B5E628700997BA0 /* RemoveProxyValidationsFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C3D7D22B5E628700997BA0 /* RemoveProxyValidationsFactory.swift */; }; 77C976202AF36A170049272C /* SwapModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C9761F2AF36A170049272C /* SwapModels.swift */; }; 77C976222AF39F180049272C /* TokenOperationTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C976212AF39F180049272C /* TokenOperationTableViewCell.swift */; }; 77C976242AF3A5280049272C /* SwapViewModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C976232AF3A5280049272C /* SwapViewModels.swift */; }; @@ -5165,6 +5168,9 @@ 77C35CE42B568ED100308F16 /* YourWalletsPresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YourWalletsPresentable.swift; sourceTree = ""; }; 77C35CE62B56D07300308F16 /* ScanAddressPresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanAddressPresentable.swift; sourceTree = ""; }; 77C35CE82B5A890500308F16 /* Web3NameServiceFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Web3NameServiceFactory.swift; sourceTree = ""; }; + 77C3D7CE2B5E624C00997BA0 /* ProxyConfirmValidationsFactoryProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProxyConfirmValidationsFactoryProtocol.swift; sourceTree = ""; }; + 77C3D7D02B5E626900997BA0 /* AddProxyValidationsFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddProxyValidationsFactory.swift; sourceTree = ""; }; + 77C3D7D22B5E628700997BA0 /* RemoveProxyValidationsFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoveProxyValidationsFactory.swift; sourceTree = ""; }; 77C9761F2AF36A170049272C /* SwapModels.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwapModels.swift; sourceTree = ""; }; 77C976212AF39F180049272C /* TokenOperationTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokenOperationTableViewCell.swift; sourceTree = ""; }; 77C976232AF3A5280049272C /* SwapViewModels.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwapViewModels.swift; sourceTree = ""; }; @@ -10250,6 +10256,9 @@ 773090542B5591AC002577AE /* Validation */ = { isa = PBXGroup; children = ( + 77C3D7CE2B5E624C00997BA0 /* ProxyConfirmValidationsFactoryProtocol.swift */, + 77C3D7D02B5E626900997BA0 /* AddProxyValidationsFactory.swift */, + 77C3D7D22B5E628700997BA0 /* RemoveProxyValidationsFactory.swift */, 773090522B5591A1002577AE /* ProxyErrorPresentable.swift */, 773090502B559196002577AE /* ProxyDataValidatorFactory.swift */, ); @@ -20823,6 +20832,7 @@ 849013DE24A927E2008F705E /* LocalizationManager+Shared.swift in Sources */, 8412AF9B2789ABBC008A6C22 /* PolkadotExtensionMetadataResponse.swift in Sources */, 84F1CB3727CE5EC30095D523 /* NftListViewModelFactory.swift in Sources */, + 77C3D7CF2B5E624C00997BA0 /* ProxyConfirmValidationsFactoryProtocol.swift in Sources */, 849013DC24A927E2008F705E /* ApplicationConfigs.swift in Sources */, 84DA03DB275A31B500E8B326 /* DAppListHeaderView.swift in Sources */, 84ACEBFA261E684A00AAE665 /* WalletHistoryFilter.swift in Sources */, @@ -21274,6 +21284,7 @@ 84CE69E82566750D00559427 /* ByteLengthProcessor.swift in Sources */, 8499FEDA27BFDB8C00712589 /* NFTStreamableSource.swift in Sources */, 849976BE27B269A400B14A6C /* DAppTransports.swift in Sources */, + 77C3D7D32B5E628700997BA0 /* RemoveProxyValidationsFactory.swift in Sources */, 842876A724AE049B00D91AD8 /* SelectionListProtocols.swift in Sources */, AE6F7FE22685E812002BBC3E /* ValidatorListFilterWireframe.swift in Sources */, 849014DD24AA8F60008F705E /* MainTabBarViewFactory.swift in Sources */, @@ -23820,6 +23831,7 @@ 9DE1757D047A4D1E97913774 /* GovernanceUnlockConfirmProtocols.swift in Sources */, 2272FB0A01000A46D097634E /* GovernanceUnlockConfirmWireframe.swift in Sources */, 0CC2E56A2A6E6EBB004092E7 /* LocalStorageProviderObserving.swift in Sources */, + 77C3D7D12B5E626900997BA0 /* AddProxyValidationsFactory.swift in Sources */, A3BDFA01A32B6C7463E6EFFA /* GovernanceUnlockConfirmPresenter.swift in Sources */, 62649D3FB6AACB508872C67A /* GovernanceUnlockConfirmInteractor.swift in Sources */, 6D603098CCF0B65AA726AD38 /* GovernanceUnlockConfirmViewController.swift in Sources */, diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift index 365fc942e0..028d1ab970 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift @@ -10,13 +10,13 @@ class StakingProxyBasePresenter: StakingSetupProxyBasePresenterProtocol { private let interactor: StakingProxyBaseInteractorInputProtocol private let wireframe: StakingSetupProxyBaseWireframeProtocol - private var assetBalance: AssetBalance? - private var proxyDeposit: ProxyDeposit? - private var priceData: PriceData? - private var fee: ExtrinsicFeeProtocol? - private var existensialDeposit: BigUInt? - private var maxProxies: Int? - private var proxy: UncertainStorage = .undefined + private(set) var assetBalance: AssetBalance? + private(set) var proxyDeposit: ProxyDeposit? + private(set) var priceData: PriceData? + private(set) var fee: ExtrinsicFeeProtocol? + private(set) var existensialDeposit: BigUInt? + private(set) var maxProxies: Int? + private(set) var proxy: UncertainStorage = .undefined init( chainAsset: ChainAsset, @@ -76,7 +76,7 @@ class StakingProxyBasePresenter: StakingSetupProxyBasePresenterProtocol { wireframe.showProxyDepositInfo(from: baseView) } - func createCommonValidations() -> [DataValidating] { + func createValidations() -> [DataValidating] { [ dataValidatingFactory.validAddress( getProxyAddress(), diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyPresenter.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyPresenter.swift index 81125e798d..c6107f3ffa 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyPresenter.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyPresenter.swift @@ -13,6 +13,7 @@ final class StakingConfirmProxyPresenter: StakingProxyBasePresenter { let wallet: MetaAccountModel let displayAddressViewModelFactory: DisplayAddressViewModelFactoryProtocol let networkViewModelFactory: NetworkViewModelFactoryProtocol + let validationsFactory: ProxyConfirmValidationsFactoryProtocol private lazy var walletIconGenerator = NovaIconGenerator() @@ -24,6 +25,7 @@ final class StakingConfirmProxyPresenter: StakingProxyBasePresenter { wireframe: StakingConfirmProxyWireframeProtocol, balanceViewModelFactory: BalanceViewModelFactoryProtocol, dataValidatingFactory: ProxyDataValidatorFactoryProtocol, + validationsFactory: ProxyConfirmValidationsFactoryProtocol, displayAddressViewModelFactory: DisplayAddressViewModelFactoryProtocol, networkViewModelFactory: NetworkViewModelFactoryProtocol, localizationManager: LocalizationManagerProtocol @@ -34,6 +36,7 @@ final class StakingConfirmProxyPresenter: StakingProxyBasePresenter { self.wireframe = wireframe self.displayAddressViewModelFactory = displayAddressViewModelFactory self.networkViewModelFactory = networkViewModelFactory + self.validationsFactory = validationsFactory super.init( chainAsset: chainAsset, @@ -87,6 +90,22 @@ final class StakingConfirmProxyPresenter: StakingProxyBasePresenter { override func getProxyAddress() -> AccountAddress { proxyAddress } + + override func createValidations() -> [DataValidating] { + let args = ConfirmProxyValidationArgs( + proxyAddress: getProxyAddress(), + chainAsset: chainAsset, + proxy: proxy, + limitProxyCount: maxProxies, + feeFetchClosure: { [weak self] in self?.interactor.estimateFee() }, + assetBalance: assetBalance, + proxyDeposit: proxyDeposit, + existensialDeposit: existensialDeposit, + fee: fee + ) + + return validationsFactory.validations(args, locale: selectedLocale) + } } extension StakingConfirmProxyPresenter: StakingConfirmProxyPresenterProtocol { @@ -116,7 +135,7 @@ extension StakingConfirmProxyPresenter: StakingConfirmProxyPresenterProtocol { func confirm() { view?.didStartLoading() - let validations = createCommonValidations() + let validations = createValidations() DataValidationRunner(validators: validations).runValidation { [weak self] in self?.interactor.submit() diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewFactory.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewFactory.swift index 71cb690ab5..d1d53fb094 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewFactory.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewFactory.swift @@ -42,6 +42,7 @@ struct StakingConfirmProxyViewFactory { wireframe: wireframe, balanceViewModelFactory: balanceViewModelFactory, dataValidatingFactory: dataValidatingFactory, + validationsFactory: confirmOperation.validationFactory(dataValidatingFactory: dataValidatingFactory), displayAddressViewModelFactory: DisplayAddressViewModelFactory(), networkViewModelFactory: NetworkViewModelFactory(), localizationManager: LocalizationManager.shared diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingProxyConfirmOperation.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingProxyConfirmOperation.swift index b1b38a88ce..6f5e079e56 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingProxyConfirmOperation.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingProxyConfirmOperation.swift @@ -45,4 +45,13 @@ enum StakingProxyConfirmOperation { } } } + + func validationFactory(dataValidatingFactory: ProxyDataValidatorFactoryProtocol) -> ProxyConfirmValidationsFactoryProtocol { + switch self { + case .add: + return AddProxyValidationsFactory(dataValidatingFactory: dataValidatingFactory) + case .remove: + return RemoveProxyValidationsFactory(dataValidatingFactory: dataValidatingFactory) + } + } } diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyPresenter.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyPresenter.swift index f1118ed9b6..95146ec417 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyPresenter.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyPresenter.swift @@ -138,7 +138,7 @@ final class StakingSetupProxyPresenter: StakingProxyBasePresenter { } private func proceedWithValidation() { - let validations = createCommonValidations() + let validations = createValidations() DataValidationRunner(validators: validations).runValidation { [weak self] in guard diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Validation/AddProxyValidationsFactory.swift b/novawallet/Modules/Staking/StakingSetupProxy/Validation/AddProxyValidationsFactory.swift new file mode 100644 index 0000000000..ee7bebed8f --- /dev/null +++ b/novawallet/Modules/Staking/StakingSetupProxy/Validation/AddProxyValidationsFactory.swift @@ -0,0 +1,56 @@ +import Foundation +import BigInt + +final class AddProxyValidationsFactory: ProxyConfirmValidationsFactoryProtocol { + let dataValidatingFactory: ProxyDataValidatorFactoryProtocol + + init(dataValidatingFactory: ProxyDataValidatorFactoryProtocol) { + self.dataValidatingFactory = dataValidatingFactory + } + + func validations(_ args: ConfirmProxyValidationArgs, locale: Locale) -> [DataValidating] { + [ + dataValidatingFactory.validAddress( + args.proxyAddress, + chain: args.chainAsset.chain, + locale: locale + ), + dataValidatingFactory.proxyNotExists( + address: args.proxyAddress, + chain: args.chainAsset.chain, + proxyList: args.proxy.map { $0?.definition ?? [] }.value, + locale: locale + ), + dataValidatingFactory.notReachedMaximimProxyCount( + args.proxy.map { $0?.definition.count ?? 0 }.value.map { $0 + 1 }, + limit: args.limitProxyCount, + chain: args.chainAsset.chain, + locale: locale + ), + dataValidatingFactory.has( + fee: args.fee, + locale: locale, + onError: args.feeFetchClosure + ), + dataValidatingFactory.canPayFeeInPlank( + balance: args.assetBalance?.regularTransferrableBalance(), + fee: args.fee, + asset: args.chainAsset.assetDisplayInfo, + locale: locale + ), + dataValidatingFactory.hasSufficientBalance( + available: (args.assetBalance?.regularTransferrableBalance() ?? 0) + (args.proxyDeposit?.current ?? 0), + deposit: args.proxyDeposit?.new, + fee: args.fee?.amountForCurrentAccount, + asset: args.chainAsset.assetDisplayInfo, + locale: locale + ), + dataValidatingFactory.exsitentialDepositIsNotViolated( + spendingAmount: args.fee?.amountForCurrentAccount, + totalAmount: args.assetBalance?.freeInPlank, + minimumBalance: args.existensialDeposit, + locale: locale + ) + ] + } +} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyConfirmValidationsFactoryProtocol.swift b/novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyConfirmValidationsFactoryProtocol.swift new file mode 100644 index 0000000000..a582fedbb2 --- /dev/null +++ b/novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyConfirmValidationsFactoryProtocol.swift @@ -0,0 +1,18 @@ +import Foundation +import BigInt + +struct ConfirmProxyValidationArgs { + let proxyAddress: AccountAddress + let chainAsset: ChainAsset + let proxy: UncertainStorage + let limitProxyCount: Int? + let feeFetchClosure: () -> Void + let assetBalance: AssetBalance? + let proxyDeposit: ProxyDeposit? + let existensialDeposit: BigUInt? + let fee: ExtrinsicFeeProtocol? +} + +protocol ProxyConfirmValidationsFactoryProtocol { + func validations(_ args: ConfirmProxyValidationArgs, locale: Locale) -> [DataValidating] +} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Validation/RemoveProxyValidationsFactory.swift b/novawallet/Modules/Staking/StakingSetupProxy/Validation/RemoveProxyValidationsFactory.swift new file mode 100644 index 0000000000..438d372fd4 --- /dev/null +++ b/novawallet/Modules/Staking/StakingSetupProxy/Validation/RemoveProxyValidationsFactory.swift @@ -0,0 +1,31 @@ +import Foundation +import BigInt + +final class RemoveProxyValidationsFactory: ProxyConfirmValidationsFactoryProtocol { + let dataValidatingFactory: ProxyDataValidatorFactoryProtocol + + init(dataValidatingFactory: ProxyDataValidatorFactoryProtocol) { + self.dataValidatingFactory = dataValidatingFactory + } + + func validations(_ args: ConfirmProxyValidationArgs, locale: Locale) -> [DataValidating] { + [ + dataValidatingFactory.validAddress( + args.proxyAddress, + chain: args.chainAsset.chain, + locale: locale + ), + dataValidatingFactory.has( + fee: args.fee, + locale: locale, + onError: args.feeFetchClosure + ), + dataValidatingFactory.canPayFeeInPlank( + balance: args.assetBalance?.regularTransferrableBalance(), + fee: args.fee, + asset: args.chainAsset.assetDisplayInfo, + locale: locale + ) + ] + } +} From 97e427b866c09406178f0ec243fae04d72cb820b Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Mon, 22 Jan 2024 14:52:02 +0300 Subject: [PATCH 31/60] separate add and remove interactors --- novawallet.xcodeproj/project.pbxproj | 20 +- .../StakingProxyManagementWireframe.swift | 5 +- .../StakingConfirmProxyInteractor.swift | 20 +- .../StakingConfirmProxyPresenter.swift | 17 ++ .../StakingConfirmProxyViewFactory.swift | 136 ++++++++++- .../StakingProxyConfirmOperation.swift | 57 ----- .../StakingRemoveProxyInteractor.swift | 211 ++++++++++++++++++ .../StakingRemoveProxyProtocols.swift | 22 ++ .../StakingSetupProxyWireframe.swift | 5 +- 9 files changed, 403 insertions(+), 90 deletions(-) delete mode 100644 novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingProxyConfirmOperation.swift create mode 100644 novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyInteractor.swift create mode 100644 novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyProtocols.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 0c7b86b831..250c60382d 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -927,13 +927,14 @@ 77AB55592AA244BB0058814E /* OperationPoolRewardOrSlashModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77AB55582AA244BB0058814E /* OperationPoolRewardOrSlashModel.swift */; }; 77AB555B2AA246CA0058814E /* OperationPoolRewardOrSlashViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77AB555A2AA246CA0058814E /* OperationPoolRewardOrSlashViewModel.swift */; }; 77AB555D2AA24BA90058814E /* OperationDetailsPoolRewardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77AB555C2AA24BA90058814E /* OperationDetailsPoolRewardView.swift */; }; - 77B00A202B5AC6F200EAAEBE /* StakingProxyConfirmOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77B00A1F2B5AC6F200EAAEBE /* StakingProxyConfirmOperation.swift */; }; 77C35CE52B568ED100308F16 /* YourWalletsPresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C35CE42B568ED100308F16 /* YourWalletsPresentable.swift */; }; 77C35CE72B56D07300308F16 /* ScanAddressPresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C35CE62B56D07300308F16 /* ScanAddressPresentable.swift */; }; 77C35CE92B5A890500308F16 /* Web3NameServiceFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C35CE82B5A890500308F16 /* Web3NameServiceFactory.swift */; }; 77C3D7CF2B5E624C00997BA0 /* ProxyConfirmValidationsFactoryProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C3D7CE2B5E624C00997BA0 /* ProxyConfirmValidationsFactoryProtocol.swift */; }; 77C3D7D12B5E626900997BA0 /* AddProxyValidationsFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C3D7D02B5E626900997BA0 /* AddProxyValidationsFactory.swift */; }; 77C3D7D32B5E628700997BA0 /* RemoveProxyValidationsFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C3D7D22B5E628700997BA0 /* RemoveProxyValidationsFactory.swift */; }; + 77C3D7D52B5E7E7800997BA0 /* StakingRemoveProxyInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C3D7D42B5E7E7800997BA0 /* StakingRemoveProxyInteractor.swift */; }; + 77C3D7D72B5E824700997BA0 /* StakingRemoveProxyProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C3D7D62B5E824700997BA0 /* StakingRemoveProxyProtocols.swift */; }; 77C976202AF36A170049272C /* SwapModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C9761F2AF36A170049272C /* SwapModels.swift */; }; 77C976222AF39F180049272C /* TokenOperationTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C976212AF39F180049272C /* TokenOperationTableViewCell.swift */; }; 77C976242AF3A5280049272C /* SwapViewModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77C976232AF3A5280049272C /* SwapViewModels.swift */; }; @@ -5164,13 +5165,14 @@ 77AB55582AA244BB0058814E /* OperationPoolRewardOrSlashModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OperationPoolRewardOrSlashModel.swift; sourceTree = ""; }; 77AB555A2AA246CA0058814E /* OperationPoolRewardOrSlashViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OperationPoolRewardOrSlashViewModel.swift; sourceTree = ""; }; 77AB555C2AA24BA90058814E /* OperationDetailsPoolRewardView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OperationDetailsPoolRewardView.swift; sourceTree = ""; }; - 77B00A1F2B5AC6F200EAAEBE /* StakingProxyConfirmOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingProxyConfirmOperation.swift; sourceTree = ""; }; 77C35CE42B568ED100308F16 /* YourWalletsPresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YourWalletsPresentable.swift; sourceTree = ""; }; 77C35CE62B56D07300308F16 /* ScanAddressPresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanAddressPresentable.swift; sourceTree = ""; }; 77C35CE82B5A890500308F16 /* Web3NameServiceFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Web3NameServiceFactory.swift; sourceTree = ""; }; 77C3D7CE2B5E624C00997BA0 /* ProxyConfirmValidationsFactoryProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProxyConfirmValidationsFactoryProtocol.swift; sourceTree = ""; }; 77C3D7D02B5E626900997BA0 /* AddProxyValidationsFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddProxyValidationsFactory.swift; sourceTree = ""; }; 77C3D7D22B5E628700997BA0 /* RemoveProxyValidationsFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoveProxyValidationsFactory.swift; sourceTree = ""; }; + 77C3D7D42B5E7E7800997BA0 /* StakingRemoveProxyInteractor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StakingRemoveProxyInteractor.swift; sourceTree = ""; }; + 77C3D7D62B5E824700997BA0 /* StakingRemoveProxyProtocols.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StakingRemoveProxyProtocols.swift; sourceTree = ""; }; 77C9761F2AF36A170049272C /* SwapModels.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwapModels.swift; sourceTree = ""; }; 77C976212AF39F180049272C /* TokenOperationTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokenOperationTableViewCell.swift; sourceTree = ""; }; 77C976232AF3A5280049272C /* SwapViewModels.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwapViewModels.swift; sourceTree = ""; }; @@ -10062,7 +10064,6 @@ B4E64E1B99253D7F875C637C /* StakingConfirmProxyViewController.swift */, 3543AE2CAA63AC0A20D532B6 /* StakingConfirmProxyViewLayout.swift */, 0E52C5919A1DA8A18297325B /* StakingConfirmProxyViewFactory.swift */, - 77B00A1F2B5AC6F200EAAEBE /* StakingProxyConfirmOperation.swift */, ); path = StakingConfirmProxy; sourceTree = ""; @@ -10518,6 +10519,15 @@ path = canonicalization; sourceTree = ""; }; + 77C3D7D82B5E825600997BA0 /* StakingRemoveProxy */ = { + isa = PBXGroup; + children = ( + 77C3D7D42B5E7E7800997BA0 /* StakingRemoveProxyInteractor.swift */, + 77C3D7D62B5E824700997BA0 /* StakingRemoveProxyProtocols.swift */, + ); + path = StakingRemoveProxy; + sourceTree = ""; + }; 77C9BCBA2ACD1AE800022EA2 /* Model */ = { isa = PBXGroup; children = ( @@ -18220,6 +18230,7 @@ A4542BFD7BBCF6B05FB2D3E4 /* StakingSetupProxy */ = { isa = PBXGroup; children = ( + 77C3D7D82B5E825600997BA0 /* StakingRemoveProxy */, 600A0B1B13D9E0897BC4FDA9 /* StakingConfirmProxy */, 773090542B5591AC002577AE /* Validation */, 7754BD542B501E3C0099C13E /* Base */, @@ -22475,6 +22486,7 @@ 84C1DBBA29C0A11200F295A5 /* XcmTransferService+Fee.swift in Sources */, 77C9BCD02ACD8A3600022EA2 /* SwapAssetsOperationViewLayout.swift in Sources */, 845B081529190056005785D3 /* Gov1UnlockReferendum.swift in Sources */, + 77C3D7D72B5E824700997BA0 /* StakingRemoveProxyProtocols.swift in Sources */, 84B24FB02A2F7B6F00F9BF59 /* StakingDashboardMoreOptionsCell.swift in Sources */, 77799ADD2A74219A00B7E564 /* ButtonState.swift in Sources */, 84BAD222293C655900C55C49 /* TokensManageViewModelFactory.swift in Sources */, @@ -22902,7 +22914,6 @@ 88FB7DD12950720800784E08 /* ContainerProtocols.swift in Sources */, 840AE2E529C9AF9C008FF665 /* EtherscanWalletHistoryDecodable.swift in Sources */, 772B1C7D2A93837800A19061 /* StartStakingCustomValidatorListWireframe.swift in Sources */, - 77B00A202B5AC6F200EAAEBE /* StakingProxyConfirmOperation.swift in Sources */, 77AAE2202AFB00CB006872CC /* OperationSwapModel.swift in Sources */, 8465DA35298EC5FB00C7CFF1 /* TitleDetailsSheetLayout.swift in Sources */, AEE5FB1C264A610C002B8FDC /* StakingRewardDestSetupLayout.swift in Sources */, @@ -23801,6 +23812,7 @@ F35B520D7955A70588AB593C /* ReferendumVoteConfirmWireframe.swift in Sources */, F0ADB63765A8EAA19D85C30B /* ReferendumVoteConfirmPresenter.swift in Sources */, 84C9CF3D291AF1B1002BF328 /* GovernanceOffchainApi.swift in Sources */, + 77C3D7D52B5E7E7800997BA0 /* StakingRemoveProxyInteractor.swift in Sources */, 84BAD21A293B18EC00C55C49 /* RemoteAssetModel.swift in Sources */, DE52F23521D54A07F558EB1B /* ReferendumVoteConfirmInteractor.swift in Sources */, 844304652A28EB0D00DE36DE /* ObservableSyncService.swift in Sources */, diff --git a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementWireframe.swift b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementWireframe.swift index 7445775aa2..a42e7d4f5a 100644 --- a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementWireframe.swift +++ b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementWireframe.swift @@ -18,10 +18,9 @@ final class StakingProxyManagementWireframe: StakingProxyManagementWireframeProt } func showRevokeProxyAccess(from view: ControllerBackedProtocol?, proxyAddress: AccountAddress) { - guard let confirmView = StakingConfirmProxyViewFactory.createView( + guard let confirmView = StakingConfirmProxyViewFactory.createRemoveProxyView( state: state, - proxyAddress: proxyAddress, - confirmOperation: .remove + proxyAddress: proxyAddress ) else { return } diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyInteractor.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyInteractor.swift index 2118cdac13..18658753cc 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyInteractor.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyInteractor.swift @@ -1,13 +1,9 @@ import UIKit final class StakingConfirmProxyInteractor: StakingProxyBaseInteractor { - weak var presenter: StakingConfirmProxyInteractorOutputProtocol? { - basePresenter as? StakingConfirmProxyInteractorOutputProtocol - } - + weak var presenter: StakingConfirmProxyInteractorOutputProtocol? let proxyAccount: AccountAddress let signingWrapper: SigningWrapperProtocol - let operation: StakingProxyConfirmOperation init( proxyAccount: AccountAddress, @@ -22,12 +18,10 @@ final class StakingConfirmProxyInteractor: StakingProxyBaseInteractor { extrinsicService: ExtrinsicServiceProtocol, selectedAccount: ChainAccountResponse, currencyManager: CurrencyManagerProtocol, - operation: StakingProxyConfirmOperation, operationQueue: OperationQueue ) { self.proxyAccount = proxyAccount self.signingWrapper = signingWrapper - self.operation = operation super.init( runtimeService: runtimeService, @@ -54,11 +48,15 @@ extension StakingConfirmProxyInteractor: StakingConfirmProxyInteractorInputProto return } + let call = callFactory.addProxy( + accountId: proxyAccountId, + type: .staking + ) + extrinsicService.submit( - operation.builderClosure( - callFactory: callFactory, - accountId: proxyAccountId - ), + { builder in + try builder.adding(call: call) + }, signer: signingWrapper, runningIn: .main, completion: { [weak self] result in diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyPresenter.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyPresenter.swift index c6107f3ffa..cde38adea4 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyPresenter.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyPresenter.swift @@ -169,3 +169,20 @@ extension StakingConfirmProxyPresenter: StakingConfirmProxyInteractorOutputProto } } } + +extension StakingConfirmProxyPresenter: StakingRemoveProxyInteractorOutputProtocol { + func didReceive(removingError: StakingRemoveProxyError) { + switch removingError { + case let .handleProxies(error): + didReceive(baseError: .handleProxies(error)) + case let .balance(error): + didReceive(baseError: .balance(error)) + case let .price(error): + didReceive(baseError: .price(error)) + case let .fee(error): + didReceive(baseError: .fee(error)) + case let .submit(error): + didReceive(error: .submit(error)) + } + } +} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewFactory.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewFactory.swift index d1d53fb094..1f83ebb54e 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewFactory.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewFactory.swift @@ -2,18 +2,16 @@ import Foundation import SoraFoundation struct StakingConfirmProxyViewFactory { - static func createView( + static func createAddProxyView( state: RelaychainStakingSharedStateProtocol, - proxyAddress: AccountAddress, - confirmOperation: StakingProxyConfirmOperation + proxyAddress: AccountAddress ) -> StakingConfirmProxyViewProtocol? { guard let currencyManager = CurrencyManager.shared, let wallet = SelectedWalletSettings.shared.value, - let interactor = createInteractor( + let interactor = createAddProxyInteractor( state: state, wallet: wallet, - proxyAddress: proxyAddress, - operation: confirmOperation + proxyAddress: proxyAddress ) else { return nil } @@ -42,7 +40,7 @@ struct StakingConfirmProxyViewFactory { wireframe: wireframe, balanceViewModelFactory: balanceViewModelFactory, dataValidatingFactory: dataValidatingFactory, - validationsFactory: confirmOperation.validationFactory(dataValidatingFactory: dataValidatingFactory), + validationsFactory: AddProxyValidationsFactory(dataValidatingFactory: dataValidatingFactory), displayAddressViewModelFactory: DisplayAddressViewModelFactory(), networkViewModelFactory: NetworkViewModelFactory(), localizationManager: LocalizationManager.shared @@ -51,7 +49,11 @@ struct StakingConfirmProxyViewFactory { let view = StakingConfirmProxyViewController( presenter: presenter, localizationManager: LocalizationManager.shared, - title: confirmOperation.title + title: .init { + R.string.localizable.delegationsAddTitle( + preferredLanguages: $0.rLanguages + ) + } ) presenter.baseView = view @@ -61,11 +63,71 @@ struct StakingConfirmProxyViewFactory { return view } - private static func createInteractor( + static func createRemoveProxyView( + state: RelaychainStakingSharedStateProtocol, + proxyAddress: AccountAddress + ) -> StakingConfirmProxyViewProtocol? { + guard let currencyManager = CurrencyManager.shared, + let wallet = SelectedWalletSettings.shared.value, + let interactor = createAddProxyInteractor( + state: state, + wallet: wallet, + proxyAddress: proxyAddress + ) else { + return nil + } + + let wireframe = StakingConfirmProxyWireframe() + + let chainAsset = state.stakingOption.chainAsset + + let priceAssetInfoFactory = PriceAssetInfoFactory(currencyManager: currencyManager) + let balanceViewModelFactory = BalanceViewModelFactory( + targetAssetInfo: chainAsset.assetDisplayInfo, + priceAssetInfoFactory: priceAssetInfoFactory + ) + let dataValidatingFactory = ProxyDataValidatorFactory( + presentable: wireframe, + balanceViewModelFactoryFacade: BalanceViewModelFactoryFacade( + priceAssetInfoFactory: priceAssetInfoFactory + ) + ) + + let presenter = StakingConfirmProxyPresenter( + chainAsset: chainAsset, + wallet: wallet, + proxyAddress: proxyAddress, + interactor: interactor, + wireframe: wireframe, + balanceViewModelFactory: balanceViewModelFactory, + dataValidatingFactory: dataValidatingFactory, + validationsFactory: RemoveProxyValidationsFactory(dataValidatingFactory: dataValidatingFactory), + displayAddressViewModelFactory: DisplayAddressViewModelFactory(), + networkViewModelFactory: NetworkViewModelFactory(), + localizationManager: LocalizationManager.shared + ) + + let view = StakingConfirmProxyViewController( + presenter: presenter, + localizationManager: LocalizationManager.shared, + title: .init { + R.string.localizable.stakingProxyManagementRevokeAccess( + preferredLanguages: $0.rLanguages + ) + } + ) + + presenter.baseView = view + interactor.presenter = presenter + dataValidatingFactory.view = view + + return view + } + + private static func createAddProxyInteractor( state: RelaychainStakingSharedStateProtocol, wallet: MetaAccountModel, - proxyAddress: AccountAddress, - operation: StakingProxyConfirmOperation + proxyAddress: AccountAddress ) -> StakingConfirmProxyInteractor? { let chainRegistry = ChainRegistryFacade.sharedRegistry let chainAsset = state.stakingOption.chainAsset @@ -111,8 +173,58 @@ struct StakingConfirmProxyViewFactory { extrinsicService: extrinsicService, selectedAccount: selectedAccount, currencyManager: currencyManager, - operation: operation, operationQueue: OperationManagerFacade.sharedDefaultQueue ) } + + private static func createRemoveProxyInteractor( + state: RelaychainStakingSharedStateProtocol, + wallet: MetaAccountModel, + proxyAddress: AccountAddress + ) -> StakingRemoveProxyInteractor? { + let chainRegistry = ChainRegistryFacade.sharedRegistry + let chainAsset = state.stakingOption.chainAsset + + guard + let selectedAccount = wallet.fetch( + for: chainAsset.chain.accountRequest() + ), + let connection = chainRegistry.getConnection(for: chainAsset.chain.chainId), + let runtimeRegistry = chainRegistry.getRuntimeProvider(for: chainAsset.chain.chainId), + let currencyManager = CurrencyManager.shared else { + return nil + } + + let extrinsicService = ExtrinsicServiceFactory( + runtimeRegistry: runtimeRegistry, + engine: connection, + operationManager: OperationManagerFacade.sharedManager, + userStorageFacade: UserDataStorageFacade.shared + ).createService(account: selectedAccount, chain: chainAsset.chain) + + let accountProviderFactory = AccountProviderFactory( + storageFacade: UserDataStorageFacade.shared, + operationManager: OperationManagerFacade.sharedManager, + logger: Logger.shared + ) + + let signingWrapper = SigningWrapperFactory().createSigningWrapper( + for: wallet.metaId, + accountResponse: selectedAccount + ) + + return StakingRemoveProxyInteractor( + proxyAccount: proxyAddress, + signingWrapper: signingWrapper, + sharedState: state, + walletLocalSubscriptionFactory: WalletLocalSubscriptionFactory.shared, + accountProviderFactory: accountProviderFactory, + priceLocalSubscriptionFactory: PriceProviderFactory.shared, + callFactory: SubstrateCallFactory(), + feeProxy: ExtrinsicFeeProxy(), + extrinsicService: extrinsicService, + selectedAccount: selectedAccount, + currencyManager: currencyManager + ) + } } diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingProxyConfirmOperation.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingProxyConfirmOperation.swift deleted file mode 100644 index 6f5e079e56..0000000000 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingProxyConfirmOperation.swift +++ /dev/null @@ -1,57 +0,0 @@ -import SubstrateSdk -import SoraFoundation - -enum StakingProxyConfirmOperation { - case add - case remove - - func builderClosure( - callFactory: SubstrateCallFactoryProtocol, - accountId: AccountId - ) -> ExtrinsicBuilderClosure { - switch self { - case .add: - let call = callFactory.addProxy( - accountId: accountId, - type: .staking - ) - return { builder in - try builder.adding(call: call) - } - case .remove: - let call = callFactory.removeProxy( - accountId: accountId, - type: .staking - ) - return { builder in - try builder.adding(call: call) - } - } - } - - var title: LocalizableResource { - switch self { - case .add: - return .init { - R.string.localizable.delegationsAddTitle( - preferredLanguages: $0.rLanguages - ) - } - case .remove: - return .init { - R.string.localizable.stakingProxyManagementRevokeAccess( - preferredLanguages: $0.rLanguages - ) - } - } - } - - func validationFactory(dataValidatingFactory: ProxyDataValidatorFactoryProtocol) -> ProxyConfirmValidationsFactoryProtocol { - switch self { - case .add: - return AddProxyValidationsFactory(dataValidatingFactory: dataValidatingFactory) - case .remove: - return RemoveProxyValidationsFactory(dataValidatingFactory: dataValidatingFactory) - } - } -} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyInteractor.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyInteractor.swift new file mode 100644 index 0000000000..4de5473e66 --- /dev/null +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyInteractor.swift @@ -0,0 +1,211 @@ +import UIKit +import RobinHood + +final class StakingRemoveProxyInteractor: StakingRemoveProxyInteractorInputProtocol, AnyProviderAutoCleaning { + weak var presenter: StakingRemoveProxyInteractorOutputProtocol? + let selectedAccount: ChainAccountResponse + let walletLocalSubscriptionFactory: WalletLocalSubscriptionFactoryProtocol + let accountProviderFactory: AccountProviderFactoryProtocol + let priceLocalSubscriptionFactory: PriceProviderFactoryProtocol + let callFactory: SubstrateCallFactoryProtocol + let feeProxy: ExtrinsicFeeProxyProtocol + let sharedState: RelaychainStakingSharedStateProtocol + let extrinsicService: ExtrinsicServiceProtocol + var chainAsset: ChainAsset { + sharedState.stakingOption.chainAsset + } + + private var proxyProvider: AnyDataProvider? + private var balanceProvider: StreamableProvider? + private var priceProvider: StreamableProvider? + + var proxyListLocalSubscriptionFactory: ProxyListLocalSubscriptionFactoryProtocol { + sharedState.proxyLocalSubscriptionFactory + } + + let proxyAccount: AccountAddress + let signingWrapper: SigningWrapperProtocol + + init( + proxyAccount: AccountAddress, + signingWrapper: SigningWrapperProtocol, + sharedState: RelaychainStakingSharedStateProtocol, + walletLocalSubscriptionFactory: WalletLocalSubscriptionFactoryProtocol, + accountProviderFactory: AccountProviderFactoryProtocol, + priceLocalSubscriptionFactory: PriceProviderFactoryProtocol, + callFactory: SubstrateCallFactoryProtocol, + feeProxy: ExtrinsicFeeProxyProtocol, + extrinsicService: ExtrinsicServiceProtocol, + selectedAccount: ChainAccountResponse, + currencyManager: CurrencyManagerProtocol + ) { + self.signingWrapper = signingWrapper + self.proxyAccount = proxyAccount + + self.extrinsicService = extrinsicService + self.sharedState = sharedState + self.walletLocalSubscriptionFactory = walletLocalSubscriptionFactory + self.accountProviderFactory = accountProviderFactory + self.priceLocalSubscriptionFactory = priceLocalSubscriptionFactory + self.callFactory = callFactory + self.feeProxy = feeProxy + self.selectedAccount = selectedAccount + self.currencyManager = currencyManager + } + + private func performPriceSubscription() { + clear(streamableProvider: &priceProvider) + + guard let priceId = chainAsset.asset.priceId else { + presenter?.didReceive(price: nil) + return + } + + priceProvider = subscribeToPrice(for: priceId, currency: selectedCurrency) + } + + func performAccountSubscriptions() { + clear(streamableProvider: &balanceProvider) + clear(dataProvider: &proxyProvider) + + let chainId = chainAsset.chain.chainId + let accountId = selectedAccount.accountId + + proxyProvider = subscribeProxies( + for: accountId, + chainId: chainId, + modifyInternalList: ProxyFilter.allProxies + ) + + balanceProvider = subscribeToAssetBalanceProvider( + for: accountId, + chainId: chainAsset.chain.chainId, + assetId: chainAsset.asset.assetId + ) + + estimateFee() + } + + // MARK: - StakingProxyBaseInteractorInputProtocol + + func setup() { + feeProxy.delegate = self + + performPriceSubscription() + performAccountSubscriptions() + } + + func estimateFee() { + guard let proxyAccountId = try? proxyAccount.toAccountId( + using: chainAsset.chain.chainFormat + ) else { + return + } + + let call = callFactory.removeProxy( + accountId: proxyAccountId, + type: .staking + ) + + feeProxy.estimateFee(using: extrinsicService, reuseIdentifier: call.callName) { builder in + try builder.adding(call: call) + } + } + + func remakeSubscriptions() { + performPriceSubscription() + performAccountSubscriptions() + } + + func submit() { + guard let proxyAccountId = try? proxyAccount.toAccountId( + using: chainAsset.chain.chainFormat + ) else { + presenter?.didReceive(removingError: .submit(CommonError.undefined)) + return + } + + let call = callFactory.removeProxy( + accountId: proxyAccountId, + type: .staking + ) + + extrinsicService.submit( + { builder in + try builder.adding(call: call) + }, + signer: signingWrapper, + runningIn: .main, + completion: { [weak self] result in + switch result { + case .success: + self?.presenter?.didSubmit() + case let .failure(error): + self?.presenter?.didReceive(removingError: .submit(error)) + } + } + ) + } +} + +extension StakingRemoveProxyInteractor: PriceLocalStorageSubscriber, PriceLocalSubscriptionHandler { + func handlePrice(result: Result, priceId: AssetModel.PriceId) { + if chainAsset.asset.priceId == priceId { + switch result { + case let .success(priceData): + presenter?.didReceive(price: priceData) + case let .failure(error): + presenter?.didReceive(removingError: .price(error)) + } + } + } +} + +extension StakingRemoveProxyInteractor: WalletLocalStorageSubscriber, WalletLocalSubscriptionHandler { + func handleAssetBalance( + result: Result, + accountId _: AccountId, + chainId _: ChainModel.Id, + assetId _: AssetModel.Id + ) { + switch result { + case let .success(assetBalance): + presenter?.didReceive(assetBalance: assetBalance) + case let .failure(error): + presenter?.didReceive(removingError: .balance(error)) + } + } +} + +extension StakingRemoveProxyInteractor: ExtrinsicFeeProxyDelegate { + func didReceiveFee(result: Result, for _: TransactionFeeId) { + switch result { + case let .success(fee): + presenter?.didReceive(fee: fee) + case let .failure(error): + presenter?.didReceive(removingError: .fee(error)) + } + } +} + +extension StakingRemoveProxyInteractor: SelectedCurrencyDepending { + func applyCurrency() { + guard presenter != nil, + let priceId = chainAsset.asset.priceId else { + return + } + + priceProvider = subscribeToPrice(for: priceId, currency: selectedCurrency) + } +} + +extension StakingRemoveProxyInteractor: ProxyListLocalSubscriptionHandler, ProxyListLocalStorageSubscriber { + func handleProxies(result: Result, accountId _: AccountId, chainId _: ChainModel.Id) { + switch result { + case let .success(proxy): + presenter?.didReceive(proxy: proxy) + case let .failure(error): + presenter?.didReceive(removingError: .handleProxies(error)) + } + } +} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyProtocols.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyProtocols.swift new file mode 100644 index 0000000000..633c41294a --- /dev/null +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyProtocols.swift @@ -0,0 +1,22 @@ +protocol StakingRemoveProxyInteractorInputProtocol: AnyObject { + func setup() + func estimateFee() + func remakeSubscriptions() +} + +protocol StakingRemoveProxyInteractorOutputProtocol: AnyObject { + func didReceive(removingError: StakingRemoveProxyError) + func didReceive(assetBalance: AssetBalance?) + func didReceive(fee: ExtrinsicFeeProtocol?) + func didReceive(proxy: ProxyDefinition?) + func didReceive(price: PriceData?) + func didSubmit() +} + +enum StakingRemoveProxyError: Error { + case handleProxies(Error) + case balance(Error) + case price(Error) + case fee(Error) + case submit(Error) +} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyWireframe.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyWireframe.swift index 36d426486e..5b5889d52a 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyWireframe.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyWireframe.swift @@ -15,10 +15,9 @@ final class StakingSetupProxyWireframe: StakingSetupProxyWireframeProtocol { from view: ControllerBackedProtocol?, proxyAddress: AccountAddress ) { - guard let confirmView = StakingConfirmProxyViewFactory.createView( + guard let confirmView = StakingConfirmProxyViewFactory.createAddProxyView( state: state, - proxyAddress: proxyAddress, - confirmOperation: .add + proxyAddress: proxyAddress ) else { return } From 93a1abb3dece656cef5335505673115c5c64fe63 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Mon, 22 Jan 2024 15:10:28 +0300 Subject: [PATCH 32/60] deposit is optional --- .../Base/StakingProxyBasePresenter.swift | 2 +- .../Base/StakingProxyBaseProtocols.swift | 2 +- .../StakingConfirmProxyPresenter.swift | 1 + .../StakingConfirmProxyViewController.swift | 9 +++++++-- .../StakingSetupProxyViewController.swift | 8 ++++++-- 5 files changed, 16 insertions(+), 6 deletions(-) diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift index 028d1ab970..30ac0fb785 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift @@ -36,7 +36,7 @@ class StakingProxyBasePresenter: StakingSetupProxyBasePresenterProtocol { func provideProxyDeposit() { guard let amount = proxyDeposit?.diff.decimal(precision: chainAsset.asset.precision) else { - baseView?.didReceiveProxyDeposit(viewModel: .loading) + baseView?.didReceiveProxyDeposit(viewModel: nil) return } let proxyDepositViewModel = balanceViewModelFactory.balanceFromPrice( diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseProtocols.swift b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseProtocols.swift index ccf3bd3bd7..9646356194 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseProtocols.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseProtocols.swift @@ -30,7 +30,7 @@ protocol StakingProxyBaseInteractorInputProtocol: AnyObject { } protocol StakingSetupProxyBaseViewProtocol: ControllerBackedProtocol { - func didReceiveProxyDeposit(viewModel: LoadableViewModelState) + func didReceiveProxyDeposit(viewModel: LoadableViewModelState?) func didReceiveFee(viewModel: BalanceViewModelProtocol?) } diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyPresenter.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyPresenter.swift index cde38adea4..e87d48b2a7 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyPresenter.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyPresenter.swift @@ -51,6 +51,7 @@ final class StakingConfirmProxyPresenter: StakingProxyBasePresenter { override func setup() { super.setup() + provideProxyDeposit() provideNetworkViewModel() provideProxiedWalletViewModel() provideProxiedAddressViewModel() diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewController.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewController.swift index 2f6a4cdd37..08a222a29f 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewController.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewController.swift @@ -108,8 +108,13 @@ final class StakingConfirmProxyViewController: UIViewController, ViewHolder { } extension StakingConfirmProxyViewController: StakingConfirmProxyViewProtocol { - func didReceiveProxyDeposit(viewModel: LoadableViewModelState) { - rootView.proxyDepositView.bind(loadableViewModel: viewModel) + func didReceiveProxyDeposit(viewModel: LoadableViewModelState?) { + if let viewModel = viewModel { + rootView.proxyDepositView.isHidden = false + rootView.proxyDepositView.bind(loadableViewModel: viewModel) + } else { + rootView.proxyDepositView.isHidden = true + } } func didReceiveFee(viewModel: BalanceViewModelProtocol?) { diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewController.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewController.swift index 450df0efc8..3f007c4b17 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewController.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewController.swift @@ -137,8 +137,12 @@ final class StakingSetupProxyViewController: UIViewController, ViewHolder { } extension StakingSetupProxyViewController: StakingSetupProxyViewProtocol { - func didReceiveProxyDeposit(viewModel: LoadableViewModelState) { - rootView.proxyDepositView.bind(loadableViewModel: viewModel) + func didReceiveProxyDeposit(viewModel: LoadableViewModelState?) { + if let viewModel = viewModel { + rootView.proxyDepositView.bind(loadableViewModel: viewModel) + } else { + rootView.proxyDepositView.bind(loadableViewModel: .loading) + } } func didReceiveFee(viewModel: BalanceViewModelProtocol?) { From 69ab2833dc0492e2a6df5b6aeed02ffbcae99e22 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Mon, 22 Jan 2024 17:51:03 +0300 Subject: [PATCH 33/60] bugfix interactor setup --- .../StakingConfirmProxy/StakingConfirmProxyInteractor.swift | 5 ++++- .../StakingConfirmProxy/StakingConfirmProxyViewFactory.swift | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyInteractor.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyInteractor.swift index 18658753cc..bce0717992 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyInteractor.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyInteractor.swift @@ -1,7 +1,10 @@ import UIKit final class StakingConfirmProxyInteractor: StakingProxyBaseInteractor { - weak var presenter: StakingConfirmProxyInteractorOutputProtocol? + weak var presenter: StakingConfirmProxyInteractorOutputProtocol? { + basePresenter as? StakingConfirmProxyInteractorOutputProtocol + } + let proxyAccount: AccountAddress let signingWrapper: SigningWrapperProtocol diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewFactory.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewFactory.swift index 1f83ebb54e..c3b85d84f7 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewFactory.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewFactory.swift @@ -69,7 +69,7 @@ struct StakingConfirmProxyViewFactory { ) -> StakingConfirmProxyViewProtocol? { guard let currencyManager = CurrencyManager.shared, let wallet = SelectedWalletSettings.shared.value, - let interactor = createAddProxyInteractor( + let interactor = createRemoveProxyInteractor( state: state, wallet: wallet, proxyAddress: proxyAddress From 992350bc8ca3c37f86c4b2c13d98f6048fb0c90c Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Mon, 22 Jan 2024 22:00:51 +0300 Subject: [PATCH 34/60] separate add and remove presenters --- novawallet.xcodeproj/project.pbxproj | 8 + .../Common/Helpers/ChainAccountFetching.swift | 5 + .../StakingProxyManagementWireframe.swift | 2 +- .../Base/StakingProxyBasePresenter.swift | 2 +- .../StakingConfirmProxyPresenter.swift | 38 +-- .../StakingConfirmProxyViewFactory.swift | 118 +--------- .../StakingRemoveProxyInteractor.swift | 51 +--- .../StakingRemoveProxyPresenter.swift | 219 ++++++++++++++++++ .../StakingRemoveProxyProtocols.swift | 4 +- .../StakingRemoveProxyViewFactory.swift | 115 +++++++++ .../StakingSetupProxyWireframe.swift | 2 +- 11 files changed, 370 insertions(+), 194 deletions(-) create mode 100644 novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyPresenter.swift create mode 100644 novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyViewFactory.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 250c60382d..b571aa3467 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -859,6 +859,8 @@ 77799AEE2A7CFB6A00B7E564 /* DirectStakingTypeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77799AED2A7CFB6A00B7E564 /* DirectStakingTypeViewModel.swift */; }; 77799AF02A7CFB7C00B7E564 /* ValidatorViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77799AEF2A7CFB7C00B7E564 /* ValidatorViewModel.swift */; }; 77799AF22A7CFB8D00B7E564 /* PoolAccountViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77799AF12A7CFB8D00B7E564 /* PoolAccountViewModel.swift */; }; + 7779D1112B5EE39C008966A8 /* StakingRemoveProxyPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7779D1102B5EE39C008966A8 /* StakingRemoveProxyPresenter.swift */; }; + 7779D1132B5EEE46008966A8 /* StakingRemoveProxyViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7779D1122B5EEE46008966A8 /* StakingRemoveProxyViewFactory.swift */; }; 777AE2AB2ABCB4A5004989C0 /* HtmlParsingOperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 777AE2AA2ABCB4A5004989C0 /* HtmlParsingOperationFactory.swift */; }; 777AE2AD2ABCB4BD004989C0 /* MarkupParsingOperationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 777AE2AC2ABCB4BD004989C0 /* MarkupParsingOperationFactory.swift */; }; 777BD86029F9730F004969A2 /* ReferendumsFilterViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 777BD85F29F9730F004969A2 /* ReferendumsFilterViewModel.swift */; }; @@ -5096,6 +5098,8 @@ 77799AED2A7CFB6A00B7E564 /* DirectStakingTypeViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DirectStakingTypeViewModel.swift; sourceTree = ""; }; 77799AEF2A7CFB7C00B7E564 /* ValidatorViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValidatorViewModel.swift; sourceTree = ""; }; 77799AF12A7CFB8D00B7E564 /* PoolAccountViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PoolAccountViewModel.swift; sourceTree = ""; }; + 7779D1102B5EE39C008966A8 /* StakingRemoveProxyPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StakingRemoveProxyPresenter.swift; sourceTree = ""; }; + 7779D1122B5EEE46008966A8 /* StakingRemoveProxyViewFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StakingRemoveProxyViewFactory.swift; sourceTree = ""; }; 777AE2AA2ABCB4A5004989C0 /* HtmlParsingOperationFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HtmlParsingOperationFactory.swift; sourceTree = ""; }; 777AE2AC2ABCB4BD004989C0 /* MarkupParsingOperationFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarkupParsingOperationFactory.swift; sourceTree = ""; }; 777BD85F29F9730F004969A2 /* ReferendumsFilterViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferendumsFilterViewModel.swift; sourceTree = ""; }; @@ -10524,6 +10528,8 @@ children = ( 77C3D7D42B5E7E7800997BA0 /* StakingRemoveProxyInteractor.swift */, 77C3D7D62B5E824700997BA0 /* StakingRemoveProxyProtocols.swift */, + 7779D1102B5EE39C008966A8 /* StakingRemoveProxyPresenter.swift */, + 7779D1122B5EEE46008966A8 /* StakingRemoveProxyViewFactory.swift */, ); path = StakingRemoveProxy; sourceTree = ""; @@ -21796,6 +21802,7 @@ 840874DE29782DD400ACFA55 /* GovernanceDelegateMetadataFactory.swift in Sources */, 77E0DC9E2A6940C400D03724 /* Calendar+Helpers.swift in Sources */, 0C626D1D2A915E2F00CDAF4E /* StakingNominationPoolsStatics.swift in Sources */, + 7779D1132B5EEE46008966A8 /* StakingRemoveProxyViewFactory.swift in Sources */, 846A835A28B8C5EC00D92892 /* TransactionExpiredPresentable.swift in Sources */, 842EBB352890A79500B952D8 /* WalletSelectionViewFactory.swift in Sources */, 844C3E602A0635DE00C4305F /* QRScanViewDisplayParams.swift in Sources */, @@ -22681,6 +22688,7 @@ 841E5567282EAC1000C8438F /* ParachainStakingInitState.swift in Sources */, 77799AEC2A7CFB5700B7E564 /* PoolStakingTypeViewModel.swift in Sources */, 77AB55592AA244BB0058814E /* OperationPoolRewardOrSlashModel.swift in Sources */, + 7779D1112B5EE39C008966A8 /* StakingRemoveProxyPresenter.swift in Sources */, 0C7945C02ABB259D001C07CA /* XTokensMetadataQueryFactory.swift in Sources */, 3250F2C0E12ED42A355853BE /* SelectValidatorsStartProtocols.swift in Sources */, EC978E6C4FBF39BE9ED10C86 /* SelectValidatorsStartWireframe.swift in Sources */, diff --git a/novawallet/Common/Helpers/ChainAccountFetching.swift b/novawallet/Common/Helpers/ChainAccountFetching.swift index 7d38c87156..1473e9a39a 100644 --- a/novawallet/Common/Helpers/ChainAccountFetching.swift +++ b/novawallet/Common/Helpers/ChainAccountFetching.swift @@ -294,6 +294,11 @@ extension MetaAccountModel { return chainAccount.proxy } + + func address(for chainAsset: ChainAsset) throws -> AccountAddress? { + let request = chainAsset.chain.accountRequest() + return try fetchChainAccountId(for: request)?.toAddress(using: chainAsset.chain.chainFormat) + } } extension ChainModel { diff --git a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementWireframe.swift b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementWireframe.swift index a42e7d4f5a..367e3a94c1 100644 --- a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementWireframe.swift +++ b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementWireframe.swift @@ -18,7 +18,7 @@ final class StakingProxyManagementWireframe: StakingProxyManagementWireframeProt } func showRevokeProxyAccess(from view: ControllerBackedProtocol?, proxyAddress: AccountAddress) { - guard let confirmView = StakingConfirmProxyViewFactory.createRemoveProxyView( + guard let confirmView = StakingRemoveProxyViewFactory.createView( state: state, proxyAddress: proxyAddress ) else { diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift index 30ac0fb785..028d1ab970 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift @@ -36,7 +36,7 @@ class StakingProxyBasePresenter: StakingSetupProxyBasePresenterProtocol { func provideProxyDeposit() { guard let amount = proxyDeposit?.diff.decimal(precision: chainAsset.asset.precision) else { - baseView?.didReceiveProxyDeposit(viewModel: nil) + baseView?.didReceiveProxyDeposit(viewModel: .loading) return } let proxyDepositViewModel = balanceViewModelFactory.balanceFromPrice( diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyPresenter.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyPresenter.swift index e87d48b2a7..bdfc3b9847 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyPresenter.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyPresenter.swift @@ -91,22 +91,6 @@ final class StakingConfirmProxyPresenter: StakingProxyBasePresenter { override func getProxyAddress() -> AccountAddress { proxyAddress } - - override func createValidations() -> [DataValidating] { - let args = ConfirmProxyValidationArgs( - proxyAddress: getProxyAddress(), - chainAsset: chainAsset, - proxy: proxy, - limitProxyCount: maxProxies, - feeFetchClosure: { [weak self] in self?.interactor.estimateFee() }, - assetBalance: assetBalance, - proxyDeposit: proxyDeposit, - existensialDeposit: existensialDeposit, - fee: fee - ) - - return validationsFactory.validations(args, locale: selectedLocale) - } } extension StakingConfirmProxyPresenter: StakingConfirmProxyPresenterProtocol { @@ -114,9 +98,12 @@ extension StakingConfirmProxyPresenter: StakingConfirmProxyPresenterProtocol { guard let view = view else { return } + guard let address = try? wallet.address(for: chainAsset) else { + return + } wireframe.presentAccountOptions( from: view, - address: "", + address: address, chain: chainAsset.chain, locale: selectedLocale ) @@ -170,20 +157,3 @@ extension StakingConfirmProxyPresenter: StakingConfirmProxyInteractorOutputProto } } } - -extension StakingConfirmProxyPresenter: StakingRemoveProxyInteractorOutputProtocol { - func didReceive(removingError: StakingRemoveProxyError) { - switch removingError { - case let .handleProxies(error): - didReceive(baseError: .handleProxies(error)) - case let .balance(error): - didReceive(baseError: .balance(error)) - case let .price(error): - didReceive(baseError: .price(error)) - case let .fee(error): - didReceive(baseError: .fee(error)) - case let .submit(error): - didReceive(error: .submit(error)) - } - } -} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewFactory.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewFactory.swift index c3b85d84f7..a35548170c 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewFactory.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewFactory.swift @@ -2,13 +2,13 @@ import Foundation import SoraFoundation struct StakingConfirmProxyViewFactory { - static func createAddProxyView( + static func createView( state: RelaychainStakingSharedStateProtocol, proxyAddress: AccountAddress ) -> StakingConfirmProxyViewProtocol? { guard let currencyManager = CurrencyManager.shared, let wallet = SelectedWalletSettings.shared.value, - let interactor = createAddProxyInteractor( + let interactor = createInteractor( state: state, wallet: wallet, proxyAddress: proxyAddress @@ -63,68 +63,7 @@ struct StakingConfirmProxyViewFactory { return view } - static func createRemoveProxyView( - state: RelaychainStakingSharedStateProtocol, - proxyAddress: AccountAddress - ) -> StakingConfirmProxyViewProtocol? { - guard let currencyManager = CurrencyManager.shared, - let wallet = SelectedWalletSettings.shared.value, - let interactor = createRemoveProxyInteractor( - state: state, - wallet: wallet, - proxyAddress: proxyAddress - ) else { - return nil - } - - let wireframe = StakingConfirmProxyWireframe() - - let chainAsset = state.stakingOption.chainAsset - - let priceAssetInfoFactory = PriceAssetInfoFactory(currencyManager: currencyManager) - let balanceViewModelFactory = BalanceViewModelFactory( - targetAssetInfo: chainAsset.assetDisplayInfo, - priceAssetInfoFactory: priceAssetInfoFactory - ) - let dataValidatingFactory = ProxyDataValidatorFactory( - presentable: wireframe, - balanceViewModelFactoryFacade: BalanceViewModelFactoryFacade( - priceAssetInfoFactory: priceAssetInfoFactory - ) - ) - - let presenter = StakingConfirmProxyPresenter( - chainAsset: chainAsset, - wallet: wallet, - proxyAddress: proxyAddress, - interactor: interactor, - wireframe: wireframe, - balanceViewModelFactory: balanceViewModelFactory, - dataValidatingFactory: dataValidatingFactory, - validationsFactory: RemoveProxyValidationsFactory(dataValidatingFactory: dataValidatingFactory), - displayAddressViewModelFactory: DisplayAddressViewModelFactory(), - networkViewModelFactory: NetworkViewModelFactory(), - localizationManager: LocalizationManager.shared - ) - - let view = StakingConfirmProxyViewController( - presenter: presenter, - localizationManager: LocalizationManager.shared, - title: .init { - R.string.localizable.stakingProxyManagementRevokeAccess( - preferredLanguages: $0.rLanguages - ) - } - ) - - presenter.baseView = view - interactor.presenter = presenter - dataValidatingFactory.view = view - - return view - } - - private static func createAddProxyInteractor( + private static func createInteractor( state: RelaychainStakingSharedStateProtocol, wallet: MetaAccountModel, proxyAddress: AccountAddress @@ -176,55 +115,4 @@ struct StakingConfirmProxyViewFactory { operationQueue: OperationManagerFacade.sharedDefaultQueue ) } - - private static func createRemoveProxyInteractor( - state: RelaychainStakingSharedStateProtocol, - wallet: MetaAccountModel, - proxyAddress: AccountAddress - ) -> StakingRemoveProxyInteractor? { - let chainRegistry = ChainRegistryFacade.sharedRegistry - let chainAsset = state.stakingOption.chainAsset - - guard - let selectedAccount = wallet.fetch( - for: chainAsset.chain.accountRequest() - ), - let connection = chainRegistry.getConnection(for: chainAsset.chain.chainId), - let runtimeRegistry = chainRegistry.getRuntimeProvider(for: chainAsset.chain.chainId), - let currencyManager = CurrencyManager.shared else { - return nil - } - - let extrinsicService = ExtrinsicServiceFactory( - runtimeRegistry: runtimeRegistry, - engine: connection, - operationManager: OperationManagerFacade.sharedManager, - userStorageFacade: UserDataStorageFacade.shared - ).createService(account: selectedAccount, chain: chainAsset.chain) - - let accountProviderFactory = AccountProviderFactory( - storageFacade: UserDataStorageFacade.shared, - operationManager: OperationManagerFacade.sharedManager, - logger: Logger.shared - ) - - let signingWrapper = SigningWrapperFactory().createSigningWrapper( - for: wallet.metaId, - accountResponse: selectedAccount - ) - - return StakingRemoveProxyInteractor( - proxyAccount: proxyAddress, - signingWrapper: signingWrapper, - sharedState: state, - walletLocalSubscriptionFactory: WalletLocalSubscriptionFactory.shared, - accountProviderFactory: accountProviderFactory, - priceLocalSubscriptionFactory: PriceProviderFactory.shared, - callFactory: SubstrateCallFactory(), - feeProxy: ExtrinsicFeeProxy(), - extrinsicService: extrinsicService, - selectedAccount: selectedAccount, - currencyManager: currencyManager - ) - } } diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyInteractor.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyInteractor.swift index 4de5473e66..8785a30e33 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyInteractor.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyInteractor.swift @@ -9,27 +9,18 @@ final class StakingRemoveProxyInteractor: StakingRemoveProxyInteractorInputProto let priceLocalSubscriptionFactory: PriceProviderFactoryProtocol let callFactory: SubstrateCallFactoryProtocol let feeProxy: ExtrinsicFeeProxyProtocol - let sharedState: RelaychainStakingSharedStateProtocol let extrinsicService: ExtrinsicServiceProtocol - var chainAsset: ChainAsset { - sharedState.stakingOption.chainAsset - } - - private var proxyProvider: AnyDataProvider? + let chainAsset: ChainAsset private var balanceProvider: StreamableProvider? private var priceProvider: StreamableProvider? - var proxyListLocalSubscriptionFactory: ProxyListLocalSubscriptionFactoryProtocol { - sharedState.proxyLocalSubscriptionFactory - } - let proxyAccount: AccountAddress let signingWrapper: SigningWrapperProtocol init( proxyAccount: AccountAddress, signingWrapper: SigningWrapperProtocol, - sharedState: RelaychainStakingSharedStateProtocol, + chainAsset: ChainAsset, walletLocalSubscriptionFactory: WalletLocalSubscriptionFactoryProtocol, accountProviderFactory: AccountProviderFactoryProtocol, priceLocalSubscriptionFactory: PriceProviderFactoryProtocol, @@ -41,9 +32,8 @@ final class StakingRemoveProxyInteractor: StakingRemoveProxyInteractorInputProto ) { self.signingWrapper = signingWrapper self.proxyAccount = proxyAccount - self.extrinsicService = extrinsicService - self.sharedState = sharedState + self.chainAsset = chainAsset self.walletLocalSubscriptionFactory = walletLocalSubscriptionFactory self.accountProviderFactory = accountProviderFactory self.priceLocalSubscriptionFactory = priceLocalSubscriptionFactory @@ -64,19 +54,11 @@ final class StakingRemoveProxyInteractor: StakingRemoveProxyInteractorInputProto priceProvider = subscribeToPrice(for: priceId, currency: selectedCurrency) } - func performAccountSubscriptions() { + func performBalanceSubscription() { clear(streamableProvider: &balanceProvider) - clear(dataProvider: &proxyProvider) - let chainId = chainAsset.chain.chainId let accountId = selectedAccount.accountId - proxyProvider = subscribeProxies( - for: accountId, - chainId: chainId, - modifyInternalList: ProxyFilter.allProxies - ) - balanceProvider = subscribeToAssetBalanceProvider( for: accountId, chainId: chainAsset.chain.chainId, @@ -92,7 +74,7 @@ final class StakingRemoveProxyInteractor: StakingRemoveProxyInteractorInputProto feeProxy.delegate = self performPriceSubscription() - performAccountSubscriptions() + performBalanceSubscription() } func estimateFee() { @@ -114,14 +96,14 @@ final class StakingRemoveProxyInteractor: StakingRemoveProxyInteractorInputProto func remakeSubscriptions() { performPriceSubscription() - performAccountSubscriptions() + performBalanceSubscription() } func submit() { guard let proxyAccountId = try? proxyAccount.toAccountId( using: chainAsset.chain.chainFormat ) else { - presenter?.didReceive(removingError: .submit(CommonError.undefined)) + presenter?.didReceive(error: .submit(CommonError.undefined)) return } @@ -141,7 +123,7 @@ final class StakingRemoveProxyInteractor: StakingRemoveProxyInteractorInputProto case .success: self?.presenter?.didSubmit() case let .failure(error): - self?.presenter?.didReceive(removingError: .submit(error)) + self?.presenter?.didReceive(error: .submit(error)) } } ) @@ -155,7 +137,7 @@ extension StakingRemoveProxyInteractor: PriceLocalStorageSubscriber, PriceLocalS case let .success(priceData): presenter?.didReceive(price: priceData) case let .failure(error): - presenter?.didReceive(removingError: .price(error)) + presenter?.didReceive(error: .price(error)) } } } @@ -172,7 +154,7 @@ extension StakingRemoveProxyInteractor: WalletLocalStorageSubscriber, WalletLoca case let .success(assetBalance): presenter?.didReceive(assetBalance: assetBalance) case let .failure(error): - presenter?.didReceive(removingError: .balance(error)) + presenter?.didReceive(error: .balance(error)) } } } @@ -183,7 +165,7 @@ extension StakingRemoveProxyInteractor: ExtrinsicFeeProxyDelegate { case let .success(fee): presenter?.didReceive(fee: fee) case let .failure(error): - presenter?.didReceive(removingError: .fee(error)) + presenter?.didReceive(error: .fee(error)) } } } @@ -198,14 +180,3 @@ extension StakingRemoveProxyInteractor: SelectedCurrencyDepending { priceProvider = subscribeToPrice(for: priceId, currency: selectedCurrency) } } - -extension StakingRemoveProxyInteractor: ProxyListLocalSubscriptionHandler, ProxyListLocalStorageSubscriber { - func handleProxies(result: Result, accountId _: AccountId, chainId _: ChainModel.Id) { - switch result { - case let .success(proxy): - presenter?.didReceive(proxy: proxy) - case let .failure(error): - presenter?.didReceive(removingError: .handleProxies(error)) - } - } -} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyPresenter.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyPresenter.swift new file mode 100644 index 0000000000..dbdd242e17 --- /dev/null +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyPresenter.swift @@ -0,0 +1,219 @@ +import Foundation +import SoraFoundation +import SubstrateSdk + +final class StakingRemoveProxyPresenter { + weak var view: StakingConfirmProxyViewProtocol? + + let wireframe: StakingConfirmProxyWireframeProtocol + let interactor: StakingRemoveProxyInteractorInputProtocol + let proxyAddress: AccountAddress + let wallet: MetaAccountModel + let chainAsset: ChainAsset + let displayAddressViewModelFactory: DisplayAddressViewModelFactoryProtocol + let networkViewModelFactory: NetworkViewModelFactoryProtocol + let dataValidatingFactory: ProxyDataValidatorFactoryProtocol + let balanceViewModelFactory: BalanceViewModelFactoryProtocol + + private var assetBalance: AssetBalance? + private var priceData: PriceData? + private var fee: ExtrinsicFeeProtocol? + + private lazy var walletIconGenerator = NovaIconGenerator() + + init( + chainAsset: ChainAsset, + wallet: MetaAccountModel, + proxyAddress: AccountAddress, + interactor: StakingRemoveProxyInteractorInputProtocol, + wireframe: StakingConfirmProxyWireframeProtocol, + dataValidatingFactory: ProxyDataValidatorFactoryProtocol, + displayAddressViewModelFactory: DisplayAddressViewModelFactoryProtocol, + networkViewModelFactory: NetworkViewModelFactoryProtocol, + balanceViewModelFactory: BalanceViewModelFactoryProtocol, + localizationManager: LocalizationManagerProtocol + ) { + self.proxyAddress = proxyAddress + self.wallet = wallet + self.chainAsset = chainAsset + self.interactor = interactor + self.wireframe = wireframe + self.displayAddressViewModelFactory = displayAddressViewModelFactory + self.networkViewModelFactory = networkViewModelFactory + self.dataValidatingFactory = dataValidatingFactory + self.balanceViewModelFactory = balanceViewModelFactory + self.localizationManager = localizationManager + } + + private func provideNetworkViewModel() { + let viewModel = networkViewModelFactory.createViewModel(from: chainAsset.chain) + view?.didReceiveNetwork(viewModel: viewModel) + } + + private func provideProxiedWalletViewModel() { + let name = wallet.name + + let icon = wallet.walletIdenticonData().flatMap { try? walletIconGenerator.generateFromAccountId($0) } + let iconViewModel = icon.map { DrawableIconViewModel(icon: $0) } + let viewModel = StackCellViewModel(details: name, imageViewModel: iconViewModel) + view?.didReceiveWallet(viewModel: viewModel) + } + + private func provideProxiedAddressViewModel() { + guard let address = wallet.fetch(for: chainAsset.chain.accountRequest())?.toAddress() else { + return + } + + let displayAddress = DisplayAddress(address: address, username: "") + let viewModel = displayAddressViewModelFactory.createViewModel(from: displayAddress) + view?.didReceiveProxiedAddress(viewModel: viewModel) + } + + private func provideProxyAddressViewModel() { + let displayAddress = DisplayAddress(address: proxyAddress, username: "") + let viewModel = displayAddressViewModelFactory.createViewModel(from: displayAddress) + view?.didReceiveProxyAddress(viewModel: viewModel) + } + + private func provideFee() { + guard let fee = fee?.amount.decimal(precision: chainAsset.asset.precision) else { + view?.didReceiveFee(viewModel: nil) + return + } + let feeViewModel = balanceViewModelFactory.balanceFromPrice( + fee, + priceData: priceData + ).value(for: selectedLocale) + view?.didReceiveFee(viewModel: feeViewModel) + } + + private func createValidations() -> [DataValidating] { + [ + dataValidatingFactory.validAddress( + proxyAddress, + chain: chainAsset.chain, + locale: selectedLocale + ), + dataValidatingFactory.has( + fee: fee, + locale: selectedLocale, + onError: { [weak self] in + self?.interactor.estimateFee() + } + ), + dataValidatingFactory.canPayFeeInPlank( + balance: assetBalance?.regularTransferrableBalance(), + fee: fee, + asset: chainAsset.assetDisplayInfo, + locale: selectedLocale + ) + ] + } + + private func updateView() { + provideNetworkViewModel() + provideProxiedWalletViewModel() + provideProxiedAddressViewModel() + provideProxyAddressViewModel() + } +} + +extension StakingRemoveProxyPresenter: StakingConfirmProxyPresenterProtocol { + func setup() { + updateView() + interactor.setup() + } + + func showProxiedAddressOptions() { + guard let view = view else { + return + } + guard let address = try? wallet.address(for: chainAsset) else { + return + } + wireframe.presentAccountOptions( + from: view, + address: address, + chain: chainAsset.chain, + locale: selectedLocale + ) + } + + func showProxyAddressOptions() { + guard let view = view else { + return + } + wireframe.presentAccountOptions( + from: view, + address: proxyAddress, + chain: chainAsset.chain, + locale: selectedLocale + ) + } + + func confirm() { + view?.didStartLoading() + let validations = createValidations() + + DataValidationRunner(validators: validations).runValidation { [weak self] in + self?.interactor.submit() + } + } + + func showDepositInfo() {} +} + +extension StakingRemoveProxyPresenter: StakingRemoveProxyInteractorOutputProtocol { + func didReceive(price: PriceData?) { + priceData = price + provideFee() + } + + func didReceive(assetBalance: AssetBalance?) { + self.assetBalance = assetBalance + } + + func didReceive(fee: ExtrinsicFeeProtocol?) { + self.fee = fee + provideFee() + } + + func didSubmit() { + view?.didStopLoading() + + wireframe.presentExtrinsicSubmission( + from: view, + completionAction: .dismiss, + locale: selectedLocale + ) + } + + func didReceive(error: StakingRemoveProxyError) { + view?.didStopLoading() + + switch error { + case .handleProxies, .balance, .price: + interactor.remakeSubscriptions() + case .fee: + wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in + self?.interactor.estimateFee() + } + case let .submit(error): + wireframe.handleExtrinsicSigningErrorPresentationElseDefault( + error, + view: view, + closeAction: .dismiss, + locale: selectedLocale, + completionClosure: nil + ) + } + } +} + +extension StakingRemoveProxyPresenter: Localizable { + func applyLocalization() { + if view?.isSetup == true { + updateView() + } + } +} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyProtocols.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyProtocols.swift index 633c41294a..6683745341 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyProtocols.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyProtocols.swift @@ -2,13 +2,13 @@ protocol StakingRemoveProxyInteractorInputProtocol: AnyObject { func setup() func estimateFee() func remakeSubscriptions() + func submit() } protocol StakingRemoveProxyInteractorOutputProtocol: AnyObject { - func didReceive(removingError: StakingRemoveProxyError) + func didReceive(error: StakingRemoveProxyError) func didReceive(assetBalance: AssetBalance?) func didReceive(fee: ExtrinsicFeeProtocol?) - func didReceive(proxy: ProxyDefinition?) func didReceive(price: PriceData?) func didSubmit() } diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyViewFactory.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyViewFactory.swift new file mode 100644 index 0000000000..317f3e4638 --- /dev/null +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyViewFactory.swift @@ -0,0 +1,115 @@ +import Foundation +import SoraFoundation + +struct StakingRemoveProxyViewFactory { + static func createView( + state: RelaychainStakingSharedStateProtocol, + proxyAddress: AccountAddress + ) -> StakingConfirmProxyViewProtocol? { + guard let currencyManager = CurrencyManager.shared, + let wallet = SelectedWalletSettings.shared.value, + let interactor = createInteractor( + state: state, + wallet: wallet, + proxyAddress: proxyAddress + ) else { + return nil + } + + let wireframe = StakingConfirmProxyWireframe() + + let chainAsset = state.stakingOption.chainAsset + + let priceAssetInfoFactory = PriceAssetInfoFactory(currencyManager: currencyManager) + let balanceViewModelFactory = BalanceViewModelFactory( + targetAssetInfo: chainAsset.assetDisplayInfo, + priceAssetInfoFactory: priceAssetInfoFactory + ) + let dataValidatingFactory = ProxyDataValidatorFactory( + presentable: wireframe, + balanceViewModelFactoryFacade: BalanceViewModelFactoryFacade( + priceAssetInfoFactory: priceAssetInfoFactory + ) + ) + + let presenter = StakingRemoveProxyPresenter( + chainAsset: chainAsset, + wallet: wallet, + proxyAddress: proxyAddress, + interactor: interactor, + wireframe: wireframe, + dataValidatingFactory: dataValidatingFactory, + displayAddressViewModelFactory: DisplayAddressViewModelFactory(), + networkViewModelFactory: NetworkViewModelFactory(), + balanceViewModelFactory: balanceViewModelFactory, + localizationManager: LocalizationManager.shared + ) + + let view = StakingConfirmProxyViewController( + presenter: presenter, + localizationManager: LocalizationManager.shared, + title: .init { + R.string.localizable.stakingProxyManagementRevokeAccess( + preferredLanguages: $0.rLanguages + ) + } + ) + + presenter.view = view + interactor.presenter = presenter + dataValidatingFactory.view = view + + return view + } + + private static func createInteractor( + state: RelaychainStakingSharedStateProtocol, + wallet: MetaAccountModel, + proxyAddress: AccountAddress + ) -> StakingRemoveProxyInteractor? { + let chainRegistry = ChainRegistryFacade.sharedRegistry + let chainAsset = state.stakingOption.chainAsset + + guard + let selectedAccount = wallet.fetch( + for: chainAsset.chain.accountRequest() + ), + let connection = chainRegistry.getConnection(for: chainAsset.chain.chainId), + let runtimeRegistry = chainRegistry.getRuntimeProvider(for: chainAsset.chain.chainId), + let currencyManager = CurrencyManager.shared else { + return nil + } + + let extrinsicService = ExtrinsicServiceFactory( + runtimeRegistry: runtimeRegistry, + engine: connection, + operationManager: OperationManagerFacade.sharedManager, + userStorageFacade: UserDataStorageFacade.shared + ).createService(account: selectedAccount, chain: chainAsset.chain) + + let accountProviderFactory = AccountProviderFactory( + storageFacade: UserDataStorageFacade.shared, + operationManager: OperationManagerFacade.sharedManager, + logger: Logger.shared + ) + + let signingWrapper = SigningWrapperFactory().createSigningWrapper( + for: wallet.metaId, + accountResponse: selectedAccount + ) + + return StakingRemoveProxyInteractor( + proxyAccount: proxyAddress, + signingWrapper: signingWrapper, + chainAsset: state.stakingOption.chainAsset, + walletLocalSubscriptionFactory: WalletLocalSubscriptionFactory.shared, + accountProviderFactory: accountProviderFactory, + priceLocalSubscriptionFactory: PriceProviderFactory.shared, + callFactory: SubstrateCallFactory(), + feeProxy: ExtrinsicFeeProxy(), + extrinsicService: extrinsicService, + selectedAccount: selectedAccount, + currencyManager: currencyManager + ) + } +} diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyWireframe.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyWireframe.swift index 5b5889d52a..a245049401 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyWireframe.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyWireframe.swift @@ -15,7 +15,7 @@ final class StakingSetupProxyWireframe: StakingSetupProxyWireframeProtocol { from view: ControllerBackedProtocol?, proxyAddress: AccountAddress ) { - guard let confirmView = StakingConfirmProxyViewFactory.createAddProxyView( + guard let confirmView = StakingConfirmProxyViewFactory.createView( state: state, proxyAddress: proxyAddress ) else { From 965bd814f148cc4764a2e7189f48e58a8c09ab9c Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Mon, 22 Jan 2024 23:24:59 +0300 Subject: [PATCH 35/60] fix type --- .../Common/Helpers/ChainAccountFetching.swift | 2 +- .../Common/Services/Proxy/ProxyModels.swift | 2 +- .../StakingProxyManagementPresenter.swift | 19 ++++++++------ .../StakingProxyManagementProtocols.swift | 6 ++--- ...StakingProxyManagementViewController.swift | 2 +- .../StakingProxyManagementWireframe.swift | 4 +-- .../StakingConfirmProxyPresenter.swift | 8 ++++++ .../StakingConfirmProxyProtocols.swift | 1 + .../StakingConfirmProxyViewController.swift | 7 +++--- .../StakingRemoveProxyInteractor.swift | 25 +++++-------------- .../StakingRemoveProxyPresenter.swift | 24 ++++++++++++------ .../StakingRemoveProxyViewFactory.swift | 15 ++++++----- 12 files changed, 63 insertions(+), 52 deletions(-) diff --git a/novawallet/Common/Helpers/ChainAccountFetching.swift b/novawallet/Common/Helpers/ChainAccountFetching.swift index 1473e9a39a..16dd1415d1 100644 --- a/novawallet/Common/Helpers/ChainAccountFetching.swift +++ b/novawallet/Common/Helpers/ChainAccountFetching.swift @@ -297,7 +297,7 @@ extension MetaAccountModel { func address(for chainAsset: ChainAsset) throws -> AccountAddress? { let request = chainAsset.chain.accountRequest() - return try fetchChainAccountId(for: request)?.toAddress(using: chainAsset.chain.chainFormat) + return try fetch(for: request)?.toAddress() } } diff --git a/novawallet/Common/Services/Proxy/ProxyModels.swift b/novawallet/Common/Services/Proxy/ProxyModels.swift index f7a61ad7d7..8c26aa8087 100644 --- a/novawallet/Common/Services/Proxy/ProxyModels.swift +++ b/novawallet/Common/Services/Proxy/ProxyModels.swift @@ -1,6 +1,6 @@ import SubstrateSdk -struct ProxyAccount { +struct ProxyAccount: Hashable { let accountId: AccountId let type: Proxy.ProxyType let delay: BlockNumber diff --git a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementPresenter.swift b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementPresenter.swift index 592fa26ba2..0b087a76ec 100644 --- a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementPresenter.swift +++ b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementPresenter.swift @@ -74,17 +74,24 @@ final class StakingProxyManagementPresenter { return StakingProxyManagementViewModel( info: info, - accountId: definition.proxy + account: .init( + accountId: definition.proxy, + type: definition.proxyType, + delay: definition.delay + ) ) } view?.didReceive(viewModels: viewModels) } - private func showAddressOptions(address: AccountAddress) { + private func showAccountOptions(account: ProxyAccount) { guard let view = view else { return } + guard let address = try? account.accountId.toAddress(using: chainAsset.chain.chainFormat) else { + return + } let revokeAccess = AccountAdditionalOption( title: .init { R.string.localizable.stakingProxyManagementRevokeAccess( @@ -94,7 +101,7 @@ final class StakingProxyManagementPresenter { icon: R.image.iconDelete(), indicator: .navigation ) { [weak self] in - self?.wireframe.showRevokeProxyAccess(from: self?.view, proxyAddress: address) + self?.wireframe.showRevokeProxyAccess(from: self?.view, proxyAccount: account) } wireframe.presentExtendedAccountOptions( @@ -116,10 +123,8 @@ extension StakingProxyManagementPresenter: StakingProxyManagementPresenterProtoc wireframe.showAddProxy(from: view) } - func showOptions(accountId: AccountId) { - if let address = try? accountId.toAddress(using: chainAsset.chain.chainFormat) { - showAddressOptions(address: address) - } + func showOptions(account: ProxyAccount) { + showAccountOptions(account: account) } } diff --git a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementProtocols.swift b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementProtocols.swift index 757bcba2bc..e128cfb00f 100644 --- a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementProtocols.swift +++ b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementProtocols.swift @@ -5,7 +5,7 @@ protocol StakingProxyManagementViewProtocol: ControllerBackedProtocol { protocol StakingProxyManagementPresenterProtocol: AnyObject { func setup() func addProxy() - func showOptions(accountId: AccountId) + func showOptions(account: ProxyAccount) } protocol StakingProxyManagementInteractorInputProtocol: AnyObject { @@ -21,7 +21,7 @@ protocol StakingProxyManagementInteractorOutputProtocol: AnyObject { protocol StakingProxyManagementWireframeProtocol: AnyObject, AddressOptionsPresentable, AlertPresentable, CommonRetryable, ErrorPresentable { func showAddProxy(from view: ControllerBackedProtocol?) - func showRevokeProxyAccess(from view: ControllerBackedProtocol?, proxyAddress: AccountAddress) + func showRevokeProxyAccess(from view: ControllerBackedProtocol?, proxyAccount: ProxyAccount) } enum StakingProxyManagementError: Error { @@ -31,5 +31,5 @@ enum StakingProxyManagementError: Error { struct StakingProxyManagementViewModel: Hashable { let info: WalletView.ViewModel - let accountId: AccountId + let account: ProxyAccount } diff --git a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementViewController.swift b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementViewController.swift index 1bb19c5b24..ef60d7e732 100644 --- a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementViewController.swift +++ b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementViewController.swift @@ -90,7 +90,7 @@ extension StakingProxyManagementViewController: UITableViewDelegate { tableView.deselectRow(at: indexPath, animated: true) if let model = dataSource.itemIdentifier(for: indexPath) { - presenter.showOptions(accountId: model.accountId) + presenter.showOptions(account: model.account) } } diff --git a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementWireframe.swift b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementWireframe.swift index 367e3a94c1..dc2ac68a43 100644 --- a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementWireframe.swift +++ b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementWireframe.swift @@ -17,10 +17,10 @@ final class StakingProxyManagementWireframe: StakingProxyManagementWireframeProt ) } - func showRevokeProxyAccess(from view: ControllerBackedProtocol?, proxyAddress: AccountAddress) { + func showRevokeProxyAccess(from view: ControllerBackedProtocol?, proxyAccount: ProxyAccount) { guard let confirmView = StakingRemoveProxyViewFactory.createView( state: state, - proxyAddress: proxyAddress + proxyAccount: proxyAccount ) else { return } diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyPresenter.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyPresenter.swift index bdfc3b9847..f4828aaeab 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyPresenter.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyPresenter.swift @@ -51,6 +51,7 @@ final class StakingConfirmProxyPresenter: StakingProxyBasePresenter { override func setup() { super.setup() + provideProxyTypeViewModel() provideProxyDeposit() provideNetworkViewModel() provideProxiedWalletViewModel() @@ -63,6 +64,13 @@ final class StakingConfirmProxyPresenter: StakingProxyBasePresenter { view?.didReceiveNetwork(viewModel: viewModel) } + private func provideProxyTypeViewModel() { + let type = R.string.localizable.stakingConfirmProxyTypeSubtitle( + preferredLanguages: selectedLocale.rLanguages + ) + view?.didReceiveProxyType(viewModel: type) + } + private func provideProxiedWalletViewModel() { let name = wallet.name diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyProtocols.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyProtocols.swift index 6ed1f3c313..51d25fa181 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyProtocols.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyProtocols.swift @@ -3,6 +3,7 @@ protocol StakingConfirmProxyViewProtocol: StakingSetupProxyBaseViewProtocol { func didReceiveWallet(viewModel: StackCellViewModel) func didReceiveProxiedAddress(viewModel: DisplayAddressViewModel) func didReceiveProxyAddress(viewModel: DisplayAddressViewModel) + func didReceiveProxyType(viewModel: String) func didStartLoading() func didStopLoading() } diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewController.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewController.swift index 08a222a29f..4920ed0660 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewController.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewController.swift @@ -55,9 +55,6 @@ final class StakingConfirmProxyViewController: UIViewController, ViewHolder { rootView.proxyTypeCell.titleLabel.text = R.string.localizable.stakingConfirmProxyTypeTitle( preferredLanguages: languages ) - rootView.proxyTypeCell.detailsLabel.text = R.string.localizable.stakingConfirmProxyTypeSubtitle( - preferredLanguages: languages - ) rootView.proxyAddressCell.titleLabel.text = R.string.localizable.stakingConfirmProxyAccountProxy( preferredLanguages: languages ) @@ -137,6 +134,10 @@ extension StakingConfirmProxyViewController: StakingConfirmProxyViewProtocol { rootView.proxyAddressCell.bind(viewModel: viewModel.cellViewModel) } + func didReceiveProxyType(viewModel: String) { + rootView.proxyTypeCell.bind(details: viewModel) + } + func didStartLoading() { rootView.actionButton.startLoading() } diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyInteractor.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyInteractor.swift index 8785a30e33..ca96b96b4b 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyInteractor.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyInteractor.swift @@ -14,11 +14,11 @@ final class StakingRemoveProxyInteractor: StakingRemoveProxyInteractorInputProto private var balanceProvider: StreamableProvider? private var priceProvider: StreamableProvider? - let proxyAccount: AccountAddress + let proxyAccount: ProxyAccount let signingWrapper: SigningWrapperProtocol init( - proxyAccount: AccountAddress, + proxyAccount: ProxyAccount, signingWrapper: SigningWrapperProtocol, chainAsset: ChainAsset, walletLocalSubscriptionFactory: WalletLocalSubscriptionFactoryProtocol, @@ -78,15 +78,9 @@ final class StakingRemoveProxyInteractor: StakingRemoveProxyInteractorInputProto } func estimateFee() { - guard let proxyAccountId = try? proxyAccount.toAccountId( - using: chainAsset.chain.chainFormat - ) else { - return - } - let call = callFactory.removeProxy( - accountId: proxyAccountId, - type: .staking + accountId: proxyAccount.accountId, + type: proxyAccount.type ) feeProxy.estimateFee(using: extrinsicService, reuseIdentifier: call.callName) { builder in @@ -100,16 +94,9 @@ final class StakingRemoveProxyInteractor: StakingRemoveProxyInteractorInputProto } func submit() { - guard let proxyAccountId = try? proxyAccount.toAccountId( - using: chainAsset.chain.chainFormat - ) else { - presenter?.didReceive(error: .submit(CommonError.undefined)) - return - } - let call = callFactory.removeProxy( - accountId: proxyAccountId, - type: .staking + accountId: proxyAccount.accountId, + type: proxyAccount.type ) extrinsicService.submit( diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyPresenter.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyPresenter.swift index dbdd242e17..b5124b31d3 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyPresenter.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyPresenter.swift @@ -7,7 +7,7 @@ final class StakingRemoveProxyPresenter { let wireframe: StakingConfirmProxyWireframeProtocol let interactor: StakingRemoveProxyInteractorInputProtocol - let proxyAddress: AccountAddress + let proxyAccount: ProxyAccount let wallet: MetaAccountModel let chainAsset: ChainAsset let displayAddressViewModelFactory: DisplayAddressViewModelFactoryProtocol @@ -20,11 +20,14 @@ final class StakingRemoveProxyPresenter { private var fee: ExtrinsicFeeProtocol? private lazy var walletIconGenerator = NovaIconGenerator() + private var proxyAddress: AccountAddress? { + try? proxyAccount.accountId.toAddress(using: chainAsset.chain.chainFormat) + } init( chainAsset: ChainAsset, wallet: MetaAccountModel, - proxyAddress: AccountAddress, + proxyAccount: ProxyAccount, interactor: StakingRemoveProxyInteractorInputProtocol, wireframe: StakingConfirmProxyWireframeProtocol, dataValidatingFactory: ProxyDataValidatorFactoryProtocol, @@ -33,7 +36,7 @@ final class StakingRemoveProxyPresenter { balanceViewModelFactory: BalanceViewModelFactoryProtocol, localizationManager: LocalizationManagerProtocol ) { - self.proxyAddress = proxyAddress + self.proxyAccount = proxyAccount self.wallet = wallet self.chainAsset = chainAsset self.interactor = interactor @@ -60,7 +63,7 @@ final class StakingRemoveProxyPresenter { } private func provideProxiedAddressViewModel() { - guard let address = wallet.fetch(for: chainAsset.chain.accountRequest())?.toAddress() else { + guard let address = try? wallet.address(for: chainAsset) else { return } @@ -70,7 +73,7 @@ final class StakingRemoveProxyPresenter { } private func provideProxyAddressViewModel() { - let displayAddress = DisplayAddress(address: proxyAddress, username: "") + let displayAddress = DisplayAddress(address: proxyAddress ?? "", username: "") let viewModel = displayAddressViewModelFactory.createViewModel(from: displayAddress) view?.didReceiveProxyAddress(viewModel: viewModel) } @@ -87,10 +90,15 @@ final class StakingRemoveProxyPresenter { view?.didReceiveFee(viewModel: feeViewModel) } + private func provideProxyTypeViewModel() { + let type = proxyAccount.type.title(locale: selectedLocale) + view?.didReceiveProxyType(viewModel: type) + } + private func createValidations() -> [DataValidating] { [ dataValidatingFactory.validAddress( - proxyAddress, + proxyAddress ?? "", chain: chainAsset.chain, locale: selectedLocale ), @@ -111,6 +119,7 @@ final class StakingRemoveProxyPresenter { } private func updateView() { + provideProxyTypeViewModel() provideNetworkViewModel() provideProxiedWalletViewModel() provideProxiedAddressViewModel() @@ -120,6 +129,7 @@ final class StakingRemoveProxyPresenter { extension StakingRemoveProxyPresenter: StakingConfirmProxyPresenterProtocol { func setup() { + view?.didReceiveProxyDeposit(viewModel: nil) updateView() interactor.setup() } @@ -140,7 +150,7 @@ extension StakingRemoveProxyPresenter: StakingConfirmProxyPresenterProtocol { } func showProxyAddressOptions() { - guard let view = view else { + guard let view = view, let proxyAddress = proxyAddress else { return } wireframe.presentAccountOptions( diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyViewFactory.swift b/novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyViewFactory.swift index 317f3e4638..0c64e6c2a1 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyViewFactory.swift +++ b/novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyViewFactory.swift @@ -4,22 +4,21 @@ import SoraFoundation struct StakingRemoveProxyViewFactory { static func createView( state: RelaychainStakingSharedStateProtocol, - proxyAddress: AccountAddress + proxyAccount: ProxyAccount ) -> StakingConfirmProxyViewProtocol? { + let chainAsset = state.stakingOption.chainAsset + guard let currencyManager = CurrencyManager.shared, let wallet = SelectedWalletSettings.shared.value, let interactor = createInteractor( state: state, wallet: wallet, - proxyAddress: proxyAddress + proxyAccount: proxyAccount ) else { return nil } let wireframe = StakingConfirmProxyWireframe() - - let chainAsset = state.stakingOption.chainAsset - let priceAssetInfoFactory = PriceAssetInfoFactory(currencyManager: currencyManager) let balanceViewModelFactory = BalanceViewModelFactory( targetAssetInfo: chainAsset.assetDisplayInfo, @@ -35,7 +34,7 @@ struct StakingRemoveProxyViewFactory { let presenter = StakingRemoveProxyPresenter( chainAsset: chainAsset, wallet: wallet, - proxyAddress: proxyAddress, + proxyAccount: proxyAccount, interactor: interactor, wireframe: wireframe, dataValidatingFactory: dataValidatingFactory, @@ -65,7 +64,7 @@ struct StakingRemoveProxyViewFactory { private static func createInteractor( state: RelaychainStakingSharedStateProtocol, wallet: MetaAccountModel, - proxyAddress: AccountAddress + proxyAccount: ProxyAccount ) -> StakingRemoveProxyInteractor? { let chainRegistry = ChainRegistryFacade.sharedRegistry let chainAsset = state.stakingOption.chainAsset @@ -99,7 +98,7 @@ struct StakingRemoveProxyViewFactory { ) return StakingRemoveProxyInteractor( - proxyAccount: proxyAddress, + proxyAccount: proxyAccount, signingWrapper: signingWrapper, chainAsset: state.stakingOption.chainAsset, walletLocalSubscriptionFactory: WalletLocalSubscriptionFactory.shared, From 55c65ed1d5b929498b5f96d5134d84de04f4acf0 Mon Sep 17 00:00:00 2001 From: ERussel Date: Tue, 23 Jan 2024 05:45:37 +0100 Subject: [PATCH 36/60] fix conflicts --- novawallet.xcodeproj/project.pbxproj | 26 ++---- .../Common/Substrate/Types/Proxy/Proxy.swift | 1 - .../ProxySignValidationViewFactory.swift | 9 +- .../ProxyDataValidatorFactory.swift | 78 ++++++++++++++++- .../Validation/ProxyErrorPresentable.swift | 28 ++++++ .../Validations/ProxyErrorPresentable.swift | 33 ------- .../Validations/ProxyValidationFactory.swift | 87 ------------------- .../StakingProxyManagementPresenter.swift | 4 +- ...StakingProxyManagementViewController.swift | 2 +- 9 files changed, 121 insertions(+), 147 deletions(-) rename novawallet/Modules/{Staking/StakingSetupProxy => Proxy}/Validation/ProxyDataValidatorFactory.swift (68%) rename novawallet/Modules/{Staking/StakingSetupProxy => Proxy}/Validation/ProxyErrorPresentable.swift (80%) delete mode 100644 novawallet/Modules/Proxy/Validations/ProxyErrorPresentable.swift delete mode 100644 novawallet/Modules/Proxy/Validations/ProxyValidationFactory.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 20cf3d801b..8bfe7e9fbe 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -95,6 +95,7 @@ 0C1BE1A02A46F1F00010933C /* ScientificStringParsing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C1BE19F2A46F1F00010933C /* ScientificStringParsing.swift */; }; 0C1BE1A22A46F93B0010933C /* BigUInt+Scientific.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C1BE1A12A46F93B0010933C /* BigUInt+Scientific.swift */; }; 0C1BE1A62A47FC240010933C /* MultistakingSyncServiceFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C1BE1A52A47FC240010933C /* MultistakingSyncServiceFactory.swift */; }; + 0C1CCC3C2B5F79D300A6EA17 /* ProxyErrorPresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C1CCC3B2B5F79D300A6EA17 /* ProxyErrorPresentable.swift */; }; 0C1FE4F42A52EE51003769E7 /* AssetSearchBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C1FE4F32A52EE51003769E7 /* AssetSearchBuilder.swift */; }; 0C1FE4F62A52F137003769E7 /* AssetSearchBuilderResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C1FE4F52A52F137003769E7 /* AssetSearchBuilderResult.swift */; }; 0C21D77C2AB42A3500EB2DBD /* ScreenOpenService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C21D77B2AB42A3500EB2DBD /* ScreenOpenService.swift */; }; @@ -241,8 +242,6 @@ 0C7C9B9B2AC16D7B009A0362 /* NSAttributedString+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C7C9B9A2AC16D7B009A0362 /* NSAttributedString+Helpers.swift */; }; 0C7E7FAB2A9F27FB00596628 /* NominationPoolsRedeemCall.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C7E7FAA2A9F27FB00596628 /* NominationPoolsRedeemCall.swift */; }; 0C80F0A42B3D7DBD00579E23 /* WalletIconView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C80F0A32B3D7DBD00579E23 /* WalletIconView.swift */; }; - 0C8102232B5A922B00F75BF9 /* ProxyValidationFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C8102222B5A922B00F75BF9 /* ProxyValidationFactory.swift */; }; - 0C8102252B5A928400F75BF9 /* ProxyErrorPresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C8102242B5A928400F75BF9 /* ProxyErrorPresentable.swift */; }; 0C83775D2A4EEB380072102D /* AssetListState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C83775C2A4EEB380072102D /* AssetListState.swift */; }; 0C893E6A2A65591C00781503 /* PoolsMultistakingUpdateService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C893E692A65591C00781503 /* PoolsMultistakingUpdateService.swift */; }; 0C893E6D2A6562B400781503 /* NominationPools.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C893E6C2A6562B400781503 /* NominationPools.swift */; }; @@ -845,7 +844,6 @@ 772B1C7D2A93837800A19061 /* StartStakingCustomValidatorListWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 772B1C7C2A93837800A19061 /* StartStakingCustomValidatorListWireframe.swift */; }; 7730904F2B557F46002577AE /* StakingProxyBasePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7730904E2B557F46002577AE /* StakingProxyBasePresenter.swift */; }; 773090512B559196002577AE /* ProxyDataValidatorFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 773090502B559196002577AE /* ProxyDataValidatorFactory.swift */; }; - 773090532B5591A1002577AE /* ProxyErrorPresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 773090522B5591A1002577AE /* ProxyErrorPresentable.swift */; }; 7731E9C42A14DA3F0085B5FF /* BorderedActionControlView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7731E9C32A14DA3F0085B5FF /* BorderedActionControlView.swift */; }; 7738FB6A2A4C5D1A00797439 /* StartStakingRelaychainInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7738FB692A4C5D1A00797439 /* StartStakingRelaychainInteractor.swift */; }; 773A37542B398CEB006AC4AA /* WalletNotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 773A37532B398CEB006AC4AA /* WalletNotificationService.swift */; }; @@ -4348,6 +4346,7 @@ 0C1BE19F2A46F1F00010933C /* ScientificStringParsing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScientificStringParsing.swift; sourceTree = ""; }; 0C1BE1A12A46F93B0010933C /* BigUInt+Scientific.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BigUInt+Scientific.swift"; sourceTree = ""; }; 0C1BE1A52A47FC240010933C /* MultistakingSyncServiceFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultistakingSyncServiceFactory.swift; sourceTree = ""; }; + 0C1CCC3B2B5F79D300A6EA17 /* ProxyErrorPresentable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProxyErrorPresentable.swift; sourceTree = ""; }; 0C1FE4F32A52EE51003769E7 /* AssetSearchBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetSearchBuilder.swift; sourceTree = ""; }; 0C1FE4F52A52F137003769E7 /* AssetSearchBuilderResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetSearchBuilderResult.swift; sourceTree = ""; }; 0C21D77B2AB42A3500EB2DBD /* ScreenOpenService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenOpenService.swift; sourceTree = ""; }; @@ -4501,8 +4500,6 @@ 0C7C9B9A2AC16D7B009A0362 /* NSAttributedString+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSAttributedString+Helpers.swift"; sourceTree = ""; }; 0C7E7FAA2A9F27FB00596628 /* NominationPoolsRedeemCall.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NominationPoolsRedeemCall.swift; sourceTree = ""; }; 0C80F0A32B3D7DBD00579E23 /* WalletIconView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WalletIconView.swift; sourceTree = ""; }; - 0C8102222B5A922B00F75BF9 /* ProxyValidationFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProxyValidationFactory.swift; sourceTree = ""; }; - 0C8102242B5A928400F75BF9 /* ProxyErrorPresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProxyErrorPresentable.swift; sourceTree = ""; }; 0C83775C2A4EEB380072102D /* AssetListState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetListState.swift; sourceTree = ""; }; 0C893E692A65591C00781503 /* PoolsMultistakingUpdateService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PoolsMultistakingUpdateService.swift; sourceTree = ""; }; 0C893E6C2A6562B400781503 /* NominationPools.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NominationPools.swift; sourceTree = ""; }; @@ -5104,7 +5101,6 @@ 772B1C7C2A93837800A19061 /* StartStakingCustomValidatorListWireframe.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StartStakingCustomValidatorListWireframe.swift; sourceTree = ""; }; 7730904E2B557F46002577AE /* StakingProxyBasePresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingProxyBasePresenter.swift; sourceTree = ""; }; 773090502B559196002577AE /* ProxyDataValidatorFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProxyDataValidatorFactory.swift; sourceTree = ""; }; - 773090522B5591A1002577AE /* ProxyErrorPresentable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProxyErrorPresentable.swift; sourceTree = ""; }; 7731E9C32A14DA3F0085B5FF /* BorderedActionControlView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BorderedActionControlView.swift; sourceTree = ""; }; 7738FB692A4C5D1A00797439 /* StartStakingRelaychainInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartStakingRelaychainInteractor.swift; sourceTree = ""; }; 773A37532B398CEB006AC4AA /* WalletNotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletNotificationService.swift; sourceTree = ""; }; @@ -9150,15 +9146,6 @@ path = NominationPools; sourceTree = ""; }; - 0C8102212B5A921D00F75BF9 /* Validations */ = { - isa = PBXGroup; - children = ( - 0C8102222B5A922B00F75BF9 /* ProxyValidationFactory.swift */, - 0C8102242B5A928400F75BF9 /* ProxyErrorPresentable.swift */, - ); - path = Validations; - sourceTree = ""; - }; 0C893E6B2A65629E00781503 /* NominationPools */ = { isa = PBXGroup; children = ( @@ -10375,7 +10362,7 @@ 773090542B5591AC002577AE /* Validation */ = { isa = PBXGroup; children = ( - 773090522B5591A1002577AE /* ProxyErrorPresentable.swift */, + 0C1CCC3B2B5F79D300A6EA17 /* ProxyErrorPresentable.swift */, 773090502B559196002577AE /* ProxyDataValidatorFactory.swift */, ); path = Validation; @@ -10897,7 +10884,7 @@ 77FF02672B21DCB300B655BC /* Proxy */ = { isa = PBXGroup; children = ( - 0C8102212B5A921D00F75BF9 /* Validations */, + 773090542B5591AC002577AE /* Validation */, 0C37AFCD2B598BAB00009ECA /* ProxySignConfirmation */, AC6B93411E3444BFB71691BE /* ProxySignValidation */, 773A37582B3B589F006AC4AA /* ProxyMessageSheet */, @@ -18333,7 +18320,6 @@ isa = PBXGroup; children = ( 600A0B1B13D9E0897BC4FDA9 /* StakingConfirmProxy */, - 773090542B5591AC002577AE /* Validation */, 7754BD542B501E3C0099C13E /* Base */, 173BB84A4695492A77AE206D /* StakingSetupProxyProtocols.swift */, 1399884D5F4905DA0BD1E5C3 /* StakingSetupProxyWireframe.swift */, @@ -20835,7 +20821,6 @@ 8430AAE126022CA1005B1066 /* BaseStakingState.swift in Sources */, 8490141124A92F6D008F705E /* OnboardingMainViewController.swift in Sources */, D9D163642744F60D00681C1F /* ExternalContribution.swift in Sources */, - 0C8102232B5A922B00F75BF9 /* ProxyValidationFactory.swift in Sources */, 84155DED2539817200A27058 /* ApplicationService.swift in Sources */, 84403D7F25E91BC100494FD4 /* SuperIdentity.swift in Sources */, 777DC2E12B2368EC0060CB2C /* ProxyType+title.swift in Sources */, @@ -21342,7 +21327,6 @@ 8402CC9C275B92AC00E5BF30 /* ControlView.swift in Sources */, 0C66102B2A73816000E44634 /* StakingSharedStateFactory.swift in Sources */, 77DC54862B1FE5C100C7E45A /* ProxySyncService.swift in Sources */, - 773090532B5591A1002577AE /* ProxyErrorPresentable.swift in Sources */, 2AB7A7FF25CD0E8000767D87 /* GitHubPhishingAPIService.swift in Sources */, 77F033972A8142D1006BC67E /* StakingSetupAmountStyles.swift in Sources */, AEF507F72625A3280098574D /* ValidatorState+Status.swift in Sources */, @@ -21375,6 +21359,7 @@ F4CE0F9527343E630094CD8A /* AcalaContributionConfirmPresenter.swift in Sources */, 889F7F3B292373560024CB1E /* RemoteAssetModel+Evm.swift in Sources */, 849D3227291CE25E00D25839 /* MarkdownViewContainer.swift in Sources */, + 0C1CCC3C2B5F79D300A6EA17 /* ProxyErrorPresentable.swift in Sources */, 0C59E8E12AA60FF0001E11F3 /* CrowdloanExternalServiceFactory.swift in Sources */, 847297CF260B4035009B86D0 /* ChangeTargetConfirmInteractor.swift in Sources */, 8455F19C2A1DF088003F072D /* ChainsStore+Multistaking.swift in Sources */, @@ -22128,7 +22113,6 @@ 840D626F29CB39EE00D5E894 /* URLBuilder.swift in Sources */, 842BA36D27B64F1000D31EEF /* DAppViewModel.swift in Sources */, 8439399C2636FAB40087658D /* YourValidatorViewModel.swift in Sources */, - 0C8102252B5A928400F75BF9 /* ProxyErrorPresentable.swift in Sources */, 84216FDE282B979900479375 /* Decimal+Conversion.swift in Sources */, 887404B229826FB100EE270A /* InAppUpdatesServiceFactory.swift in Sources */, 841E2E4E2738159400F250C1 /* RemoteSubscriptionHandlingFactory.swift in Sources */, diff --git a/novawallet/Common/Substrate/Types/Proxy/Proxy.swift b/novawallet/Common/Substrate/Types/Proxy/Proxy.swift index 7202a5d998..2f2099e58a 100644 --- a/novawallet/Common/Substrate/Types/Proxy/Proxy.swift +++ b/novawallet/Common/Substrate/Types/Proxy/Proxy.swift @@ -97,7 +97,6 @@ enum Proxy { case .any, .nonTransfer, .staking: return true case .governance, - .staking, .nominationPools, .identityJudgement, .cancelProxy, diff --git a/novawallet/Modules/Proxy/ProxySignValidation/ProxySignValidationViewFactory.swift b/novawallet/Modules/Proxy/ProxySignValidation/ProxySignValidationViewFactory.swift index 209f30e447..35245859f4 100644 --- a/novawallet/Modules/Proxy/ProxySignValidation/ProxySignValidationViewFactory.swift +++ b/novawallet/Modules/Proxy/ProxySignValidation/ProxySignValidationViewFactory.swift @@ -20,7 +20,14 @@ struct ProxySignValidationViewFactory { let view = ControllerBacked(controller: viewController) - let dataValidatorFactory = ProxyDataValidatorFactory(presentable: wireframe) + let priceAssetInfoFactory = PriceAssetInfoFactory(currencyManager: currencyManager) + + let dataValidatorFactory = ProxyDataValidatorFactory( + presentable: wireframe, + balanceViewModelFactoryFacade: BalanceViewModelFactoryFacade( + priceAssetInfoFactory: priceAssetInfoFactory + ) + ) dataValidatorFactory.view = view diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyDataValidatorFactory.swift b/novawallet/Modules/Proxy/Validation/ProxyDataValidatorFactory.swift similarity index 68% rename from novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyDataValidatorFactory.swift rename to novawallet/Modules/Proxy/Validation/ProxyDataValidatorFactory.swift index 3aaccfb823..773f8d4204 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyDataValidatorFactory.swift +++ b/novawallet/Modules/Proxy/Validation/ProxyDataValidatorFactory.swift @@ -30,6 +30,35 @@ protocol ProxyDataValidatorFactoryProtocol: BaseDataValidatingFactoryProtocol { chain: ChainModel, locale: Locale ) -> DataValidating + + func canPayFee( + balance: Decimal?, + fee: ExtrinsicFeeProtocol?, + proxyName: String, + asset: AssetBalanceDisplayInfo, + locale: Locale + ) -> DataValidating +} + +extension ProxyDataValidatorFactoryProtocol { + func canPayFeeInPlank( + balance: BigUInt?, + fee: ExtrinsicFeeProtocol?, + proxyName: String, + asset: AssetBalanceDisplayInfo, + locale: Locale + ) -> DataValidating { + let precision = asset.assetPrecision + let balanceDecimal = balance.flatMap { Decimal.fromSubstrateAmount($0, precision: precision) } + + return canPayFee( + balance: balanceDecimal, + fee: fee, + proxyName: proxyName, + asset: asset, + locale: locale + ) + } } final class ProxyDataValidatorFactory: ProxyDataValidatorFactoryProtocol { @@ -66,7 +95,7 @@ final class ProxyDataValidatorFactory: ProxyDataValidatorFactoryProtocol { let balanceModel = viewModelFactory.amountFromValue( targetAssetInfo: asset, - value: balanceDecimal ?? 0 + value: balanceDecimal ).value(for: locale) let depositModel = viewModelFactory.amountFromValue( targetAssetInfo: asset, @@ -159,4 +188,51 @@ final class ProxyDataValidatorFactory: ProxyDataValidatorFactoryProtocol { return accountId != nil }) } + + func canPayFee( + balance: Decimal?, + fee: ExtrinsicFeeProtocol?, + proxyName: String, + asset: AssetBalanceDisplayInfo, + locale: Locale + ) -> DataValidating { + ErrorConditionViolation(onError: { [weak self] in + guard let view = self?.view, let viewModelFactory = self?.balanceViewModelFactoryFacade else { + return + } + + let balanceString = viewModelFactory.amountFromValue( + targetAssetInfo: asset, + value: balance ?? 0 + ).value(for: locale) + + let feeDecimal = fee?.amountForCurrentAccount?.decimal(assetInfo: asset) + + let feeString = viewModelFactory.amountFromValue( + targetAssetInfo: asset, + value: feeDecimal ?? 0 + ).value(for: locale) + + self?.presentable.presentFeeTooHigh( + from: view, + balance: balanceString, + fee: feeString, + accountName: proxyName, + locale: locale + ) + + }, preservesCondition: { + guard let balance = balance, let fee = fee else { + return false + } + + guard let feeAmountInPlank = fee.amountForCurrentAccount else { + return true + } + + let feeAmount = feeAmountInPlank.decimal(assetInfo: asset) + + return feeAmount <= balance + }) + } } diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyErrorPresentable.swift b/novawallet/Modules/Proxy/Validation/ProxyErrorPresentable.swift similarity index 80% rename from novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyErrorPresentable.swift rename to novawallet/Modules/Proxy/Validation/ProxyErrorPresentable.swift index 08d3fa7b95..64463e56ba 100644 --- a/novawallet/Modules/Staking/StakingSetupProxy/Validation/ProxyErrorPresentable.swift +++ b/novawallet/Modules/Proxy/Validation/ProxyErrorPresentable.swift @@ -26,6 +26,14 @@ protocol ProxyErrorPresentable: BaseErrorPresentable { networkName: String, locale: Locale? ) + + func presentFeeTooHigh( + from view: ControllerBackedProtocol, + balance: String, + fee: String, + accountName: String, + locale: Locale? + ) } extension ProxyErrorPresentable where Self: AlertPresentable & ErrorPresentable { @@ -100,4 +108,24 @@ extension ProxyErrorPresentable where Self: AlertPresentable & ErrorPresentable present(message: message, title: title, closeAction: closeAction, from: view) } + + func presentFeeTooHigh( + from view: ControllerBackedProtocol, + balance: String, + fee: String, + accountName: String, + locale: Locale? + ) { + let message = R.string.localizable.proxyFeeErrorMessage( + accountName, + fee, + balance, + preferredLanguages: locale?.rLanguages + ) + + let title = R.string.localizable.commonNotEnoughFeeTitle(preferredLanguages: locale?.rLanguages) + let closeAction = R.string.localizable.commonClose(preferredLanguages: locale?.rLanguages) + + present(message: message, title: title, closeAction: closeAction, from: view) + } } diff --git a/novawallet/Modules/Proxy/Validations/ProxyErrorPresentable.swift b/novawallet/Modules/Proxy/Validations/ProxyErrorPresentable.swift deleted file mode 100644 index 846cb011e9..0000000000 --- a/novawallet/Modules/Proxy/Validations/ProxyErrorPresentable.swift +++ /dev/null @@ -1,33 +0,0 @@ -import Foundation - -protocol ProxyErrorPresentable: BaseErrorPresentable { - func presentFeeTooHigh( - from view: ControllerBackedProtocol, - balance: String, - fee: String, - accountName: String, - locale: Locale? - ) -} - -extension ProxyErrorPresentable where Self: AlertPresentable & ErrorPresentable { - func presentFeeTooHigh( - from view: ControllerBackedProtocol, - balance: String, - fee: String, - accountName: String, - locale: Locale? - ) { - let message = R.string.localizable.proxyFeeErrorMessage( - accountName, - fee, - balance, - preferredLanguages: locale?.rLanguages - ) - - let title = R.string.localizable.commonNotEnoughFeeTitle(preferredLanguages: locale?.rLanguages) - let closeAction = R.string.localizable.commonClose(preferredLanguages: locale?.rLanguages) - - present(message: message, title: title, closeAction: closeAction, from: view) - } -} diff --git a/novawallet/Modules/Proxy/Validations/ProxyValidationFactory.swift b/novawallet/Modules/Proxy/Validations/ProxyValidationFactory.swift deleted file mode 100644 index 2ea64241e8..0000000000 --- a/novawallet/Modules/Proxy/Validations/ProxyValidationFactory.swift +++ /dev/null @@ -1,87 +0,0 @@ -import Foundation -import SoraFoundation -import BigInt - -protocol ProxyDataValidatorFactoryProtocol: BaseDataValidatingFactoryProtocol { - func canPayFee( - balance: Decimal?, - fee: ExtrinsicFeeProtocol?, - proxyName: String, - asset: AssetBalanceDisplayInfo, - locale: Locale - ) -> DataValidating -} - -extension ProxyDataValidatorFactoryProtocol { - func canPayFeeInPlank( - balance: BigUInt?, - fee: ExtrinsicFeeProtocol?, - proxyName: String, - asset: AssetBalanceDisplayInfo, - locale: Locale - ) -> DataValidating { - let precision = asset.assetPrecision - let balanceDecimal = balance.flatMap { Decimal.fromSubstrateAmount($0, precision: precision) } - - return canPayFee( - balance: balanceDecimal, - fee: fee, - proxyName: proxyName, - asset: asset, - locale: locale - ) - } -} - -final class ProxyDataValidatorFactory: ProxyDataValidatorFactoryProtocol { - weak var view: ControllerBackedProtocol? - - var basePresentable: BaseErrorPresentable { presentable } - - let presentable: ProxyErrorPresentable - - init(presentable: ProxyErrorPresentable) { - self.presentable = presentable - } - - func canPayFee( - balance: Decimal?, - fee: ExtrinsicFeeProtocol?, - proxyName: String, - asset: AssetBalanceDisplayInfo, - locale: Locale - ) -> DataValidating { - ErrorConditionViolation(onError: { [weak self] in - guard let view = self?.view else { - return - } - - let tokenFormatter = AssetBalanceFormatterFactory().createTokenFormatter(for: asset) - - let balanceString = tokenFormatter.value(for: locale).stringFromDecimal(balance ?? 0) ?? "" - let feeDecimal = fee?.amountForCurrentAccount?.decimal(assetInfo: asset) - let feeString = tokenFormatter.value(for: locale).stringFromDecimal(feeDecimal ?? 0) ?? "" - - self?.presentable.presentFeeTooHigh( - from: view, - balance: balanceString, - fee: feeString, - accountName: proxyName, - locale: locale - ) - - }, preservesCondition: { - guard let balance = balance, let fee = fee else { - return false - } - - guard let feeAmountInPlank = fee.amountForCurrentAccount else { - return true - } - - let feeAmount = feeAmountInPlank.decimal(assetInfo: asset) - - return feeAmount <= balance - }) - } -} diff --git a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementPresenter.swift b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementPresenter.swift index f54388b298..d5eae1ce56 100644 --- a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementPresenter.swift +++ b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementPresenter.swift @@ -55,7 +55,7 @@ final class StakingProxyManagementPresenter { } else { let icon = try? self.polkadotIconGenerator.generateFromAccountId(definition.proxy) let imageViewModel = self.imageViewModel(from: icon, accountId: definition.proxy) - let address = try? definition.proxy.toAddress(using: chainAsset.chain.chainFormat) ?? "" + let address = try? definition.proxy.toAddress(using: chainAsset.chain.chainFormat) walletInfo = .init( icon: imageViewModel, name: address ?? "" @@ -138,7 +138,7 @@ extension StakingProxyManagementPresenter: StakingProxyManagementInteractorOutpu switch error { case let .identities(error): logger.error("Error occured while fetching identities: \(error.localizedDescription)") - case let .proxyDefifnition: + case .proxyDefifnition: wireframe.presentRequestStatus( on: view, locale: localizationManager.selectedLocale diff --git a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementViewController.swift b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementViewController.swift index 1bb19c5b24..925e8d350c 100644 --- a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementViewController.swift +++ b/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementViewController.swift @@ -54,7 +54,7 @@ final class StakingProxyManagementViewController: UIViewController, ViewHolder { } private func makeDataSource() -> DataSource { - .init(tableView: rootView.tableView) { [weak self] tableView, _, viewModel in + .init(tableView: rootView.tableView) { tableView, _, viewModel in let cell = tableView.dequeueReusableCellWithType(WalletsListTableViewCell.self) cell?.contentDisplayView.valueView.image = R.image.iconMore()?.withTintColor(R.color.colorIconSecondary()!) cell?.infoView.bind(viewModel: viewModel.info) From df7dbd8d0f468e81e481ccf9004d8d73663b1e37 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Tue, 23 Jan 2024 11:40:47 +0300 Subject: [PATCH 37/60] rearrange --- novawallet.xcodeproj/project.pbxproj | 34 ++++++++++++------- .../Add}/ProxyDepositView.swift | 0 .../Add}/StakingSetupProxyInteractor.swift | 0 .../Add}/StakingSetupProxyPresenter.swift | 0 .../Add}/StakingSetupProxyProtocols.swift | 0 .../StakingSetupProxyViewController.swift | 0 .../Add}/StakingSetupProxyViewFactory.swift | 0 .../Add}/StakingSetupProxyViewLayout.swift | 0 .../Add}/StakingSetupProxyWireframe.swift | 0 .../Base/ProxyDepositCalculator.swift | 0 .../Base/StakingProxyBaseInteractor.swift | 0 .../Base/StakingProxyBasePresenter.swift | 0 .../Base/StakingProxyBaseProtocols.swift | 0 .../StakingConfirmProxyInteractor.swift | 0 .../StakingConfirmProxyPresenter.swift | 0 .../StakingConfirmProxyProtocols.swift | 0 .../StakingConfirmProxyViewController.swift | 0 .../StakingConfirmProxyViewFactory.swift | 0 .../StakingConfirmProxyViewLayout.swift | 0 .../StakingConfirmProxyWireframe.swift | 0 .../StakingProxyManagementInteractor.swift | 0 .../StakingProxyManagementPresenter.swift | 0 .../StakingProxyManagementProtocols.swift | 0 ...StakingProxyManagementViewController.swift | 0 .../StakingProxyManagementViewFactory.swift | 0 .../StakingProxyManagementViewLayout.swift | 0 .../StakingProxyManagementWireframe.swift | 0 .../StakingRemoveProxyInteractor.swift | 0 .../Remove}/StakingRemoveProxyPresenter.swift | 0 .../Remove}/StakingRemoveProxyProtocols.swift | 0 .../StakingRemoveProxyViewFactory.swift | 0 31 files changed, 21 insertions(+), 13 deletions(-) rename novawallet/Modules/Staking/{StakingSetupProxy => StakingProxy/Add}/ProxyDepositView.swift (100%) rename novawallet/Modules/Staking/{StakingSetupProxy => StakingProxy/Add}/StakingSetupProxyInteractor.swift (100%) rename novawallet/Modules/Staking/{StakingSetupProxy => StakingProxy/Add}/StakingSetupProxyPresenter.swift (100%) rename novawallet/Modules/Staking/{StakingSetupProxy => StakingProxy/Add}/StakingSetupProxyProtocols.swift (100%) rename novawallet/Modules/Staking/{StakingSetupProxy => StakingProxy/Add}/StakingSetupProxyViewController.swift (100%) rename novawallet/Modules/Staking/{StakingSetupProxy => StakingProxy/Add}/StakingSetupProxyViewFactory.swift (100%) rename novawallet/Modules/Staking/{StakingSetupProxy => StakingProxy/Add}/StakingSetupProxyViewLayout.swift (100%) rename novawallet/Modules/Staking/{StakingSetupProxy => StakingProxy/Add}/StakingSetupProxyWireframe.swift (100%) rename novawallet/Modules/Staking/{StakingSetupProxy => StakingProxy}/Base/ProxyDepositCalculator.swift (100%) rename novawallet/Modules/Staking/{StakingSetupProxy => StakingProxy}/Base/StakingProxyBaseInteractor.swift (100%) rename novawallet/Modules/Staking/{StakingSetupProxy => StakingProxy}/Base/StakingProxyBasePresenter.swift (100%) rename novawallet/Modules/Staking/{StakingSetupProxy => StakingProxy}/Base/StakingProxyBaseProtocols.swift (100%) rename novawallet/Modules/Staking/{StakingSetupProxy/StakingConfirmProxy => StakingProxy/Confirm}/StakingConfirmProxyInteractor.swift (100%) rename novawallet/Modules/Staking/{StakingSetupProxy/StakingConfirmProxy => StakingProxy/Confirm}/StakingConfirmProxyPresenter.swift (100%) rename novawallet/Modules/Staking/{StakingSetupProxy/StakingConfirmProxy => StakingProxy/Confirm}/StakingConfirmProxyProtocols.swift (100%) rename novawallet/Modules/Staking/{StakingSetupProxy/StakingConfirmProxy => StakingProxy/Confirm}/StakingConfirmProxyViewController.swift (100%) rename novawallet/Modules/Staking/{StakingSetupProxy/StakingConfirmProxy => StakingProxy/Confirm}/StakingConfirmProxyViewFactory.swift (100%) rename novawallet/Modules/Staking/{StakingSetupProxy/StakingConfirmProxy => StakingProxy/Confirm}/StakingConfirmProxyViewLayout.swift (100%) rename novawallet/Modules/Staking/{StakingSetupProxy/StakingConfirmProxy => StakingProxy/Confirm}/StakingConfirmProxyWireframe.swift (100%) rename novawallet/Modules/Staking/{StakingProxyManagement => StakingProxy/Management}/StakingProxyManagementInteractor.swift (100%) rename novawallet/Modules/Staking/{StakingProxyManagement => StakingProxy/Management}/StakingProxyManagementPresenter.swift (100%) rename novawallet/Modules/Staking/{StakingProxyManagement => StakingProxy/Management}/StakingProxyManagementProtocols.swift (100%) rename novawallet/Modules/Staking/{StakingProxyManagement => StakingProxy/Management}/StakingProxyManagementViewController.swift (100%) rename novawallet/Modules/Staking/{StakingProxyManagement => StakingProxy/Management}/StakingProxyManagementViewFactory.swift (100%) rename novawallet/Modules/Staking/{StakingProxyManagement => StakingProxy/Management}/StakingProxyManagementViewLayout.swift (100%) rename novawallet/Modules/Staking/{StakingProxyManagement => StakingProxy/Management}/StakingProxyManagementWireframe.swift (100%) rename novawallet/Modules/Staking/{StakingSetupProxy/StakingRemoveProxy => StakingProxy/Remove}/StakingRemoveProxyInteractor.swift (100%) rename novawallet/Modules/Staking/{StakingSetupProxy/StakingRemoveProxy => StakingProxy/Remove}/StakingRemoveProxyPresenter.swift (100%) rename novawallet/Modules/Staking/{StakingSetupProxy/StakingRemoveProxy => StakingProxy/Remove}/StakingRemoveProxyProtocols.swift (100%) rename novawallet/Modules/Staking/{StakingSetupProxy/StakingRemoveProxy => StakingProxy/Remove}/StakingRemoveProxyViewFactory.swift (100%) diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 30ff1915bf..beacf6ac5b 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -10170,7 +10170,7 @@ path = StakingRewardFilters; sourceTree = ""; }; - 600A0B1B13D9E0897BC4FDA9 /* StakingConfirmProxy */ = { + 600A0B1B13D9E0897BC4FDA9 /* Confirm */ = { isa = PBXGroup; children = ( 42787EE71C10AD13B8584EFC /* StakingConfirmProxyProtocols.swift */, @@ -10181,7 +10181,7 @@ 3543AE2CAA63AC0A20D532B6 /* StakingConfirmProxyViewLayout.swift */, 0E52C5919A1DA8A18297325B /* StakingConfirmProxyViewFactory.swift */, ); - path = StakingConfirmProxy; + path = Confirm; sourceTree = ""; }; 6B9FCD7484C894D77EE13328 /* DelegateSearch */ = { @@ -10458,6 +10458,18 @@ name = "Recovered References"; sourceTree = ""; }; + 7750CC352B5FB29300002991 /* StakingProxy */ = { + isa = PBXGroup; + children = ( + 7754BD542B501E3C0099C13E /* Base */, + A4542BFD7BBCF6B05FB2D3E4 /* Add */, + 600A0B1B13D9E0897BC4FDA9 /* Confirm */, + 8AE87694A810D25060A567E1 /* Management */, + 77C3D7D82B5E825600997BA0 /* Remove */, + ); + path = StakingProxy; + sourceTree = ""; + }; 7752E16B2AD878A4006E2F92 /* Model */ = { isa = PBXGroup; children = ( @@ -10643,7 +10655,7 @@ path = canonicalization; sourceTree = ""; }; - 77C3D7D82B5E825600997BA0 /* StakingRemoveProxy */ = { + 77C3D7D82B5E825600997BA0 /* Remove */ = { isa = PBXGroup; children = ( 77C3D7D42B5E7E7800997BA0 /* StakingRemoveProxyInteractor.swift */, @@ -10651,7 +10663,7 @@ 7779D1102B5EE39C008966A8 /* StakingRemoveProxyPresenter.swift */, 7779D1122B5EEE46008966A8 /* StakingRemoveProxyViewFactory.swift */, ); - path = StakingRemoveProxy; + path = Remove; sourceTree = ""; }; 77C9BCBA2ACD1AE800022EA2 /* Model */ = { @@ -17345,8 +17357,7 @@ 7066B343B912F72345D541F2 /* StakingSetupAmount */, 17432B4B5D8D9DC5C22CA238 /* StakingType */, 92CDAD21CEED554306CAF5D8 /* StartStakingConfirm */, - A4542BFD7BBCF6B05FB2D3E4 /* StakingSetupProxy */, - 8AE87694A810D25060A567E1 /* StakingProxyManagement */, + 7750CC352B5FB29300002991 /* StakingProxy */, ); path = Staking; sourceTree = ""; @@ -18219,7 +18230,7 @@ path = "CAIP-2"; sourceTree = ""; }; - 8AE87694A810D25060A567E1 /* StakingProxyManagement */ = { + 8AE87694A810D25060A567E1 /* Management */ = { isa = PBXGroup; children = ( DE5C4D40180946CA35A0E2F8 /* StakingProxyManagementProtocols.swift */, @@ -18230,7 +18241,7 @@ DBADD72EE1AFA6E549D779FB /* StakingProxyManagementViewLayout.swift */, 7DDEB59CB3BDF9BDAAC4E3C5 /* StakingProxyManagementViewFactory.swift */, ); - path = StakingProxyManagement; + path = Management; sourceTree = ""; }; 8C1DCF40C8BE3290D4BB9843 /* ParaStkStakeConfirm */ = { @@ -18349,12 +18360,9 @@ path = AssetsSearch; sourceTree = ""; }; - A4542BFD7BBCF6B05FB2D3E4 /* StakingSetupProxy */ = { + A4542BFD7BBCF6B05FB2D3E4 /* Add */ = { isa = PBXGroup; children = ( - 77C3D7D82B5E825600997BA0 /* StakingRemoveProxy */, - 600A0B1B13D9E0897BC4FDA9 /* StakingConfirmProxy */, - 7754BD542B501E3C0099C13E /* Base */, 173BB84A4695492A77AE206D /* StakingSetupProxyProtocols.swift */, 1399884D5F4905DA0BD1E5C3 /* StakingSetupProxyWireframe.swift */, 5B882BFEED7C8CB1EA5A853D /* StakingSetupProxyPresenter.swift */, @@ -18364,7 +18372,7 @@ 90D17F206E8C9D755346CFCC /* StakingSetupProxyViewFactory.swift */, 779F1F8A2B4D807200EF1EE9 /* ProxyDepositView.swift */, ); - path = StakingSetupProxy; + path = Add; sourceTree = ""; }; A798A35104CE0BC5AD2645F3 /* DAppTxDetails */ = { diff --git a/novawallet/Modules/Staking/StakingSetupProxy/ProxyDepositView.swift b/novawallet/Modules/Staking/StakingProxy/Add/ProxyDepositView.swift similarity index 100% rename from novawallet/Modules/Staking/StakingSetupProxy/ProxyDepositView.swift rename to novawallet/Modules/Staking/StakingProxy/Add/ProxyDepositView.swift diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyInteractor.swift b/novawallet/Modules/Staking/StakingProxy/Add/StakingSetupProxyInteractor.swift similarity index 100% rename from novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyInteractor.swift rename to novawallet/Modules/Staking/StakingProxy/Add/StakingSetupProxyInteractor.swift diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyPresenter.swift b/novawallet/Modules/Staking/StakingProxy/Add/StakingSetupProxyPresenter.swift similarity index 100% rename from novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyPresenter.swift rename to novawallet/Modules/Staking/StakingProxy/Add/StakingSetupProxyPresenter.swift diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyProtocols.swift b/novawallet/Modules/Staking/StakingProxy/Add/StakingSetupProxyProtocols.swift similarity index 100% rename from novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyProtocols.swift rename to novawallet/Modules/Staking/StakingProxy/Add/StakingSetupProxyProtocols.swift diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewController.swift b/novawallet/Modules/Staking/StakingProxy/Add/StakingSetupProxyViewController.swift similarity index 100% rename from novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewController.swift rename to novawallet/Modules/Staking/StakingProxy/Add/StakingSetupProxyViewController.swift diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewFactory.swift b/novawallet/Modules/Staking/StakingProxy/Add/StakingSetupProxyViewFactory.swift similarity index 100% rename from novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewFactory.swift rename to novawallet/Modules/Staking/StakingProxy/Add/StakingSetupProxyViewFactory.swift diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewLayout.swift b/novawallet/Modules/Staking/StakingProxy/Add/StakingSetupProxyViewLayout.swift similarity index 100% rename from novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyViewLayout.swift rename to novawallet/Modules/Staking/StakingProxy/Add/StakingSetupProxyViewLayout.swift diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyWireframe.swift b/novawallet/Modules/Staking/StakingProxy/Add/StakingSetupProxyWireframe.swift similarity index 100% rename from novawallet/Modules/Staking/StakingSetupProxy/StakingSetupProxyWireframe.swift rename to novawallet/Modules/Staking/StakingProxy/Add/StakingSetupProxyWireframe.swift diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Base/ProxyDepositCalculator.swift b/novawallet/Modules/Staking/StakingProxy/Base/ProxyDepositCalculator.swift similarity index 100% rename from novawallet/Modules/Staking/StakingSetupProxy/Base/ProxyDepositCalculator.swift rename to novawallet/Modules/Staking/StakingProxy/Base/ProxyDepositCalculator.swift diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseInteractor.swift b/novawallet/Modules/Staking/StakingProxy/Base/StakingProxyBaseInteractor.swift similarity index 100% rename from novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseInteractor.swift rename to novawallet/Modules/Staking/StakingProxy/Base/StakingProxyBaseInteractor.swift diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift b/novawallet/Modules/Staking/StakingProxy/Base/StakingProxyBasePresenter.swift similarity index 100% rename from novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBasePresenter.swift rename to novawallet/Modules/Staking/StakingProxy/Base/StakingProxyBasePresenter.swift diff --git a/novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseProtocols.swift b/novawallet/Modules/Staking/StakingProxy/Base/StakingProxyBaseProtocols.swift similarity index 100% rename from novawallet/Modules/Staking/StakingSetupProxy/Base/StakingProxyBaseProtocols.swift rename to novawallet/Modules/Staking/StakingProxy/Base/StakingProxyBaseProtocols.swift diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyInteractor.swift b/novawallet/Modules/Staking/StakingProxy/Confirm/StakingConfirmProxyInteractor.swift similarity index 100% rename from novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyInteractor.swift rename to novawallet/Modules/Staking/StakingProxy/Confirm/StakingConfirmProxyInteractor.swift diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyPresenter.swift b/novawallet/Modules/Staking/StakingProxy/Confirm/StakingConfirmProxyPresenter.swift similarity index 100% rename from novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyPresenter.swift rename to novawallet/Modules/Staking/StakingProxy/Confirm/StakingConfirmProxyPresenter.swift diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyProtocols.swift b/novawallet/Modules/Staking/StakingProxy/Confirm/StakingConfirmProxyProtocols.swift similarity index 100% rename from novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyProtocols.swift rename to novawallet/Modules/Staking/StakingProxy/Confirm/StakingConfirmProxyProtocols.swift diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewController.swift b/novawallet/Modules/Staking/StakingProxy/Confirm/StakingConfirmProxyViewController.swift similarity index 100% rename from novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewController.swift rename to novawallet/Modules/Staking/StakingProxy/Confirm/StakingConfirmProxyViewController.swift diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewFactory.swift b/novawallet/Modules/Staking/StakingProxy/Confirm/StakingConfirmProxyViewFactory.swift similarity index 100% rename from novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewFactory.swift rename to novawallet/Modules/Staking/StakingProxy/Confirm/StakingConfirmProxyViewFactory.swift diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewLayout.swift b/novawallet/Modules/Staking/StakingProxy/Confirm/StakingConfirmProxyViewLayout.swift similarity index 100% rename from novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyViewLayout.swift rename to novawallet/Modules/Staking/StakingProxy/Confirm/StakingConfirmProxyViewLayout.swift diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyWireframe.swift b/novawallet/Modules/Staking/StakingProxy/Confirm/StakingConfirmProxyWireframe.swift similarity index 100% rename from novawallet/Modules/Staking/StakingSetupProxy/StakingConfirmProxy/StakingConfirmProxyWireframe.swift rename to novawallet/Modules/Staking/StakingProxy/Confirm/StakingConfirmProxyWireframe.swift diff --git a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementInteractor.swift b/novawallet/Modules/Staking/StakingProxy/Management/StakingProxyManagementInteractor.swift similarity index 100% rename from novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementInteractor.swift rename to novawallet/Modules/Staking/StakingProxy/Management/StakingProxyManagementInteractor.swift diff --git a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementPresenter.swift b/novawallet/Modules/Staking/StakingProxy/Management/StakingProxyManagementPresenter.swift similarity index 100% rename from novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementPresenter.swift rename to novawallet/Modules/Staking/StakingProxy/Management/StakingProxyManagementPresenter.swift diff --git a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementProtocols.swift b/novawallet/Modules/Staking/StakingProxy/Management/StakingProxyManagementProtocols.swift similarity index 100% rename from novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementProtocols.swift rename to novawallet/Modules/Staking/StakingProxy/Management/StakingProxyManagementProtocols.swift diff --git a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementViewController.swift b/novawallet/Modules/Staking/StakingProxy/Management/StakingProxyManagementViewController.swift similarity index 100% rename from novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementViewController.swift rename to novawallet/Modules/Staking/StakingProxy/Management/StakingProxyManagementViewController.swift diff --git a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementViewFactory.swift b/novawallet/Modules/Staking/StakingProxy/Management/StakingProxyManagementViewFactory.swift similarity index 100% rename from novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementViewFactory.swift rename to novawallet/Modules/Staking/StakingProxy/Management/StakingProxyManagementViewFactory.swift diff --git a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementViewLayout.swift b/novawallet/Modules/Staking/StakingProxy/Management/StakingProxyManagementViewLayout.swift similarity index 100% rename from novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementViewLayout.swift rename to novawallet/Modules/Staking/StakingProxy/Management/StakingProxyManagementViewLayout.swift diff --git a/novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementWireframe.swift b/novawallet/Modules/Staking/StakingProxy/Management/StakingProxyManagementWireframe.swift similarity index 100% rename from novawallet/Modules/Staking/StakingProxyManagement/StakingProxyManagementWireframe.swift rename to novawallet/Modules/Staking/StakingProxy/Management/StakingProxyManagementWireframe.swift diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyInteractor.swift b/novawallet/Modules/Staking/StakingProxy/Remove/StakingRemoveProxyInteractor.swift similarity index 100% rename from novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyInteractor.swift rename to novawallet/Modules/Staking/StakingProxy/Remove/StakingRemoveProxyInteractor.swift diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyPresenter.swift b/novawallet/Modules/Staking/StakingProxy/Remove/StakingRemoveProxyPresenter.swift similarity index 100% rename from novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyPresenter.swift rename to novawallet/Modules/Staking/StakingProxy/Remove/StakingRemoveProxyPresenter.swift diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyProtocols.swift b/novawallet/Modules/Staking/StakingProxy/Remove/StakingRemoveProxyProtocols.swift similarity index 100% rename from novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyProtocols.swift rename to novawallet/Modules/Staking/StakingProxy/Remove/StakingRemoveProxyProtocols.swift diff --git a/novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyViewFactory.swift b/novawallet/Modules/Staking/StakingProxy/Remove/StakingRemoveProxyViewFactory.swift similarity index 100% rename from novawallet/Modules/Staking/StakingSetupProxy/StakingRemoveProxy/StakingRemoveProxyViewFactory.swift rename to novawallet/Modules/Staking/StakingProxy/Remove/StakingRemoveProxyViewFactory.swift From cb19cd34f33c0339f1b50b9bcee51478d139a639 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Tue, 23 Jan 2024 11:44:42 +0300 Subject: [PATCH 38/60] remove unused files --- .../AddProxyValidationsFactory.swift | 56 ------------------- ...oxyConfirmValidationsFactoryProtocol.swift | 18 ------ .../RemoveProxyValidationsFactory.swift | 31 ---------- 3 files changed, 105 deletions(-) delete mode 100644 novawallet/Modules/Proxy/Validation/AddProxyValidationsFactory.swift delete mode 100644 novawallet/Modules/Proxy/Validation/ProxyConfirmValidationsFactoryProtocol.swift delete mode 100644 novawallet/Modules/Proxy/Validation/RemoveProxyValidationsFactory.swift diff --git a/novawallet/Modules/Proxy/Validation/AddProxyValidationsFactory.swift b/novawallet/Modules/Proxy/Validation/AddProxyValidationsFactory.swift deleted file mode 100644 index ee7bebed8f..0000000000 --- a/novawallet/Modules/Proxy/Validation/AddProxyValidationsFactory.swift +++ /dev/null @@ -1,56 +0,0 @@ -import Foundation -import BigInt - -final class AddProxyValidationsFactory: ProxyConfirmValidationsFactoryProtocol { - let dataValidatingFactory: ProxyDataValidatorFactoryProtocol - - init(dataValidatingFactory: ProxyDataValidatorFactoryProtocol) { - self.dataValidatingFactory = dataValidatingFactory - } - - func validations(_ args: ConfirmProxyValidationArgs, locale: Locale) -> [DataValidating] { - [ - dataValidatingFactory.validAddress( - args.proxyAddress, - chain: args.chainAsset.chain, - locale: locale - ), - dataValidatingFactory.proxyNotExists( - address: args.proxyAddress, - chain: args.chainAsset.chain, - proxyList: args.proxy.map { $0?.definition ?? [] }.value, - locale: locale - ), - dataValidatingFactory.notReachedMaximimProxyCount( - args.proxy.map { $0?.definition.count ?? 0 }.value.map { $0 + 1 }, - limit: args.limitProxyCount, - chain: args.chainAsset.chain, - locale: locale - ), - dataValidatingFactory.has( - fee: args.fee, - locale: locale, - onError: args.feeFetchClosure - ), - dataValidatingFactory.canPayFeeInPlank( - balance: args.assetBalance?.regularTransferrableBalance(), - fee: args.fee, - asset: args.chainAsset.assetDisplayInfo, - locale: locale - ), - dataValidatingFactory.hasSufficientBalance( - available: (args.assetBalance?.regularTransferrableBalance() ?? 0) + (args.proxyDeposit?.current ?? 0), - deposit: args.proxyDeposit?.new, - fee: args.fee?.amountForCurrentAccount, - asset: args.chainAsset.assetDisplayInfo, - locale: locale - ), - dataValidatingFactory.exsitentialDepositIsNotViolated( - spendingAmount: args.fee?.amountForCurrentAccount, - totalAmount: args.assetBalance?.freeInPlank, - minimumBalance: args.existensialDeposit, - locale: locale - ) - ] - } -} diff --git a/novawallet/Modules/Proxy/Validation/ProxyConfirmValidationsFactoryProtocol.swift b/novawallet/Modules/Proxy/Validation/ProxyConfirmValidationsFactoryProtocol.swift deleted file mode 100644 index a582fedbb2..0000000000 --- a/novawallet/Modules/Proxy/Validation/ProxyConfirmValidationsFactoryProtocol.swift +++ /dev/null @@ -1,18 +0,0 @@ -import Foundation -import BigInt - -struct ConfirmProxyValidationArgs { - let proxyAddress: AccountAddress - let chainAsset: ChainAsset - let proxy: UncertainStorage - let limitProxyCount: Int? - let feeFetchClosure: () -> Void - let assetBalance: AssetBalance? - let proxyDeposit: ProxyDeposit? - let existensialDeposit: BigUInt? - let fee: ExtrinsicFeeProtocol? -} - -protocol ProxyConfirmValidationsFactoryProtocol { - func validations(_ args: ConfirmProxyValidationArgs, locale: Locale) -> [DataValidating] -} diff --git a/novawallet/Modules/Proxy/Validation/RemoveProxyValidationsFactory.swift b/novawallet/Modules/Proxy/Validation/RemoveProxyValidationsFactory.swift deleted file mode 100644 index 438d372fd4..0000000000 --- a/novawallet/Modules/Proxy/Validation/RemoveProxyValidationsFactory.swift +++ /dev/null @@ -1,31 +0,0 @@ -import Foundation -import BigInt - -final class RemoveProxyValidationsFactory: ProxyConfirmValidationsFactoryProtocol { - let dataValidatingFactory: ProxyDataValidatorFactoryProtocol - - init(dataValidatingFactory: ProxyDataValidatorFactoryProtocol) { - self.dataValidatingFactory = dataValidatingFactory - } - - func validations(_ args: ConfirmProxyValidationArgs, locale: Locale) -> [DataValidating] { - [ - dataValidatingFactory.validAddress( - args.proxyAddress, - chain: args.chainAsset.chain, - locale: locale - ), - dataValidatingFactory.has( - fee: args.fee, - locale: locale, - onError: args.feeFetchClosure - ), - dataValidatingFactory.canPayFeeInPlank( - balance: args.assetBalance?.regularTransferrableBalance(), - fee: args.fee, - asset: args.chainAsset.assetDisplayInfo, - locale: locale - ) - ] - } -} From adf3e28d785e43dbe756a1016f7de41a95dc2f86 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Tue, 23 Jan 2024 11:49:39 +0300 Subject: [PATCH 39/60] cleanup --- .../Remove/StakingRemoveProxyInteractor.swift | 8 ++++---- .../StakingProxy/Remove/StakingRemoveProxyPresenter.swift | 2 +- .../StakingProxy/Remove/StakingRemoveProxyProtocols.swift | 1 - 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/novawallet/Modules/Staking/StakingProxy/Remove/StakingRemoveProxyInteractor.swift b/novawallet/Modules/Staking/StakingProxy/Remove/StakingRemoveProxyInteractor.swift index ca96b96b4b..b924b51989 100644 --- a/novawallet/Modules/Staking/StakingProxy/Remove/StakingRemoveProxyInteractor.swift +++ b/novawallet/Modules/Staking/StakingProxy/Remove/StakingRemoveProxyInteractor.swift @@ -1,7 +1,7 @@ import UIKit import RobinHood -final class StakingRemoveProxyInteractor: StakingRemoveProxyInteractorInputProtocol, AnyProviderAutoCleaning { +final class StakingRemoveProxyInteractor: AnyProviderAutoCleaning { weak var presenter: StakingRemoveProxyInteractorOutputProtocol? let selectedAccount: ChainAccountResponse let walletLocalSubscriptionFactory: WalletLocalSubscriptionFactoryProtocol @@ -54,7 +54,7 @@ final class StakingRemoveProxyInteractor: StakingRemoveProxyInteractorInputProto priceProvider = subscribeToPrice(for: priceId, currency: selectedCurrency) } - func performBalanceSubscription() { + private func performBalanceSubscription() { clear(streamableProvider: &balanceProvider) let accountId = selectedAccount.accountId @@ -67,9 +67,9 @@ final class StakingRemoveProxyInteractor: StakingRemoveProxyInteractorInputProto estimateFee() } +} - // MARK: - StakingProxyBaseInteractorInputProtocol - +extension StakingRemoveProxyInteractor: StakingRemoveProxyInteractorInputProtocol { func setup() { feeProxy.delegate = self diff --git a/novawallet/Modules/Staking/StakingProxy/Remove/StakingRemoveProxyPresenter.swift b/novawallet/Modules/Staking/StakingProxy/Remove/StakingRemoveProxyPresenter.swift index b5124b31d3..13692127c2 100644 --- a/novawallet/Modules/Staking/StakingProxy/Remove/StakingRemoveProxyPresenter.swift +++ b/novawallet/Modules/Staking/StakingProxy/Remove/StakingRemoveProxyPresenter.swift @@ -202,7 +202,7 @@ extension StakingRemoveProxyPresenter: StakingRemoveProxyInteractorOutputProtoco view?.didStopLoading() switch error { - case .handleProxies, .balance, .price: + case .balance, .price: interactor.remakeSubscriptions() case .fee: wireframe.presentRequestStatus(on: view, locale: selectedLocale) { [weak self] in diff --git a/novawallet/Modules/Staking/StakingProxy/Remove/StakingRemoveProxyProtocols.swift b/novawallet/Modules/Staking/StakingProxy/Remove/StakingRemoveProxyProtocols.swift index 6683745341..7d1ea01633 100644 --- a/novawallet/Modules/Staking/StakingProxy/Remove/StakingRemoveProxyProtocols.swift +++ b/novawallet/Modules/Staking/StakingProxy/Remove/StakingRemoveProxyProtocols.swift @@ -14,7 +14,6 @@ protocol StakingRemoveProxyInteractorOutputProtocol: AnyObject { } enum StakingRemoveProxyError: Error { - case handleProxies(Error) case balance(Error) case price(Error) case fee(Error) From 551725c05e6974aaf4f823ecb1282d69370cfbb2 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Tue, 23 Jan 2024 12:11:30 +0300 Subject: [PATCH 40/60] bugdix --- .../Confirm/StakingConfirmProxyPresenter.swift | 17 +++++++++++++++++ .../Confirm/StakingConfirmProxyProtocols.swift | 2 ++ .../StakingConfirmProxyViewController.swift | 14 ++++++++------ .../Remove/StakingRemoveProxyPresenter.swift | 15 ++++++++++++++- novawallet/en.lproj/Localizable.strings | 4 +++- novawallet/ru.lproj/Localizable.strings | 4 +++- 6 files changed, 47 insertions(+), 9 deletions(-) diff --git a/novawallet/Modules/Staking/StakingProxy/Confirm/StakingConfirmProxyPresenter.swift b/novawallet/Modules/Staking/StakingProxy/Confirm/StakingConfirmProxyPresenter.swift index 82c40fe11d..dc9137ac6e 100644 --- a/novawallet/Modules/Staking/StakingProxy/Confirm/StakingConfirmProxyPresenter.swift +++ b/novawallet/Modules/Staking/StakingProxy/Confirm/StakingConfirmProxyPresenter.swift @@ -48,6 +48,7 @@ final class StakingConfirmProxyPresenter: StakingProxyBasePresenter { override func setup() { super.setup() + provideTitles() provideProxyTypeViewModel() provideProxyDeposit() provideNetworkViewModel() @@ -93,9 +94,25 @@ final class StakingConfirmProxyPresenter: StakingProxyBasePresenter { view?.didReceiveProxyAddress(viewModel: viewModel) } + private func provideTitles() { + let typeTitle = R.string.localizable.stakingConfirmProxyTypeTitle( + preferredLanguages: selectedLocale.rLanguages + ) + let proxyAddressTitle = R.string.localizable.stakingConfirmProxyAccountProxy( + preferredLanguages: selectedLocale.rLanguages + ) + view?.didReceiveProxyType(title: typeTitle) + view?.didReceiveProxyAddress(title: proxyAddressTitle) + } + override func getProxyAddress() -> AccountAddress { proxyAddress } + + override func updateView() { + super.updateView() + provideTitles() + } } extension StakingConfirmProxyPresenter: StakingConfirmProxyPresenterProtocol { diff --git a/novawallet/Modules/Staking/StakingProxy/Confirm/StakingConfirmProxyProtocols.swift b/novawallet/Modules/Staking/StakingProxy/Confirm/StakingConfirmProxyProtocols.swift index 51d25fa181..84f3f63456 100644 --- a/novawallet/Modules/Staking/StakingProxy/Confirm/StakingConfirmProxyProtocols.swift +++ b/novawallet/Modules/Staking/StakingProxy/Confirm/StakingConfirmProxyProtocols.swift @@ -6,6 +6,8 @@ protocol StakingConfirmProxyViewProtocol: StakingSetupProxyBaseViewProtocol { func didReceiveProxyType(viewModel: String) func didStartLoading() func didStopLoading() + func didReceiveProxyAddress(title: String) + func didReceiveProxyType(title: String) } protocol StakingConfirmProxyPresenterProtocol: StakingSetupProxyBasePresenterProtocol { diff --git a/novawallet/Modules/Staking/StakingProxy/Confirm/StakingConfirmProxyViewController.swift b/novawallet/Modules/Staking/StakingProxy/Confirm/StakingConfirmProxyViewController.swift index 4920ed0660..26f911b72b 100644 --- a/novawallet/Modules/Staking/StakingProxy/Confirm/StakingConfirmProxyViewController.swift +++ b/novawallet/Modules/Staking/StakingProxy/Confirm/StakingConfirmProxyViewController.swift @@ -52,12 +52,6 @@ final class StakingConfirmProxyViewController: UIViewController, ViewHolder { preferredLanguages: languages ) rootView.feeCell.rowContentView.locale = selectedLocale - rootView.proxyTypeCell.titleLabel.text = R.string.localizable.stakingConfirmProxyTypeTitle( - preferredLanguages: languages - ) - rootView.proxyAddressCell.titleLabel.text = R.string.localizable.stakingConfirmProxyAccountProxy( - preferredLanguages: languages - ) rootView.actionButton.actionButton.imageWithTitleView?.title = R.string.localizable.commonConfirm( preferredLanguages: languages ) @@ -130,10 +124,18 @@ extension StakingConfirmProxyViewController: StakingConfirmProxyViewProtocol { rootView.proxiedAddressCell.bind(viewModel: viewModel.cellViewModel) } + func didReceiveProxyAddress(title: String) { + rootView.proxyAddressCell.titleLabel.text = title + } + func didReceiveProxyAddress(viewModel: DisplayAddressViewModel) { rootView.proxyAddressCell.bind(viewModel: viewModel.cellViewModel) } + func didReceiveProxyType(title: String) { + rootView.proxyTypeCell.titleLabel.text = title + } + func didReceiveProxyType(viewModel: String) { rootView.proxyTypeCell.bind(details: viewModel) } diff --git a/novawallet/Modules/Staking/StakingProxy/Remove/StakingRemoveProxyPresenter.swift b/novawallet/Modules/Staking/StakingProxy/Remove/StakingRemoveProxyPresenter.swift index 13692127c2..edf8074c05 100644 --- a/novawallet/Modules/Staking/StakingProxy/Remove/StakingRemoveProxyPresenter.swift +++ b/novawallet/Modules/Staking/StakingProxy/Remove/StakingRemoveProxyPresenter.swift @@ -118,18 +118,31 @@ final class StakingRemoveProxyPresenter { ] } + private func provideTitles() { + let typeTitle = R.string.localizable.stakingProxyRevokeAccessType( + preferredLanguages: selectedLocale.rLanguages + ) + let proxyAddressTitle = R.string.localizable.stakingProxyRevokeAccessProxyAddress( + preferredLanguages: selectedLocale.rLanguages + ) + view?.didReceiveProxyType(title: typeTitle) + view?.didReceiveProxyAddress(title: proxyAddressTitle) + } + private func updateView() { provideProxyTypeViewModel() provideNetworkViewModel() provideProxiedWalletViewModel() provideProxiedAddressViewModel() provideProxyAddressViewModel() + provideTitles() + + view?.didReceiveProxyDeposit(viewModel: nil) } } extension StakingRemoveProxyPresenter: StakingConfirmProxyPresenterProtocol { func setup() { - view?.didReceiveProxyDeposit(viewModel: nil) updateView() interactor.setup() } diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index 912904598a..ba094b0277 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -1384,6 +1384,8 @@ "staking.confirm.proxy.account.proxy" = "Delegate to"; "staking.proxy.management.title" = "Delegated authorities (proxy)"; "staking.proxy.management.revoke.access" = "Revoke access"; +"staking.proxy.revoke.access.type" = "Revoke access type"; +"staking.proxy.revoke.access.proxy.address" = "Revoke for"; "common.time.in" = "in"; "common.and" = " and "; "common.time.period.after" = "after"; @@ -1482,4 +1484,4 @@ "proxy.fee.error.message" = "Delegated account %@ doesn\'t have enough balance to pay the network fee of %@. Available balance to pay fee: %@"; "proxy.signing.checkmark.title" = "Automatically continue in the future"; "deeplink.error.invalid.referendum.id.message" = "Referendum is not found"; -"governance.referendum.not.found.message" = "Referendum is not found"; \ No newline at end of file +"governance.referendum.not.found.message" = "Referendum is not found"; diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index 5f8b0b1afb..51371538a1 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1385,6 +1385,8 @@ "staking.confirm.proxy.account.proxy" = "Делегировать"; "staking.proxy.management.title" = "Делегированные полномочия (прокси)"; "staking.proxy.management.revoke.access" = "Отозвать доступ"; +"staking.proxy.revoke.access.type" = "Отзыввемый доступ"; +"staking.proxy.revoke.access.proxy.address" = "Отозвать для"; "common.and" = " и "; "common.time.period.after" = "через"; "common.time.period.every" = "раз в"; @@ -1482,4 +1484,4 @@ "proxy.fee.error.message" = "Делегированный аккаунт %@ не имеет достаточного баланса для оплаты сетевой комиссии %@. Доступный баланс для оплаты комиссии: %@"; "proxy.signing.checkmark.title" = "Автоматически проводить в будущем"; "deeplink.error.invalid.referendum.id.message" = "Референдум не найден"; -"governance.referendum.not.found.message" = "Референдум не найден"; \ No newline at end of file +"governance.referendum.not.found.message" = "Референдум не найден"; From 1d0f055eba301419d01ec4ac44bf8ec444c9f4b0 Mon Sep 17 00:00:00 2001 From: Gulnaz <666lynx666@mail.ru> Date: Thu, 25 Jan 2024 13:18:15 +0300 Subject: [PATCH 41/60] Proxy: controller alert (#953) * init * bugfix --- ...ingRelaychainInteractor+Subscription.swift | 13 ++++--- .../StakingRelaychainPresenter.swift | 35 ++++++++++++++++++- novawallet/en.lproj/Localizable.strings | 4 ++- novawallet/ru.lproj/Localizable.strings | 4 ++- 4 files changed, 48 insertions(+), 8 deletions(-) diff --git a/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainInteractor+Subscription.swift b/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainInteractor+Subscription.swift index 0202de8bde..a4f153944e 100644 --- a/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainInteractor+Subscription.swift +++ b/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainInteractor+Subscription.swift @@ -26,11 +26,6 @@ extension StakingRelaychainInteractor { nominatorProvider = subscribeNomination(for: stashAccountId, chainId: chainId) validatorProvider = subscribeValidator(for: stashAccountId, chainId: chainId) payeeProvider = subscribePayee(for: stashAccountId, chainId: chainId) - proxyProvider = subscribeProxies( - for: stashAccountId, - chainId: chainId, - modifyInternalList: ProxyFilter.filteredStakingProxy - ) performTotalRewardSubscription() @@ -39,6 +34,14 @@ extension StakingRelaychainInteractor { if stashItem.controller != stashItem.stash { subscribeToStashAccount(address: stashItem.stash, chain: chainAsset.chain) } + + if selectedAccount?.accountId == stashAccountId { + proxyProvider = subscribeProxies( + for: stashAccountId, + chainId: chainId, + modifyInternalList: ProxyFilter.filteredStakingProxy + ) + } } presenter?.didReceive(stashItem: stashItem) diff --git a/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainPresenter.swift b/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainPresenter.swift index 992ee00c7a..d70d4336ef 100644 --- a/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainPresenter.swift +++ b/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainPresenter.swift @@ -224,6 +224,33 @@ final class StakingRelaychainPresenter { wireframe.present(viewModel: viewModel, style: .actionSheet, from: view) } + + private func presentSwitchToStashAccountAlert(stashAddress: AccountAddress) { + let locale = view?.selectedLocale + let displayName: String + if let displayAddress = try? accountForAddress(stashAddress)?.toWalletDisplayAddress() { + displayName = displayAddress.walletName ?? displayAddress.address + } else { + displayName = stashAddress + } + let title = R.string.localizable.stakingAlertSwitchToStashTitle( + preferredLanguages: locale?.rLanguages + ) + let message = R.string.localizable.stakingAlertSwitchToStashMessage( + displayName, + preferredLanguages: locale?.rLanguages + ) + let closeTitle = R.string.localizable.commonClose( + preferredLanguages: locale?.rLanguages + ) + + wireframe.present( + message: message, + title: title, + closeAction: closeTitle, + from: view + ) + } } extension StakingRelaychainPresenter: StakingStateMachineDelegate { @@ -343,7 +370,13 @@ extension StakingRelaychainPresenter: StakingMainChildPresenterProtocol { wireframe.showYourValidatorInfo(stashAddress, from: view) } case .addProxy: - wireframe.showAddProxy(from: view) + if let state = stateMachine.viewState(using: { (state: BaseStashNextState) in state }) { + if state.commonData.address != state.stashItem.stash { + presentSwitchToStashAccountAlert(stashAddress: state.stashItem.stash) + } else { + wireframe.showAddProxy(from: view) + } + } case .editProxies: wireframe.showEditProxies(from: view) default: diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index 912904598a..88e1378093 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -1369,6 +1369,8 @@ "staking.setup.proxy.deposit.details" = "The deposit stays reserved on your account until the proxy is removed."; "staking.setup.your.proxies" = "Your delegations"; "staking.setup.add.your.proxy" = "Add delegated authority (Proxy)"; +"staking.alert.switch.to.stash.title" = "Select stash account to setup proxy"; +"staking.alert.switch.to.stash.message" = "Please switch your wallet to %@ to setup a proxy"; "staking.setup.proxy.error.insufficient.balance.title" = "Not enough tokens"; "staking.setup.proxy.error.insufficient.balance.message" = "You don’t have enough balance for proxy deposit of %@. Available balance: %@"; "staking.setup.proxy.error.invalid.address.title" = "Invalid proxy address"; @@ -1482,4 +1484,4 @@ "proxy.fee.error.message" = "Delegated account %@ doesn\'t have enough balance to pay the network fee of %@. Available balance to pay fee: %@"; "proxy.signing.checkmark.title" = "Automatically continue in the future"; "deeplink.error.invalid.referendum.id.message" = "Referendum is not found"; -"governance.referendum.not.found.message" = "Referendum is not found"; \ No newline at end of file +"governance.referendum.not.found.message" = "Referendum is not found"; diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index 5f8b0b1afb..6c20fcf96c 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1369,6 +1369,8 @@ "staking.setup.proxy.deposit.details" = "Депозит остается зарезервированным на вашем счете до тех пор, пока прокси не будет удален."; "staking.setup.your.proxies" = "Ваши делегации"; "staking.setup.add.your.proxy" = "Добавить делегацию (Прокси)"; +"staking.alert.switch.to.stash.title" = "Выберите стэш-аккаунт для настройки прокси."; +"staking.alert.switch.to.stash.message" = "Переключите свой кошелек на %@, чтобы настроить прокси."; "staking.setup.proxy.error.insufficient.balance.title" = "Недостаточно токенов"; "staking.setup.proxy.error.insufficient.balance.message" = "У вас недостаточно средств для депозита прокси %@. Доступный баланс: %@"; "staking.setup.proxy.error.invalid.address.title" = "Некорректный адрес прокси"; @@ -1482,4 +1484,4 @@ "proxy.fee.error.message" = "Делегированный аккаунт %@ не имеет достаточного баланса для оплаты сетевой комиссии %@. Доступный баланс для оплаты комиссии: %@"; "proxy.signing.checkmark.title" = "Автоматически проводить в будущем"; "deeplink.error.invalid.referendum.id.message" = "Референдум не найден"; -"governance.referendum.not.found.message" = "Референдум не найден"; \ No newline at end of file +"governance.referendum.not.found.message" = "Референдум не найден"; From 4eca8a23e3722e84b24a70c29c53dcc63a4f25df Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Mon, 29 Jan 2024 13:04:42 +0300 Subject: [PATCH 42/60] bugfixes --- novawallet.xcodeproj/project.pbxproj | 8 + .../Proxy/ChainProxySyncService.swift | 24 +-- .../Proxy/ProxyOperationFactory.swift | 11 +- .../Services/Proxy/ProxySyncService.swift | 13 +- .../Substrate/ProxyAccountSubscription.swift | 200 ++++++++++++++++++ .../ProxyAccountUpdatingService.swift | 52 +++++ .../StakingAccountSubscription.swift | 7 - .../StakingAccountUpdatingService.swift | 7 +- .../Dashboard/StakingDashboardWireframe.swift | 5 +- .../RelaychainStakingSharedState.swift | 13 +- .../RelaychainStartStakingState.swift | 7 +- .../StakingSharedStateFactory.swift | 20 +- .../StakingMain/StakingMainViewFactory.swift | 6 +- .../StartStakingInfoViewFactory.swift | 2 + 14 files changed, 336 insertions(+), 39 deletions(-) create mode 100644 novawallet/Common/Services/RemoteSubscription/Substrate/ProxyAccountSubscription.swift create mode 100644 novawallet/Common/Services/RemoteSubscription/Substrate/ProxyAccountUpdatingService.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index beacf6ac5b..28211a4c0c 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -931,6 +931,7 @@ 77A0B2F92A3CA40E00CBF653 /* StakingMoreOptionsSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77A0B2F82A3CA40E00CBF653 /* StakingMoreOptionsSection.swift */; }; 77A4F4012B035027006294BC /* AssetOperationState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77A4F4002B035027006294BC /* AssetOperationState.swift */; }; 77A4F4032B036615006294BC /* Optional+Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77A4F4022B036615006294BC /* Optional+Result.swift */; }; + 77A502F12B63E3830062FA51 /* ProxyAccountSubscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77A502F02B63E3830062FA51 /* ProxyAccountSubscription.swift */; }; 77A6F5AB2A2E0B31004AFD1A /* ReceiveAssetOperationPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77A6F5AA2A2E0B31004AFD1A /* ReceiveAssetOperationPresenter.swift */; }; 77A6F5AE2A2E0C7C004AFD1A /* ReceiveAssetOperationWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77A6F5AD2A2E0C7C004AFD1A /* ReceiveAssetOperationWireframe.swift */; }; 77A6F5B92A2E2AAD004AFD1A /* BuyAssetOperationPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77A6F5B72A2E2AAD004AFD1A /* BuyAssetOperationPresenter.swift */; }; @@ -1047,6 +1048,7 @@ 77F9FB0D2A9D9C5600820625 /* NominationPoolBondMoreBaseProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77F9FB0C2A9D9C5600820625 /* NominationPoolBondMoreBaseProtocols.swift */; }; 77FDFC462B0DEB34005A3569 /* OpenDAppUrlParsingService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77FDFC452B0DEB34005A3569 /* OpenDAppUrlParsingService.swift */; }; 77FDFC482B0E1CBD005A3569 /* ImportWalletUrlParsingService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77FDFC472B0E1CBD005A3569 /* ImportWalletUrlParsingService.swift */; }; + 77FE76402B67682A00ADA73F /* ProxyAccountUpdatingService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77FE763F2B67682A00ADA73F /* ProxyAccountUpdatingService.swift */; }; 77FF02692B21ECB900B655BC /* ProxyTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77FF02682B21ECB900B655BC /* ProxyTableViewCell.swift */; }; 77FFB2B12B0D392A00C7C879 /* OpenStakingUrlParsingService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77FFB2B02B0D392A00C7C879 /* OpenStakingUrlParsingService.swift */; }; 77FFB2B32B0D394700C7C879 /* OpenGovernanceUrlParsingService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77FFB2B22B0D394700C7C879 /* OpenGovernanceUrlParsingService.swift */; }; @@ -5192,6 +5194,7 @@ 77A0B2F82A3CA40E00CBF653 /* StakingMoreOptionsSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingMoreOptionsSection.swift; sourceTree = ""; }; 77A4F4002B035027006294BC /* AssetOperationState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssetOperationState.swift; sourceTree = ""; }; 77A4F4022B036615006294BC /* Optional+Result.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Optional+Result.swift"; sourceTree = ""; }; + 77A502F02B63E3830062FA51 /* ProxyAccountSubscription.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProxyAccountSubscription.swift; sourceTree = ""; }; 77A6F5AA2A2E0B31004AFD1A /* ReceiveAssetOperationPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReceiveAssetOperationPresenter.swift; sourceTree = ""; }; 77A6F5AD2A2E0C7C004AFD1A /* ReceiveAssetOperationWireframe.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReceiveAssetOperationWireframe.swift; sourceTree = ""; }; 77A6F5B72A2E2AAD004AFD1A /* BuyAssetOperationPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BuyAssetOperationPresenter.swift; sourceTree = ""; }; @@ -5314,6 +5317,7 @@ 77F9FB0C2A9D9C5600820625 /* NominationPoolBondMoreBaseProtocols.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NominationPoolBondMoreBaseProtocols.swift; sourceTree = ""; }; 77FDFC452B0DEB34005A3569 /* OpenDAppUrlParsingService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenDAppUrlParsingService.swift; sourceTree = ""; }; 77FDFC472B0E1CBD005A3569 /* ImportWalletUrlParsingService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImportWalletUrlParsingService.swift; sourceTree = ""; }; + 77FE763F2B67682A00ADA73F /* ProxyAccountUpdatingService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProxyAccountUpdatingService.swift; sourceTree = ""; }; 77FF02682B21ECB900B655BC /* ProxyTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProxyTableViewCell.swift; sourceTree = ""; }; 77FFB2B02B0D392A00C7C879 /* OpenStakingUrlParsingService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenStakingUrlParsingService.swift; sourceTree = ""; }; 77FFB2B22B0D394700C7C879 /* OpenGovernanceUrlParsingService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenGovernanceUrlParsingService.swift; sourceTree = ""; }; @@ -16177,6 +16181,8 @@ 0CC2E5612A6E5C43004092E7 /* NominationPoolsAccountUpdatingService.swift */, 0CE1504F2A6FAC1200B61CC1 /* NominationPoolsPoolSubscriptionService.swift */, 0CAC02FC2B4BFB9400DDEC3A /* WalletRemoteQueryWrapperFactory.swift */, + 77FE763F2B67682A00ADA73F /* ProxyAccountUpdatingService.swift */, + 77A502F02B63E3830062FA51 /* ProxyAccountSubscription.swift */, ); path = Substrate; sourceTree = ""; @@ -23630,6 +23636,7 @@ 848F8B2B2864824200204BC4 /* AssetListChainControlView.swift in Sources */, 4F03B1138E7160AEA00B7793 /* ParaStkCollatorInfoViewFactory.swift in Sources */, 0119531FAE0D22EA9464F84D /* ParaStkYourCollatorsProtocols.swift in Sources */, + 77FE76402B67682A00ADA73F /* ProxyAccountUpdatingService.swift in Sources */, 542588DA751A44C993BC1F27 /* ParaStkYourCollatorsWireframe.swift in Sources */, D6D9D16440AB588F581AF5BA /* ParaStkYourCollatorsPresenter.swift in Sources */, FA62AACACA15CB04275DE957 /* ParaStkYourCollatorsInteractor.swift in Sources */, @@ -24209,6 +24216,7 @@ 77F9FB0B2A9D97A100820625 /* NominationPoolBondMoreSetupWireframe.swift in Sources */, F0C3DCA3CD4F850C16406716 /* GovernanceDelegateSearchViewFactory.swift in Sources */, 0C13DFD52AFA4F1500E5F355 /* SwapIssueCheckParams.swift in Sources */, + 77A502F12B63E3830062FA51 /* ProxyAccountSubscription.swift in Sources */, C98A02D4DEAC6E4CACB9E47E /* StakingRebagConfirmProtocols.swift in Sources */, B09F155D14D146377FB2952A /* StakingRebagConfirmWireframe.swift in Sources */, 840AE2E329C9A715008FF665 /* OptionStringCodable+Empty.swift in Sources */, diff --git a/novawallet/Common/Services/Proxy/ChainProxySyncService.swift b/novawallet/Common/Services/Proxy/ChainProxySyncService.swift index 112c639b89..03c39726d4 100644 --- a/novawallet/Common/Services/Proxy/ChainProxySyncService.swift +++ b/novawallet/Common/Services/Proxy/ChainProxySyncService.swift @@ -2,7 +2,11 @@ import SubstrateSdk import RobinHood import BigInt -final class ChainProxySyncService: ObservableSyncService, AnyCancellableCleaning { +protocol ChainProxySyncServiceProtocol: ObservableSyncServiceProtocol { + func sync(at blockHash: Data?) +} + +final class ChainProxySyncService: ObservableSyncService, ChainProxySyncServiceProtocol, AnyCancellableCleaning { let walletUpdateMediator: WalletUpdateMediating let metaAccountsRepository: AnyDataProviderRepository let chainRegistry: ChainRegistryProtocol @@ -47,8 +51,11 @@ final class ChainProxySyncService: ObservableSyncService, AnyCancellableCleaning } override func performSyncUp() { - let chainId = chainModel.chainId + sync(at: nil) + } + func sync(at blockHash: Data?) { + let chainId = chainModel.chainId guard let connection = chainRegistry.getConnection(for: chainId) else { completeImmediate(ChainRegistryError.connectionUnavailable) return @@ -59,22 +66,13 @@ final class ChainProxySyncService: ObservableSyncService, AnyCancellableCleaning return } - performSyncUp( - connection: connection, - runtimeProvider: runtimeProvider - ) - } - - private func performSyncUp( - connection: JSONRPCEngine, - runtimeProvider: RuntimeCodingServiceProtocol - ) { pendingCall.cancel() let proxyListWrapper = proxyOperationFactory.fetchProxyList( requestFactory: requestFactory, connection: connection, - runtimeProvider: runtimeProvider + runtimeProvider: runtimeProvider, + at: blockHash ) let walletsWrapper = createWalletsWrapper(for: chainWalletFilter, chain: chainModel) diff --git a/novawallet/Common/Services/Proxy/ProxyOperationFactory.swift b/novawallet/Common/Services/Proxy/ProxyOperationFactory.swift index aa2b5b2b8b..1db638e852 100644 --- a/novawallet/Common/Services/Proxy/ProxyOperationFactory.swift +++ b/novawallet/Common/Services/Proxy/ProxyOperationFactory.swift @@ -7,7 +7,8 @@ protocol ProxyOperationFactoryProtocol { func fetchProxyList( requestFactory: StorageRequestFactoryProtocol, connection: JSONRPCEngine, - runtimeProvider: RuntimeCodingServiceProtocol + runtimeProvider: RuntimeCodingServiceProtocol, + at blockHash: Data? ) -> CompoundOperationWrapper<[ProxiedAccountId: [ProxyAccount]]> } @@ -15,12 +16,16 @@ final class ProxyOperationFactory: ProxyOperationFactoryProtocol { func fetchProxyList( requestFactory: StorageRequestFactoryProtocol, connection: JSONRPCEngine, - runtimeProvider: RuntimeCodingServiceProtocol + runtimeProvider: RuntimeCodingServiceProtocol, + at blockHash: Data? ) -> CompoundOperationWrapper<[ProxiedAccountId: [ProxyAccount]]> { let request = UnkeyedRemoteStorageRequest(storagePath: Proxy.proxyList) let codingFactoryOperation = runtimeProvider.fetchCoderFactoryOperation() - let options = StorageQueryListOptions(ignoresFailedItems: true) + let options = StorageQueryListOptions( + atBlock: blockHash, + ignoresFailedItems: true + ) let fetchWrapper: CompoundOperationWrapper<[AccountIdKey: ProxyDefinition]> = requestFactory.queryByPrefix( engine: connection, diff --git a/novawallet/Common/Services/Proxy/ProxySyncService.swift b/novawallet/Common/Services/Proxy/ProxySyncService.swift index 145e31d1b5..cca3a0f908 100644 --- a/novawallet/Common/Services/Proxy/ProxySyncService.swift +++ b/novawallet/Common/Services/Proxy/ProxySyncService.swift @@ -13,6 +13,10 @@ protocol ProxySyncServiceProtocol: ApplicationServiceProtocol { func unsubscribeSyncState(_ target: AnyObject) func updateWalletsStatuses() func syncUp() + func syncUp( + chainId: ChainModel.Id, + blockHash: Data? + ) } typealias ProxySyncChainFilter = (ChainModel) -> Bool @@ -32,7 +36,7 @@ final class ProxySyncService { private(set) var isActive: Bool = false - private(set) var updaters: [ChainModel.Id: ObservableSyncServiceProtocol & ApplicationServiceProtocol] = [:] + private(set) var updaters: [ChainModel.Id: ChainProxySyncServiceProtocol & ApplicationServiceProtocol] = [:] private let mutex = NSLock() private var stateObserver = Observable(state: [:]) @@ -272,4 +276,11 @@ extension ProxySyncService: ProxySyncServiceProtocol { func syncUp() { updaters.values.forEach { $0.syncUp() } } + + func syncUp( + chainId: ChainModel.Id, + blockHash: Data? + ) { + updaters[chainId]?.sync(at: blockHash) + } } diff --git a/novawallet/Common/Services/RemoteSubscription/Substrate/ProxyAccountSubscription.swift b/novawallet/Common/Services/RemoteSubscription/Substrate/ProxyAccountSubscription.swift new file mode 100644 index 0000000000..4a00f8252f --- /dev/null +++ b/novawallet/Common/Services/RemoteSubscription/Substrate/ProxyAccountSubscription.swift @@ -0,0 +1,200 @@ +import Foundation +import RobinHood +import IrohaCrypto +import SubstrateSdk + +final class ProxyAccountSubscription: WebSocketSubscribing { + let accountId: AccountId + let chainId: ChainModel.Id + let chainRegistry: ChainRegistryProtocol + let proxySyncService: ProxySyncServiceProtocol + let logger: LoggerProtocol? + let childSubscriptionFactory: ChildSubscriptionFactoryProtocol + + private let mutex = NSLock() + private let operationQueue: OperationQueue + private var subscriptionId: UInt16? + private var remoteStorageKey: Data? + private var storageSubscriptionHandler: StorageChildSubscribing? + + init( + accountId: AccountId, + chainId: ChainModel.Id, + chainRegistry: ChainRegistryProtocol, + proxySyncService: ProxySyncServiceProtocol, + childSubscriptionFactory: ChildSubscriptionFactoryProtocol, + operationQueue: OperationQueue, + logger: LoggerProtocol? = nil + ) { + self.accountId = accountId + self.chainId = chainId + self.chainRegistry = chainRegistry + self.proxySyncService = proxySyncService + self.childSubscriptionFactory = childSubscriptionFactory + self.operationQueue = operationQueue + self.logger = logger + + subscribeRemote(for: accountId) + } + + deinit { + unsubscribeRemote() + } + + private func unsubscribeRemote() { + mutex.lock() + + if let subscriptionId = subscriptionId { + chainRegistry.getConnection(for: chainId)?.cancelForIdentifier(subscriptionId) + } + + subscriptionId = nil + remoteStorageKey = nil + storageSubscriptionHandler = nil + + mutex.unlock() + } + + private func subscribeRemote(for accountId: AccountId) { + mutex.lock() + + defer { + mutex.unlock() + } + + do { + guard let runtimeService = chainRegistry.getRuntimeProvider(for: chainId) else { + throw ChainRegistryError.runtimeMetadaUnavailable + } + let path = Proxy.proxyList + let localKey = try LocalStorageKeyFactory().createFromStoragePath( + path, + accountId: accountId, + chainId: chainId + ) + + let codingFactoryOperation = runtimeService.fetchCoderFactoryOperation() + + let storageKeyFactory = StorageKeyFactory() + + let codingOperation = MapKeyEncodingOperation( + path: path, + storageKeyFactory: storageKeyFactory, + keyParams: [accountId] + ) + + codingOperation.addDependency(codingFactoryOperation) + + codingOperation.configurationBlock = { + do { + guard let result = try codingFactoryOperation.extractResultData() else { + codingOperation.cancel() + return + } + + codingOperation.codingFactory = result + + } catch { + codingOperation.result = .failure(error) + } + } + + let mapOperation = ClosureOperation { [weak self] in + do { + return try codingOperation.extractNoCancellableResultData().first + } catch StorageKeyEncodingOperationError.invalidStoragePath { + self?.logger?.warning("Subscription path missing in runtime: \(codingOperation.path)") + return nil + } + } + + mapOperation.addDependency(codingOperation) + + mapOperation.completionBlock = { [weak self] in + do { + if let remoteKey = try mapOperation.extractNoCancellableResultData() { + let key = SubscriptionStorageKeys(remote: remoteKey, local: localKey) + self?.subscribeToRemote(with: key) + } + } catch { + self?.logger?.error("Did receive error: \(error)") + } + } + + let operations = [codingFactoryOperation, codingOperation, mapOperation] + + operationQueue.addOperations(operations, waitUntilFinished: false) + + } catch { + logger?.error("Did receive unexpected error \(error)") + } + } + + private func subscribeToRemote( + with keyPair: SubscriptionStorageKeys + ) { + mutex.lock() + + defer { + mutex.unlock() + } + + do { + guard let connection = chainRegistry.getConnection(for: chainId) else { + throw ChainRegistryError.connectionUnavailable + } + + let storageParam = keyPair.remote.toHex(includePrefix: true) + + let updateClosure: (StorageSubscriptionUpdate) -> Void = { [weak self] update in + self?.handleUpdate(update.params.result) + } + + let failureClosure: (Error, Bool) -> Void = { [weak self] error, unsubscribed in + self?.logger?.error("Did receive subscription error: \(error) \(unsubscribed)") + } + + let subscriptionId = try connection.subscribe( + RPCMethod.storageSubscribe, + params: [[storageParam]], + updateClosure: updateClosure, + failureClosure: failureClosure + ) + + self.subscriptionId = subscriptionId + remoteStorageKey = keyPair.remote + storageSubscriptionHandler = childSubscriptionFactory.createEmptyHandlingSubscription(keys: keyPair) + } catch { + logger?.error("Can't subscribe to storage: \(error)") + } + } + + private func handleUpdate(_ update: StorageUpdate) { + mutex.lock() + + defer { + mutex.unlock() + } + + guard let subscriptionId = subscriptionId else { + logger?.warning("Staking update received but subscription is missing") + return + } + + guard let remoteStorageKey = remoteStorageKey else { + logger?.warning("Remote storage key is missing") + return + } + + let storageUpdate = StorageUpdateData(update: update) + + if let change = storageUpdate.changes.first(where: { $0.key == remoteStorageKey }) { + let blockHashData = update.blockHash.map { try? Data(hexString: $0) } ?? nil + storageSubscriptionHandler?.processUpdate(change.value, blockHash: blockHashData) + + if let blockHashData = blockHashData { + proxySyncService.syncUp(chainId: chainId, blockHash: blockHashData) + } + } + } +} diff --git a/novawallet/Common/Services/RemoteSubscription/Substrate/ProxyAccountUpdatingService.swift b/novawallet/Common/Services/RemoteSubscription/Substrate/ProxyAccountUpdatingService.swift new file mode 100644 index 0000000000..f9640397e2 --- /dev/null +++ b/novawallet/Common/Services/RemoteSubscription/Substrate/ProxyAccountUpdatingService.swift @@ -0,0 +1,52 @@ +import Foundation + +protocol ProxyAccountUpdatingServiceProtocol { + func setupSubscription( + for accountId: AccountId, + chainId: ChainModel.Id + ) throws + + func clearSubscription() +} + +class ProxyAccountUpdatingService: ProxyAccountUpdatingServiceProtocol { + private var proxySubscription: ProxyAccountSubscription? + + let chainRegistry: ChainRegistryProtocol + let proxySyncService: ProxySyncServiceProtocol + let operationQueue: OperationQueue + let logger: LoggerProtocol? + let childSubscriptionFactory: ChildSubscriptionFactoryProtocol + + init( + chainRegistry: ChainRegistryProtocol, + proxySyncService: ProxySyncServiceProtocol, + childSubscriptionFactory: ChildSubscriptionFactoryProtocol, + operationQueue: OperationQueue, + logger: LoggerProtocol? = nil + ) { + self.chainRegistry = chainRegistry + self.proxySyncService = proxySyncService + self.childSubscriptionFactory = childSubscriptionFactory + self.operationQueue = operationQueue + self.logger = logger + } + + func setupSubscription( + for accountId: AccountId, + chainId: ChainModel.Id + ) throws { + proxySubscription = ProxyAccountSubscription( + accountId: accountId, + chainId: chainId, + chainRegistry: chainRegistry, + proxySyncService: proxySyncService, + childSubscriptionFactory: childSubscriptionFactory, + operationQueue: operationQueue + ) + } + + func clearSubscription() { + proxySubscription = nil + } +} diff --git a/novawallet/Common/Services/RemoteSubscription/Substrate/StakingAccountSubscription.swift b/novawallet/Common/Services/RemoteSubscription/Substrate/StakingAccountSubscription.swift index c675de1d75..4999397f08 100644 --- a/novawallet/Common/Services/RemoteSubscription/Substrate/StakingAccountSubscription.swift +++ b/novawallet/Common/Services/RemoteSubscription/Substrate/StakingAccountSubscription.swift @@ -39,7 +39,6 @@ final class StakingAccountSubscription: WebSocketSubscribing { let childSubscriptionFactory: ChildSubscriptionFactoryProtocol let operationQueue: OperationQueue let logger: LoggerProtocol? - let chainHasProxy: Bool private let mutex = NSLock() private var subscription: Subscription? @@ -48,7 +47,6 @@ final class StakingAccountSubscription: WebSocketSubscribing { accountId: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat, - chainHasProxy: Bool, chainRegistry: ChainRegistryProtocol, provider: StreamableProvider, childSubscriptionFactory: ChildSubscriptionFactoryProtocol, @@ -58,7 +56,6 @@ final class StakingAccountSubscription: WebSocketSubscribing { self.accountId = accountId self.chainId = chainId self.chainFormat = chainFormat - self.chainHasProxy = chainHasProxy self.chainRegistry = chainRegistry self.provider = provider self.childSubscriptionFactory = childSubscriptionFactory @@ -132,10 +129,6 @@ final class StakingAccountSubscription: WebSocketSubscribing { ) } - if chainHasProxy { - requests.append(.init(storagePath: Proxy.proxyList, accountId: stashId)) - } - return requests } diff --git a/novawallet/Common/Services/RemoteSubscription/Substrate/StakingAccountUpdatingService.swift b/novawallet/Common/Services/RemoteSubscription/Substrate/StakingAccountUpdatingService.swift index 34aa486c32..b706d6dfaf 100644 --- a/novawallet/Common/Services/RemoteSubscription/Substrate/StakingAccountUpdatingService.swift +++ b/novawallet/Common/Services/RemoteSubscription/Substrate/StakingAccountUpdatingService.swift @@ -5,8 +5,7 @@ protocol StakingAccountUpdatingServiceProtocol { func setupSubscription( for accountId: AccountId, chainId: ChainModel.Id, - chainFormat: ChainFormat, - chainHasProxy: Bool + chainFormat: ChainFormat ) throws func clearSubscription() @@ -41,8 +40,7 @@ class StakingAccountUpdatingService: StakingAccountUpdatingServiceProtocol { func setupSubscription( for accountId: AccountId, chainId: ChainModel.Id, - chainFormat: ChainFormat, - chainHasProxy: Bool + chainFormat: ChainFormat ) throws { let address = try accountId.toAddress(using: chainFormat) let stashItemProvider = substrateDataProviderFactory.createStashItemProvider(for: address, chainId: chainId) @@ -51,7 +49,6 @@ class StakingAccountUpdatingService: StakingAccountUpdatingServiceProtocol { accountId: accountId, chainId: chainId, chainFormat: chainFormat, - chainHasProxy: chainHasProxy, chainRegistry: chainRegistry, provider: stashItemProvider, childSubscriptionFactory: childSubscriptionFactory, diff --git a/novawallet/Modules/Staking/Dashboard/StakingDashboardWireframe.swift b/novawallet/Modules/Staking/Dashboard/StakingDashboardWireframe.swift index 47a4caae11..a04617d926 100644 --- a/novawallet/Modules/Staking/Dashboard/StakingDashboardWireframe.swift +++ b/novawallet/Modules/Staking/Dashboard/StakingDashboardWireframe.swift @@ -29,7 +29,10 @@ final class StakingDashboardWireframe: StakingDashboardWireframeProtocol { from view: StakingDashboardViewProtocol?, option: Multistaking.ChainAssetOption ) { - guard let detailsView = StakingMainViewFactory.createView(for: option) else { + guard let detailsView = StakingMainViewFactory.createView( + for: option, + proxySyncService: proxySyncService + ) else { return } diff --git a/novawallet/Modules/Staking/Model/StakingSharedState/RelaychainStakingSharedState.swift b/novawallet/Modules/Staking/Model/StakingSharedState/RelaychainStakingSharedState.swift index 93c842ce3b..485f0b9c1c 100644 --- a/novawallet/Modules/Staking/Model/StakingSharedState/RelaychainStakingSharedState.swift +++ b/novawallet/Modules/Staking/Model/StakingSharedState/RelaychainStakingSharedState.swift @@ -34,6 +34,7 @@ final class RelaychainStakingSharedState: RelaychainStakingSharedStateProtocol { let eraValidatorService: EraValidatorServiceProtocol let rewardCalculatorService: RewardCalculatorServiceProtocol let logger: LoggerProtocol + let proxyRemoteSubscriptionService: ProxyAccountUpdatingServiceProtocol? private var globalSubscriptionId: UUID? @@ -46,6 +47,7 @@ final class RelaychainStakingSharedState: RelaychainStakingSharedStateProtocol { stakingOption: Multistaking.ChainAssetOption, globalRemoteSubscriptionService: StakingRemoteSubscriptionServiceProtocol, accountRemoteSubscriptionService: StakingAccountUpdatingServiceProtocol, + proxyRemoteSubscriptionService: ProxyAccountUpdatingServiceProtocol?, localSubscriptionFactory: StakingLocalSubscriptionFactoryProtocol, proxyLocalSubscriptionFactory: ProxyListLocalSubscriptionFactoryProtocol, eraValidatorService: EraValidatorServiceProtocol, @@ -57,6 +59,7 @@ final class RelaychainStakingSharedState: RelaychainStakingSharedStateProtocol { self.stakingOption = stakingOption self.globalRemoteSubscriptionService = globalRemoteSubscriptionService self.accountRemoteSubscriptionService = accountRemoteSubscriptionService + self.proxyRemoteSubscriptionService = proxyRemoteSubscriptionService self.localSubscriptionFactory = localSubscriptionFactory self.proxyLocalSubscriptionFactory = proxyLocalSubscriptionFactory self.eraValidatorService = eraValidatorService @@ -86,9 +89,14 @@ final class RelaychainStakingSharedState: RelaychainStakingSharedStateProtocol { try accountRemoteSubscriptionService.setupSubscription( for: accountId, chainId: chain.chainId, - chainFormat: chain.chainFormat, - chainHasProxy: chain.hasProxy + chainFormat: chain.chainFormat ) + if chain.hasProxy { + try proxyRemoteSubscriptionService?.setupSubscription( + for: accountId, + chainId: chain.chainId + ) + } logger.debug("Relaychain staking account data subscription succeeded") } else { @@ -117,6 +125,7 @@ final class RelaychainStakingSharedState: RelaychainStakingSharedStateProtocol { timeModel.blockTimeService?.throttle() accountRemoteSubscriptionService.clearSubscription() + proxyRemoteSubscriptionService?.clearSubscription() } func createNetworkInfoOperationFactory( diff --git a/novawallet/Modules/Staking/Model/StakingSharedState/RelaychainStartStakingState.swift b/novawallet/Modules/Staking/Model/StakingSharedState/RelaychainStartStakingState.swift index 0ae944826a..ecc89597f8 100644 --- a/novawallet/Modules/Staking/Model/StakingSharedState/RelaychainStartStakingState.swift +++ b/novawallet/Modules/Staking/Model/StakingSharedState/RelaychainStartStakingState.swift @@ -78,7 +78,7 @@ final class RelaychainStartStakingState: RelaychainStartStakingStateProtocol { relaychainLocalSubscriptionFactory: StakingLocalSubscriptionFactoryProtocol, eraValidatorService: EraValidatorServiceProtocol, relaychainRewardCalculatorService: RewardCalculatorServiceProtocol, - npRemoteSubstriptionService: NominationPoolsRemoteSubscriptionServiceProtocol?, + npRemoteSubscriptionService: NominationPoolsRemoteSubscriptionServiceProtocol?, npAccountSubscriptionServiceFactory: NominationPoolsAccountUpdatingFactoryProtocol?, npLocalSubscriptionFactory: NPoolsLocalSubscriptionFactoryProtocol, activePoolsService: EraNominationPoolsServiceProtocol?, @@ -93,7 +93,7 @@ final class RelaychainStartStakingState: RelaychainStartStakingStateProtocol { self.relaychainLocalSubscriptionFactory = relaychainLocalSubscriptionFactory self.eraValidatorService = eraValidatorService self.relaychainRewardCalculatorService = relaychainRewardCalculatorService - npRemoteSubscriptionService = npRemoteSubstriptionService + self.npRemoteSubscriptionService = npRemoteSubscriptionService self.npAccountSubscriptionServiceFactory = npAccountSubscriptionServiceFactory self.npLocalSubscriptionFactory = npLocalSubscriptionFactory self.activePoolsService = activePoolsService @@ -137,8 +137,7 @@ final class RelaychainStartStakingState: RelaychainStartStakingStateProtocol { try relaychainAccountSubscriptionService.setupSubscription( for: accountId, chainId: chainId, - chainFormat: chainAsset.chain.chainFormat, - chainHasProxy: chainAsset.chain.hasProxy + chainFormat: chainAsset.chain.chainFormat ) npAccountService = try npAccountSubscriptionServiceFactory?.create( diff --git a/novawallet/Modules/Staking/Model/StakingSharedState/StakingSharedStateFactory.swift b/novawallet/Modules/Staking/Model/StakingSharedState/StakingSharedStateFactory.swift index 8d3229cec5..e8e19b5a4a 100644 --- a/novawallet/Modules/Staking/Model/StakingSharedState/StakingSharedStateFactory.swift +++ b/novawallet/Modules/Staking/Model/StakingSharedState/StakingSharedStateFactory.swift @@ -44,6 +44,7 @@ final class StakingSharedStateFactory { let timeModel: StakingTimeModel let localSubscriptionFactory: StakingLocalSubscriptionFactoryProtocol let proxySubscriptionFactory: ProxyListLocalSubscriptionFactoryProtocol + let proxyRemoteSubscriptionService: ProxyAccountUpdatingServiceProtocol? } struct NominationPoolsServices { @@ -56,6 +57,7 @@ final class StakingSharedStateFactory { let storageFacade: StorageFacadeProtocol let chainRegistry: ChainRegistryProtocol let eventCenter: EventCenterProtocol + let proxySyncService: ProxySyncServiceProtocol? let syncOperationQueue: OperationQueue let repositoryOperationQueue: OperationQueue let logger: LoggerProtocol @@ -63,12 +65,14 @@ final class StakingSharedStateFactory { init( storageFacade: StorageFacadeProtocol, chainRegistry: ChainRegistryProtocol, + proxySyncService: ProxySyncServiceProtocol?, eventCenter: EventCenterProtocol, syncOperationQueue: OperationQueue, repositoryOperationQueue: OperationQueue, logger: LoggerProtocol ) { self.storageFacade = storageFacade + self.proxySyncService = proxySyncService self.chainRegistry = chainRegistry self.eventCenter = eventCenter self.syncOperationQueue = syncOperationQueue @@ -165,6 +169,16 @@ final class StakingSharedStateFactory { operationQueue: syncOperationQueue ) + let proxyRemoteSubscriptionService = proxySyncService.map { + ProxyAccountUpdatingService( + chainRegistry: chainRegistry, + proxySyncService: $0, + childSubscriptionFactory: childSubscriptionFactory, + operationQueue: syncOperationQueue, + logger: logger + ) + } + return .init( globalRemoteSubscriptionService: globalServices.globalRemoteSubscriptionService, accountRemoteSubscriptionService: accountRemoteSubscriptionService, @@ -172,7 +186,8 @@ final class StakingSharedStateFactory { rewardCalculatorService: globalServices.rewardCalculatorService, timeModel: globalServices.timeModel, localSubscriptionFactory: globalServices.localSubscriptionFactory, - proxySubscriptionFactory: ProxyListLocalSubscriptionFactory.shared + proxySubscriptionFactory: ProxyListLocalSubscriptionFactory.shared, + proxyRemoteSubscriptionService: proxyRemoteSubscriptionService ) } @@ -265,6 +280,7 @@ extension StakingSharedStateFactory: StakingSharedStateFactoryProtocol { stakingOption: stakingOption, globalRemoteSubscriptionService: services.globalRemoteSubscriptionService, accountRemoteSubscriptionService: services.accountRemoteSubscriptionService, + proxyRemoteSubscriptionService: services.proxyRemoteSubscriptionService, localSubscriptionFactory: services.localSubscriptionFactory, proxyLocalSubscriptionFactory: services.proxySubscriptionFactory, eraValidatorService: services.eraValidatorService, @@ -399,7 +415,7 @@ extension StakingSharedStateFactory: StakingSharedStateFactoryProtocol { relaychainLocalSubscriptionFactory: relaychainServices.localSubscriptionFactory, eraValidatorService: relaychainServices.eraValidatorService, relaychainRewardCalculatorService: relaychainServices.rewardCalculatorService, - npRemoteSubstriptionService: nominationPoolsService.remoteSubscriptionService, + npRemoteSubscriptionService: nominationPoolsService.remoteSubscriptionService, npAccountSubscriptionServiceFactory: nominationPoolsService.accountSubscriptionServiceFactory, npLocalSubscriptionFactory: nominationPoolsService.localSubscriptionFactory, activePoolsService: nominationPoolsService.activePoolsService, diff --git a/novawallet/Modules/Staking/StakingMain/StakingMainViewFactory.swift b/novawallet/Modules/Staking/StakingMain/StakingMainViewFactory.swift index ae7f455865..4b81d54166 100644 --- a/novawallet/Modules/Staking/StakingMain/StakingMainViewFactory.swift +++ b/novawallet/Modules/Staking/StakingMain/StakingMainViewFactory.swift @@ -5,7 +5,10 @@ import SoraKeystore import RobinHood enum StakingMainViewFactory { - static func createView(for stakingOption: Multistaking.ChainAssetOption) -> StakingMainViewProtocol? { + static func createView( + for stakingOption: Multistaking.ChainAssetOption, + proxySyncService: ProxySyncServiceProtocol + ) -> StakingMainViewProtocol? { let settings = SettingsManager.shared let interactor = createInteractor(with: settings, stakingOption: stakingOption) @@ -17,6 +20,7 @@ enum StakingMainViewFactory { let sharedStateFactory = StakingSharedStateFactory( storageFacade: SubstrateDataStorageFacade.shared, chainRegistry: ChainRegistryFacade.sharedRegistry, + proxySyncService: proxySyncService, eventCenter: EventCenter.shared, syncOperationQueue: OperationManagerFacade.sharedDefaultQueue, repositoryOperationQueue: OperationManagerFacade.sharedDefaultQueue, diff --git a/novawallet/Modules/Staking/StartStakingInfo/StartStakingInfoViewFactory.swift b/novawallet/Modules/Staking/StartStakingInfo/StartStakingInfoViewFactory.swift index a5ce8b46d9..d0169de159 100644 --- a/novawallet/Modules/Staking/StartStakingInfo/StartStakingInfoViewFactory.swift +++ b/novawallet/Modules/Staking/StartStakingInfo/StartStakingInfoViewFactory.swift @@ -54,6 +54,7 @@ struct StartStakingInfoViewFactory { let stateFactory = StakingSharedStateFactory( storageFacade: SubstrateDataStorageFacade.shared, chainRegistry: ChainRegistryFacade.sharedRegistry, + proxySyncService: nil, eventCenter: EventCenter.shared, syncOperationQueue: operationQueue, repositoryOperationQueue: operationQueue, @@ -153,6 +154,7 @@ struct StartStakingInfoViewFactory { let stateFactory = StakingSharedStateFactory( storageFacade: SubstrateDataStorageFacade.shared, chainRegistry: ChainRegistryFacade.sharedRegistry, + proxySyncService: nil, eventCenter: EventCenter.shared, syncOperationQueue: operationQueue, repositoryOperationQueue: operationQueue, From 8a032fdba73ce29370e9ac4b217904a6c21810a1 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Mon, 29 Jan 2024 14:34:41 +0300 Subject: [PATCH 43/60] fix tests --- .../Proxy/ProxyOperationFactoryTests.swift | 3 +- novawalletTests/Mocks/CommonMocks.swift | 50 +++++++++---------- novawalletTests/Mocks/DefaultStub.swift | 2 +- novawalletTests/Mocks/ModuleMocks.swift | 32 ++++++++++++ 4 files changed, 60 insertions(+), 27 deletions(-) diff --git a/novawalletIntegrationTests/Proxy/ProxyOperationFactoryTests.swift b/novawalletIntegrationTests/Proxy/ProxyOperationFactoryTests.swift index 22e6c7858e..4544c696ad 100644 --- a/novawalletIntegrationTests/Proxy/ProxyOperationFactoryTests.swift +++ b/novawalletIntegrationTests/Proxy/ProxyOperationFactoryTests.swift @@ -25,7 +25,8 @@ final class ProxyOperationFactoryTests: XCTestCase { ) let wrapper = operationFactory.fetchProxyList(requestFactory: storageRequestFactory, connection: connection, - runtimeProvider: runtimeService) + runtimeProvider: runtimeService, + at: nil) queue.addOperations( wrapper.allOperations, diff --git a/novawalletTests/Mocks/CommonMocks.swift b/novawalletTests/Mocks/CommonMocks.swift index 9e149ed439..1e739c1916 100644 --- a/novawalletTests/Mocks/CommonMocks.swift +++ b/novawalletTests/Mocks/CommonMocks.swift @@ -5792,16 +5792,16 @@ import RobinHood - func setupSubscription(for accountId: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat, chainHasProxy: Bool) throws { + func setupSubscription(for accountId: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat) throws { - return try cuckoo_manager.callThrows("setupSubscription(for: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat, chainHasProxy: Bool) throws", - parameters: (accountId, chainId, chainFormat, chainHasProxy), - escapingParameters: (accountId, chainId, chainFormat, chainHasProxy), + return try cuckoo_manager.callThrows("setupSubscription(for: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat) throws", + parameters: (accountId, chainId, chainFormat), + escapingParameters: (accountId, chainId, chainFormat), superclassCall: Cuckoo.MockManager.crashOnProtocolSuperclassCall() , - defaultCall: __defaultImplStub!.setupSubscription(for: accountId, chainId: chainId, chainFormat: chainFormat, chainHasProxy: chainHasProxy)) + defaultCall: __defaultImplStub!.setupSubscription(for: accountId, chainId: chainId, chainFormat: chainFormat)) } @@ -5829,9 +5829,9 @@ import RobinHood } - func setupSubscription(for accountId: M1, chainId: M2, chainFormat: M3, chainHasProxy: M4) -> Cuckoo.ProtocolStubNoReturnThrowingFunction<(AccountId, ChainModel.Id, ChainFormat, Bool)> where M1.MatchedType == AccountId, M2.MatchedType == ChainModel.Id, M3.MatchedType == ChainFormat, M4.MatchedType == Bool { - let matchers: [Cuckoo.ParameterMatcher<(AccountId, ChainModel.Id, ChainFormat, Bool)>] = [wrap(matchable: accountId) { $0.0 }, wrap(matchable: chainId) { $0.1 }, wrap(matchable: chainFormat) { $0.2 }, wrap(matchable: chainHasProxy) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingAccountUpdatingServiceProtocol.self, method: "setupSubscription(for: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat, chainHasProxy: Bool) throws", parameterMatchers: matchers)) + func setupSubscription(for accountId: M1, chainId: M2, chainFormat: M3) -> Cuckoo.ProtocolStubNoReturnThrowingFunction<(AccountId, ChainModel.Id, ChainFormat)> where M1.MatchedType == AccountId, M2.MatchedType == ChainModel.Id, M3.MatchedType == ChainFormat { + let matchers: [Cuckoo.ParameterMatcher<(AccountId, ChainModel.Id, ChainFormat)>] = [wrap(matchable: accountId) { $0.0 }, wrap(matchable: chainId) { $0.1 }, wrap(matchable: chainFormat) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingAccountUpdatingServiceProtocol.self, method: "setupSubscription(for: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat) throws", parameterMatchers: matchers)) } func clearSubscription() -> Cuckoo.ProtocolStubNoReturnFunction<()> { @@ -5856,9 +5856,9 @@ import RobinHood @discardableResult - func setupSubscription(for accountId: M1, chainId: M2, chainFormat: M3, chainHasProxy: M4) -> Cuckoo.__DoNotUse<(AccountId, ChainModel.Id, ChainFormat, Bool), Void> where M1.MatchedType == AccountId, M2.MatchedType == ChainModel.Id, M3.MatchedType == ChainFormat, M4.MatchedType == Bool { - let matchers: [Cuckoo.ParameterMatcher<(AccountId, ChainModel.Id, ChainFormat, Bool)>] = [wrap(matchable: accountId) { $0.0 }, wrap(matchable: chainId) { $0.1 }, wrap(matchable: chainFormat) { $0.2 }, wrap(matchable: chainHasProxy) { $0.3 }] - return cuckoo_manager.verify("setupSubscription(for: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat, chainHasProxy: Bool) throws", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func setupSubscription(for accountId: M1, chainId: M2, chainFormat: M3) -> Cuckoo.__DoNotUse<(AccountId, ChainModel.Id, ChainFormat), Void> where M1.MatchedType == AccountId, M2.MatchedType == ChainModel.Id, M3.MatchedType == ChainFormat { + let matchers: [Cuckoo.ParameterMatcher<(AccountId, ChainModel.Id, ChainFormat)>] = [wrap(matchable: accountId) { $0.0 }, wrap(matchable: chainId) { $0.1 }, wrap(matchable: chainFormat) { $0.2 }] + return cuckoo_manager.verify("setupSubscription(for: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat) throws", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult @@ -5878,7 +5878,7 @@ import RobinHood - func setupSubscription(for accountId: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat, chainHasProxy: Bool) throws { + func setupSubscription(for accountId: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat) throws { return DefaultValueRegistry.defaultValue(for: (Void).self) } @@ -5917,16 +5917,16 @@ import RobinHood - override func setupSubscription(for accountId: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat, chainHasProxy: Bool) throws { + override func setupSubscription(for accountId: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat) throws { - return try cuckoo_manager.callThrows("setupSubscription(for: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat, chainHasProxy: Bool) throws", - parameters: (accountId, chainId, chainFormat, chainHasProxy), - escapingParameters: (accountId, chainId, chainFormat, chainHasProxy), + return try cuckoo_manager.callThrows("setupSubscription(for: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat) throws", + parameters: (accountId, chainId, chainFormat), + escapingParameters: (accountId, chainId, chainFormat), superclassCall: - super.setupSubscription(for: accountId, chainId: chainId, chainFormat: chainFormat, chainHasProxy: chainHasProxy) + super.setupSubscription(for: accountId, chainId: chainId, chainFormat: chainFormat) , - defaultCall: __defaultImplStub!.setupSubscription(for: accountId, chainId: chainId, chainFormat: chainFormat, chainHasProxy: chainHasProxy)) + defaultCall: __defaultImplStub!.setupSubscription(for: accountId, chainId: chainId, chainFormat: chainFormat)) } @@ -5954,9 +5954,9 @@ import RobinHood } - func setupSubscription(for accountId: M1, chainId: M2, chainFormat: M3, chainHasProxy: M4) -> Cuckoo.ClassStubNoReturnThrowingFunction<(AccountId, ChainModel.Id, ChainFormat, Bool)> where M1.MatchedType == AccountId, M2.MatchedType == ChainModel.Id, M3.MatchedType == ChainFormat, M4.MatchedType == Bool { - let matchers: [Cuckoo.ParameterMatcher<(AccountId, ChainModel.Id, ChainFormat, Bool)>] = [wrap(matchable: accountId) { $0.0 }, wrap(matchable: chainId) { $0.1 }, wrap(matchable: chainFormat) { $0.2 }, wrap(matchable: chainHasProxy) { $0.3 }] - return .init(stub: cuckoo_manager.createStub(for: MockStakingAccountUpdatingService.self, method: "setupSubscription(for: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat, chainHasProxy: Bool) throws", parameterMatchers: matchers)) + func setupSubscription(for accountId: M1, chainId: M2, chainFormat: M3) -> Cuckoo.ClassStubNoReturnThrowingFunction<(AccountId, ChainModel.Id, ChainFormat)> where M1.MatchedType == AccountId, M2.MatchedType == ChainModel.Id, M3.MatchedType == ChainFormat { + let matchers: [Cuckoo.ParameterMatcher<(AccountId, ChainModel.Id, ChainFormat)>] = [wrap(matchable: accountId) { $0.0 }, wrap(matchable: chainId) { $0.1 }, wrap(matchable: chainFormat) { $0.2 }] + return .init(stub: cuckoo_manager.createStub(for: MockStakingAccountUpdatingService.self, method: "setupSubscription(for: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat) throws", parameterMatchers: matchers)) } func clearSubscription() -> Cuckoo.ClassStubNoReturnFunction<()> { @@ -5981,9 +5981,9 @@ import RobinHood @discardableResult - func setupSubscription(for accountId: M1, chainId: M2, chainFormat: M3, chainHasProxy: M4) -> Cuckoo.__DoNotUse<(AccountId, ChainModel.Id, ChainFormat, Bool), Void> where M1.MatchedType == AccountId, M2.MatchedType == ChainModel.Id, M3.MatchedType == ChainFormat, M4.MatchedType == Bool { - let matchers: [Cuckoo.ParameterMatcher<(AccountId, ChainModel.Id, ChainFormat, Bool)>] = [wrap(matchable: accountId) { $0.0 }, wrap(matchable: chainId) { $0.1 }, wrap(matchable: chainFormat) { $0.2 }, wrap(matchable: chainHasProxy) { $0.3 }] - return cuckoo_manager.verify("setupSubscription(for: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat, chainHasProxy: Bool) throws", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + func setupSubscription(for accountId: M1, chainId: M2, chainFormat: M3) -> Cuckoo.__DoNotUse<(AccountId, ChainModel.Id, ChainFormat), Void> where M1.MatchedType == AccountId, M2.MatchedType == ChainModel.Id, M3.MatchedType == ChainFormat { + let matchers: [Cuckoo.ParameterMatcher<(AccountId, ChainModel.Id, ChainFormat)>] = [wrap(matchable: accountId) { $0.0 }, wrap(matchable: chainId) { $0.1 }, wrap(matchable: chainFormat) { $0.2 }] + return cuckoo_manager.verify("setupSubscription(for: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat) throws", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } @discardableResult @@ -6003,7 +6003,7 @@ import RobinHood - override func setupSubscription(for accountId: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat, chainHasProxy: Bool) throws { + override func setupSubscription(for accountId: AccountId, chainId: ChainModel.Id, chainFormat: ChainFormat) throws { return DefaultValueRegistry.defaultValue(for: (Void).self) } diff --git a/novawalletTests/Mocks/DefaultStub.swift b/novawalletTests/Mocks/DefaultStub.swift index 713c3a2571..5677bf70df 100644 --- a/novawalletTests/Mocks/DefaultStub.swift +++ b/novawalletTests/Mocks/DefaultStub.swift @@ -124,7 +124,7 @@ extension MockStakingRemoteSubscriptionServiceProtocol { extension MockStakingAccountUpdatingServiceProtocol { func applyDefault() -> MockStakingAccountUpdatingServiceProtocol { stub(self) { stub in - stub.setupSubscription(for: any(), chainId: any(), chainFormat: any(), chainHasProxy: any()).thenDoNothing() + stub.setupSubscription(for: any(), chainId: any(), chainFormat: any()).thenDoNothing() stub.clearSubscription().thenDoNothing() } diff --git a/novawalletTests/Mocks/ModuleMocks.swift b/novawalletTests/Mocks/ModuleMocks.swift index 6378ad82d2..8d887e9f8f 100644 --- a/novawalletTests/Mocks/ModuleMocks.swift +++ b/novawalletTests/Mocks/ModuleMocks.swift @@ -1571,6 +1571,21 @@ import RobinHood + func syncUp(chainId: ChainModel.Id, blockHash: Data?) { + + return cuckoo_manager.call("syncUp(chainId: ChainModel.Id, blockHash: Data?)", + parameters: (chainId, blockHash), + escapingParameters: (chainId, blockHash), + superclassCall: + + Cuckoo.MockManager.crashOnProtocolSuperclassCall() + , + defaultCall: __defaultImplStub!.syncUp(chainId: chainId, blockHash: blockHash)) + + } + + + func setup() { return cuckoo_manager.call("setup()", @@ -1628,6 +1643,11 @@ import RobinHood return .init(stub: cuckoo_manager.createStub(for: MockProxySyncServiceProtocol.self, method: "syncUp()", parameterMatchers: matchers)) } + func syncUp(chainId: M1, blockHash: M2) -> Cuckoo.ProtocolStubNoReturnFunction<(ChainModel.Id, Data?)> where M1.MatchedType == ChainModel.Id, M2.OptionalMatchedType == Data { + let matchers: [Cuckoo.ParameterMatcher<(ChainModel.Id, Data?)>] = [wrap(matchable: chainId) { $0.0 }, wrap(matchable: blockHash) { $0.1 }] + return .init(stub: cuckoo_manager.createStub(for: MockProxySyncServiceProtocol.self, method: "syncUp(chainId: ChainModel.Id, blockHash: Data?)", parameterMatchers: matchers)) + } + func setup() -> Cuckoo.ProtocolStubNoReturnFunction<()> { let matchers: [Cuckoo.ParameterMatcher] = [] return .init(stub: cuckoo_manager.createStub(for: MockProxySyncServiceProtocol.self, method: "setup()", parameterMatchers: matchers)) @@ -1678,6 +1698,12 @@ import RobinHood return cuckoo_manager.verify("syncUp()", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) } + @discardableResult + func syncUp(chainId: M1, blockHash: M2) -> Cuckoo.__DoNotUse<(ChainModel.Id, Data?), Void> where M1.MatchedType == ChainModel.Id, M2.OptionalMatchedType == Data { + let matchers: [Cuckoo.ParameterMatcher<(ChainModel.Id, Data?)>] = [wrap(matchable: chainId) { $0.0 }, wrap(matchable: blockHash) { $0.1 }] + return cuckoo_manager.verify("syncUp(chainId: ChainModel.Id, blockHash: Data?)", callMatcher: callMatcher, parameterMatchers: matchers, sourceLocation: sourceLocation) + } + @discardableResult func setup() -> Cuckoo.__DoNotUse<(), Void> { let matchers: [Cuckoo.ParameterMatcher] = [] @@ -1725,6 +1751,12 @@ import RobinHood + func syncUp(chainId: ChainModel.Id, blockHash: Data?) { + return DefaultValueRegistry.defaultValue(for: (Void).self) + } + + + func setup() { return DefaultValueRegistry.defaultValue(for: (Void).self) } From 1fdc800da40ed6c7fcb600edfe747ed08a14cce4 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Tue, 30 Jan 2024 17:37:02 +0300 Subject: [PATCH 44/60] init --- .../Common/Services/Proxy/ProxyModels.swift | 2 +- .../Staking/Model/StakingManageOption.swift | 12 ++++--- ...ingRelaychainInteractor+Subscription.swift | 2 +- .../States/StakingStateCommonData.swift | 6 ++-- .../StakingStateViewModelFactory.swift | 6 ++-- .../StartStakingInfoBasePresenter.swift | 32 +++++++++++++++---- 6 files changed, 41 insertions(+), 19 deletions(-) diff --git a/novawallet/Common/Services/Proxy/ProxyModels.swift b/novawallet/Common/Services/Proxy/ProxyModels.swift index 8c26aa8087..2ab7395f4a 100644 --- a/novawallet/Common/Services/Proxy/ProxyModels.swift +++ b/novawallet/Common/Services/Proxy/ProxyModels.swift @@ -46,7 +46,7 @@ struct ProxyDefinition: Decodable, Equatable { enum ProxyFilter { static func filteredStakingProxy(from proxy: ProxyDefinition) -> ProxyDefinition { - ProxyDefinition(definition: proxy.definition.filter { $0.proxyType.allowStaking }) + ProxyDefinition(definition: proxy.definition.filter { $0.proxyType == .staking }) } static func allProxies(from proxy: ProxyDefinition) -> ProxyDefinition { diff --git a/novawallet/Modules/Staking/Model/StakingManageOption.swift b/novawallet/Modules/Staking/Model/StakingManageOption.swift index ddc750b3e6..6c261fd1e8 100644 --- a/novawallet/Modules/Staking/Model/StakingManageOption.swift +++ b/novawallet/Modules/Staking/Model/StakingManageOption.swift @@ -91,11 +91,15 @@ enum StakingManageOption { } } - static func proxyAction(from proxyDefinition: ProxyDefinition?) -> StakingManageOption { - guard let proxiesCount = proxyDefinition?.definition.count, proxiesCount > 0 else { + static func proxyAction(from proxyDefinition: UncertainStorage) -> StakingManageOption? { + guard proxyDefinition.isDefined else { + return nil + } + let proxiesCount = proxyDefinition.value??.definition.count ?? 0 + if proxiesCount > 0 { + return .editProxies(currentCount: proxiesCount) + } else { return .addProxy } - - return .editProxies(currentCount: proxiesCount) } } diff --git a/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainInteractor+Subscription.swift b/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainInteractor+Subscription.swift index a4f153944e..9f5fdaa3fb 100644 --- a/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainInteractor+Subscription.swift +++ b/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainInteractor+Subscription.swift @@ -35,7 +35,7 @@ extension StakingRelaychainInteractor { subscribeToStashAccount(address: stashItem.stash, chain: chainAsset.chain) } - if selectedAccount?.accountId == stashAccountId { + if selectedAccount?.accountId == stashAccountId, chainAsset.chain.hasProxy { proxyProvider = subscribeProxies( for: stashAccountId, chainId: chainId, diff --git a/novawallet/Modules/Staking/StakingMain/Relaychain/StateMachine/States/StakingStateCommonData.swift b/novawallet/Modules/Staking/StakingMain/Relaychain/StateMachine/States/StakingStateCommonData.swift index ca8635c257..87b73aea73 100644 --- a/novawallet/Modules/Staking/StakingMain/Relaychain/StateMachine/States/StakingStateCommonData.swift +++ b/novawallet/Modules/Staking/StakingMain/Relaychain/StateMachine/States/StakingStateCommonData.swift @@ -17,7 +17,7 @@ struct StakingStateCommonData { private(set) var bagListScoreFactor: BigUInt? private(set) var eraCountdown: EraCountdown? private(set) var totalRewardFilter: StakingRewardFiltersPeriod? - private(set) var proxy: ProxyDefinition? + private(set) var proxy: UncertainStorage } extension StakingStateCommonData { @@ -38,7 +38,7 @@ extension StakingStateCommonData { bagListScoreFactor: nil, eraCountdown: nil, totalRewardFilter: nil, - proxy: nil + proxy: .undefined ) } @@ -134,7 +134,7 @@ extension StakingStateCommonData { func byReplacing(proxy: ProxyDefinition?) -> StakingStateCommonData { replace { - $0.proxy = proxy + $0.proxy = .defined(proxy) } } diff --git a/novawallet/Modules/Staking/StakingMain/Relaychain/ViewModel/StakingStateViewModelFactory.swift b/novawallet/Modules/Staking/StakingMain/Relaychain/ViewModel/StakingStateViewModelFactory.swift index 9c04e33b83..019827e613 100644 --- a/novawallet/Modules/Staking/StakingMain/Relaychain/ViewModel/StakingStateViewModelFactory.swift +++ b/novawallet/Modules/Staking/StakingMain/Relaychain/ViewModel/StakingStateViewModelFactory.swift @@ -257,7 +257,7 @@ extension StakingStateViewModelFactory: StakingStateVisitorProtocol { .setupValidators, .proxyAction(from: state.commonData.proxy), .controllerAccount - ] + ].compactMap { $0 } let unbondings = state.commonData.eraCountdown.flatMap { countdown in createUnbondingViewModel( @@ -322,7 +322,7 @@ extension StakingStateViewModelFactory: StakingStateVisitorProtocol { .changeValidators(count: state.nomination.targets.count), .proxyAction(from: state.commonData.proxy), .controllerAccount - ] + ].compactMap { $0 } let unbondings = state.commonData.eraCountdown.flatMap { countdown in createUnbondingViewModel( @@ -387,7 +387,7 @@ extension StakingStateViewModelFactory: StakingStateVisitorProtocol { .yourValidator, .proxyAction(from: state.commonData.proxy), .controllerAccount - ] + ].compactMap { $0 } let unbondings = state.commonData.eraCountdown.flatMap { countdown in createUnbondingViewModel( diff --git a/novawallet/Modules/Staking/StartStakingInfo/StartStakingInfoBasePresenter.swift b/novawallet/Modules/Staking/StartStakingInfo/StartStakingInfoBasePresenter.swift index d0f67e8e98..2fa9471e99 100644 --- a/novawallet/Modules/Staking/StartStakingInfo/StartStakingInfoBasePresenter.swift +++ b/novawallet/Modules/Staking/StartStakingInfo/StartStakingInfoBasePresenter.swift @@ -11,6 +11,7 @@ class StartStakingInfoBasePresenter: StartStakingInfoInteractorOutputProtocol, S let applicationConfig: ApplicationConfigProtocol let chainAsset: ChainAsset let logger: LoggerProtocol + let accountManagementFilter: AccountManagementFilterProtocol private(set) var price: PriceData? private(set) var accountExistense: AccountExistense? @@ -25,6 +26,7 @@ class StartStakingInfoBasePresenter: StartStakingInfoInteractorOutputProtocol, S balanceDerivationFactory: StakingTypeBalanceFactoryProtocol, localizationManager: LocalizationManagerProtocol, applicationConfig: ApplicationConfigProtocol, + accountManagementFilter: AccountManagementFilterProtocol = AccountManagementFilter(), logger: LoggerProtocol ) { self.chainAsset = chainAsset @@ -33,6 +35,7 @@ class StartStakingInfoBasePresenter: StartStakingInfoInteractorOutputProtocol, S self.startStakingViewModelFactory = startStakingViewModelFactory self.balanceDerivationFactory = balanceDerivationFactory self.applicationConfig = applicationConfig + self.accountManagementFilter = accountManagementFilter self.logger = logger self.localizationManager = localizationManager } @@ -192,20 +195,16 @@ class StartStakingInfoBasePresenter: StartStakingInfoInteractorOutputProtocol, S baseInteractor.setup() } - func startStaking() { + func showNoAccountAlert() { guard let view = view, - let wallet = wallet, - let accountExistense = accountExistense else { + let wallet = wallet else { return } - - switch accountExistense { - case .noAccount: + if accountManagementFilter.canAddAccount(to: wallet, chain: chainAsset.chain) { let message = R.string.localizable.commonChainAccountMissingMessageFormat( chainAsset.chain.name, preferredLanguages: selectedLocale.rLanguages ) - wireframe.presentAddAccount( from: view, chainName: chainAsset.chain.name, @@ -217,6 +216,25 @@ class StartStakingInfoBasePresenter: StartStakingInfoInteractorOutputProtocol, S wallet: wallet ) } + } else { + wireframe.presentNoAccountSupport( + from: view, + walletType: wallet.type, + chainName: chainAsset.chain.name, + locale: selectedLocale + ) + } + } + + func startStaking() { + guard let view = view, + let accountExistense = accountExistense else { + return + } + + switch accountExistense { + case .noAccount: + showNoAccountAlert() case .assetBalance: wireframe.showSetupAmount(from: view) } From 5c6e99f1638972c94e2ccec6a5d4275c2d449f65 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Tue, 30 Jan 2024 20:10:55 +0300 Subject: [PATCH 45/60] add validation --- novawallet.xcodeproj/project.pbxproj | 16 ++++++++++ .../DelegationErrorPresentable.swift | 27 +++++++++++++++++ .../DelegationValidatorFactoryProtocol.swift | 30 +++++++++++++++++++ .../ProxyDataValidatorFactory.swift | 3 +- .../Validation/ProxyErrorPresentable.swift | 2 +- .../Add/StakingSetupProxyPresenter.swift | 2 ++ .../Add/StakingSetupProxyViewFactory.swift | 4 ++- .../Base/StakingProxyBasePresenter.swift | 18 +++++++++++ .../StakingConfirmProxyPresenter.swift | 3 +- .../GovernanceErrorPresentable.swift | 24 +-------------- .../GovernanceValidatorFactory.swift | 26 ++-------------- 11 files changed, 104 insertions(+), 51 deletions(-) create mode 100644 novawallet/Common/Validation/Delegation/DelegationErrorPresentable.swift create mode 100644 novawallet/Common/Validation/Delegation/DelegationValidatorFactoryProtocol.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index beacf6ac5b..200d21d89d 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -807,6 +807,8 @@ 766FE2FAB8509BF0F56EA3C0 /* ParaStkCollatorInfoProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F3B8502E5BF8CDD7ACE2DD0 /* ParaStkCollatorInfoProtocols.swift */; }; 76B0B7147181747A7CEDDDF6 /* GovernanceUnavailableTracksViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30E25CF67173500E0AC19387 /* GovernanceUnavailableTracksViewController.swift */; }; 76CF8508C6936FC9941F3C3E /* TokensManageAddProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = C995D640129977CAB05982EC /* TokensManageAddProtocols.swift */; }; + 770589FA2B695E4600778DCA /* DelegationValidatorFactoryProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 770589F92B695E4600778DCA /* DelegationValidatorFactoryProtocol.swift */; }; + 770589FC2B695E6700778DCA /* DelegationErrorPresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 770589FB2B695E6700778DCA /* DelegationErrorPresentable.swift */; }; 770955712AC722A800A2D388 /* StakingBaseDataValidatingFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 770955702AC722A800A2D388 /* StakingBaseDataValidatingFactory.swift */; }; 770F57882A8A2CE0005FD7C1 /* StakingSelectPoolViewStyles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 770F57872A8A2CE0005FD7C1 /* StakingSelectPoolViewStyles.swift */; }; 770F578B2A8A48FF005FD7C1 /* ButtonViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 770F578A2A8A48FF005FD7C1 /* ButtonViewModel.swift */; }; @@ -5066,6 +5068,8 @@ 75ADB95DAB1F29E6A3FDD166 /* WalletConnectSessionDetailsPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = WalletConnectSessionDetailsPresenter.swift; sourceTree = ""; }; 75CFAA1D2D04553B10421C69 /* DAppAuthConfirmProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppAuthConfirmProtocols.swift; sourceTree = ""; }; 76AA6A6232B1CF2D5AF74D0D /* ParaStkUnstakeInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkUnstakeInteractor.swift; sourceTree = ""; }; + 770589F92B695E4600778DCA /* DelegationValidatorFactoryProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DelegationValidatorFactoryProtocol.swift; sourceTree = ""; }; + 770589FB2B695E6700778DCA /* DelegationErrorPresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DelegationErrorPresentable.swift; sourceTree = ""; }; 770955702AC722A800A2D388 /* StakingBaseDataValidatingFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingBaseDataValidatingFactory.swift; sourceTree = ""; }; 770F57872A8A2CE0005FD7C1 /* StakingSelectPoolViewStyles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingSelectPoolViewStyles.swift; sourceTree = ""; }; 770F578A2A8A48FF005FD7C1 /* ButtonViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonViewModel.swift; sourceTree = ""; }; @@ -10281,6 +10285,15 @@ path = DelegationReferendumVoters; sourceTree = ""; }; + 770589F82B695E3600778DCA /* Delegation */ = { + isa = PBXGroup; + children = ( + 770589F92B695E4600778DCA /* DelegationValidatorFactoryProtocol.swift */, + 770589FB2B695E6700778DCA /* DelegationErrorPresentable.swift */, + ); + path = Delegation; + sourceTree = ""; + }; 770F57892A8A48F7005FD7C1 /* Model */ = { isa = PBXGroup; children = ( @@ -16933,6 +16946,7 @@ 84DD5F3C263DE5DF00425ACF /* Validation */ = { isa = PBXGroup; children = ( + 770589F82B695E3600778DCA /* Delegation */, 84DD5F50263DEB9500425ACF /* Validators */, 84DD5F3D263DE5FF00425ACF /* DataValidationProtocols.swift */, 84DD5F4B263DE82C00425ACF /* DataValidationRunner.swift */, @@ -22127,6 +22141,7 @@ 0C9951CA2AE2ABA400B65615 /* AssetListBannerCell.swift in Sources */, 84E172CF28BE468D00DC85B6 /* MessageSheetPresentable.swift in Sources */, 8487583727F06AF300495306 /* AddressScanDelegate.swift in Sources */, + 770589FA2B695E4600778DCA /* DelegationValidatorFactoryProtocol.swift in Sources */, 3E480EEAF501AEB5D543506D /* UsernameSetupPresenter.swift in Sources */, 880059DA28EF092800E87B9B /* ThumbView.swift in Sources */, 84F4387525D9C6EB00AEDA56 /* SubstrateDataProviderFactory.swift in Sources */, @@ -23673,6 +23688,7 @@ EDD5551608E7ACDDBBC054C4 /* ParaStkRebondProtocols.swift in Sources */, F85F1BCAD47F0596FBFBA110 /* ParaStkRebondWireframe.swift in Sources */, 77A6F5D22A31DB8C004AFD1A /* JsonCanonicalizer.swift in Sources */, + 770589FC2B695E6700778DCA /* DelegationErrorPresentable.swift in Sources */, 777BD86029F9730F004969A2 /* ReferendumsFilterViewModel.swift in Sources */, B61457C5248F3B0E88A7990E /* ParaStkRebondPresenter.swift in Sources */, 84E8BA2829FFCA4000FD9F40 /* WalletConnectEthereumTransaction.swift in Sources */, diff --git a/novawallet/Common/Validation/Delegation/DelegationErrorPresentable.swift b/novawallet/Common/Validation/Delegation/DelegationErrorPresentable.swift new file mode 100644 index 0000000000..38ad33d00c --- /dev/null +++ b/novawallet/Common/Validation/Delegation/DelegationErrorPresentable.swift @@ -0,0 +1,27 @@ +import Foundation + +protocol DelegationErrorPresentable { + func presentSelfDelegating( + from view: ControllerBackedProtocol, + locale: Locale? + ) +} + +extension DelegationErrorPresentable where Self: AlertPresentable & ErrorPresentable { + func presentSelfDelegating( + from view: ControllerBackedProtocol, + locale: Locale? + ) { + let title = R.string.localizable.govAddDelegateSelfErrorTitle( + preferredLanguages: locale?.rLanguages + ) + + let message = R.string.localizable.govAddDelegateSelfErrorMessage( + preferredLanguages: locale?.rLanguages + ) + + let close = R.string.localizable.commonClose(preferredLanguages: locale?.rLanguages) + + present(message: message, title: title, closeAction: close, from: view) + } +} diff --git a/novawallet/Common/Validation/Delegation/DelegationValidatorFactoryProtocol.swift b/novawallet/Common/Validation/Delegation/DelegationValidatorFactoryProtocol.swift new file mode 100644 index 0000000000..54a79e7557 --- /dev/null +++ b/novawallet/Common/Validation/Delegation/DelegationValidatorFactoryProtocol.swift @@ -0,0 +1,30 @@ +import Foundation + +protocol DelegationValidatorFactoryProtocol: AnyObject { + var delegationErrorPresentable: DelegationErrorPresentable { get } + var view: ControllerBackedProtocol? { get } + + func notSelfDelegating( + selfId: AccountId?, + delegateId: AccountId?, + locale: Locale? + ) -> DataValidating +} + +extension DelegationValidatorFactoryProtocol { + func notSelfDelegating( + selfId: AccountId?, + delegateId: AccountId?, + locale: Locale? + ) -> DataValidating { + ErrorConditionViolation(onError: { [weak self] in + guard let view = self?.view else { + return + } + + self?.delegationErrorPresentable.presentSelfDelegating(from: view, locale: locale) + }, preservesCondition: { + selfId != nil && delegateId != nil && selfId != delegateId + }) + } +} diff --git a/novawallet/Modules/Proxy/Validation/ProxyDataValidatorFactory.swift b/novawallet/Modules/Proxy/Validation/ProxyDataValidatorFactory.swift index 773f8d4204..9b4b56ace3 100644 --- a/novawallet/Modules/Proxy/Validation/ProxyDataValidatorFactory.swift +++ b/novawallet/Modules/Proxy/Validation/ProxyDataValidatorFactory.swift @@ -2,7 +2,7 @@ import Foundation import BigInt import SoraFoundation -protocol ProxyDataValidatorFactoryProtocol: BaseDataValidatingFactoryProtocol { +protocol ProxyDataValidatorFactoryProtocol: BaseDataValidatingFactoryProtocol, DelegationValidatorFactoryProtocol { func hasSufficientBalance( available: BigUInt, deposit: BigUInt?, @@ -65,6 +65,7 @@ final class ProxyDataValidatorFactory: ProxyDataValidatorFactoryProtocol { weak var view: ControllerBackedProtocol? var basePresentable: BaseErrorPresentable { presentable } + var delegationErrorPresentable: DelegationErrorPresentable { presentable } let presentable: ProxyErrorPresentable let balanceViewModelFactoryFacade: BalanceViewModelFactoryFacadeProtocol diff --git a/novawallet/Modules/Proxy/Validation/ProxyErrorPresentable.swift b/novawallet/Modules/Proxy/Validation/ProxyErrorPresentable.swift index 64463e56ba..f6d711bdc0 100644 --- a/novawallet/Modules/Proxy/Validation/ProxyErrorPresentable.swift +++ b/novawallet/Modules/Proxy/Validation/ProxyErrorPresentable.swift @@ -1,6 +1,6 @@ import Foundation -protocol ProxyErrorPresentable: BaseErrorPresentable { +protocol ProxyErrorPresentable: BaseErrorPresentable, DelegationErrorPresentable { func presentNotEnoughBalanceForDeposit( from view: ControllerBackedProtocol, deposit: String, diff --git a/novawallet/Modules/Staking/StakingProxy/Add/StakingSetupProxyPresenter.swift b/novawallet/Modules/Staking/StakingProxy/Add/StakingSetupProxyPresenter.swift index 95146ec417..c67302a823 100644 --- a/novawallet/Modules/Staking/StakingProxy/Add/StakingSetupProxyPresenter.swift +++ b/novawallet/Modules/Staking/StakingProxy/Add/StakingSetupProxyPresenter.swift @@ -32,6 +32,7 @@ final class StakingSetupProxyPresenter: StakingProxyBasePresenter { private(set) lazy var iconGenerator = PolkadotIconGenerator() init( + wallet: MetaAccountModel, chainAsset: ChainAsset, interactor: StakingSetupProxyInteractorInputProtocol, wireframe: StakingSetupProxyWireframeProtocol, @@ -45,6 +46,7 @@ final class StakingSetupProxyPresenter: StakingProxyBasePresenter { self.web3NameViewModelFactory = web3NameViewModelFactory super.init( + wallet: wallet, chainAsset: chainAsset, interactor: interactor, wireframe: wireframe, diff --git a/novawallet/Modules/Staking/StakingProxy/Add/StakingSetupProxyViewFactory.swift b/novawallet/Modules/Staking/StakingProxy/Add/StakingSetupProxyViewFactory.swift index 54aacfe86e..1a7b61c6ae 100644 --- a/novawallet/Modules/Staking/StakingProxy/Add/StakingSetupProxyViewFactory.swift +++ b/novawallet/Modules/Staking/StakingProxy/Add/StakingSetupProxyViewFactory.swift @@ -4,7 +4,8 @@ import RobinHood struct StakingSetupProxyViewFactory { static func createView(state: RelaychainStakingSharedStateProtocol) -> StakingSetupProxyViewProtocol? { - guard let currencyManager = CurrencyManager.shared else { + guard let wallet = SelectedWalletSettings.shared.value, + let currencyManager = CurrencyManager.shared else { return nil } guard let interactor = createInteractor(state: state) else { @@ -25,6 +26,7 @@ struct StakingSetupProxyViewFactory { ) ) let presenter = StakingSetupProxyPresenter( + wallet: wallet, chainAsset: chainAsset, interactor: interactor, wireframe: wireframe, diff --git a/novawallet/Modules/Staking/StakingProxy/Base/StakingProxyBasePresenter.swift b/novawallet/Modules/Staking/StakingProxy/Base/StakingProxyBasePresenter.swift index 028d1ab970..f6fff3520a 100644 --- a/novawallet/Modules/Staking/StakingProxy/Base/StakingProxyBasePresenter.swift +++ b/novawallet/Modules/Staking/StakingProxy/Base/StakingProxyBasePresenter.swift @@ -7,6 +7,7 @@ class StakingProxyBasePresenter: StakingSetupProxyBasePresenterProtocol { let balanceViewModelFactory: BalanceViewModelFactoryProtocol let chainAsset: ChainAsset let dataValidatingFactory: ProxyDataValidatorFactoryProtocol + let wallet: MetaAccountModel private let interactor: StakingProxyBaseInteractorInputProtocol private let wireframe: StakingSetupProxyBaseWireframeProtocol @@ -19,6 +20,7 @@ class StakingProxyBasePresenter: StakingSetupProxyBasePresenterProtocol { private(set) var proxy: UncertainStorage = .undefined init( + wallet: MetaAccountModel, chainAsset: ChainAsset, interactor: StakingProxyBaseInteractorInputProtocol, wireframe: StakingSetupProxyBaseWireframeProtocol, @@ -26,6 +28,7 @@ class StakingProxyBasePresenter: StakingSetupProxyBasePresenterProtocol { dataValidatingFactory: ProxyDataValidatorFactoryProtocol, localizationManager: LocalizationManagerProtocol ) { + self.wallet = wallet self.chainAsset = chainAsset self.interactor = interactor self.wireframe = wireframe @@ -83,6 +86,11 @@ class StakingProxyBasePresenter: StakingSetupProxyBasePresenterProtocol { chain: chainAsset.chain, locale: selectedLocale ), + dataValidatingFactory.notSelfDelegating( + selfId: getAccountId(), + delegateId: getProxyAccountId(), + locale: selectedLocale + ), dataValidatingFactory.proxyNotExists( address: getProxyAddress(), chain: chainAsset.chain, @@ -126,6 +134,16 @@ class StakingProxyBasePresenter: StakingSetupProxyBasePresenterProtocol { func getProxyAddress() -> AccountAddress { fatalError("This function should be overriden") } + + func getProxyAccountId() -> AccountId? { + let address = getProxyAddress() + return try? address.toAccountId(using: chainAsset.chain.chainFormat) + } + + func getAccountId() -> AccountId? { + let request = chainAsset.chain.accountRequest() + return try? wallet.fetch(for: request)?.accountId + } } extension StakingProxyBasePresenter: StakingProxyBaseInteractorOutputProtocol { diff --git a/novawallet/Modules/Staking/StakingProxy/Confirm/StakingConfirmProxyPresenter.swift b/novawallet/Modules/Staking/StakingProxy/Confirm/StakingConfirmProxyPresenter.swift index dc9137ac6e..949e9cfeb5 100644 --- a/novawallet/Modules/Staking/StakingProxy/Confirm/StakingConfirmProxyPresenter.swift +++ b/novawallet/Modules/Staking/StakingProxy/Confirm/StakingConfirmProxyPresenter.swift @@ -10,7 +10,6 @@ final class StakingConfirmProxyPresenter: StakingProxyBasePresenter { let wireframe: StakingConfirmProxyWireframeProtocol let interactor: StakingConfirmProxyInteractorInputProtocol let proxyAddress: AccountAddress - let wallet: MetaAccountModel let displayAddressViewModelFactory: DisplayAddressViewModelFactoryProtocol let networkViewModelFactory: NetworkViewModelFactoryProtocol @@ -29,13 +28,13 @@ final class StakingConfirmProxyPresenter: StakingProxyBasePresenter { localizationManager: LocalizationManagerProtocol ) { self.proxyAddress = proxyAddress - self.wallet = wallet self.interactor = interactor self.wireframe = wireframe self.displayAddressViewModelFactory = displayAddressViewModelFactory self.networkViewModelFactory = networkViewModelFactory super.init( + wallet: wallet, chainAsset: chainAsset, interactor: interactor, wireframe: wireframe, diff --git a/novawallet/Modules/Vote/Governance/Validating/GovernanceErrorPresentable.swift b/novawallet/Modules/Vote/Governance/Validating/GovernanceErrorPresentable.swift index 2820bc39ac..0f70246565 100644 --- a/novawallet/Modules/Vote/Governance/Validating/GovernanceErrorPresentable.swift +++ b/novawallet/Modules/Vote/Governance/Validating/GovernanceErrorPresentable.swift @@ -1,6 +1,6 @@ import Foundation -protocol GovernanceErrorPresentable: BaseErrorPresentable { +protocol GovernanceErrorPresentable: BaseErrorPresentable, DelegationErrorPresentable { func presentNotEnoughTokensToVote( from view: ControllerBackedProtocol, available: String, @@ -23,11 +23,6 @@ protocol GovernanceErrorPresentable: BaseErrorPresentable { locale: Locale? ) - func presentSelfDelegating( - from view: ControllerBackedProtocol, - locale: Locale? - ) - func presentAlreadyVoting( from view: ControllerBackedProtocol, locale: Locale? @@ -90,23 +85,6 @@ extension GovernanceErrorPresentable where Self: AlertPresentable & ErrorPresent present(message: message, title: title, closeAction: close, from: view) } - func presentSelfDelegating( - from view: ControllerBackedProtocol, - locale: Locale? - ) { - let title = R.string.localizable.govAddDelegateSelfErrorTitle( - preferredLanguages: locale?.rLanguages - ) - - let message = R.string.localizable.govAddDelegateSelfErrorMessage( - preferredLanguages: locale?.rLanguages - ) - - let close = R.string.localizable.commonClose(preferredLanguages: locale?.rLanguages) - - present(message: message, title: title, closeAction: close, from: view) - } - func presentAlreadyVoting( from view: ControllerBackedProtocol, locale: Locale? diff --git a/novawallet/Modules/Vote/Governance/Validating/GovernanceValidatorFactory.swift b/novawallet/Modules/Vote/Governance/Validating/GovernanceValidatorFactory.swift index 803f5b15a4..064c0a40e6 100644 --- a/novawallet/Modules/Vote/Governance/Validating/GovernanceValidatorFactory.swift +++ b/novawallet/Modules/Vote/Governance/Validating/GovernanceValidatorFactory.swift @@ -2,7 +2,7 @@ import Foundation import BigInt import SoraFoundation -protocol GovernanceValidatorFactoryProtocol: BaseDataValidatingFactoryProtocol { +protocol GovernanceValidatorFactoryProtocol: BaseDataValidatingFactoryProtocol, DelegationValidatorFactoryProtocol { func enoughTokensForVoting( _ assetBalance: AssetBalance?, votingAmount: BigUInt?, @@ -35,12 +35,6 @@ protocol GovernanceValidatorFactoryProtocol: BaseDataValidatingFactoryProtocol { locale: Locale? ) -> DataValidating - func notSelfDelegating( - selfId: AccountId?, - delegateId: AccountId?, - locale: Locale? - ) -> DataValidating - func notVoting( _ accountVotingDistribution: ReferendumAccountVotingDistribution?, tracks: Set?, @@ -59,6 +53,8 @@ final class GovernanceValidatorFactory { weak var view: ControllerBackedProtocol? var basePresentable: BaseErrorPresentable { presentable } + var delegationErrorPresentable: DelegationErrorPresentable { presentable } + let assetBalanceFormatterFactory: AssetBalanceFormatterFactoryProtocol let quantityFormatter: LocalizableResource let presentable: GovernanceErrorPresentable @@ -240,22 +236,6 @@ extension GovernanceValidatorFactory: GovernanceValidatorFactoryProtocol { }) } - func notSelfDelegating( - selfId: AccountId?, - delegateId: AccountId?, - locale: Locale? - ) -> DataValidating { - ErrorConditionViolation(onError: { [weak self] in - guard let view = self?.view else { - return - } - - self?.presentable.presentSelfDelegating(from: view, locale: locale) - }, preservesCondition: { - selfId != nil && delegateId != nil && selfId != delegateId - }) - } - func notVoting( _ accountVotingDistribution: ReferendumAccountVotingDistribution?, tracks: Set?, From 2bd4424027c6623426a8be4dfad8572a6f890f4d Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Wed, 31 Jan 2024 11:34:12 +0300 Subject: [PATCH 46/60] refactor --- .../RelaychainMultistakingUpdateService.swift | 2 +- .../Substrate/ProxyAccountSubscription.swift | 211 +++++------------- .../ProxyAccountUpdatingService.swift | 11 +- .../StakingSharedStateFactory.swift | 2 +- 4 files changed, 70 insertions(+), 156 deletions(-) diff --git a/novawallet/Common/Services/Multistaking/RelaychainMultistakingUpdateService.swift b/novawallet/Common/Services/Multistaking/RelaychainMultistakingUpdateService.swift index f5d44dc39f..8216bef6ad 100644 --- a/novawallet/Common/Services/Multistaking/RelaychainMultistakingUpdateService.swift +++ b/novawallet/Common/Services/Multistaking/RelaychainMultistakingUpdateService.swift @@ -96,7 +96,7 @@ final class RelaychainMultistakingUpdateService: ObservableSyncService { ) { BytesCodable(wrappedValue: accountId) }, - mappingKey: Multistaking.RelaychainAccountsChange.Key.stash.rawValue + mappingKey: nil ) controllerSubscription = CallbackBatchStorageSubscription( diff --git a/novawallet/Common/Services/RemoteSubscription/Substrate/ProxyAccountSubscription.swift b/novawallet/Common/Services/RemoteSubscription/Substrate/ProxyAccountSubscription.swift index 4a00f8252f..7009b7789b 100644 --- a/novawallet/Common/Services/RemoteSubscription/Substrate/ProxyAccountSubscription.swift +++ b/novawallet/Common/Services/RemoteSubscription/Substrate/ProxyAccountSubscription.swift @@ -8,33 +8,45 @@ final class ProxyAccountSubscription: WebSocketSubscribing { let chainId: ChainModel.Id let chainRegistry: ChainRegistryProtocol let proxySyncService: ProxySyncServiceProtocol + let storageFacade: StorageFacadeProtocol let logger: LoggerProtocol? - let childSubscriptionFactory: ChildSubscriptionFactoryProtocol private let mutex = NSLock() private let operationQueue: OperationQueue - private var subscriptionId: UInt16? - private var remoteStorageKey: Data? + private let workingQueue: DispatchQueue + private var subscription: CallbackBatchStorageSubscription? private var storageSubscriptionHandler: StorageChildSubscribing? + private lazy var repository: AnyDataProviderRepository = { + let coreDataRepository: CoreDataRepository = + storageFacade.createRepository() + return AnyDataProviderRepository(coreDataRepository) + }() + init( accountId: AccountId, chainId: ChainModel.Id, chainRegistry: ChainRegistryProtocol, proxySyncService: ProxySyncServiceProtocol, - childSubscriptionFactory: ChildSubscriptionFactoryProtocol, + storageFacade: StorageFacadeProtocol, operationQueue: OperationQueue, + workingQueue: DispatchQueue, logger: LoggerProtocol? = nil ) { self.accountId = accountId self.chainId = chainId self.chainRegistry = chainRegistry self.proxySyncService = proxySyncService - self.childSubscriptionFactory = childSubscriptionFactory self.operationQueue = operationQueue + self.workingQueue = workingQueue self.logger = logger + self.storageFacade = storageFacade - subscribeRemote(for: accountId) + do { + try subscribeRemote(for: accountId) + } catch { + logger?.error(error.localizedDescription) + } } deinit { @@ -42,159 +54,60 @@ final class ProxyAccountSubscription: WebSocketSubscribing { } private func unsubscribeRemote() { - mutex.lock() - - if let subscriptionId = subscriptionId { - chainRegistry.getConnection(for: chainId)?.cancelForIdentifier(subscriptionId) - } - - subscriptionId = nil - remoteStorageKey = nil - storageSubscriptionHandler = nil - - mutex.unlock() + subscription?.unsubscribe() + subscription = nil } - private func subscribeRemote(for accountId: AccountId) { - mutex.lock() - - defer { - mutex.unlock() + private func subscribeRemote(for accountId: AccountId) throws { + guard let connection = chainRegistry.getConnection(for: chainId) else { + throw ChainRegistryError.connectionUnavailable } - - do { - guard let runtimeService = chainRegistry.getRuntimeProvider(for: chainId) else { - throw ChainRegistryError.runtimeMetadaUnavailable - } - let path = Proxy.proxyList - let localKey = try LocalStorageKeyFactory().createFromStoragePath( - path, - accountId: accountId, - chainId: chainId - ) - - let codingFactoryOperation = runtimeService.fetchCoderFactoryOperation() - - let storageKeyFactory = StorageKeyFactory() - - let codingOperation = MapKeyEncodingOperation( - path: path, - storageKeyFactory: storageKeyFactory, - keyParams: [accountId] - ) - - codingOperation.addDependency(codingFactoryOperation) - - codingOperation.configurationBlock = { - do { - guard let result = try codingFactoryOperation.extractResultData() else { - codingOperation.cancel() - return - } - - codingOperation.codingFactory = result - - } catch { - codingOperation.result = .failure(error) - } - } - - let mapOperation = ClosureOperation { [weak self] in - do { - return try codingOperation.extractNoCancellableResultData().first - } catch StorageKeyEncodingOperationError.invalidStoragePath { - self?.logger?.warning("Subscription path missing in runtime: \(codingOperation.path)") - return nil - } - } - - mapOperation.addDependency(codingOperation) - - mapOperation.completionBlock = { [weak self] in - do { - if let remoteKey = try mapOperation.extractNoCancellableResultData() { - let key = SubscriptionStorageKeys(remote: remoteKey, local: localKey) - self?.subscribeToRemote(with: key) - } - } catch { - self?.logger?.error("Did receive error: \(error)") - } - } - - let operations = [codingFactoryOperation, codingOperation, mapOperation] - - operationQueue.addOperations(operations, waitUntilFinished: false) - - } catch { - logger?.error("Did receive unexpected error \(error)") + guard let runtimeService = chainRegistry.getRuntimeProvider(for: chainId) else { + throw ChainRegistryError.runtimeMetadaUnavailable } - } - private func subscribeToRemote( - with keyPair: SubscriptionStorageKeys - ) { - mutex.lock() - - defer { - mutex.unlock() + let localKey = try LocalStorageKeyFactory().createFromStoragePath( + Proxy.proxyList, + accountId: accountId, + chainId: chainId + ) + + let request = BatchStorageSubscriptionRequest( + innerRequest: MapSubscriptionRequest( + storagePath: Proxy.proxyList, + localKey: localKey + ) { + BytesCodable(wrappedValue: accountId) + }, + mappingKey: nil + ) + + subscription = CallbackBatchStorageSubscription( + requests: [request], + connection: connection, + runtimeService: runtimeService, + repository: repository, + operationQueue: operationQueue, + callbackQueue: workingQueue + ) { [weak self] result in + self?.mutex.lock() + + self?.handleSubscription(result) + + self?.mutex.unlock() } - do { - guard let connection = chainRegistry.getConnection(for: chainId) else { - throw ChainRegistryError.connectionUnavailable - } - - let storageParam = keyPair.remote.toHex(includePrefix: true) - - let updateClosure: (StorageSubscriptionUpdate) -> Void = { [weak self] update in - self?.handleUpdate(update.params.result) - } - - let failureClosure: (Error, Bool) -> Void = { [weak self] error, unsubscribed in - self?.logger?.error("Did receive subscription error: \(error) \(unsubscribed)") - } - - let subscriptionId = try connection.subscribe( - RPCMethod.storageSubscribe, - params: [[storageParam]], - updateClosure: updateClosure, - failureClosure: failureClosure - ) - - self.subscriptionId = subscriptionId - remoteStorageKey = keyPair.remote - storageSubscriptionHandler = childSubscriptionFactory.createEmptyHandlingSubscription(keys: keyPair) - } catch { - logger?.error("Can't subscribe to storage: \(error)") - } + subscription?.subscribe() } - private func handleUpdate(_ update: StorageUpdate) { - mutex.lock() - - defer { - mutex.unlock() - } - - guard let subscriptionId = subscriptionId else { - logger?.warning("Staking update received but subscription is missing") - return - } - - guard let remoteStorageKey = remoteStorageKey else { - logger?.warning("Remote storage key is missing") - return - } - - let storageUpdate = StorageUpdateData(update: update) - - if let change = storageUpdate.changes.first(where: { $0.key == remoteStorageKey }) { - let blockHashData = update.blockHash.map { try? Data(hexString: $0) } ?? nil - storageSubscriptionHandler?.processUpdate(change.value, blockHash: blockHashData) - - if let blockHashData = blockHashData { - proxySyncService.syncUp(chainId: chainId, blockHash: blockHashData) + private func handleSubscription(_ result: Result) { + switch result { + case let .success(handler): + if let blockHash = handler.blockHash { + proxySyncService.syncUp(chainId: chainId, blockHash: blockHash) } + case let .failure(error): + logger?.error(error.localizedDescription) } } } diff --git a/novawallet/Common/Services/RemoteSubscription/Substrate/ProxyAccountUpdatingService.swift b/novawallet/Common/Services/RemoteSubscription/Substrate/ProxyAccountUpdatingService.swift index f9640397e2..4b554c1272 100644 --- a/novawallet/Common/Services/RemoteSubscription/Substrate/ProxyAccountUpdatingService.swift +++ b/novawallet/Common/Services/RemoteSubscription/Substrate/ProxyAccountUpdatingService.swift @@ -16,18 +16,18 @@ class ProxyAccountUpdatingService: ProxyAccountUpdatingServiceProtocol { let proxySyncService: ProxySyncServiceProtocol let operationQueue: OperationQueue let logger: LoggerProtocol? - let childSubscriptionFactory: ChildSubscriptionFactoryProtocol + let storageFacade: StorageFacadeProtocol init( chainRegistry: ChainRegistryProtocol, proxySyncService: ProxySyncServiceProtocol, - childSubscriptionFactory: ChildSubscriptionFactoryProtocol, + storageFacade: StorageFacadeProtocol, operationQueue: OperationQueue, logger: LoggerProtocol? = nil ) { self.chainRegistry = chainRegistry self.proxySyncService = proxySyncService - self.childSubscriptionFactory = childSubscriptionFactory + self.storageFacade = storageFacade self.operationQueue = operationQueue self.logger = logger } @@ -41,8 +41,9 @@ class ProxyAccountUpdatingService: ProxyAccountUpdatingServiceProtocol { chainId: chainId, chainRegistry: chainRegistry, proxySyncService: proxySyncService, - childSubscriptionFactory: childSubscriptionFactory, - operationQueue: operationQueue + storageFacade: storageFacade, + operationQueue: operationQueue, + workingQueue: DispatchQueue.global() ) } diff --git a/novawallet/Modules/Staking/Model/StakingSharedState/StakingSharedStateFactory.swift b/novawallet/Modules/Staking/Model/StakingSharedState/StakingSharedStateFactory.swift index e8e19b5a4a..accce90335 100644 --- a/novawallet/Modules/Staking/Model/StakingSharedState/StakingSharedStateFactory.swift +++ b/novawallet/Modules/Staking/Model/StakingSharedState/StakingSharedStateFactory.swift @@ -173,7 +173,7 @@ final class StakingSharedStateFactory { ProxyAccountUpdatingService( chainRegistry: chainRegistry, proxySyncService: $0, - childSubscriptionFactory: childSubscriptionFactory, + storageFacade: storageFacade, operationQueue: syncOperationQueue, logger: logger ) From 49c3b2345a2a4b917e8141c0247b95ba067c0c5a Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Wed, 31 Jan 2024 12:21:05 +0300 Subject: [PATCH 47/60] PR fixes --- novawallet.xcodeproj/project.pbxproj | 16 ---------- .../DelegationErrorPresentable.swift | 27 ----------------- .../DelegationValidatorFactoryProtocol.swift | 30 ------------------- .../ProxyDataValidatorFactory.swift | 26 ++++++++++++++-- .../Validation/ProxyErrorPresentable.swift | 24 ++++++++++++++- .../Staking/Model/StakingManageOption.swift | 4 +-- .../StakingStateViewModelFactory.swift | 6 ++-- .../GovernanceErrorPresentable.swift | 24 ++++++++++++++- .../GovernanceValidatorFactory.swift | 26 ++++++++++++++-- 9 files changed, 97 insertions(+), 86 deletions(-) delete mode 100644 novawallet/Common/Validation/Delegation/DelegationErrorPresentable.swift delete mode 100644 novawallet/Common/Validation/Delegation/DelegationValidatorFactoryProtocol.swift diff --git a/novawallet.xcodeproj/project.pbxproj b/novawallet.xcodeproj/project.pbxproj index 200d21d89d..beacf6ac5b 100644 --- a/novawallet.xcodeproj/project.pbxproj +++ b/novawallet.xcodeproj/project.pbxproj @@ -807,8 +807,6 @@ 766FE2FAB8509BF0F56EA3C0 /* ParaStkCollatorInfoProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F3B8502E5BF8CDD7ACE2DD0 /* ParaStkCollatorInfoProtocols.swift */; }; 76B0B7147181747A7CEDDDF6 /* GovernanceUnavailableTracksViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 30E25CF67173500E0AC19387 /* GovernanceUnavailableTracksViewController.swift */; }; 76CF8508C6936FC9941F3C3E /* TokensManageAddProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = C995D640129977CAB05982EC /* TokensManageAddProtocols.swift */; }; - 770589FA2B695E4600778DCA /* DelegationValidatorFactoryProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 770589F92B695E4600778DCA /* DelegationValidatorFactoryProtocol.swift */; }; - 770589FC2B695E6700778DCA /* DelegationErrorPresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 770589FB2B695E6700778DCA /* DelegationErrorPresentable.swift */; }; 770955712AC722A800A2D388 /* StakingBaseDataValidatingFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 770955702AC722A800A2D388 /* StakingBaseDataValidatingFactory.swift */; }; 770F57882A8A2CE0005FD7C1 /* StakingSelectPoolViewStyles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 770F57872A8A2CE0005FD7C1 /* StakingSelectPoolViewStyles.swift */; }; 770F578B2A8A48FF005FD7C1 /* ButtonViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 770F578A2A8A48FF005FD7C1 /* ButtonViewModel.swift */; }; @@ -5068,8 +5066,6 @@ 75ADB95DAB1F29E6A3FDD166 /* WalletConnectSessionDetailsPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = WalletConnectSessionDetailsPresenter.swift; sourceTree = ""; }; 75CFAA1D2D04553B10421C69 /* DAppAuthConfirmProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DAppAuthConfirmProtocols.swift; sourceTree = ""; }; 76AA6A6232B1CF2D5AF74D0D /* ParaStkUnstakeInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ParaStkUnstakeInteractor.swift; sourceTree = ""; }; - 770589F92B695E4600778DCA /* DelegationValidatorFactoryProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DelegationValidatorFactoryProtocol.swift; sourceTree = ""; }; - 770589FB2B695E6700778DCA /* DelegationErrorPresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DelegationErrorPresentable.swift; sourceTree = ""; }; 770955702AC722A800A2D388 /* StakingBaseDataValidatingFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingBaseDataValidatingFactory.swift; sourceTree = ""; }; 770F57872A8A2CE0005FD7C1 /* StakingSelectPoolViewStyles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StakingSelectPoolViewStyles.swift; sourceTree = ""; }; 770F578A2A8A48FF005FD7C1 /* ButtonViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonViewModel.swift; sourceTree = ""; }; @@ -10285,15 +10281,6 @@ path = DelegationReferendumVoters; sourceTree = ""; }; - 770589F82B695E3600778DCA /* Delegation */ = { - isa = PBXGroup; - children = ( - 770589F92B695E4600778DCA /* DelegationValidatorFactoryProtocol.swift */, - 770589FB2B695E6700778DCA /* DelegationErrorPresentable.swift */, - ); - path = Delegation; - sourceTree = ""; - }; 770F57892A8A48F7005FD7C1 /* Model */ = { isa = PBXGroup; children = ( @@ -16946,7 +16933,6 @@ 84DD5F3C263DE5DF00425ACF /* Validation */ = { isa = PBXGroup; children = ( - 770589F82B695E3600778DCA /* Delegation */, 84DD5F50263DEB9500425ACF /* Validators */, 84DD5F3D263DE5FF00425ACF /* DataValidationProtocols.swift */, 84DD5F4B263DE82C00425ACF /* DataValidationRunner.swift */, @@ -22141,7 +22127,6 @@ 0C9951CA2AE2ABA400B65615 /* AssetListBannerCell.swift in Sources */, 84E172CF28BE468D00DC85B6 /* MessageSheetPresentable.swift in Sources */, 8487583727F06AF300495306 /* AddressScanDelegate.swift in Sources */, - 770589FA2B695E4600778DCA /* DelegationValidatorFactoryProtocol.swift in Sources */, 3E480EEAF501AEB5D543506D /* UsernameSetupPresenter.swift in Sources */, 880059DA28EF092800E87B9B /* ThumbView.swift in Sources */, 84F4387525D9C6EB00AEDA56 /* SubstrateDataProviderFactory.swift in Sources */, @@ -23688,7 +23673,6 @@ EDD5551608E7ACDDBBC054C4 /* ParaStkRebondProtocols.swift in Sources */, F85F1BCAD47F0596FBFBA110 /* ParaStkRebondWireframe.swift in Sources */, 77A6F5D22A31DB8C004AFD1A /* JsonCanonicalizer.swift in Sources */, - 770589FC2B695E6700778DCA /* DelegationErrorPresentable.swift in Sources */, 777BD86029F9730F004969A2 /* ReferendumsFilterViewModel.swift in Sources */, B61457C5248F3B0E88A7990E /* ParaStkRebondPresenter.swift in Sources */, 84E8BA2829FFCA4000FD9F40 /* WalletConnectEthereumTransaction.swift in Sources */, diff --git a/novawallet/Common/Validation/Delegation/DelegationErrorPresentable.swift b/novawallet/Common/Validation/Delegation/DelegationErrorPresentable.swift deleted file mode 100644 index 38ad33d00c..0000000000 --- a/novawallet/Common/Validation/Delegation/DelegationErrorPresentable.swift +++ /dev/null @@ -1,27 +0,0 @@ -import Foundation - -protocol DelegationErrorPresentable { - func presentSelfDelegating( - from view: ControllerBackedProtocol, - locale: Locale? - ) -} - -extension DelegationErrorPresentable where Self: AlertPresentable & ErrorPresentable { - func presentSelfDelegating( - from view: ControllerBackedProtocol, - locale: Locale? - ) { - let title = R.string.localizable.govAddDelegateSelfErrorTitle( - preferredLanguages: locale?.rLanguages - ) - - let message = R.string.localizable.govAddDelegateSelfErrorMessage( - preferredLanguages: locale?.rLanguages - ) - - let close = R.string.localizable.commonClose(preferredLanguages: locale?.rLanguages) - - present(message: message, title: title, closeAction: close, from: view) - } -} diff --git a/novawallet/Common/Validation/Delegation/DelegationValidatorFactoryProtocol.swift b/novawallet/Common/Validation/Delegation/DelegationValidatorFactoryProtocol.swift deleted file mode 100644 index 54a79e7557..0000000000 --- a/novawallet/Common/Validation/Delegation/DelegationValidatorFactoryProtocol.swift +++ /dev/null @@ -1,30 +0,0 @@ -import Foundation - -protocol DelegationValidatorFactoryProtocol: AnyObject { - var delegationErrorPresentable: DelegationErrorPresentable { get } - var view: ControllerBackedProtocol? { get } - - func notSelfDelegating( - selfId: AccountId?, - delegateId: AccountId?, - locale: Locale? - ) -> DataValidating -} - -extension DelegationValidatorFactoryProtocol { - func notSelfDelegating( - selfId: AccountId?, - delegateId: AccountId?, - locale: Locale? - ) -> DataValidating { - ErrorConditionViolation(onError: { [weak self] in - guard let view = self?.view else { - return - } - - self?.delegationErrorPresentable.presentSelfDelegating(from: view, locale: locale) - }, preservesCondition: { - selfId != nil && delegateId != nil && selfId != delegateId - }) - } -} diff --git a/novawallet/Modules/Proxy/Validation/ProxyDataValidatorFactory.swift b/novawallet/Modules/Proxy/Validation/ProxyDataValidatorFactory.swift index 9b4b56ace3..ad4c22a44e 100644 --- a/novawallet/Modules/Proxy/Validation/ProxyDataValidatorFactory.swift +++ b/novawallet/Modules/Proxy/Validation/ProxyDataValidatorFactory.swift @@ -2,7 +2,7 @@ import Foundation import BigInt import SoraFoundation -protocol ProxyDataValidatorFactoryProtocol: BaseDataValidatingFactoryProtocol, DelegationValidatorFactoryProtocol { +protocol ProxyDataValidatorFactoryProtocol: BaseDataValidatingFactoryProtocol { func hasSufficientBalance( available: BigUInt, deposit: BigUInt?, @@ -38,6 +38,12 @@ protocol ProxyDataValidatorFactoryProtocol: BaseDataValidatingFactoryProtocol, D asset: AssetBalanceDisplayInfo, locale: Locale ) -> DataValidating + + func notSelfDelegating( + selfId: AccountId?, + delegateId: AccountId?, + locale: Locale? + ) -> DataValidating } extension ProxyDataValidatorFactoryProtocol { @@ -65,8 +71,6 @@ final class ProxyDataValidatorFactory: ProxyDataValidatorFactoryProtocol { weak var view: ControllerBackedProtocol? var basePresentable: BaseErrorPresentable { presentable } - var delegationErrorPresentable: DelegationErrorPresentable { presentable } - let presentable: ProxyErrorPresentable let balanceViewModelFactoryFacade: BalanceViewModelFactoryFacadeProtocol @@ -236,4 +240,20 @@ final class ProxyDataValidatorFactory: ProxyDataValidatorFactoryProtocol { return feeAmount <= balance }) } + + func notSelfDelegating( + selfId: AccountId?, + delegateId: AccountId?, + locale: Locale? + ) -> DataValidating { + ErrorConditionViolation(onError: { [weak self] in + guard let view = self?.view else { + return + } + + self?.presentable.presentSelfDelegating(from: view, locale: locale) + }, preservesCondition: { + selfId != nil && delegateId != nil && selfId != delegateId + }) + } } diff --git a/novawallet/Modules/Proxy/Validation/ProxyErrorPresentable.swift b/novawallet/Modules/Proxy/Validation/ProxyErrorPresentable.swift index f6d711bdc0..4a2c7bee9c 100644 --- a/novawallet/Modules/Proxy/Validation/ProxyErrorPresentable.swift +++ b/novawallet/Modules/Proxy/Validation/ProxyErrorPresentable.swift @@ -1,6 +1,6 @@ import Foundation -protocol ProxyErrorPresentable: BaseErrorPresentable, DelegationErrorPresentable { +protocol ProxyErrorPresentable: BaseErrorPresentable { func presentNotEnoughBalanceForDeposit( from view: ControllerBackedProtocol, deposit: String, @@ -34,6 +34,11 @@ protocol ProxyErrorPresentable: BaseErrorPresentable, DelegationErrorPresentable accountName: String, locale: Locale? ) + + func presentSelfDelegating( + from view: ControllerBackedProtocol, + locale: Locale? + ) } extension ProxyErrorPresentable where Self: AlertPresentable & ErrorPresentable { @@ -128,4 +133,21 @@ extension ProxyErrorPresentable where Self: AlertPresentable & ErrorPresentable present(message: message, title: title, closeAction: closeAction, from: view) } + + func presentSelfDelegating( + from view: ControllerBackedProtocol, + locale: Locale? + ) { + let title = R.string.localizable.govAddDelegateSelfErrorTitle( + preferredLanguages: locale?.rLanguages + ) + + let message = R.string.localizable.govAddDelegateSelfErrorMessage( + preferredLanguages: locale?.rLanguages + ) + + let close = R.string.localizable.commonClose(preferredLanguages: locale?.rLanguages) + + present(message: message, title: title, closeAction: close, from: view) + } } diff --git a/novawallet/Modules/Staking/Model/StakingManageOption.swift b/novawallet/Modules/Staking/Model/StakingManageOption.swift index 6c261fd1e8..c1cd8f68b8 100644 --- a/novawallet/Modules/Staking/Model/StakingManageOption.swift +++ b/novawallet/Modules/Staking/Model/StakingManageOption.swift @@ -91,8 +91,8 @@ enum StakingManageOption { } } - static func proxyAction(from proxyDefinition: UncertainStorage) -> StakingManageOption? { - guard proxyDefinition.isDefined else { + static func proxyAction(from proxyDefinition: UncertainStorage, chain: ChainModel) -> StakingManageOption? { + guard proxyDefinition.isDefined, chain.hasProxy else { return nil } let proxiesCount = proxyDefinition.value??.definition.count ?? 0 diff --git a/novawallet/Modules/Staking/StakingMain/Relaychain/ViewModel/StakingStateViewModelFactory.swift b/novawallet/Modules/Staking/StakingMain/Relaychain/ViewModel/StakingStateViewModelFactory.swift index 019827e613..5eacc03b42 100644 --- a/novawallet/Modules/Staking/StakingMain/Relaychain/ViewModel/StakingStateViewModelFactory.swift +++ b/novawallet/Modules/Staking/StakingMain/Relaychain/ViewModel/StakingStateViewModelFactory.swift @@ -255,7 +255,7 @@ extension StakingStateViewModelFactory: StakingStateVisitorProtocol { .unstake, .rewardDestination, .setupValidators, - .proxyAction(from: state.commonData.proxy), + .proxyAction(from: state.commonData.proxy, chain: chainAsset.chain), .controllerAccount ].compactMap { $0 } @@ -320,7 +320,7 @@ extension StakingStateViewModelFactory: StakingStateVisitorProtocol { .rewardDestination, .pendingRewards, .changeValidators(count: state.nomination.targets.count), - .proxyAction(from: state.commonData.proxy), + .proxyAction(from: state.commonData.proxy, chain: chainAsset.chain), .controllerAccount ].compactMap { $0 } @@ -385,7 +385,7 @@ extension StakingStateViewModelFactory: StakingStateVisitorProtocol { .rewardDestination, .pendingRewards, .yourValidator, - .proxyAction(from: state.commonData.proxy), + .proxyAction(from: state.commonData.proxy, chain: chainAsset.chain), .controllerAccount ].compactMap { $0 } diff --git a/novawallet/Modules/Vote/Governance/Validating/GovernanceErrorPresentable.swift b/novawallet/Modules/Vote/Governance/Validating/GovernanceErrorPresentable.swift index 0f70246565..2820bc39ac 100644 --- a/novawallet/Modules/Vote/Governance/Validating/GovernanceErrorPresentable.swift +++ b/novawallet/Modules/Vote/Governance/Validating/GovernanceErrorPresentable.swift @@ -1,6 +1,6 @@ import Foundation -protocol GovernanceErrorPresentable: BaseErrorPresentable, DelegationErrorPresentable { +protocol GovernanceErrorPresentable: BaseErrorPresentable { func presentNotEnoughTokensToVote( from view: ControllerBackedProtocol, available: String, @@ -23,6 +23,11 @@ protocol GovernanceErrorPresentable: BaseErrorPresentable, DelegationErrorPresen locale: Locale? ) + func presentSelfDelegating( + from view: ControllerBackedProtocol, + locale: Locale? + ) + func presentAlreadyVoting( from view: ControllerBackedProtocol, locale: Locale? @@ -85,6 +90,23 @@ extension GovernanceErrorPresentable where Self: AlertPresentable & ErrorPresent present(message: message, title: title, closeAction: close, from: view) } + func presentSelfDelegating( + from view: ControllerBackedProtocol, + locale: Locale? + ) { + let title = R.string.localizable.govAddDelegateSelfErrorTitle( + preferredLanguages: locale?.rLanguages + ) + + let message = R.string.localizable.govAddDelegateSelfErrorMessage( + preferredLanguages: locale?.rLanguages + ) + + let close = R.string.localizable.commonClose(preferredLanguages: locale?.rLanguages) + + present(message: message, title: title, closeAction: close, from: view) + } + func presentAlreadyVoting( from view: ControllerBackedProtocol, locale: Locale? diff --git a/novawallet/Modules/Vote/Governance/Validating/GovernanceValidatorFactory.swift b/novawallet/Modules/Vote/Governance/Validating/GovernanceValidatorFactory.swift index 064c0a40e6..803f5b15a4 100644 --- a/novawallet/Modules/Vote/Governance/Validating/GovernanceValidatorFactory.swift +++ b/novawallet/Modules/Vote/Governance/Validating/GovernanceValidatorFactory.swift @@ -2,7 +2,7 @@ import Foundation import BigInt import SoraFoundation -protocol GovernanceValidatorFactoryProtocol: BaseDataValidatingFactoryProtocol, DelegationValidatorFactoryProtocol { +protocol GovernanceValidatorFactoryProtocol: BaseDataValidatingFactoryProtocol { func enoughTokensForVoting( _ assetBalance: AssetBalance?, votingAmount: BigUInt?, @@ -35,6 +35,12 @@ protocol GovernanceValidatorFactoryProtocol: BaseDataValidatingFactoryProtocol, locale: Locale? ) -> DataValidating + func notSelfDelegating( + selfId: AccountId?, + delegateId: AccountId?, + locale: Locale? + ) -> DataValidating + func notVoting( _ accountVotingDistribution: ReferendumAccountVotingDistribution?, tracks: Set?, @@ -53,8 +59,6 @@ final class GovernanceValidatorFactory { weak var view: ControllerBackedProtocol? var basePresentable: BaseErrorPresentable { presentable } - var delegationErrorPresentable: DelegationErrorPresentable { presentable } - let assetBalanceFormatterFactory: AssetBalanceFormatterFactoryProtocol let quantityFormatter: LocalizableResource let presentable: GovernanceErrorPresentable @@ -236,6 +240,22 @@ extension GovernanceValidatorFactory: GovernanceValidatorFactoryProtocol { }) } + func notSelfDelegating( + selfId: AccountId?, + delegateId: AccountId?, + locale: Locale? + ) -> DataValidating { + ErrorConditionViolation(onError: { [weak self] in + guard let view = self?.view else { + return + } + + self?.presentable.presentSelfDelegating(from: view, locale: locale) + }, preservesCondition: { + selfId != nil && delegateId != nil && selfId != delegateId + }) + } + func notVoting( _ accountVotingDistribution: ReferendumAccountVotingDistribution?, tracks: Set?, From f8876ed70206c3fc8db844756138e24f624ea1a3 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Wed, 31 Jan 2024 12:26:50 +0300 Subject: [PATCH 48/60] typo --- .../Multistaking/RelaychainMultistakingUpdateService.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/novawallet/Common/Services/Multistaking/RelaychainMultistakingUpdateService.swift b/novawallet/Common/Services/Multistaking/RelaychainMultistakingUpdateService.swift index 8216bef6ad..2418baf9d2 100644 --- a/novawallet/Common/Services/Multistaking/RelaychainMultistakingUpdateService.swift +++ b/novawallet/Common/Services/Multistaking/RelaychainMultistakingUpdateService.swift @@ -96,7 +96,7 @@ final class RelaychainMultistakingUpdateService: ObservableSyncService { ) { BytesCodable(wrappedValue: accountId) }, - mappingKey: nil + mappingkey: Multistaking.RelaychainAccountsChange.Key.stash.rawValue ) controllerSubscription = CallbackBatchStorageSubscription( From 78c3bf29e3e040f6c826ce6d8d1c7b6f46dfad1f Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Wed, 31 Jan 2024 12:32:58 +0300 Subject: [PATCH 49/60] buildfix --- .../Multistaking/RelaychainMultistakingUpdateService.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/novawallet/Common/Services/Multistaking/RelaychainMultistakingUpdateService.swift b/novawallet/Common/Services/Multistaking/RelaychainMultistakingUpdateService.swift index 2418baf9d2..f5d44dc39f 100644 --- a/novawallet/Common/Services/Multistaking/RelaychainMultistakingUpdateService.swift +++ b/novawallet/Common/Services/Multistaking/RelaychainMultistakingUpdateService.swift @@ -96,7 +96,7 @@ final class RelaychainMultistakingUpdateService: ObservableSyncService { ) { BytesCodable(wrappedValue: accountId) }, - mappingkey: Multistaking.RelaychainAccountsChange.Key.stash.rawValue + mappingKey: Multistaking.RelaychainAccountsChange.Key.stash.rawValue ) controllerSubscription = CallbackBatchStorageSubscription( From 40bf82117195759aeac7ccf0ed971524590921bb Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Wed, 31 Jan 2024 15:18:41 +0300 Subject: [PATCH 50/60] bugfix --- .../Proxy/ChainProxySyncService.swift | 24 ++++++++++++++++++- .../ProxyAccountUpdatingService.swift | 2 +- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/novawallet/Common/Services/Proxy/ChainProxySyncService.swift b/novawallet/Common/Services/Proxy/ChainProxySyncService.swift index 03c39726d4..cd5e074b43 100644 --- a/novawallet/Common/Services/Proxy/ChainProxySyncService.swift +++ b/novawallet/Common/Services/Proxy/ChainProxySyncService.swift @@ -51,10 +51,32 @@ final class ChainProxySyncService: ObservableSyncService, ChainProxySyncServiceP } override func performSyncUp() { - sync(at: nil) + performSync(at: nil) } func sync(at blockHash: Data?) { + mutex.lock() + + defer { + mutex.unlock() + } + + guard isActive else { + return + } + + if isSyncing { + stopSyncUp() + + isSyncing = false + } + + isSyncing = true + + performSync(at: blockHash) + } + + func performSync(at blockHash: Data?) { let chainId = chainModel.chainId guard let connection = chainRegistry.getConnection(for: chainId) else { completeImmediate(ChainRegistryError.connectionUnavailable) diff --git a/novawallet/Common/Services/RemoteSubscription/Substrate/ProxyAccountUpdatingService.swift b/novawallet/Common/Services/RemoteSubscription/Substrate/ProxyAccountUpdatingService.swift index 4b554c1272..a9c2becb10 100644 --- a/novawallet/Common/Services/RemoteSubscription/Substrate/ProxyAccountUpdatingService.swift +++ b/novawallet/Common/Services/RemoteSubscription/Substrate/ProxyAccountUpdatingService.swift @@ -43,7 +43,7 @@ class ProxyAccountUpdatingService: ProxyAccountUpdatingServiceProtocol { proxySyncService: proxySyncService, storageFacade: storageFacade, operationQueue: operationQueue, - workingQueue: DispatchQueue.global() + workingQueue: .init(label: "com.novawallet.proxy.updating", qos: .userInitiated) ) } From af2a4acfbfc1e39bb8ab05e116f9318304c8ed61 Mon Sep 17 00:00:00 2001 From: Holyberry <666lynx666@mail.ru> Date: Fri, 2 Feb 2024 13:52:06 +0300 Subject: [PATCH 51/60] init --- .../Relaychain/StakingRelaychainInteractor+Subscription.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainInteractor+Subscription.swift b/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainInteractor+Subscription.swift index 9f5fdaa3fb..fa23eefffb 100644 --- a/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainInteractor+Subscription.swift +++ b/novawallet/Modules/Staking/StakingMain/Relaychain/StakingRelaychainInteractor+Subscription.swift @@ -35,9 +35,9 @@ extension StakingRelaychainInteractor { subscribeToStashAccount(address: stashItem.stash, chain: chainAsset.chain) } - if selectedAccount?.accountId == stashAccountId, chainAsset.chain.hasProxy { + if let accountId = selectedAccount?.accountId, chainAsset.chain.hasProxy { proxyProvider = subscribeProxies( - for: stashAccountId, + for: accountId, chainId: chainId, modifyInternalList: ProxyFilter.filteredStakingProxy ) From 2c5538991e537137769c949aedfe09821ad44442 Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 7 Feb 2024 05:35:34 +0100 Subject: [PATCH 52/60] enable proxieds on add staking proxy --- .../Staking/StakingProxy/Add/StakingSetupProxyInteractor.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/novawallet/Modules/Staking/StakingProxy/Add/StakingSetupProxyInteractor.swift b/novawallet/Modules/Staking/StakingProxy/Add/StakingSetupProxyInteractor.swift index 70e5ecc6b7..bee30a1f05 100644 --- a/novawallet/Modules/Staking/StakingProxy/Add/StakingSetupProxyInteractor.swift +++ b/novawallet/Modules/Staking/StakingProxy/Add/StakingSetupProxyInteractor.swift @@ -67,7 +67,7 @@ final class StakingSetupProxyInteractor: StakingProxyBaseInteractor, AccountFetc presenter?.didReceive(error: .fetchMetaAccounts(error)) presenter?.didReceive(yourWallets: []) case let .success(accounts): - let excludedWalletTypes: [MetaAccountModelType] = [.watchOnly, .proxied] + let excludedWalletTypes: [MetaAccountModelType] = [.watchOnly] let filteredAccounts = accounts.filter { !excludedWalletTypes.contains($0.metaAccount.type) && $0.chainAccountResponse != nil } From 385d118fe4a9a80e5b3f4e40e34a36994d278406 Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 7 Feb 2024 05:41:03 +0100 Subject: [PATCH 53/60] fix duplicated proxy validation --- .../Modules/Proxy/Validation/ProxyDataValidatorFactory.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/novawallet/Modules/Proxy/Validation/ProxyDataValidatorFactory.swift b/novawallet/Modules/Proxy/Validation/ProxyDataValidatorFactory.swift index ad4c22a44e..214ce6c67c 100644 --- a/novawallet/Modules/Proxy/Validation/ProxyDataValidatorFactory.swift +++ b/novawallet/Modules/Proxy/Validation/ProxyDataValidatorFactory.swift @@ -170,7 +170,7 @@ final class ProxyDataValidatorFactory: ProxyDataValidatorFactoryProtocol { return false } let accountId = try? address.toAccountId(using: chain.chainFormat) - return proxyList.contains(where: { $0.proxy == accountId }) == false + return !proxyList.contains(where: { $0.proxy == accountId && $0.proxyType == .staking }) }) } From ca4727c1d27068f17f36f671faf3069faa67966f Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 7 Feb 2024 06:26:15 +0100 Subject: [PATCH 54/60] fix active stakers parsing when nil --- .../Network/Subquery/Models/SubqueryMultistaking.swift | 6 +++--- .../Subquery/SubqueryMultistakingOperationFactory.swift | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/novawallet/Common/Network/Subquery/Models/SubqueryMultistaking.swift b/novawallet/Common/Network/Subquery/Models/SubqueryMultistaking.swift index 99ebbc1bd0..01431e2d86 100644 --- a/novawallet/Common/Network/Subquery/Models/SubqueryMultistaking.swift +++ b/novawallet/Common/Network/Subquery/Models/SubqueryMultistaking.swift @@ -42,9 +42,9 @@ enum SubqueryMultistaking { } struct StatsResponse: Decodable { - let activeStakers: SubqueryNodes + let activeStakers: SubqueryNodes? let stakingApies: SubqueryNodes - let rewards: SubqueryAggregates - let slashes: SubqueryAggregates + let rewards: SubqueryAggregates? + let slashes: SubqueryAggregates? } } diff --git a/novawallet/Common/Network/Subquery/SubqueryMultistakingOperationFactory.swift b/novawallet/Common/Network/Subquery/SubqueryMultistakingOperationFactory.swift index ccbda3b075..1cfad2ba91 100644 --- a/novawallet/Common/Network/Subquery/SubqueryMultistakingOperationFactory.swift +++ b/novawallet/Common/Network/Subquery/SubqueryMultistakingOperationFactory.swift @@ -138,9 +138,9 @@ extension SubqueryMultistakingOperationFactory: MultistakingOffchainOperationFac do { let query = try buildQuery(for: request) let operation = createOperation(for: query) { (result: SubqueryMultistaking.StatsResponse) in - let activeStakers = result.activeStakers.groupByNetworkAccountStaking() - let rewards = result.rewards.groupByNetworkStaking() - let slashes = result.slashes.groupByNetworkStaking() + let activeStakers = result.activeStakers?.groupByNetworkAccountStaking() ?? [:] + let rewards = result.rewards?.groupByNetworkStaking() ?? [:] + let slashes = result.slashes?.groupByNetworkStaking() ?? [:] let stateFilterByNetworkStaking = request.stateFilters.groupByNetworkStaking() From 034959c8f26220023711819cd460a385643dd76a Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 7 Feb 2024 06:46:49 +0100 Subject: [PATCH 55/60] fix texts --- .../Management/StakingProxyManagementViewController.swift | 2 +- .../StakingProxy/Remove/StakingRemoveProxyPresenter.swift | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/novawallet/Modules/Staking/StakingProxy/Management/StakingProxyManagementViewController.swift b/novawallet/Modules/Staking/StakingProxy/Management/StakingProxyManagementViewController.swift index f72a41ce90..8adb80318f 100644 --- a/novawallet/Modules/Staking/StakingProxy/Management/StakingProxyManagementViewController.swift +++ b/novawallet/Modules/Staking/StakingProxy/Management/StakingProxyManagementViewController.swift @@ -44,7 +44,7 @@ final class StakingProxyManagementViewController: UIViewController, ViewHolder { } private func setupLocalization() { - title = R.string.localizable.stakingProxyManagementTitle( + title = R.string.localizable.stakingSetupYourProxies( preferredLanguages: selectedLocale.rLanguages ) diff --git a/novawallet/Modules/Staking/StakingProxy/Remove/StakingRemoveProxyPresenter.swift b/novawallet/Modules/Staking/StakingProxy/Remove/StakingRemoveProxyPresenter.swift index edf8074c05..c45b669eb5 100644 --- a/novawallet/Modules/Staking/StakingProxy/Remove/StakingRemoveProxyPresenter.swift +++ b/novawallet/Modules/Staking/StakingProxy/Remove/StakingRemoveProxyPresenter.swift @@ -91,7 +91,10 @@ final class StakingRemoveProxyPresenter { } private func provideProxyTypeViewModel() { - let type = proxyAccount.type.title(locale: selectedLocale) + let type = R.string.localizable.stakingConfirmProxyTypeSubtitle( + preferredLanguages: selectedLocale.rLanguages + ) + view?.didReceiveProxyType(viewModel: type) } From b32b471dd780747eaac79c3c877227780c1c6f0e Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 7 Feb 2024 09:42:00 +0100 Subject: [PATCH 56/60] sync localization --- .../StakingConfirmProxyViewFactory.swift | 2 +- novawallet/en.lproj/Localizable.strings | 53 ++++++++++--------- novawallet/ru.lproj/Localizable.strings | 53 ++++++++++--------- 3 files changed, 55 insertions(+), 53 deletions(-) diff --git a/novawallet/Modules/Staking/StakingProxy/Confirm/StakingConfirmProxyViewFactory.swift b/novawallet/Modules/Staking/StakingProxy/Confirm/StakingConfirmProxyViewFactory.swift index 8fc83de51c..30ffbbb599 100644 --- a/novawallet/Modules/Staking/StakingProxy/Confirm/StakingConfirmProxyViewFactory.swift +++ b/novawallet/Modules/Staking/StakingProxy/Confirm/StakingConfirmProxyViewFactory.swift @@ -49,7 +49,7 @@ struct StakingConfirmProxyViewFactory { presenter: presenter, localizationManager: LocalizationManager.shared, title: .init { - R.string.localizable.delegationsAddTitle( + R.string.localizable.stakingAddProxyConfirmationTitle( preferredLanguages: $0.rLanguages ) } diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index a5729c3ec2..293cbb742e 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -1270,7 +1270,7 @@ "welcome.polkadot.vault.step3" = "Polkadot Vault will provide you QR code to scan"; "welcome.polkadot.vault.step3.highlighted" = "QR code to scan"; "staking.controller.deprecated.title" = "Controller Accounts Are Being Deprecated"; -"staking.controller.deprecated.details" = "Network is migrating towards replacing Controllers to Proxies feature. Nova Wallet will support Proxies in future updates"; +"staking.controller.deprecated.details" = "Use Proxies to delegate Staking operations to another account"; "staking.controller.deprecated.action" = "Update Controller to Stash"; "staking.estimated.earnings" = "Estimated rewards"; "common.per.year.long" = "per year"; @@ -1363,31 +1363,6 @@ "staking.pool.is.not.open.title" = "Pool is not open"; "staking.start.balance" = "Available balance: %@"; "staking.start.no.account" = "No %@ account"; -"staking.setup.proxy.title" = "Add delegation for %@ staking"; -"staking.setup.proxy.authority" = "Give authority to"; -"staking.setup.proxy.deposit" = "Proxy deposit"; -"staking.setup.proxy.deposit.details" = "The deposit stays reserved on your account until the proxy is removed."; -"staking.setup.your.proxies" = "Your delegations"; -"staking.setup.add.your.proxy" = "Add delegated authority (Proxy)"; -"staking.alert.switch.to.stash.title" = "Select stash account to setup proxy"; -"staking.alert.switch.to.stash.message" = "Please switch your wallet to %@ to setup a proxy"; -"staking.setup.proxy.error.insufficient.balance.title" = "Not enough tokens"; -"staking.setup.proxy.error.insufficient.balance.message" = "You don’t have enough balance for proxy deposit of %@. Available balance: %@"; -"staking.setup.proxy.error.invalid.address.title" = "Invalid proxy address"; -"staking.setup.proxy.error.invalid.address.message" = "Proxy address should be a valid %@ address"; -"staking.setup.proxy.error.invalid.maximum.proxies.title" = "Maximum number of proxies has been reached"; -"staking.setup.proxy.error.invalid.maximum.proxies.message" = "You have reached the limit of %@ added proxies in %@. Remove proxies to add new ones."; -"staking.setup.proxy.error.proxy.already.exists.title" = "Delegation already exists"; -"staking.setup.proxy.error.proxy.already.exists.message" = "You are already delegating to this account: %@"; -"staking.confirm.proxy.wallet" = "Delegating wallet"; -"staking.confirm.proxy.account.proxied" = "Delegating account"; -"staking.confirm.proxy.type.title" = "Grant access type"; -"staking.confirm.proxy.type.subtitle" = "Staking operations"; -"staking.confirm.proxy.account.proxy" = "Delegate to"; -"staking.proxy.management.title" = "Delegated authorities (proxy)"; -"staking.proxy.management.revoke.access" = "Revoke access"; -"staking.proxy.revoke.access.type" = "Revoke access type"; -"staking.proxy.revoke.access.proxy.address" = "Revoke for"; "common.time.in" = "in"; "common.and" = " and "; "common.time.period.after" = "after"; @@ -1487,3 +1462,29 @@ "proxy.signing.checkmark.title" = "Automatically continue in the future"; "deeplink.error.invalid.referendum.id.message" = "Referendum is not found"; "governance.referendum.not.found.message" = "Referendum is not found"; +"staking.alert.switch.to.stash.title" = "Select stash account to setup proxy"; +"staking.alert.switch.to.stash.message" = "Please switch your wallet to %@ to setup a proxy"; +"staking.proxy.revoke.access.type" = "Revoke access type"; +"staking.proxy.revoke.access.proxy.address" = "Revoke for"; +"staking.proxy.management.title" = "Delegated authorities (proxy)"; +"staking.proxy.management.revoke.access" = "Revoke access"; +"staking.confirm.proxy.type.subtitle" = "Staking operations"; +"staking.confirm.proxy.wallet" = "Delegating wallet"; +"staking.confirm.proxy.account.proxied" = "Delegating account"; +"staking.confirm.proxy.type.title" = "Grant access type"; +"staking.confirm.proxy.account.proxy" = "Delegate to"; +"staking.add.proxy.confirmation.title" = "Add delegation"; +"staking.setup.proxy.error.proxy.already.exists.title" = "Delegation already exists"; +"staking.setup.proxy.error.proxy.already.exists.message" = "You are already delegating to this account: %@"; +"staking.setup.proxy.error.invalid.address.title" = "Invalid proxy address"; +"staking.setup.proxy.error.invalid.address.message" = "Proxy address should be a valid %s address"; +"staking.setup.proxy.deposit.details" = "The deposit stays reserved on your account until the proxy is removed."; +"staking.setup.proxy.error.invalid.maximum.proxies.title" = "Maximum number of proxies has been reached"; +"staking.setup.proxy.error.invalid.maximum.proxies.message" = "You have reached the limit of %@ added proxies in %@. Remove proxies to add new ones."; +"staking.setup.proxy.error.insufficient.balance.title" = "Not enough tokens"; +"staking.setup.proxy.error.insufficient.balance.message" = "You don’t have enough balance for proxy deposit of %@. Available balance: %@"; +"staking.setup.your.proxies" = "Your delegations"; +"staking.setup.add.your.proxy" = "Add delegated authority (Proxy)"; +"staking.setup.proxy.authority" = "Give authority to"; +"staking.setup.proxy.deposit" = "Proxy deposit"; +"staking.setup.proxy.title" = "Add delegation for %@ staking"; \ No newline at end of file diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index ac9dd975f8..7f0b9d9a46 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1270,7 +1270,7 @@ "welcome.polkadot.vault.step3" = "Polkadot Vault предоставит вам QR-код для сканирования"; "welcome.polkadot.vault.step3.highlighted" = "QR-код для сканирования"; "staking.controller.deprecated.title" = "Контроллер Аккаунты Устаревают"; -"staking.controller.deprecated.details" = "Сеть мигрирует в сторону замены контроллеров на прокси. Nova Wallet будет поддерживать прокси в будущих обновлениях"; +"staking.controller.deprecated.details" = "Используйте прокси для делегирования операций стейкинга другому аккаунту"; "staking.controller.deprecated.action" = "Изменить контроллер на стэш"; "staking.estimated.earnings" = "Примерный доход"; "common.per.year.long" = "в год"; @@ -1363,32 +1363,7 @@ "staking.pool.is.not.open.title" = "Пул не открыт"; "staking.start.balance" = "Доступный баланс: %@"; "staking.start.no.account" = "Нет %@ аккаунта"; -"staking.setup.proxy.title" = "Добавить делегацию для %@ стекинга"; -"staking.setup.proxy.authority" = "Дать доступ"; -"staking.setup.proxy.deposit" = "Прокси депозит"; -"staking.setup.proxy.deposit.details" = "Депозит остается зарезервированным на вашем счете до тех пор, пока прокси не будет удален."; -"staking.setup.your.proxies" = "Ваши делегации"; -"staking.setup.add.your.proxy" = "Добавить делегацию (Прокси)"; -"staking.alert.switch.to.stash.title" = "Выберите стэш-аккаунт для настройки прокси."; -"staking.alert.switch.to.stash.message" = "Переключите свой кошелек на %@, чтобы настроить прокси."; -"staking.setup.proxy.error.insufficient.balance.title" = "Недостаточно токенов"; -"staking.setup.proxy.error.insufficient.balance.message" = "У вас недостаточно средств для депозита прокси %@. Доступный баланс: %@"; -"staking.setup.proxy.error.invalid.address.title" = "Некорректный адрес прокси"; -"staking.setup.proxy.error.invalid.address.message" = "Адрес прокси должен быть допустимым адресом в сети %@"; -"staking.setup.proxy.error.invalid.maximum.proxies.title" = "Достигнуто максимальное количество прокси"; -"staking.setup.proxy.error.invalid.maximum.proxies.message" = "Вы достигли лимита добавленных прокси (%@) в %@. Чтобы добавить новые, удалите существующие."; -"staking.setup.proxy.error.proxy.already.exists.title" = "Прокси уже добавлен"; -"staking.setup.proxy.error.proxy.already.exists.message" = "Вы уже делегируете этой учетной записи: %@"; "common.time.in" = "через"; -"staking.confirm.proxy.wallet" = "Делегирующий кошелек"; -"staking.confirm.proxy.account.proxied" = "Делегирующий аккаунт"; -"staking.confirm.proxy.type.title" = "Выданный тип доступа"; -"staking.confirm.proxy.type.subtitle" = "Операции стекинга"; -"staking.confirm.proxy.account.proxy" = "Делегировать"; -"staking.proxy.management.title" = "Делегированные полномочия (прокси)"; -"staking.proxy.management.revoke.access" = "Отозвать доступ"; -"staking.proxy.revoke.access.type" = "Отзыввемый доступ"; -"staking.proxy.revoke.access.proxy.address" = "Отозвать для"; "common.and" = " и "; "common.time.period.after" = "через"; "common.time.period.every" = "раз в"; @@ -1487,3 +1462,29 @@ "proxy.signing.checkmark.title" = "Автоматически проводить в будущем"; "deeplink.error.invalid.referendum.id.message" = "Референдум не найден"; "governance.referendum.not.found.message" = "Референдум не найден"; +"staking.alert.switch.to.stash.title" = "Выберите стэш-аккаунт для настройки прокси"; +"staking.alert.switch.to.stash.message" = "Пожалуйста, переключите свой кошелек на %@ , чтобы настроить прокси."; +"staking.proxy.revoke.access.type" = "Отзываемый типа доступа"; +"staking.proxy.revoke.access.proxy.address" = "Отозвать у"; +"staking.proxy.management.title" = "Делегированные полномочия (прокси)"; +"staking.proxy.management.revoke.access" = "Отозвать доступ"; +"staking.confirm.proxy.type.subtitle" = "Операции стейкинга"; +"staking.confirm.proxy.wallet" = "Кошелек делегирования"; +"staking.confirm.proxy.account.proxied" = "Аккаунт делегирования"; +"staking.confirm.proxy.type.title" = "Тип доступа"; +"staking.confirm.proxy.account.proxy" = "Делегировать аккаунту"; +"staking.add.proxy.confirmation.title" = "Добавить делегацию"; +"staking.setup.proxy.error.proxy.already.exists.title" = "Делегация уже существует"; +"staking.setup.proxy.error.proxy.already.exists.message" = "Вы уже делегируете полномочия этому аккаунту: %@"; +"staking.setup.proxy.error.invalid.address.title" = "Неверный адрес прокси"; +"staking.setup.proxy.error.invalid.address.message" = "Адрес прокси должен быть действительным адресом %s"; +"staking.setup.proxy.deposit.details" = "Депозит остается зарезервированным на вашем счете до тех пор, пока прокси не будет удален."; +"staking.setup.proxy.error.invalid.maximum.proxies.title" = "Достигнуто максимальное количество прокси"; +"staking.setup.proxy.error.invalid.maximum.proxies.message" = "Вы достигли лимита добавленных прокси (%@) в %@ . Удалите прокси, чтобы добавить новые."; +"staking.setup.proxy.error.insufficient.balance.title" = "Недостаточно токенов"; +"staking.setup.proxy.error.insufficient.balance.message" = "У вас недостаточный баланс для прокси-депозита %@. Доступный баланс: %@"; +"staking.setup.your.proxies" = "Ваши делегации"; +"staking.setup.add.your.proxy" = "Делегировать полномочия (прокси)"; +"staking.setup.proxy.authority" = "Выдать полномочия аккаунту"; +"staking.setup.proxy.deposit" = "Прокси депозит"; +"staking.setup.proxy.title" = "Добавить делегацию для %@ стекинга"; \ No newline at end of file From 46518d9a5cef14aaa25dfdd0cb15f42bec51b85a Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 7 Feb 2024 10:09:34 +0100 Subject: [PATCH 57/60] fix links open logic --- novawallet/Common/Protocols/WebPresentable.swift | 7 +------ .../Proxy/ProxiedsUpdate/ProxiedsUpdatePresenter.swift | 5 +---- .../Proxy/ProxiedsUpdate/ProxiedsUpdateProtocols.swift | 1 + .../Proxy/ProxiedsUpdate/ProxiedsUpdateWireframe.swift | 10 ++++++++++ 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/novawallet/Common/Protocols/WebPresentable.swift b/novawallet/Common/Protocols/WebPresentable.swift index c6309b8956..15e077e038 100644 --- a/novawallet/Common/Protocols/WebPresentable.swift +++ b/novawallet/Common/Protocols/WebPresentable.swift @@ -17,12 +17,7 @@ extension WebPresentable { } func showWeb(url: URL, from view: ControllerBackedProtocol, style: WebPresentableStyle) { - let defaultController = UIApplication.shared.delegate?.window??.rootViewController - guard let viewController = view.controller.presentingViewController ?? defaultController else { - return - } - - showWeb(url: url, from: viewController, style: style) + showWeb(url: url, from: view.controller, style: style) } func showWeb(url: URL, from viewController: UIViewController, style: WebPresentableStyle) { diff --git a/novawallet/Modules/Proxy/ProxiedsUpdate/ProxiedsUpdatePresenter.swift b/novawallet/Modules/Proxy/ProxiedsUpdate/ProxiedsUpdatePresenter.swift index 2d6faf53cd..bd0c0c2af7 100644 --- a/novawallet/Modules/Proxy/ProxiedsUpdate/ProxiedsUpdatePresenter.swift +++ b/novawallet/Modules/Proxy/ProxiedsUpdate/ProxiedsUpdatePresenter.swift @@ -83,10 +83,7 @@ extension ProxiedsUpdatePresenter: ProxiedsUpdatePresenterProtocol { return } - wireframe.close(from: view) - - let wikiUrl = applicationConfig.proxyWikiURL - wireframe.showWeb(url: wikiUrl, from: view, style: .automatic) + wireframe.close(from: view, andPresent: applicationConfig.proxyWikiURL) } } diff --git a/novawallet/Modules/Proxy/ProxiedsUpdate/ProxiedsUpdateProtocols.swift b/novawallet/Modules/Proxy/ProxiedsUpdate/ProxiedsUpdateProtocols.swift index 87c9222576..23dee774be 100644 --- a/novawallet/Modules/Proxy/ProxiedsUpdate/ProxiedsUpdateProtocols.swift +++ b/novawallet/Modules/Proxy/ProxiedsUpdate/ProxiedsUpdateProtocols.swift @@ -29,6 +29,7 @@ protocol ProxiedsUpdateInteractorOutputProtocol: AnyObject { protocol ProxiedsUpdateWireframeProtocol: AnyObject, WebPresentable { func close(from view: ControllerBackedProtocol?) + func close(from view: ControllerBackedProtocol?, andPresent url: URL) } enum ProxiedsUpdateError: Error { diff --git a/novawallet/Modules/Proxy/ProxiedsUpdate/ProxiedsUpdateWireframe.swift b/novawallet/Modules/Proxy/ProxiedsUpdate/ProxiedsUpdateWireframe.swift index 0e87ac4910..ddd0e75ef1 100644 --- a/novawallet/Modules/Proxy/ProxiedsUpdate/ProxiedsUpdateWireframe.swift +++ b/novawallet/Modules/Proxy/ProxiedsUpdate/ProxiedsUpdateWireframe.swift @@ -4,4 +4,14 @@ final class ProxiedsUpdateWireframe: ProxiedsUpdateWireframeProtocol { func close(from view: ControllerBackedProtocol?) { view?.controller.dismiss(animated: true, completion: nil) } + + func close(from view: ControllerBackedProtocol?, andPresent url: URL) { + guard let presentingController = view?.controller.presentingViewController else { + return + } + + view?.controller.dismiss(animated: true) { + self.showWeb(url: url, from: presentingController, style: .automatic) + } + } } From 26abb8af104c163d4ac34cb473e9a8b004a06f41 Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 7 Feb 2024 10:42:13 +0100 Subject: [PATCH 58/60] fix formating --- .../Staking/StakingProxy/Add/StakingSetupProxyPresenter.swift | 2 +- novawallet/en.lproj/Localizable.strings | 2 +- novawallet/ru.lproj/Localizable.strings | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/novawallet/Modules/Staking/StakingProxy/Add/StakingSetupProxyPresenter.swift b/novawallet/Modules/Staking/StakingProxy/Add/StakingSetupProxyPresenter.swift index c67302a823..75eed337bb 100644 --- a/novawallet/Modules/Staking/StakingProxy/Add/StakingSetupProxyPresenter.swift +++ b/novawallet/Modules/Staking/StakingProxy/Add/StakingSetupProxyPresenter.swift @@ -253,7 +253,7 @@ extension StakingSetupProxyPresenter: StakingSetupProxyInteractorOutputProtocol recipient: .loaded(value: nil) )) } - case let .fetchMetaAccounts(error): + case .fetchMetaAccounts: wireframe.presentRequestStatus( on: view, locale: selectedLocale diff --git a/novawallet/en.lproj/Localizable.strings b/novawallet/en.lproj/Localizable.strings index 293cbb742e..dbd63a9dba 100644 --- a/novawallet/en.lproj/Localizable.strings +++ b/novawallet/en.lproj/Localizable.strings @@ -1477,7 +1477,7 @@ "staking.setup.proxy.error.proxy.already.exists.title" = "Delegation already exists"; "staking.setup.proxy.error.proxy.already.exists.message" = "You are already delegating to this account: %@"; "staking.setup.proxy.error.invalid.address.title" = "Invalid proxy address"; -"staking.setup.proxy.error.invalid.address.message" = "Proxy address should be a valid %s address"; +"staking.setup.proxy.error.invalid.address.message" = "Proxy address should be a valid %@ address"; "staking.setup.proxy.deposit.details" = "The deposit stays reserved on your account until the proxy is removed."; "staking.setup.proxy.error.invalid.maximum.proxies.title" = "Maximum number of proxies has been reached"; "staking.setup.proxy.error.invalid.maximum.proxies.message" = "You have reached the limit of %@ added proxies in %@. Remove proxies to add new ones."; diff --git a/novawallet/ru.lproj/Localizable.strings b/novawallet/ru.lproj/Localizable.strings index 7f0b9d9a46..968ba1b940 100644 --- a/novawallet/ru.lproj/Localizable.strings +++ b/novawallet/ru.lproj/Localizable.strings @@ -1477,7 +1477,7 @@ "staking.setup.proxy.error.proxy.already.exists.title" = "Делегация уже существует"; "staking.setup.proxy.error.proxy.already.exists.message" = "Вы уже делегируете полномочия этому аккаунту: %@"; "staking.setup.proxy.error.invalid.address.title" = "Неверный адрес прокси"; -"staking.setup.proxy.error.invalid.address.message" = "Адрес прокси должен быть действительным адресом %s"; +"staking.setup.proxy.error.invalid.address.message" = "Адрес прокси должен быть действительным адресом %@"; "staking.setup.proxy.deposit.details" = "Депозит остается зарезервированным на вашем счете до тех пор, пока прокси не будет удален."; "staking.setup.proxy.error.invalid.maximum.proxies.title" = "Достигнуто максимальное количество прокси"; "staking.setup.proxy.error.invalid.maximum.proxies.message" = "Вы достигли лимита добавленных прокси (%@) в %@ . Удалите прокси, чтобы добавить новые."; From 543ea15efb39b44c6752598818b4c00c6335b4d2 Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 7 Feb 2024 12:01:56 +0100 Subject: [PATCH 59/60] display full amount for total balance --- .../AssetBalanceFormatterFactory.swift | 63 ++++++++++++------- .../ViewModel/AssetListViewModelFactory.swift | 38 +++++++++-- 2 files changed, 73 insertions(+), 28 deletions(-) diff --git a/novawallet/Common/Helpers/AssetBalanceFormatterFactory.swift b/novawallet/Common/Helpers/AssetBalanceFormatterFactory.swift index 036f55e28c..89329e4056 100644 --- a/novawallet/Common/Helpers/AssetBalanceFormatterFactory.swift +++ b/novawallet/Common/Helpers/AssetBalanceFormatterFactory.swift @@ -17,6 +17,8 @@ protocol AssetBalanceFormatterFactoryProtocol { func createAssetPriceFormatter(for info: AssetBalanceDisplayInfo) -> LocalizableResource + func createTotalPriceFormatter(for info: AssetBalanceDisplayInfo) -> LocalizableResource + func createInputTokenFormatter( for info: AssetBalanceDisplayInfo ) -> LocalizableResource @@ -40,12 +42,14 @@ class AssetBalanceFormatterFactory { private func createTokenFormatterCommon( for info: AssetBalanceDisplayInfo, roundingMode: NumberFormatter.RoundingMode, - preferredPrecisionOffset: UInt8 = 0 + preferredPrecisionOffset: UInt8 = 0, + usesSuffixForBigNumbers: Bool = true ) -> LocalizableResource { let formatter = createCompoundFormatter( for: info.displayPrecision, roundingMode: roundingMode, - prefferedPrecisionOffset: preferredPrecisionOffset + prefferedPrecisionOffset: preferredPrecisionOffset, + usesSuffixForBigNumber: usesSuffixForBigNumbers ) let tokenFormatter = TokenFormatter( @@ -65,9 +69,10 @@ class AssetBalanceFormatterFactory { private func createCompoundFormatter( for preferredPrecision: UInt16, roundingMode: NumberFormatter.RoundingMode = .down, - prefferedPrecisionOffset: UInt8 = 0 + prefferedPrecisionOffset: UInt8 = 0, + usesSuffixForBigNumber: Bool = true ) -> LocalizableDecimalFormatting { - let abbreviations: [BigNumberAbbreviation] = [ + var abbreviations: [BigNumberAbbreviation] = [ BigNumberAbbreviation( threshold: 0, divisor: 1.0, @@ -93,27 +98,32 @@ class AssetBalanceFormatterFactory { divisor: 1.0, suffix: "", formatter: nil - ), - BigNumberAbbreviation( - threshold: 1_000_000, - divisor: 1_000_000.0, - suffix: "M", - formatter: nil - ), - BigNumberAbbreviation( - threshold: 1_000_000_000, - divisor: 1_000_000_000.0, - suffix: "B", - formatter: nil - ), - BigNumberAbbreviation( - threshold: 1_000_000_000_000, - divisor: 1_000_000_000_000.0, - suffix: "T", - formatter: nil ) ] + if usesSuffixForBigNumber { + abbreviations.append(contentsOf: [ + BigNumberAbbreviation( + threshold: 1_000_000, + divisor: 1_000_000.0, + suffix: "M", + formatter: nil + ), + BigNumberAbbreviation( + threshold: 1_000_000_000, + divisor: 1_000_000_000.0, + suffix: "B", + formatter: nil + ), + BigNumberAbbreviation( + threshold: 1_000_000_000_000, + divisor: 1_000_000_000_000.0, + suffix: "T", + formatter: nil + ) + ]) + } + return BigNumberFormatter( abbreviations: abbreviations, precision: 2, @@ -154,6 +164,15 @@ extension AssetBalanceFormatterFactory: AssetBalanceFormatterFactoryProtocol { createTokenFormatterCommon(for: info, roundingMode: .down, preferredPrecisionOffset: 2) } + func createTotalPriceFormatter(for info: AssetBalanceDisplayInfo) -> LocalizableResource { + createTokenFormatterCommon( + for: info, + roundingMode: .down, + preferredPrecisionOffset: 2, + usesSuffixForBigNumbers: false + ) + } + func createInputTokenFormatter( for info: AssetBalanceDisplayInfo ) -> LocalizableResource { diff --git a/novawallet/Modules/AssetList/ViewModel/AssetListViewModelFactory.swift b/novawallet/Modules/AssetList/ViewModel/AssetListViewModelFactory.swift index 36e49f4c42..6e87615454 100644 --- a/novawallet/Modules/AssetList/ViewModel/AssetListViewModelFactory.swift +++ b/novawallet/Modules/AssetList/ViewModel/AssetListViewModelFactory.swift @@ -55,8 +55,8 @@ final class AssetListViewModelFactory: AssetListAssetViewModelFactory { private lazy var iconGenerator = NovaIconGenerator() - private func formatTotalPrice(from prices: [AssetListAssetAccountPrice], locale: Locale) -> String { - let totalPrice = prices.reduce(Decimal(0)) { result, item in + private func calculateTotalPrice(from prices: [AssetListAssetAccountPrice]) -> Decimal { + prices.reduce(Decimal(0)) { result, item in let balance = Decimal.fromSubstrateAmount( item.balance, precision: item.assetInfo.assetPrecision @@ -66,8 +66,18 @@ final class AssetListViewModelFactory: AssetListAssetViewModelFactory { return result + balance * price } + } + + private func createTotalPriceString( + from price: Decimal, + priceData: PriceData?, + locale: Locale + ) -> String { + let currencyId = priceData?.currencyId ?? currencyManager.selectedCurrency.id + let assetDisplayInfo = priceAssetInfoFactory.createAssetBalanceDisplayInfo(from: currencyId) + let priceFormatter = assetFormatterFactory.createTotalPriceFormatter(for: assetDisplayInfo) - return formatPrice(amount: totalPrice, priceData: prices.first?.price, locale: locale) + return priceFormatter.value(for: locale).stringFromDecimal(price) ?? "" } private func createTotalPrice( @@ -78,10 +88,20 @@ final class AssetListViewModelFactory: AssetListAssetViewModelFactory { case .loading: return .loading case let .cached(value): - let formattedPrice = formatTotalPrice(from: value, locale: locale) + let formattedPrice = createTotalPriceString( + from: calculateTotalPrice(from: value), + priceData: value.first?.price, + locale: locale + ) + return .cached(value: .init(amount: formattedPrice, decimalSeparator: locale.decimalSeparator)) case let .loaded(value): - let formattedPrice = formatTotalPrice(from: value, locale: locale) + let formattedPrice = createTotalPriceString( + from: calculateTotalPrice(from: value), + priceData: value.first?.price, + locale: locale + ) + return .loaded(value: .init(amount: formattedPrice, decimalSeparator: locale.decimalSeparator)) } } @@ -107,7 +127,13 @@ extension AssetListViewModelFactory: AssetListViewModelFactoryProtocol { walletConnectSessionsCount: formattedWalletConnectSessionsCount, title: params.title, amount: totalPrice, - locksAmount: params.locks.map { formatTotalPrice(from: $0, locale: locale) }, + locksAmount: params.locks.map { lock in + formatPrice( + amount: calculateTotalPrice(from: lock), + priceData: lock.first?.price, + locale: locale + ) + }, walletSwitch: walletSwitch, hasSwaps: params.hasSwaps ) From 992dbc4b4e9e4de664cd56b76fac5d8bd88cf050 Mon Sep 17 00:00:00 2001 From: ERussel Date: Wed, 7 Feb 2024 12:14:07 +0100 Subject: [PATCH 60/60] fix crash on DApp browser when address prefix too large --- .../DAppBrowser/StateMachine/DAppBrowserStateDataSource.swift | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/novawallet/Modules/DApp/DAppBrowser/StateMachine/DAppBrowserStateDataSource.swift b/novawallet/Modules/DApp/DAppBrowser/StateMachine/DAppBrowserStateDataSource.swift index 75f361e770..ff1f87f1e9 100644 --- a/novawallet/Modules/DApp/DAppBrowser/StateMachine/DAppBrowserStateDataSource.swift +++ b/novawallet/Modules/DApp/DAppBrowser/StateMachine/DAppBrowserStateDataSource.swift @@ -75,10 +75,8 @@ final class DAppBrowserStateDataSource { return nil } - let addressPrefix = UInt16(addressPrefixValue) - return chainStore.values.first { model in - model.isEthereumBased && model.addressPrefix == addressPrefix + model.isEthereumBased && BigUInt(model.addressPrefix) == addressPrefixValue } }