Skip to content

Commit

Permalink
Merge pull request #1173 from novasamatech/feature/historical-votes-f…
Browse files Browse the repository at this point in the history
…or-ended-referendums

Feature/historical votes for ended referendums
  • Loading branch information
svojsu authored Aug 1, 2024
2 parents ff11e89 + 8239991 commit f882465
Show file tree
Hide file tree
Showing 14 changed files with 653 additions and 235 deletions.
12 changes: 8 additions & 4 deletions novawallet.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -872,6 +872,7 @@
2D039DE82BFCA83600A928E5 /* BindableGestureRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D039DE72BFCA83600A928E5 /* BindableGestureRecognizer.swift */; };
2D039DEA2BFCAB9000A928E5 /* ExportViewModelFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D039DE92BFCAB9000A928E5 /* ExportViewModelFactory.swift */; };
2D077E472BFDCB8700FE422E /* ManualBackupChainTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D077E462BFDCB8700FE422E /* ManualBackupChainTableViewCell.swift */; };
2D141FDC2C5AE4230013D952 /* EndedReferendumProgressViewModelFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D141FDB2C5AE4230013D952 /* EndedReferendumProgressViewModelFactory.swift */; };
2D1A5F552C358E280073773D /* CustomNetworkSetupFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D1A5F542C358E280073773D /* CustomNetworkSetupFactory.swift */; };
2D1A5F572C35A8720073773D /* PartialCustomChainModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D1A5F562C35A8720073773D /* PartialCustomChainModel.swift */; };
2D1A5F5A2C35A8A30073773D /* ChainType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D1A5F592C35A8A30073773D /* ChainType.swift */; };
Expand Down Expand Up @@ -929,7 +930,7 @@
2DC075E32BF24AB400868563 /* CheckBoxIconDetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DC075E22BF24AB400868563 /* CheckBoxIconDetailsView.swift */; };
2DC075E92BF4B97900868563 /* BackupAttentionTableTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DC075E82BF4B97900868563 /* BackupAttentionTableTitleView.swift */; };
2DCC875B2C5820BA0028C3CA /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849013D424A927E2008F705E /* Logger.swift */; };
2DCC875D2C58D0D00028C3CA /* GovernanceSplitAbstainTotalVotesFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DCC875C2C58D0D00028C3CA /* GovernanceSplitAbstainTotalVotesFactory.swift */; };
2DCC875D2C58D0D00028C3CA /* GovernanceTotalVotesFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DCC875C2C58D0D00028C3CA /* GovernanceTotalVotesFactory.swift */; };
2DD9DB8D2BED08C500F68665 /* SingleTitleWalletView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DD9DB8C2BED08C500F68665 /* SingleTitleWalletView.swift */; };
2DD9DB8F2BED227E00F68665 /* WalletViewProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DD9DB8E2BED227E00F68665 /* WalletViewProtocol.swift */; };
2DE302ED2C32E4D10082FB5C /* CustomNetworkBaseInteractorError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DE302EC2C32E4D10082FB5C /* CustomNetworkBaseInteractorError.swift */; };
Expand Down Expand Up @@ -5847,6 +5848,7 @@
2D039DE72BFCA83600A928E5 /* BindableGestureRecognizer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BindableGestureRecognizer.swift; sourceTree = "<group>"; };
2D039DE92BFCAB9000A928E5 /* ExportViewModelFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExportViewModelFactory.swift; sourceTree = "<group>"; };
2D077E462BFDCB8700FE422E /* ManualBackupChainTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManualBackupChainTableViewCell.swift; sourceTree = "<group>"; };
2D141FDB2C5AE4230013D952 /* EndedReferendumProgressViewModelFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EndedReferendumProgressViewModelFactory.swift; sourceTree = "<group>"; };
2D1A5F542C358E280073773D /* CustomNetworkSetupFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomNetworkSetupFactory.swift; sourceTree = "<group>"; };
2D1A5F562C35A8720073773D /* PartialCustomChainModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PartialCustomChainModel.swift; sourceTree = "<group>"; };
2D1A5F592C35A8A30073773D /* ChainType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChainType.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -5907,7 +5909,7 @@
2DC075E82BF4B97900868563 /* BackupAttentionTableTitleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackupAttentionTableTitleView.swift; sourceTree = "<group>"; };
2DC70DB97D2E9350022A899B /* TokensManagePresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TokensManagePresenter.swift; sourceTree = "<group>"; };
2DCC87582C57DE260028C3CA /* SubstrateDataModel31.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = SubstrateDataModel31.xcdatamodel; sourceTree = "<group>"; };
2DCC875C2C58D0D00028C3CA /* GovernanceSplitAbstainTotalVotesFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceSplitAbstainTotalVotesFactory.swift; sourceTree = "<group>"; };
2DCC875C2C58D0D00028C3CA /* GovernanceTotalVotesFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GovernanceTotalVotesFactory.swift; sourceTree = "<group>"; };
2DD67B16420C6E889884BF26 /* BackupAttentionViewFactory.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = BackupAttentionViewFactory.swift; sourceTree = "<group>"; };
2DD9DB8C2BED08C500F68665 /* SingleTitleWalletView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SingleTitleWalletView.swift; sourceTree = "<group>"; };
2DD9DB8E2BED227E00F68665 /* WalletViewProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletViewProtocol.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -15234,6 +15236,7 @@
84F1D66E29066F740050F4E3 /* ReferendumVotesViewModel.swift */,
848701092907055900F2C0C3 /* ReferendumTimelineViewModelFactory.swift */,
8487010B2907AA9B00F2C0C3 /* ReferendumMetadataViewModelFactory.swift */,
2D141FDB2C5AE4230013D952 /* EndedReferendumProgressViewModelFactory.swift */,
84033054290FD745009C18E6 /* ReferendumsUnlocksViewModel.swift */,
88D42CF32977AA9600DDE01E /* ReferendumsDelegationViewModel.swift */,
8463781E2979DACB0034162B /* ReferendumsActivityViewModelFactory.swift */,
Expand Down Expand Up @@ -15312,7 +15315,7 @@
children = (
84592F49298716140001BB56 /* SubqueryVotingOperationFactory.swift */,
84592F4B298716540001BB56 /* GovernanceOffchainVotingFactory.swift */,
2DCC875C2C58D0D00028C3CA /* GovernanceSplitAbstainTotalVotesFactory.swift */,
2DCC875C2C58D0D00028C3CA /* GovernanceTotalVotesFactory.swift */,
84592F4E298716E80001BB56 /* GovernanceOffchainVoting.swift */,
84592F502987B2E80001BB56 /* SubqueryVotingResponse.swift */,
84F52402298AFB9E0026AD08 /* GovernanceOffchainVotingWrapperFactory.swift */,
Expand Down Expand Up @@ -24260,7 +24263,7 @@
844B6EC728A3B05300A8BE83 /* MessageSheetViewModel.swift in Sources */,
846CF0CD2914DC25008A96A1 /* RemoteStateCallRequest.swift in Sources */,
845D8ED32977CBD000F22133 /* SubqueryDelegatorStatsOperationFactory.swift in Sources */,
2DCC875D2C58D0D00028C3CA /* GovernanceSplitAbstainTotalVotesFactory.swift in Sources */,
2DCC875D2C58D0D00028C3CA /* GovernanceTotalVotesFactory.swift in Sources */,
84EE780227C4C2A40027357F /* DAppListFeaturedHeaderView.swift in Sources */,
845BB8D125E45F1300E5FCDC /* NominateCall.swift in Sources */,
88421057289BBA8D00306F2C /* CurrencyProtocols.swift in Sources */,
Expand Down Expand Up @@ -26015,6 +26018,7 @@
8430AAF12602306A005B1066 /* BondedState.swift in Sources */,
848F8B1D2863616E00204BC4 /* ChainsStore.swift in Sources */,
886A278829E93D2A003B269F /* CommonOperationWrapper.swift in Sources */,
2D141FDC2C5AE4230013D952 /* EndedReferendumProgressViewModelFactory.swift in Sources */,
0C8AF7B22B36A88100005AC9 /* Pdc20Nft.swift in Sources */,
84333BD7285682EC00C76A4F /* ValidatorsSelectionParams.swift in Sources */,
84C3F77B2601F08B00D47501 /* NominationViewModel.swift in Sources */,
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import Foundation
import Operation_iOS
import BigInt

struct ReferendumVotingAmount {
let aye: BigUInt
let nay: BigUInt
let abstain: BigUInt
}

protocol GovernanceTotalVotesFactoryProtocol {
func createOperation(
referendumId: ReferendumIdLocal,
votersType: ReferendumVotersType?
) -> BaseOperation<ReferendumVotingAmount>
}

final class GovernanceTotalVotesFactory: SubqueryBaseOperationFactory {
private func prepareSplitAbstainVotesQuery(referendumId: ReferendumIdLocal) -> String {
"""
{
castingVotings(
filter: {
referendumId: { equalTo: "\(referendumId)" },
splitAbstainVote: { isNull: false }
}
) {
nodes {
voter
referendumId
splitAbstainVote
}
}
}
"""
}

private func prepareStandardVotesQuery(referendumId: ReferendumIdLocal, isAye: Bool) -> String {
"""
{
castingVotings (filter: {
referendumId: {equalTo: "\(referendumId)"},
or: [
{splitVote: { isNull: false }},
{splitAbstainVote: {isNull: false}},
{standardVote: { contains: { aye: \(isAye)}}}
]
}) {
nodes {
referendumId
standardVote
splitVote
splitAbstainVote
voters
delegatorVotes {
nodes {
delegator
vote
}
}
}
}
}
"""
}

private func prepareAllVotesQuery(referendumId: ReferendumIdLocal) -> String {
"""
{
castingVotings(
filter: {
referendumId: { equalTo: "\(referendumId)" }
}
) {
nodes {
referendumId
voter
splitVote
splitAbstainVote
standardVote
delegatorVotes {
nodes {
delegator
vote
}
}
}
}
}
"""
}
}

extension GovernanceTotalVotesFactory: GovernanceTotalVotesFactoryProtocol {
func createOperation(referendumId: ReferendumIdLocal, votersType: ReferendumVotersType?) -> BaseOperation<ReferendumVotingAmount> {
let query = if let votersType {
switch votersType {
case .ayes:
prepareStandardVotesQuery(referendumId: referendumId, isAye: true)
case .nays:
prepareStandardVotesQuery(referendumId: referendumId, isAye: false)
case .abstains:
prepareSplitAbstainVotesQuery(referendumId: referendumId)
}

} else {
prepareAllVotesQuery(referendumId: referendumId)
}

let operation = createOperation(
for: query
) { [weak self] (response: SubqueryVotingResponse.ReferendumVotesResponse) -> ReferendumVotingAmount in
response.castingVotings.nodes
.compactMap { ReferendumVoterLocal(from: $0) }
.reduce(
ReferendumVotingAmount(
aye: 0,
nay: 0,
abstain: 0
)
) { self?.sum($0, with: $1) ?? $0 }
}

return operation
}

private func sum(
_ amount: ReferendumVotingAmount,
with voter: ReferendumVoterLocal
) -> ReferendumVotingAmount {
var accAye = amount.aye
var accNay = amount.nay
var accAbstain = amount.abstain

switch voter.vote {
case .split:
accAye += voter.vote.ayes
accNay += voter.vote.nays
case .splitAbstain:
accAbstain += voter.vote.abstains
case let .standard(model) where model.vote.aye:
accAye += (voter.vote.ayes + voter.delegatorsVotes)
case let .standard(model):
accNay += (voter.vote.nays + voter.delegatorsVotes)
}

return ReferendumVotingAmount(
aye: accAye,
nay: accNay,
abstain: accAbstain
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ final class ReferendumDetailsInteractor {
let generalLocalSubscriptionFactory: GeneralStorageSubscriptionFactoryProtocol
let referendumsSubscriptionFactory: GovernanceSubscriptionFactoryProtocol
let govMetadataLocalSubscriptionFactory: GovMetadataLocalSubscriptionFactoryProtocol
let totalAbstainVotesFactory: GovernanceSplitAbstainTotalVotesFactoryProtocol?
let totalVotesFactory: GovernanceTotalVotesFactoryProtocol?
let dAppsProvider: AnySingleValueProvider<GovernanceDAppList>
let operationQueue: OperationQueue

Expand All @@ -32,6 +32,7 @@ final class ReferendumDetailsInteractor {
private var actionDetailsCancellable = CancellableCallStore()
private var blockTimeCancellable = CancellableCallStore()
private var abstainsFetchCancellable = CancellableCallStore()
private var allVotesFetchCancellable = CancellableCallStore()

var chain: ChainModel {
option.chain
Expand All @@ -51,7 +52,7 @@ final class ReferendumDetailsInteractor {
generalLocalSubscriptionFactory: GeneralStorageSubscriptionFactoryProtocol,
govMetadataLocalSubscriptionFactory: GovMetadataLocalSubscriptionFactoryProtocol,
referendumsSubscriptionFactory: GovernanceSubscriptionFactoryProtocol,
totalAbstainVotesFactory: GovernanceSplitAbstainTotalVotesFactoryProtocol?,
totalVotesFactory: GovernanceTotalVotesFactoryProtocol?,
dAppsProvider: AnySingleValueProvider<GovernanceDAppList>,
currencyManager: CurrencyManagerProtocol,
operationQueue: OperationQueue
Expand All @@ -69,7 +70,7 @@ final class ReferendumDetailsInteractor {
self.blockTimeFactory = blockTimeFactory
self.govMetadataLocalSubscriptionFactory = govMetadataLocalSubscriptionFactory
self.referendumsSubscriptionFactory = referendumsSubscriptionFactory
self.totalAbstainVotesFactory = totalAbstainVotesFactory
self.totalVotesFactory = totalVotesFactory
self.dAppsProvider = dAppsProvider
self.operationQueue = operationQueue
self.currencyManager = currencyManager
Expand All @@ -80,6 +81,7 @@ final class ReferendumDetailsInteractor {
actionDetailsCancellable.cancel()
blockTimeCancellable.cancel()
abstainsFetchCancellable.cancel()
allVotesFetchCancellable.cancel()

referendumsSubscriptionFactory.unsubscribeFromReferendum(self, referendumIndex: referendum.index)

Expand All @@ -101,7 +103,11 @@ final class ReferendumDetailsInteractor {
self?.referendum = referendum
self?.presenter?.didReceiveReferendum(referendum)

self?.provideAbstains()
if referendum.state.completed {
self?.provideAllVotes()
} else {
self?.provideAbstains()
}
}
case let .failure(error):
self?.presenter?.didReceiveError(.referendumFailed(error))
Expand Down Expand Up @@ -279,12 +285,15 @@ final class ReferendumDetailsInteractor {
private func provideAbstains() {
guard
!abstainsFetchCancellable.hasCall,
let totalAbstainVotesFactory
let totalVotesFactory
else {
return
}

let operation = totalAbstainVotesFactory.createOperation(referendumId: referendum.index)
let operation = totalVotesFactory.createOperation(
referendumId: referendum.index,
votersType: .abstains
)

execute(
operation: operation,
Expand All @@ -294,7 +303,35 @@ final class ReferendumDetailsInteractor {
) { [weak self] result in
switch result {
case let .success(amount):
self?.presenter?.didReceiveAbstainsTotalAmount(amount)
self?.presenter?.didReceiveVotingAmount(amount)
case let .failure(error):
self?.presenter?.didReceiveError(.accountVotesFailed(error))
}
}
}

private func provideAllVotes() {
guard
!allVotesFetchCancellable.hasCall,
let totalVotesFactory
else {
return
}

let operation = totalVotesFactory.createOperation(
referendumId: referendum.index,
votersType: nil
)

execute(
operation: operation,
inOperationQueue: operationQueue,
backingCallIn: allVotesFetchCancellable,
runningCallbackIn: .main
) { [weak self] result in
switch result {
case let .success(amount):
self?.presenter?.didReceiveVotingAmount(amount)
case let .failure(error):
self?.presenter?.didReceiveError(.accountVotesFailed(error))
}
Expand Down
Loading

0 comments on commit f882465

Please sign in to comment.