Skip to content
This repository has been archived by the owner on Sep 28, 2022. It is now read-only.

Commit

Permalink
add function for plurality tally (#294)
Browse files Browse the repository at this point in the history
* add function for plurality tally

* test: Add tests for plurality vote and change the output

* Remove TODO

* Get all votes then sum support

* Fix bignumber sort

* fix tests

Co-authored-by: rafinskipg <[email protected]>
Co-authored-by: Adam Goth <[email protected]>
  • Loading branch information
3 people authored Oct 12, 2021
1 parent 24a83be commit fd9e662
Show file tree
Hide file tree
Showing 3 changed files with 171 additions and 1 deletion.
55 changes: 55 additions & 0 deletions packages/dai-plugin-governance/src/GovPollingService.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { PrivateService } from '@makerdao/services-core';
import BigNumber from 'bignumber.js';
import { POLLING, BATCH_POLLING } from './utils/constants';
import { MKR } from './utils/constants';
import { fromBuffer, toBuffer, paddedArray } from './utils/helpers';
Expand Down Expand Up @@ -310,6 +311,60 @@ export default class GovPollingService extends PrivateService {
return votes;
}

async getTallyPlurality(pollId) {
const poll = await this._getPoll(pollId);
if (!poll) return null;

const endUnix = Math.floor(poll.endDate / 1000);
const currentVotes = await this.get(
'govQueryApi'
).getMkrSupportRankedChoice(pollId, endUnix);

const numVoters = currentVotes.length;

const resultsObject = currentVotes.reduce((acc, cur) => {
if (acc[cur.optionIdRaw]) {
acc[cur.optionIdRaw] = new BigNumber(acc[cur.optionIdRaw]).plus(
cur.mkrSupport
);
} else {
acc[cur.optionIdRaw] = new BigNumber(cur.mkrSupport);
}
return acc;
}, {});

const summedSupport = Object.keys(resultsObject).map(option => ({
optionId: option,
mkrSupport: resultsObject[option]
}));

const sorted = summedSupport.sort((prev, next) =>
prev.mkrSupport.gt(next.mkrSupport) ? -1 : 1
);

const winner = (sorted[0] ? sorted[0].optionId : 0).toString();

const totalMkrParticipation = summedSupport.reduce(
(acc, cur) => new BigNumber(cur.mkrSupport || 0).plus(acc),
new BigNumber(0)
);

const options = summedSupport.reduce((a, v) => {
a[v.optionId] = {
mkrSupport: new BigNumber(v.mkrSupport || 0),
winner: v.optionId === winner
};
return a;
}, {});

return {
winner,
totalMkrParticipation,
numVoters,
options
};
}

async getTallyRankedChoiceIrv(pollId) {
const poll = await this._getPoll(pollId);
if (!poll) return {};
Expand Down
64 changes: 63 additions & 1 deletion packages/dai-plugin-governance/test/GovPollingService.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ import {
dummyBallotDontMoveToEliminated,
dummyBallotDontMoveToEliminatedExpect,
dummyBallotStopWhenOneRemains,
dummyBallotStopWhenOneRemainsExpect
dummyBallotStopWhenOneRemainsExpect,
dummyMkrGetMkrSupportRCForPluralityData,
dummyMkrGetMkrSupportRCForPluralityDataAdjusted
} from './fixtures';
import { MKR } from '../src/utils/constants';

Expand Down Expand Up @@ -328,6 +330,66 @@ test('should correctly decode ranked choice options from event logs', () => {
expect(decodedOptions).toEqual(expectedOptions);
});

test('plurality tally', async () => {
govQueryApiService.getMkrSupportRankedChoice = jest.fn(
() => dummyMkrGetMkrSupportRCForPluralityData
);
govPollingService._getPoll = jest.fn(() => ({
endDate: 123
}));
const tally = await govPollingService.getTallyPlurality();

const expectedResult = {
winner: '1',
totalMkrParticipation: '809',
numVoters: 5,
options: {
'0': {
mkrSupport: '109',
winner: false
},
'1': {
mkrSupport: '700',
winner: true
}
}
};

expect(JSON.parse(JSON.stringify(tally))).toEqual(expectedResult);
});

test('plurality tally with adjusted votes', async () => {
govQueryApiService.getMkrSupportRankedChoice = jest.fn(
() => dummyMkrGetMkrSupportRCForPluralityDataAdjusted
);
govPollingService._getPoll = jest.fn(() => ({
endDate: 123
}));
const tally = await govPollingService.getTallyPlurality();

const expectedResult = {
winner: '2',
totalMkrParticipation: '2041',
numVoters: 7,
options: {
'0': {
mkrSupport: '109',
winner: false
},
'1': {
mkrSupport: '700',
winner: false
},
'2': {
mkrSupport: '1232',
winner: true
}
}
};

expect(JSON.parse(JSON.stringify(tally))).toEqual(expectedResult);
});

// IRV algo tests

test('ranked choice tally with majority', async () => {
Expand Down
53 changes: 53 additions & 0 deletions packages/dai-plugin-governance/test/fixtures.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,59 @@ export const dummyMkrSupportData = [
}
];

export const dummyMkrGetMkrSupportRCForPluralityData = [
{
optionIdRaw: '1',
mkrSupport: '40'
},
{
optionIdRaw: '1',
mkrSupport: '60'
},
{
optionIdRaw: '0',
mkrSupport: '77'
},
{
optionIdRaw: '0',
mkrSupport: '32'
},
{
optionIdRaw: '1',
mkrSupport: '600'
}
];
export const dummyMkrGetMkrSupportRCForPluralityDataAdjusted = [
{
optionIdRaw: '1',
mkrSupport: '40'
},
{
optionIdRaw: '1',
mkrSupport: '60'
},
{
optionIdRaw: '0',
mkrSupport: '77'
},
{
optionIdRaw: '0',
mkrSupport: '32'
},
{
optionIdRaw: '1',
mkrSupport: '600'
},
{
optionIdRaw: '2',
mkrSupport: '32'
},
{
optionIdRaw: '2',
mkrSupport: '1200'
}
];

export const dummyAllPollsData = [
{
creator: '0xeda95d1bdb60f901986f43459151b6d1c734b8a2',
Expand Down

0 comments on commit fd9e662

Please sign in to comment.