Skip to content
This repository was archived by the owner on Aug 22, 2025. It is now read-only.

Commit 144fade

Browse files
committed
fix: only process addresses from relevant protocols
1 parent cd892cb commit 144fade

7 files changed

Lines changed: 419 additions & 116 deletions

File tree

src/utils.ts

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -122,10 +122,7 @@ function validateProtocols(protocols: Protocol[]): void {
122122
* Formats addresses according to the specified blockchain protocols.
123123
*
124124
* This function takes a list of addresses and formats them according to the provided
125-
* protocols. It prioritizes EVM formatting when multiple protocols are specified and
126-
* an address is valid for both. If EVM formatting fails but Starknet is supported,
127-
* it falls back to Starknet formatting. Throws an error if any address cannot be
128-
* formatted according to the specified protocols.
125+
* protocols.
129126
*
130127
* @param addresses - Array of blockchain addresses to format
131128
* @param protocols - Array of protocol names to validate against. Defaults to ['evm'].
@@ -140,20 +137,14 @@ export function getFormattedAddressesByProtocol(
140137
validateProtocols(protocols);
141138

142139
return addresses.map((address) => {
143-
if (protocols.includes('evm')) {
140+
if (protocols.includes('evm') && address.length === 42) {
144141
try {
145142
return snapshot.utils.getFormattedAddress(address, 'evm');
146-
} catch (e) {
147-
// Continue to starknet if evm formatting fails and starknet is supported
148-
}
149-
}
150-
151-
if (protocols.includes('starknet')) {
143+
} catch (e) {}
144+
} else if (protocols.includes('starknet') && address.length === 66) {
152145
try {
153146
return snapshot.utils.getFormattedAddress(address, 'starknet');
154-
} catch (e) {
155-
// Address format not supported by any protocol
156-
}
147+
} catch (e) {}
157148
}
158149

159150
throw new Error(
@@ -162,6 +153,46 @@ export function getFormattedAddressesByProtocol(
162153
});
163154
}
164155

156+
/**
157+
* Filters addresses by the specified protocols.
158+
*
159+
* This function takes a list of addresses and filters them based on the provided
160+
* protocols. It checks if each address matches the expected format for EVM or
161+
* Starknet protocols
162+
*
163+
* This function DOES NOT format/validate the addresses, and may return invalid addresses
164+
*
165+
* @param addresses - Array of addresses to filter
166+
* @param protocols - Array of protocol names to validate against. Defaults to ['evm'].
167+
* Valid protocols are 'evm' and 'starknet'.
168+
*
169+
* @returns Array of addresses that match the specified protocols
170+
*/
171+
export function getAddressesByProtocol(
172+
addresses: string[],
173+
protocols: Protocol[] = ['evm']
174+
): string[] {
175+
validateProtocols(protocols);
176+
177+
return addresses.filter((address) => {
178+
if (protocols.includes('evm') && /^0x[a-fA-F0-9]{40}$/.test(address)) {
179+
return true;
180+
}
181+
if (protocols.includes('starknet') && /^0x[a-fA-F0-9]{64}$/.test(address)) {
182+
return true;
183+
}
184+
return false;
185+
});
186+
}
187+
188+
export function validateAddress(address: string): void {
189+
try {
190+
getFormattedAddressesByProtocol([address], ['evm', 'starknet']);
191+
} catch {
192+
throw new Error('invalid address');
193+
}
194+
}
195+
165196
export const {
166197
multicall,
167198
Multicaller,
@@ -181,6 +212,7 @@ export default {
181212
getScoresDirect,
182213
customFetch,
183214
getFormattedAddressesByProtocol,
215+
getAddressesByProtocol,
184216
multicall,
185217
Multicaller,
186218
subgraphRequest,

src/utils/vp.ts

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
import { formatBytes32String } from '@ethersproject/strings';
2-
import { getAddress } from '@ethersproject/address';
2+
import { getAddress, isAddress } from '@ethersproject/address';
33
import subgraphs from '@snapshot-labs/snapshot.js/src/delegationSubgraphs.json';
44
import {
5+
getAddressesByProtocol,
56
getFormattedAddressesByProtocol,
67
getProvider,
78
getSnapshots,
89
Multicaller,
9-
subgraphRequest
10+
subgraphRequest,
11+
validateAddress
1012
} from '../utils';
1113
import _strategies from '../strategies';
1214
import { Score, Snapshot, VotingPower } from '../types';
13-
import { DEFAULT_SUPPORTED_PROTOCOLS } from '../constants';
1415

1516
const DELEGATION_CONTRACT = '0x469788fE6E9E9681C6ebF3bF78e7Fd26Fc015446';
1617
const EMPTY_ADDRESS = '0x0000000000000000000000000000000000000000';
@@ -30,6 +31,12 @@ export async function getVp(
3031
space: string,
3132
delegation?: boolean
3233
): Promise<VotingPower> {
34+
if (strategies.some((s) => !_strategies[s.name])) {
35+
throw new Error('invalid strategies');
36+
}
37+
// Ensure that the address is either a valid EVM address or Starknet address
38+
validateAddress(address);
39+
3340
const networks = [...new Set(strategies.map((s) => s.network || network))];
3441
const snapshots = await getSnapshots(
3542
network,
@@ -38,8 +45,10 @@ export async function getVp(
3845
networks
3946
);
4047

48+
// TODO: Delegation support for Starknet
49+
const delegationSupported = delegation && isAddress(address);
4150
const delegations = {};
42-
if (delegation) {
51+
if (delegationSupported) {
4352
const ds = await Promise.all(
4453
networks.map((n) => getDelegations(address, n, snapshots[n], space))
4554
);
@@ -49,19 +58,20 @@ export async function getVp(
4958
const p: Score[] = strategies.map((strategy) => {
5059
const n = strategy.network || network;
5160
let addresses = [address];
61+
const supportedProtocols = _strategies[strategy.name].supportedProtocols;
5262

53-
if (delegation) {
63+
if (delegationSupported && supportedProtocols.includes('evm')) {
5464
addresses = delegations[n].in;
5565
if (!delegations[n].out) addresses.push(address);
5666
addresses = [...new Set(addresses)];
5767
if (addresses.length === 0) return {};
5868
}
5969

60-
addresses = getFormattedAddressesByProtocol(
61-
addresses,
62-
_strategies[strategy.name].supportedProtocols ??
63-
DEFAULT_SUPPORTED_PROTOCOLS
64-
);
70+
addresses = getAddressesByProtocol(addresses, supportedProtocols);
71+
addresses = getFormattedAddressesByProtocol(addresses, supportedProtocols);
72+
73+
if (addresses.length === 0) return {};
74+
6575
return _strategies[strategy.name].strategy(
6676
space,
6777
n,
@@ -76,18 +86,17 @@ export async function getVp(
7686
const vpByStrategy = scores.map((score, i) => {
7787
const n = strategies[i].network || network;
7888
let addresses = [address];
89+
const supportedProtocols =
90+
_strategies[strategies[i].name].supportedProtocols;
7991

80-
if (delegation) {
92+
if (delegationSupported && supportedProtocols.includes('evm')) {
8193
addresses = delegations[n].in;
8294
if (!delegations[n].out) addresses.push(address);
8395
addresses = [...new Set(addresses)];
8496
}
8597

86-
addresses = getFormattedAddressesByProtocol(
87-
addresses,
88-
_strategies[strategies[i].name].supportedProtocols ??
89-
DEFAULT_SUPPORTED_PROTOCOLS
90-
);
98+
addresses = getAddressesByProtocol(addresses, supportedProtocols);
99+
addresses = getFormattedAddressesByProtocol(addresses, supportedProtocols);
91100
return addresses.reduce((a, b) => a + (score[b] || 0), 0);
92101
});
93102
const vp = vpByStrategy.reduce((a, b) => a + b, 0);

test/__snapshots__/vp.test.ts.snap

Lines changed: 0 additions & 27 deletions
This file was deleted.
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`VP Calculation Integration Tests getVp() should calculate VP for EVM address on mixed protocol 1`] = `
4+
{
5+
"vp": 10.998985610441185,
6+
"vp_by_strategy": [
7+
1,
8+
9.998985610441185,
9+
],
10+
"vp_state": "final",
11+
}
12+
`;
13+
14+
exports[`VP Calculation Integration Tests getVp() should calculate VP for Starknet address on evm protocol 1`] = `
15+
{
16+
"vp": 0,
17+
"vp_by_strategy": [
18+
0,
19+
],
20+
"vp_state": "final",
21+
}
22+
`;
23+
24+
exports[`VP Calculation Integration Tests getVp() should calculate VP for Starknet address on evm protocol with delegation enabled 1`] = `
25+
{
26+
"vp": 0,
27+
"vp_by_strategy": [
28+
0,
29+
],
30+
"vp_state": "final",
31+
}
32+
`;
33+
34+
exports[`VP Calculation Integration Tests getVp() should calculate VP for Starknet address on mixed protocol 1`] = `
35+
{
36+
"vp": 1,
37+
"vp_by_strategy": [
38+
1,
39+
0,
40+
],
41+
"vp_state": "final",
42+
}
43+
`;
44+
45+
exports[`VP Calculation Integration Tests getVp() should calculate VP for Starknet address on mixed protocol with delegation enabled 1`] = `
46+
{
47+
"vp": 1,
48+
"vp_by_strategy": [
49+
1,
50+
0,
51+
],
52+
"vp_state": "final",
53+
}
54+
`;
55+
56+
exports[`VP Calculation Integration Tests getVp() should calculate VP with delegation enabled 1`] = `
57+
{
58+
"vp": 10.077130335431244,
59+
"vp_by_strategy": [
60+
0,
61+
10.028706352441185,
62+
0,
63+
0.04842398299005922,
64+
],
65+
"vp_state": "final",
66+
}
67+
`;
68+
69+
exports[`VP Calculation Integration Tests getVp() should calculate VP without delegation 1`] = `
70+
{
71+
"vp": 21.55404462002206,
72+
"vp_by_strategy": [
73+
0,
74+
9.998985610441185,
75+
11.506635026590818,
76+
0.04842398299005922,
77+
],
78+
"vp_state": "final",
79+
}
80+
`;

0 commit comments

Comments
 (0)