Skip to content

Commit 1dfdecf

Browse files
committed
feat: pull overriding strategies from strategies list
1 parent 884d421 commit 1dfdecf

File tree

3 files changed

+163
-30
lines changed

3 files changed

+163
-30
lines changed

src/helpers/utils.ts

Lines changed: 9 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { capture } from '@snapshot-labs/snapshot-sentry';
77
import snapshot from '@snapshot-labs/snapshot.js';
88
import { Response } from 'express';
99
import fetch from 'node-fetch';
10+
import { getStrategies } from './strategies';
1011

1112
const MAINNET_NETWORK_ID_WHITELIST = ['s', 'eth', 'arb1', 'oeth', 'sn', 'base', 'mnt', 'ape'];
1213
const TESTNET_NETWORK_ID_WHITELIST = ['s-tn', 'sep', 'curtis', 'linea-testnet', 'sn-sep'];
@@ -62,37 +63,15 @@ export function rpcError(res, code, e, id) {
6263
});
6364
}
6465

65-
export function hasStrategyOverride(strategies: any[]) {
66-
const keywords = [
67-
'"aura-vlaura-vebal-with-overrides"',
68-
'"balance-of-with-linear-vesting-power"',
69-
'"balancer-delegation"',
70-
'"cyberkongz"',
71-
'"cyberkongz-v2"',
72-
'"delegation"',
73-
'"delegation-with-cap"',
74-
'"delegation-with-overrides"',
75-
'"erc20-balance-of-delegation"',
76-
'"erc20-balance-of-fixed-total"',
77-
'"erc20-balance-of-quadratic-delegation"',
78-
'"erc20-votes-with-override"',
79-
'"esd-delegation"',
80-
'"ocean-dao-brightid"',
81-
'"orbs-network-delegation"',
82-
'"api-v2-override"',
83-
'"rocketpool-node-operator-delegate-v8"',
84-
'"eden-online-override"',
85-
'"split-delegation"',
86-
'"sonic-staked-balance"'
87-
];
66+
export function hasStrategyOverride(strategies: any[]): boolean {
67+
if (!strategies?.length) return false;
68+
8869
const strategiesStr = JSON.stringify(strategies).toLowerCase();
89-
if (keywords.some(keyword => strategiesStr.includes(`"name":${keyword}`))) return true;
90-
// Check for split-delegation with delegationOverride
91-
const splitDelegation = strategies.filter(strategy => strategy.name === 'split-delegation');
92-
return (
93-
splitDelegation.length > 0 &&
94-
splitDelegation.some(strategy => strategy.params?.delegationOverride)
95-
);
70+
const overridingStrategies = Object.values(getStrategies())
71+
.filter(s => s.override)
72+
.map(s => s.id);
73+
74+
return overridingStrategies.some(strategyId => strategiesStr.includes(`"name":"${strategyId}"`));
9675
}
9776

9877
export function validateChoices({ type, choices }): boolean {

test/fixtures/strategies.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Real strategies from score.snapshot.org/api/strategies
2+
// Includes only whitelist, ticket, delegation, and multichain strategies for testing
3+
4+
export const STRATEGIES_FIXTURE = {
5+
whitelist: {
6+
id: 'whitelist',
7+
override: false,
8+
disabled: false
9+
},
10+
ticket: {
11+
id: 'ticket',
12+
override: false,
13+
disabled: false
14+
},
15+
delegation: {
16+
id: 'delegation',
17+
override: true,
18+
disabled: false
19+
},
20+
multichain: {
21+
id: 'multichain',
22+
override: false,
23+
disabled: true
24+
},
25+
'delegation-with-cap': {
26+
id: 'delegation-with-cap',
27+
override: true,
28+
disabled: false
29+
}
30+
};
31+

test/unit/helpers/utils.test.ts

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import * as strategies from '../../../src/helpers/strategies';
2+
import { hasStrategyOverride } from '../../../src/helpers/utils';
3+
import { STRATEGIES_FIXTURE } from '../../fixtures/strategies';
4+
5+
// Mock the getStrategies function
6+
jest.mock('../../../src/helpers/strategies');
7+
const mockGetStrategies = jest.mocked(strategies.getStrategies);
8+
9+
describe('Utils', () => {
10+
describe('hasStrategyOverride()', () => {
11+
beforeEach(() => {
12+
jest.clearAllMocks();
13+
mockGetStrategies.mockReturnValue(STRATEGIES_FIXTURE);
14+
});
15+
16+
it('should return false when strategies array is empty', () => {
17+
expect(hasStrategyOverride([])).toBe(false);
18+
});
19+
20+
it('should return false when no overriding strategies exist', () => {
21+
const strategies = [
22+
{ name: 'whitelist', network: '1', params: {} },
23+
{ name: 'ticket', network: '1', params: {} }
24+
];
25+
26+
expect(hasStrategyOverride(strategies)).toBe(false);
27+
});
28+
29+
it('should return true when an overriding strategy is used', () => {
30+
const strategies = [
31+
{ name: 'whitelist', network: '1', params: {} },
32+
{ name: 'delegation', network: '1', params: {} }
33+
];
34+
35+
expect(hasStrategyOverride(strategies)).toBe(true);
36+
});
37+
38+
it('should return true when multiple overriding strategies are used', () => {
39+
const strategies = [
40+
{ name: 'delegation', network: '1', params: {} },
41+
{ name: 'delegation-with-cap', network: '1', params: {} }
42+
];
43+
44+
expect(hasStrategyOverride(strategies)).toBe(true);
45+
});
46+
47+
it('should handle mixed case strategy names correctly', () => {
48+
const strategies = [{ name: 'Delegation', network: '1', params: {} }];
49+
50+
expect(hasStrategyOverride(strategies)).toBe(true);
51+
});
52+
53+
it('should handle case where overriding strategy is disabled', () => {
54+
mockGetStrategies.mockReturnValue({
55+
delegation: { id: 'delegation', override: true, disabled: true }
56+
});
57+
58+
const strategies = [{ name: 'delegation', network: '1', params: {} }];
59+
60+
expect(hasStrategyOverride(strategies)).toBe(true);
61+
});
62+
63+
it('should handle inner strategies', () => {
64+
const strategies = [
65+
{
66+
name: 'multichain',
67+
network: '1',
68+
params: {
69+
symbol: 'MULTI',
70+
strategies: [
71+
{
72+
name: 'erc20-balance-of',
73+
network: '1',
74+
params: {
75+
address: '0x579cea1889991f68acc35ff5c3dd0621ff29b0c9',
76+
decimals: 18
77+
}
78+
},
79+
{
80+
name: 'delegation',
81+
network: '137',
82+
params: {
83+
delegationSpace: 'test.eth',
84+
strategies: [
85+
{
86+
name: 'erc20-balance-of',
87+
params: {
88+
address: '0xB9638272aD6998708de56BBC0A290a1dE534a578',
89+
decimals: 18
90+
}
91+
}
92+
]
93+
}
94+
}
95+
]
96+
}
97+
}
98+
];
99+
100+
expect(hasStrategyOverride(strategies)).toBe(true);
101+
});
102+
103+
it('should not match when strategy id appears in other fields', () => {
104+
const strategies = [
105+
{
106+
name: 'whitelist',
107+
network: '1',
108+
params: { description: 'delegation' }
109+
}
110+
];
111+
112+
expect(hasStrategyOverride(strategies)).toBe(false);
113+
});
114+
115+
it('should handle empty getStrategies result', () => {
116+
mockGetStrategies.mockReturnValue({});
117+
118+
const strategies = [{ name: 'delegation', network: '1', params: {} }];
119+
120+
expect(hasStrategyOverride(strategies)).toBe(false);
121+
});
122+
});
123+
});

0 commit comments

Comments
 (0)