Skip to content
Open
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
21 changes: 0 additions & 21 deletions src/helpers/entityValue.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import { jsonRpcRequest } from './utils';

type Vote = {
vp_by_strategy: number[];
};

type Proposal = {
network: string;
strategies: any[];
Expand All @@ -28,20 +24,3 @@ export async function getVpValueByStrategy(proposal: Proposal): Promise<number[]

return result.map(value => parseFloat(value.toFixed(STRATEGIES_VALUE_PRECISION)));
}

/**
* Calculates the total vote value based on the voting power and the proposal's value per strategy.
* @returns The total vote value, in the currency unit specified by the proposal's vp_value_by_strategy values
**/
export function getVoteValue(proposal: { vp_value_by_strategy: number[] }, vote: Vote): number {
if (!proposal.vp_value_by_strategy.length) return 0;

if (proposal.vp_value_by_strategy.length !== vote.vp_by_strategy.length) {
throw new Error('invalid data to compute vote value');
}

return proposal.vp_value_by_strategy.reduce(
(sum, value, index) => sum + value * vote.vp_by_strategy[index],
0
);
}
94 changes: 94 additions & 0 deletions src/helpers/votesVpValue.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { capture } from '@snapshot-labs/snapshot-sentry';
import snapshot from '@snapshot-labs/snapshot.js';
import { z } from 'zod';
import db from './mysql';
import { CB } from '../constants';

type Datum = {
id: string;
vpState: string;
vpByStrategy: number[];
vpValueByStrategy: number[];
};

const REFRESH_INTERVAL = 10 * 1000;
const BATCH_SIZE = 100;

const datumSchema = z
.object({
id: z.string(),
vpState: z.string(),
vpValueByStrategy: z.array(z.number().finite()),
vpByStrategy: z.array(z.number().finite())
})
.refine(data => data.vpValueByStrategy.length === data.vpByStrategy.length, {
message: 'Array length mismatch: vpValueByStrategy and vpByStrategy must have the same length'
});

async function getVotes(): Promise<Datum[]> {
const query = `
SELECT votes.id, votes.vp_state, votes.vp_by_strategy, proposals.vp_value_by_strategy
FROM votes
JOIN proposals ON votes.proposal = proposals.id
WHERE proposals.cb IN (?) AND votes.cb = ?
ORDER BY votes.created ASC
LIMIT ?`;
const results = await db.queryAsync(query, [
[CB.PENDING_FINAL, CB.PENDING_COMPUTE, CB.FINAL],
CB.PENDING_COMPUTE,
BATCH_SIZE
]);

return results.map((r: any) => {
return {
id: r.id,
vpState: r.vp_state,
vpValueByStrategy: JSON.parse(r.vp_value_by_strategy),
vpByStrategy: JSON.parse(r.vp_by_strategy)
};
});
}

async function refreshVotesVpValues(data: Datum[]) {
const query: string[] = [];
const params: any[] = [];

for (const datum of data) {
query.push('UPDATE votes SET vp_value = ?, cb = ? WHERE id = ? LIMIT 1');

try {
const validatedDatum = datumSchema.parse(datum);
const value = validatedDatum.vpValueByStrategy.reduce(
(sum, value, index) => sum + value * validatedDatum.vpByStrategy[index],
0
);

params.push(
value,
validatedDatum.vpState === 'final' ? CB.FINAL : CB.PENDING_FINAL,
validatedDatum.id
);
} catch (e) {
capture(e);
params.push(0, CB.INELIGIBLE, datum.id);
}
}

if (query.length) {
await db.queryAsync(query.join(';'), params);
}
}

export default async function run() {
while (true) {
const votes = await getVotes();

if (votes.length) {
await refreshVotesVpValues(votes);
}

if (votes.length < BATCH_SIZE) {
await snapshot.utils.sleep(REFRESH_INTERVAL);
}
}
}
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
stop as stopStrategies
} from './helpers/strategies';
import { trackTurboStatuses } from './helpers/turbo';
import refreshVotesVpValue from './helpers/votesVpValue';

const app = express();

Expand All @@ -24,6 +25,7 @@ async function startServer() {
refreshModeration();
refreshProposalsVpValue();
refreshProposalsScoresValue();
refreshVotesVpValue();

await initializeStrategies();
refreshStrategies();
Expand Down
5 changes: 2 additions & 3 deletions src/scores.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import snapshot from '@snapshot-labs/snapshot.js';
import { CB } from './constants';
import { getVoteValue } from './helpers/entityValue';
import log from './helpers/log';
import db from './helpers/mysql';
import { getDecryptionKey } from './helpers/shutter';
Expand Down Expand Up @@ -62,12 +61,13 @@ async function updateVotesVp(votes: any[], vpState: string, proposalId: string)
let query = '';
votesInPage.forEach((vote: any) => {
query += `UPDATE votes
SET vp = ?, vp_by_strategy = ?, vp_state = ?, vp_value = ?
SET vp = ?, vp_by_strategy = ?, vp_state = ?, vp_value = ?, cb = ?
WHERE id = ? AND proposal = ? LIMIT 1; `;
params.push(vote.balance);
params.push(JSON.stringify(vote.scores));
params.push(vpState);
params.push(vote.vp_value);
params.push(CB.PENDING_COMPUTE);
params.push(vote.id);
params.push(proposalId);
});
Expand Down Expand Up @@ -165,7 +165,6 @@ export async function updateProposalAndVotes(proposalId: string, force = false)
votes = votes.map((vote: any) => {
vote.scores = proposal.strategies.map((strategy, i) => scores[i][vote.voter] || 0);
vote.balance = vote.scores.reduce((a, b: any) => a + b, 0);
vote.vp_value = getVoteValue(proposal, vote);
return vote;
});
}
Expand Down
71 changes: 0 additions & 71 deletions test/unit/helpers/entityValue.test.ts

This file was deleted.