Skip to content

Commit

Permalink
Improves results calculation and exports
Browse files Browse the repository at this point in the history
utils function.

Signed-off-by: emmdim <[email protected]>
  • Loading branch information
emmdim committed Sep 28, 2023
1 parent b6f7621 commit fa19c40
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 61 deletions.
1 change: 1 addition & 0 deletions packages/js-client/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './client';
export * from './context';
export * from './types';
export * from './internal/utils';
25 changes: 15 additions & 10 deletions packages/js-client/src/internal/modules/decoding.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,29 @@
import { InterfaceParams, getFunctionFragment } from "@aragon/sdk-client-common";
import { OffchainVotingClientCore } from "../core";
import { IOffchainVotingClientDecoding } from "../interfaces";
import { AVAILABLE_FUNCTION_SIGNATURES } from "../constants";
import { bytesToHex } from "@aragon/sdk-common";
import { AVAILABLE_FUNCTION_SIGNATURES } from '../constants';
import { OffchainVotingClientCore } from '../core';
import { IOffchainVotingClientDecoding } from '../interfaces';
import {
InterfaceParams,
getFunctionFragment,
} from '@aragon/sdk-client-common';
import { bytesToHex } from '@aragon/sdk-common';

export class OffchainVotingClientDecoding extends OffchainVotingClientCore
implements IOffchainVotingClientDecoding {
export class OffchainVotingClientDecoding
extends OffchainVotingClientCore
implements IOffchainVotingClientDecoding
{
// add your action decoders here
/**
/**
* Returns the decoded function info given the encoded data of an action
*
* @param {Uint8Array} data
* @return {*} {(InterfaceParams | null)}
* @memberof OffchainVotingClientDecoding
*/
public findInterface(data: Uint8Array): InterfaceParams | null {
public findInterface(data: Uint8Array): InterfaceParams | null {
try {
const func = getFunctionFragment(data, AVAILABLE_FUNCTION_SIGNATURES);
return {
id: func.format("minimal"),
id: func.format('minimal'),
functionName: func.name,
hash: bytesToHex(data).substring(0, 10),
};
Expand Down
105 changes: 58 additions & 47 deletions packages/js-client/src/internal/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ import {
VoteOption,
ProposalFromSC,
GaslessProposalParametersStruct,
InvalidResults,
GaslessVotingProposalFromSC,
} from '../types';
import { MintTokenParams, VoteValues } from '@aragon/sdk-client';
import {
MintTokenParams,
TokenVotingProposalResult,
VoteValues,
} from '@aragon/sdk-client';
import {
DaoAction,
EMPTY_PROPOSAL_METADATA_LINK,
Expand All @@ -23,7 +26,12 @@ import { AddressZero } from '@ethersproject/constants';
import { Contract } from '@ethersproject/contracts';
import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers';
import { VocdoniVoting } from '@vocdoni/offchain-voting-ethers';
import { ElectionStatus, PublishedElection } from '@vocdoni/sdk';
import {
ElectionStatus,
IChoice,
IQuestion,
PublishedElection,
} from '@vocdoni/sdk';

// export function votingModeFromContracts(votingMode: number): VotingMode {
// switch (votingMode) {
Expand Down Expand Up @@ -221,66 +229,62 @@ export function toGaslessVotingProposal(
};
}

function vochainVoteResultsToProposal(results: string[][]): {
[key: string]: number;
} {
let parsedResults: { [key: string]: number } = {};
Object.keys(VoteValues)
.filter((key) => isNaN(Number(key)))
.forEach((key, i) => {
parsedResults[key] = Number(results[i]);
});
return parsedResults;
export function vochainVoteResultsToProposal(
questions: IQuestion[]
): TokenVotingProposalResult {
let parsedResults: { [key: string]: bigint } = {};
questions[0].choices.map((choice: IChoice) => {
if (VoteValues[choice.title.default.toUpperCase() as any] !== undefined) {
parsedResults[choice.title.default.toLowerCase()] =
choice.results !== undefined ? BigInt(choice.results) : BigInt(0);
}
});
return parsedResults as TokenVotingProposalResult;
}

function hasSupportThreshold(
yes: number,
no: number,
export function hasSupportThreshold(
yes: bigint,
no: bigint,
supportThreshold: number
): boolean {
return (1 - supportThreshold) * yes > supportThreshold * no;
return (
(BigInt(1) - BigInt(supportThreshold)) * yes > BigInt(supportThreshold) * no
);
}

function hasMinParticipation(
yes: number,
no: number,
abstain: number,
totalVotes: number,
export function hasMinParticipation(
yes: bigint,
no: bigint,
abstain: bigint,
minParticipation: number
): boolean {
return yes + no + abstain > minParticipation * totalVotes;
// const calculatedTotal = Object.values(results)
// // .map((x) => results[x])
// .reduce((a, b) => a + b);
// // if (calculatedTotal != totalVotes) throw new InvalidResults();

return yes + no + abstain > BigInt(minParticipation) * (yes + no + abstain);
}

function isProposalApproved(
results: string[][],
totalVotes: number,
export function isProposalApproved(
results: TokenVotingProposalResult,
supportThreshold: number,
minParticipation: number
): boolean {
const parsedResults = vochainVoteResultsToProposal(results);
const calculatedTotal = Object.keys(VoteValues)
.filter((key) => isNaN(Number(key)))
.map((x) => parsedResults[x])
.reduce((a, b) => a + b);
if (calculatedTotal != totalVotes) throw new InvalidResults();

if (!results) return false;
return (
hasSupportThreshold(
parsedResults[VoteValues.YES.toString()],
parsedResults[VoteValues.NO.toString()],
supportThreshold
) &&
hasSupportThreshold(results.yes, results.no, supportThreshold) &&
hasMinParticipation(
parsedResults[VoteValues.YES.toString()],
parsedResults[VoteValues.NO.toString()],
parsedResults[VoteValues.ABSTAIN.toString()],
totalVotes,
results.yes,
results.no,
results.abstain,
minParticipation
)
);
}

export function vochainStatusToProposalStatus(
parsedResults: TokenVotingProposalResult,
vochainProposal: PublishedElection,
executed: boolean,
supportThreshold: number,
Expand All @@ -296,8 +300,7 @@ export function vochainStatusToProposalStatus(
if (executed) return ProposalStatus.EXECUTED;
else if (vochainProposal.finalResults) {
return isProposalApproved(
vochainProposal.results,
vochainProposal.voteCount,
parsedResults,
supportThreshold,
minParticipation
)
Expand Down Expand Up @@ -331,6 +334,7 @@ export function toNewProposal(
metadata.title = vochainProposal.title.default;
metadata.description =
vochainProposal.description?.default || metadata.description;
const result = vochainVoteResultsToProposal(vochainProposal.questions);
return {
id: `0x${SCproposalID.toString()}`, // string;
dao: {
Expand All @@ -344,6 +348,7 @@ export function toNewProposal(
creationDate: vochainProposal.creationTime, //Date;
actions: SCProposal.actions, //DaoAction[];
status: vochainStatusToProposalStatus(
result,
vochainProposal,
SCProposal.executed,
settings.supportThreshold,
Expand All @@ -360,8 +365,14 @@ export function toNewProposal(
allowFailureMap: SCProposal.allowFailureMap, //number;
tally: SCProposal.tally, //number[][];
settings,
vochainMetadata: vochainProposal,
tallyVochain: vochainProposal.results.map((x) => x.map((y) => BigInt(y))),
tallyVochainFinal: vochainProposal.finalResults,
vochain: {
metadata: vochainProposal,
tally: {
final: vochainProposal.finalResults,
value: vochainProposal.results[0].map((y) => BigInt(y)),
parsed: result,
},
},
totalVotingWeight: Object.values(result).reduce((a, b) => a + b),
} as GaslessVotingProposal;
}
17 changes: 13 additions & 4 deletions packages/js-client/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { IDAO } from '@aragon/osx-ethers';
import { CreateProposalBaseParams } from '@aragon/sdk-client';
import {
CreateProposalBaseParams,
TokenVotingProposalResult,
} from '@aragon/sdk-client';
import {
ContextState,
OverriddenState,
Expand Down Expand Up @@ -170,9 +173,15 @@ export type GaslessVotingProposal = ProposalBase & {
allowFailureMap: number;
tally: number[][];
settings: GaslessPluginVotingSettings;
vochainMetadata: PublishedElection;
tallyVochain: number[][];
tallyVochainFinal: boolean;
vochain: {
metadata: PublishedElection;
tally: {
final: boolean;
value: bigint[];
parsed: TokenVotingProposalResult;
};
};
totalVotingWeight: bigint;
};

export type CreateGasslessProposalParams = CreateProposalBaseParams &
Expand Down

0 comments on commit fa19c40

Please sign in to comment.