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
7 changes: 7 additions & 0 deletions src/helpers/strategies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const URI = new URL(
let consecutiveFailsCount = 0;
let shouldStop = false;
let strategies: Record<Strategy['id'], Strategy> = {};
let overridingStrategies: string[] = [];

async function loadStrategies() {
const res = await snapshot.utils.getJSON(URI);
Expand All @@ -40,13 +41,19 @@ async function loadStrategies() {
}));

strategies = Object.fromEntries(strategiesList.map(strategy => [strategy.id, strategy]));

overridingStrategies = strategiesList.filter(s => s.override).map(s => s.id);
}

// Using a getter to avoid potential reference initialization issues
export function getStrategies(): Record<Strategy['id'], Strategy> {
return strategies;
}

export function getOverridingStrategies(): string[] {
return overridingStrategies;
}

export async function initialize() {
log.info('[strategies] Initial strategies load');
await loadStrategies();
Expand Down
33 changes: 4 additions & 29 deletions src/helpers/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { capture } from '@snapshot-labs/snapshot-sentry';
import snapshot from '@snapshot-labs/snapshot.js';
import { Response } from 'express';
import fetch from 'node-fetch';
import { getOverridingStrategies } from './strategies';

const MAINNET_NETWORK_ID_WHITELIST = ['s', 'eth', 'arb1', 'oeth', 'sn', 'base', 'mnt', 'ape'];
const TESTNET_NETWORK_ID_WHITELIST = ['s-tn', 'sep', 'curtis', 'linea-testnet', 'sn-sep'];
Expand Down Expand Up @@ -62,36 +63,10 @@ export function rpcError(res, code, e, id) {
});
}

export function hasStrategyOverride(strategies: any[]) {
const keywords = [
'"aura-vlaura-vebal-with-overrides"',
'"balance-of-with-linear-vesting-power"',
'"balancer-delegation"',
'"cyberkongz"',
'"cyberkongz-v2"',
'"delegation"',
'"delegation-with-cap"',
'"delegation-with-overrides"',
'"erc20-balance-of-delegation"',
'"erc20-balance-of-fixed-total"',
'"erc20-balance-of-quadratic-delegation"',
'"erc20-votes-with-override"',
'"esd-delegation"',
'"ocean-dao-brightid"',
'"orbs-network-delegation"',
'"api-v2-override"',
'"rocketpool-node-operator-delegate-v8"',
'"eden-online-override"',
'"split-delegation"',
'"sonic-staked-balance"'
];
export function hasStrategyOverride(strategies: any[]): boolean {
const strategiesStr = JSON.stringify(strategies).toLowerCase();
if (keywords.some(keyword => strategiesStr.includes(`"name":${keyword}`))) return true;
// Check for split-delegation with delegationOverride
const splitDelegation = strategies.filter(strategy => strategy.name === 'split-delegation');
return (
splitDelegation.length > 0 &&
splitDelegation.some(strategy => strategy.params?.delegationOverride)
return getOverridingStrategies().some(strategyId =>
strategiesStr.includes(`"name":"${strategyId}"`)
);
}

Expand Down
114 changes: 114 additions & 0 deletions test/unit/helpers/utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import * as strategies from '../../../src/helpers/strategies';
import { hasStrategyOverride } from '../../../src/helpers/utils';

const OVERRIDING_STRATEGIES = ['delegation', 'delegation-with-cap'];

// Mock the getOverridingStrategies function
jest.mock('../../../src/helpers/strategies');
const mockGetOverridingStrategies = jest.mocked(strategies.getOverridingStrategies);

describe('Utils', () => {
describe('hasStrategyOverride()', () => {
beforeEach(() => {
jest.clearAllMocks();
mockGetOverridingStrategies.mockReturnValue(OVERRIDING_STRATEGIES);
});

it('should return false when strategies array is empty', () => {
expect(hasStrategyOverride([])).toBe(false);
});

it('should return false when no overriding strategies exist', () => {
const strategies = [
{ name: 'whitelist', network: '1', params: {} },
{ name: 'ticket', network: '1', params: {} }
];

expect(hasStrategyOverride(strategies)).toBe(false);
});

it('should return true when an overriding strategy is used', () => {
const strategies = [
{ name: 'whitelist', network: '1', params: {} },
{ name: 'delegation', network: '1', params: {} }
];

expect(hasStrategyOverride(strategies)).toBe(true);
});

it('should return true when multiple overriding strategies are used', () => {
const strategies = [
{ name: 'delegation', network: '1', params: {} },
{ name: 'delegation-with-cap', network: '1', params: {} }
];

expect(hasStrategyOverride(strategies)).toBe(true);
});

it('should handle mixed case strategy names correctly', () => {
const strategies = [{ name: 'Delegation', network: '1', params: {} }];

expect(hasStrategyOverride(strategies)).toBe(true);
});

it('should handle inner strategies', () => {
const strategies = [
{
name: 'multichain',
network: '1',
params: {
symbol: 'MULTI',
strategies: [
{
name: 'erc20-balance-of',
network: '1',
params: {
address: '0x579cea1889991f68acc35ff5c3dd0621ff29b0c9',
decimals: 18
}
},
{
name: 'delegation',
network: '137',
params: {
delegationSpace: 'test.eth',
strategies: [
{
name: 'erc20-balance-of',
params: {
address: '0xB9638272aD6998708de56BBC0A290a1dE534a578',
decimals: 18
}
}
]
}
}
]
}
}
];

expect(hasStrategyOverride(strategies)).toBe(true);
});

it('should not match when strategy id appears in other fields', () => {
const strategies = [
{
name: 'whitelist',
network: '1',
params: { description: 'delegation' }
}
];

expect(hasStrategyOverride(strategies)).toBe(false);
});

it('should handle empty getOverridingStrategies result', () => {
mockGetOverridingStrategies.mockReturnValue([]);

const strategies = [{ name: 'delegation', network: '1', params: {} }];

expect(hasStrategyOverride(strategies)).toBe(false);
});
});
});