Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@snapshot-labs/snapshot.js",
"version": "0.12.52",
"version": "0.12.53",
"repository": "snapshot-labs/snapshot.js",
"license": "MIT",
"main": "dist/snapshot.cjs.js",
Expand Down
99 changes: 66 additions & 33 deletions src/voting/__snapshots__/copeland.spec.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,27 @@

exports[`Partial ranking 1`] = `
[
4,
6,
2,
1.6666666666666665,
2.5,
0.8333333333333333,
0,
]
`;

exports[`getScores 1`] = `
[
5,
5,
2,
1.6666666666666667,
1.6666666666666667,
0.6666666666666666,
0,
]
`;

exports[`getScores 2`] = `
[
5,
5,
2,
1.6666666666666667,
1.6666666666666667,
0.6666666666666666,
0,
]
`;
Expand All @@ -45,16 +45,32 @@ exports[`getScores 4`] = `
]
`;

exports[`getScores with 0 votes 1`] = `
[
0,
0,
0,
]
`;

exports[`getScores with mixed voting powers 1`] = `
[
668334.3333333333,
334167.1666666666,
0,
]
`;

exports[`getScoresByStrategy 1`] = `
[
[
5,
1.6666666666666667,
],
[
5,
1.6666666666666667,
],
[
2,
0.6666666666666666,
],
[
0,
Expand All @@ -65,13 +81,13 @@ exports[`getScoresByStrategy 1`] = `
exports[`getScoresByStrategy 2`] = `
[
[
5,
1.6666666666666667,
],
[
5,
1.6666666666666667,
],
[
2,
0.6666666666666666,
],
[
0,
Expand All @@ -82,19 +98,19 @@ exports[`getScoresByStrategy 2`] = `
exports[`getScoresByStrategy 3`] = `
[
[
5,
5,
5,
1.6666666666666667,
1.6666666666666667,
1.6666666666666667,
],
[
5,
5,
5,
1.6666666666666667,
1.6666666666666667,
1.6666666666666667,
],
[
2,
2,
2,
0.6666666666666666,
0.6666666666666666,
0.6666666666666666,
],
[
0,
Expand All @@ -107,19 +123,19 @@ exports[`getScoresByStrategy 3`] = `
exports[`getScoresByStrategy 4`] = `
[
[
5,
5,
5,
1.6666666666666667,
1.6666666666666667,
1.6666666666666667,
],
[
5,
5,
5,
1.6666666666666667,
1.6666666666666667,
1.6666666666666667,
],
[
2,
2,
2,
0.6666666666666666,
0.6666666666666666,
0.6666666666666666,
],
[
0,
Expand All @@ -129,6 +145,23 @@ exports[`getScoresByStrategy 4`] = `
]
`;

exports[`getScoresByStrategy normalizes correctly 1`] = `
[
[
7.5,
22.5,
],
[
7.5,
22.5,
],
[
7.5,
22.5,
],
]
`;

exports[`getScoresTotal 1`] = `4`;

exports[`getScoresTotal 2`] = `12`;
101 changes: 101 additions & 0 deletions src/voting/copeland.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,44 @@ const votesWithInvalidChoices2 = () => {
return [...invalidVotes, ...example2().votes];
};

// Helper function to create example with decimal voting powers
const exampleWithDecimals = () => {
const proposal = {
choices: ['Alice', 'Bob', 'Carol']
};
const strategies = [{ name: 'ticket', network: '1', params: {} }];
const votes = [
{ choice: [1, 2, 3], balance: 1.5, scores: [1.5] },
{ choice: [2, 1, 3], balance: 2.75, scores: [2.75] },
{ choice: [3, 2, 1], balance: 0.25, scores: [0.25] }
];

return {
proposal,
strategies,
votes
};
};

// Helper function to create example with high voting powers
const exampleWithHighPowers = () => {
const proposal = {
choices: ['Alice', 'Bob', 'Carol']
};
const strategies = [{ name: 'ticket', network: '1', params: {} }];
const votes = [
{ choice: [1, 2, 3], balance: 1000000, scores: [1000000] },
{ choice: [2, 1, 3], balance: 2500000, scores: [2500000] },
{ choice: [3, 2, 1], balance: 1500000, scores: [1500000] }
];

return {
proposal,
strategies,
votes
};
};

// Test cases for getScores method
test.each([
[example.proposal, example.votes, example.strategies],
Expand Down Expand Up @@ -81,6 +119,42 @@ test.each([
expect(copeland.getScoresByStrategy()).toMatchSnapshot();
});

// Add test for verifying strategy normalization
test('getScoresByStrategy normalizes correctly', () => {
const proposal = {
choices: ['Alice', 'Bob', 'Carol']
};
const strategies = [
{ name: 'ticket', network: '1', params: {} },
{ name: 'erc20-balance-of', network: '1', params: {} }
];
const votes = [
{ choice: [1, 2, 3], balance: 10, scores: [5, 15] },
{ choice: [2, 3, 1], balance: 20, scores: [10, 30] },
{ choice: [3, 1, 2], balance: 15, scores: [7.5, 22.5] }
];

const copeland = new CopelandVoting(proposal, votes, strategies, [1]);

const scoresByStrategy = copeland.getScoresByStrategy();
expect(scoresByStrategy).toMatchSnapshot();

// Verify totals per strategy
const strategyTotals = [22.5, 67.5]; // Sum of all votes per strategy

// Sum the scores for each strategy
const strategyTotalResults = [0, 0];
for (let i = 0; i < strategies.length; i++) {
for (let j = 0; j < proposal.choices.length; j++) {
strategyTotalResults[i] += scoresByStrategy[j][i];
}
}

// Verify total voting power is preserved for each strategy
expect(strategyTotalResults[0]).toBeCloseTo(strategyTotals[0], 5);
expect(strategyTotalResults[1]).toBeCloseTo(strategyTotals[1], 5);
});

// Test cases for getScoresTotal method
test.each([
[example.proposal, example.votes, example.strategies],
Expand Down Expand Up @@ -127,3 +201,30 @@ test('Partial ranking', () => {
);
expect(copeland.getScores()).toMatchSnapshot();
});

test('getScores with mixed voting powers', () => {
const proposal = {
choices: ['Alice', 'Bob', 'Carol']
};
const votes = [
{ choice: [1, 2, 3], balance: 1000000.75, scores: [1000000.75] },
{ choice: [2, 3, 1], balance: 0.25, scores: [0.25] },
{ choice: [3, 1, 2], balance: 2500.5, scores: [2500.5] }
];
const copeland = new CopelandVoting(proposal, votes, example.strategies, [1]);
const scores = copeland.getScores();
expect(scores).toMatchSnapshot();
// Verify total voting power is preserved
expect(scores.reduce((a, b) => a + b)).toBeCloseTo(1002501.5, 5);
});

test('getScores with 0 votes', () => {
const proposal = {
choices: ['Alice', 'Bob', 'Carol']
};
const votes = [];
const copeland = new CopelandVoting(proposal, votes, example.strategies, [1]);
const scores = copeland.getScores();
expect(scores).toMatchSnapshot();
// Verify total voting power is preserved
});
Loading