Skip to content

Commit 7277e60

Browse files
wa0x6eChaituVRbonustrackSekhmetdependabot[bot]
authored
feat: validate space strategies (#513)
* feat: validate space strategies * fix: duplicate request preventor for EIP-1271 requests (#515) * fix: duplicate request preventor for EIP-1271 requests * fix test * chore: increase follow limit for Turbo users (#516) * chore: allows 50 follows for turbo users * chore: allows 50 follows for turbo users * fix: allow copeland on production (#517) * fix: all copeland on production * fix: remove unused variable * feat: use unified API to check if SX space exists (#520) * feat: add mnt, ape, curtis to networks whitelist (#521) Updated mantle to mnt as it's new NetworkID for it. * chore(deps): bump @snapshot-labs/snapshot.js from 0.12.54 to 0.12.55 (#524) Bumps [@snapshot-labs/snapshot.js](https://github.com/snapshot-labs/snapshot.js) from 0.12.54 to 0.12.55. - [Release notes](https://github.com/snapshot-labs/snapshot.js/releases) - [Commits](snapshot-labs/snapshot.js@v0.12.54...v0.12.55) --- updated-dependencies: - dependency-name: "@snapshot-labs/snapshot.js" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump @snapshot-labs/snapshot.js from 0.12.55 to 0.12.56 (#525) Bumps [@snapshot-labs/snapshot.js](https://github.com/snapshot-labs/snapshot.js) from 0.12.55 to 0.12.56. - [Release notes](https://github.com/snapshot-labs/snapshot.js/releases) - [Commits](snapshot-labs/snapshot.js@v0.12.55...v0.12.56) --- updated-dependencies: - dependency-name: "@snapshot-labs/snapshot.js" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump @snapshot-labs/snapshot.js from 0.12.56 to 0.12.57 (#526) Bumps [@snapshot-labs/snapshot.js](https://github.com/snapshot-labs/snapshot.js) from 0.12.56 to 0.12.57. - [Release notes](https://github.com/snapshot-labs/snapshot.js/releases) - [Commits](snapshot-labs/snapshot.js@v0.12.56...v0.12.57) --- updated-dependencies: - dependency-name: "@snapshot-labs/snapshot.js" dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * feat: sync spaces custom domain with walletconnect allowed origins (#487) * feat: sync spaces custom domain with walletconnect allowed origins * refactor: better variable name * Update .env.example Co-authored-by: Less <[email protected]> * chore: only use domain without protocol prefix --------- Co-authored-by: Chaitanya <[email protected]> Co-authored-by: Less <[email protected]> * fix: prevent non-premium networks (#522) * feat: prevent non-premium networks * add testcases * Improve network filtering and fix test case * fix: allow turbo spaces to create proposals with non-premuim networks (#528) * feat: use correct network when fetching shib space controller (#527) * feat: use correct network when fetching shib space controller * chore: use network realm instead of chain id * fix: allow network param override * chore(deps): bump @snapshot-labs/snapshot.js from 0.12.57 to 0.12.58 (#531) Bumps [@snapshot-labs/snapshot.js](https://github.com/snapshot-labs/snapshot.js) from 0.12.57 to 0.12.58. - [Release notes](https://github.com/snapshot-labs/snapshot.js/releases) - [Commits](snapshot-labs/snapshot.js@v0.12.57...v0.12.58) --- updated-dependencies: - dependency-name: "@snapshot-labs/snapshot.js" dependency-version: 0.12.58 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * feat: add turbo tracking (#523) * feat: add turbo tracking every 10s * fix: correct syntax for GetSpaces query * ci: deactivate schnaps for tests * refactor: rename to turbo_expiration * chore: remove quotes around url in .env.example Co-authored-by: Chaitanya <[email protected]> * refactor: only track if SCHNAPS_API_URL is set * chore: remove log * chore: remove dead env var Co-authored-by: Wan <[email protected]> * refactor: move while loop out of if condition Co-authored-by: Wan <[email protected]> * lint: fix * chore: remove track turbo status * ci: move loop in if condition * refactor: move while loop out of if condition * fix: process only relevant spaces for the instance network * fix: use sentry to capture errors * fix: use fech with keep alive * fix: fix invalid comparison * docs: add note about future feature * fix: only update `turbo_expiration` field * fix: improve sql query --------- Co-authored-by: Chaitanya <[email protected]> Co-authored-by: Wan <[email protected]> * chore(deps): bump @snapshot-labs/snapshot.js from 0.12.58 to 0.12.59 (#532) Bumps [@snapshot-labs/snapshot.js](https://github.com/snapshot-labs/snapshot.js) from 0.12.58 to 0.12.59. - [Release notes](https://github.com/snapshot-labs/snapshot.js/releases) - [Commits](snapshot-labs/snapshot.js@v0.12.58...v0.12.59) --- updated-dependencies: - dependency-name: "@snapshot-labs/snapshot.js" dependency-version: 0.12.59 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump @snapshot-labs/snapshot.js from 0.12.59 to 0.12.60 (#533) Bumps [@snapshot-labs/snapshot.js](https://github.com/snapshot-labs/snapshot.js) from 0.12.59 to 0.12.60. - [Release notes](https://github.com/snapshot-labs/snapshot.js/releases) - [Commits](snapshot-labs/snapshot.js@v0.12.59...v0.12.60) --- updated-dependencies: - dependency-name: "@snapshot-labs/snapshot.js" dependency-version: 0.12.60 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore: use pineapple gateway to get JSON on poke (#535) * fix: skip indexing from outdated schnaps api (#537) * fix: assign fallback value (#538) * fix: infer turbo status from turbo expiration date (#539) * fix: infer turbo status from turbo expiration date * fix: update schema.sql * chore: mark eden-online-override strategy as overriding * chore(deps): bump @snapshot-labs/snapshot.js from 0.12.60 to 0.12.62 (#540) Bumps [@snapshot-labs/snapshot.js](https://github.com/snapshot-labs/snapshot.js) from 0.12.60 to 0.12.62. - [Release notes](https://github.com/snapshot-labs/snapshot.js/releases) - [Commits](snapshot-labs/snapshot.js@v0.12.60...v0.12.62) --- updated-dependencies: - dependency-name: "@snapshot-labs/snapshot.js" dependency-version: 0.12.62 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump @snapshot-labs/snapshot.js from 0.12.62 to 0.12.63 (#543) Bumps [@snapshot-labs/snapshot.js](https://github.com/snapshot-labs/snapshot.js) from 0.12.62 to 0.12.63. - [Release notes](https://github.com/snapshot-labs/snapshot.js/releases) - [Commits](snapshot-labs/snapshot.js@v0.12.62...v0.12.63) --- updated-dependencies: - dependency-name: "@snapshot-labs/snapshot.js" dependency-version: 0.12.63 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump @snapshot-labs/snapshot.js from 0.12.63 to 0.12.64 (#544) Bumps [@snapshot-labs/snapshot.js](https://github.com/snapshot-labs/snapshot.js) from 0.12.63 to 0.12.64. - [Release notes](https://github.com/snapshot-labs/snapshot.js/releases) - [Commits](snapshot-labs/snapshot.js@v0.12.63...v0.12.64) --- updated-dependencies: - dependency-name: "@snapshot-labs/snapshot.js" dependency-version: 0.12.64 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump @snapshot-labs/snapshot.js from 0.12.64 to 0.12.65 (#545) Bumps [@snapshot-labs/snapshot.js](https://github.com/snapshot-labs/snapshot.js) from 0.12.64 to 0.12.65. - [Release notes](https://github.com/snapshot-labs/snapshot.js/releases) - [Commits](snapshot-labs/snapshot.js@v0.12.64...v0.12.65) --- updated-dependencies: - dependency-name: "@snapshot-labs/snapshot.js" dependency-version: 0.12.65 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump @snapshot-labs/snapshot.js from 0.12.65 to 0.13.0 (#546) Bumps [@snapshot-labs/snapshot.js](https://github.com/snapshot-labs/snapshot.js) from 0.12.65 to 0.13.0. - [Release notes](https://github.com/snapshot-labs/snapshot.js/releases) - [Commits](snapshot-labs/snapshot.js@v0.12.65...v0.13.0) --- updated-dependencies: - dependency-name: "@snapshot-labs/snapshot.js" dependency-version: 0.13.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * feat: add delay before finalizing proposal scores (#541) * feat: add delay before finalising proposal scores * Revert "feat: add delay before finalising proposal scores" This reverts commit f174357. * fix: add delay up to 1min after proposal close * Update src/scores.ts Co-authored-by: Chaitanya <[email protected]> * Update src/scores.ts * Update src/scores.ts Co-authored-by: Chaitanya <[email protected]> --------- Co-authored-by: Chaitanya <[email protected]> * refactor: remove unused requestEonKey function from shutter helper (#549) * feat: allow vote and proposal handling from starknet aliases (#542) * feat: allow vote and proposal handling from starknet aliases * Update src/helpers/alias.ts Co-authored-by: Copilot <[email protected]> * test: update test name * feat: allow starknet aliases to update proposal * test: test improvement * fix: remove duplicate * test: improve tests * refactor: code improvement * fix: fix invalid date comparison * fix: allow optional alias to update proposal * fix lint here for now --------- Co-authored-by: Copilot <[email protected]> Co-authored-by: Chaitanya <[email protected]> * chore(deps): bump @snapshot-labs/snapshot.js from 0.13.0 to 0.14.1 (#552) Bumps [@snapshot-labs/snapshot.js](https://github.com/snapshot-labs/snapshot.js) from 0.13.0 to 0.14.1. - [Release notes](https://github.com/snapshot-labs/snapshot.js/releases) - [Commits](snapshot-labs/snapshot.js@v0.13.0...v0.14.1) --- updated-dependencies: - dependency-name: "@snapshot-labs/snapshot.js" dependency-version: 0.14.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * fix: remove duplicate promisification of Pool and Connection in mysql helper (#551) Co-authored-by: Chaitanya <[email protected]> * feat: allow starknet aliases to flag proposals (#550) * feat: allow starknet aliases to flag proposals * Update src/helpers/alias.ts Co-authored-by: Chaitanya <[email protected]> --------- Co-authored-by: Chaitanya <[email protected]> * fix: add split-delegation to list of override strategies (#547) * refactor: simplify retry logic in fetchWithRetry method (#553) * fix: remove duplicate promisification of Pool and Connection in mysql helper * refactor: simplify retry logic in fetchWithRetry method --------- Co-authored-by: Chaitanya <[email protected]> * chore(deps): bump @snapshot-labs/snapshot.js from 0.14.1 to 0.14.2 (#556) Bumps [@snapshot-labs/snapshot.js](https://github.com/snapshot-labs/snapshot.js) from 0.14.1 to 0.14.2. - [Release notes](https://github.com/snapshot-labs/snapshot.js/releases) - [Commits](snapshot-labs/snapshot.js@v0.14.1...v0.14.2) --- updated-dependencies: - dependency-name: "@snapshot-labs/snapshot.js" dependency-version: 0.14.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * fix: update `network` column to support starknet chain id (#558) * chore(deps): bump @snapshot-labs/snapshot.js from 0.14.2 to 0.14.4 (#559) Bumps [@snapshot-labs/snapshot.js](https://github.com/snapshot-labs/snapshot.js) from 0.14.2 to 0.14.4. - [Release notes](https://github.com/snapshot-labs/snapshot.js/releases) - [Commits](snapshot-labs/snapshot.js@v0.14.2...v0.14.4) --- updated-dependencies: - dependency-name: "@snapshot-labs/snapshot.js" dependency-version: 0.14.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * feat: prevent spaces from setting themselves as parent or child (#560) - Add validation to prevent circular references in space hierarchy - Reject when space.parent equals the space ID - Reject when space.children array contains the space ID - Add comprehensive tests for parent/child validation - Ensure proper error messages for validation failures * chore(deps): bump @snapshot-labs/snapshot.js from 0.14.4 to 0.14.5 (#561) Bumps [@snapshot-labs/snapshot.js](https://github.com/snapshot-labs/snapshot.js) from 0.14.4 to 0.14.5. - [Release notes](https://github.com/snapshot-labs/snapshot.js/releases) - [Commits](snapshot-labs/snapshot.js@v0.14.4...v0.14.5) --- updated-dependencies: - dependency-name: "@snapshot-labs/snapshot.js" dependency-version: 0.14.5 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * feat: add support for sonic domain name (#562) * feat: add support for sonic domain name * fix: fix wrong sonic network * chore: add sonic-staked-balance to override strategy (#568) * chore: remove matic from sx (#573) * chore(deps): bump @snapshot-labs/snapshot.js from 0.14.5 to 0.14.6 (#565) Bumps [@snapshot-labs/snapshot.js](https://github.com/snapshot-labs/snapshot.js) from 0.14.5 to 0.14.6. - [Release notes](https://github.com/snapshot-labs/snapshot.js/releases) - [Commits](snapshot-labs/snapshot.js@v0.14.5...v0.14.6) --- updated-dependencies: - dependency-name: "@snapshot-labs/snapshot.js" dependency-version: 0.14.6 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Wan <[email protected]> * chore(deps): bump @snapshot-labs/pineapple from 1.1.0 to 1.2.0 (#564) Bumps @snapshot-labs/pineapple from 1.1.0 to 1.2.0. --- updated-dependencies: - dependency-name: "@snapshot-labs/pineapple" dependency-version: 1.2.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Wan <[email protected]> * chore(deps): bump @snapshot-labs/snapshot.js from 0.14.6 to 0.14.7 (#575) Bumps [@snapshot-labs/snapshot.js](https://github.com/snapshot-labs/snapshot.js) from 0.14.6 to 0.14.7. - [Release notes](https://github.com/snapshot-labs/snapshot.js/releases) - [Commits](snapshot-labs/snapshot.js@v0.14.6...v0.14.7) --- updated-dependencies: - dependency-name: "@snapshot-labs/snapshot.js" dependency-version: 0.14.7 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * feat: validate space strategies * chore: lint fix * feat: validate space strategies * chore: lint fix * refactor: better strategies handling refactor: refactor: * fix: stop infinite loop on app shutdown * refactor: remove magic number * fix: update error message to reflect disabled status * refactor: remove useless try/catch * test: reset mock after each test * feat: only allow override strategies on pro spaces (#581) * refactor: better filename to avoid confusion * fix: increase refresh interval to 5min * fix: start express app only after loading all strategies * tests: mock strategies list * Update src/helpers/strategies.ts Co-authored-by: Copilot <[email protected]> * tests: fix race condition in E2E tests * fix: strategy should honor the Strategy signature * fix: throw error on internal error from score-api * fix: use getter to avoid reference invalidation * refactor: use default argument * fix: use single quote * fix: delay first strategies loop run --------- Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: Chaitanya <[email protected]> Co-authored-by: Less <[email protected]> Co-authored-by: Wiktor Tkaczyński <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: pscott <[email protected]> Co-authored-by: Yoginth <[email protected]> Co-authored-by: Copilot <[email protected]>
1 parent c36c82e commit 7277e60

File tree

10 files changed

+544
-302
lines changed

10 files changed

+544
-302
lines changed

src/helpers/spaceValidation.ts

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import snapshot from '@snapshot-labs/snapshot.js';
2+
import log from './log';
3+
import { getStrategies } from './strategies';
4+
5+
const DEFAULT_SNAPSHOT_ENV: string = 'testnet';
6+
7+
export async function validateSpaceSettings(
8+
originalSpace: any,
9+
snapshotEnv = process.env.NETWORK ?? DEFAULT_SNAPSHOT_ENV
10+
): Promise<void> {
11+
const spaceType = originalSpace.turbo ? 'turbo' : 'default';
12+
const space = snapshot.utils.clone(originalSpace);
13+
14+
if (space?.deleted) return Promise.reject('space deleted, contact admin');
15+
16+
delete space.deleted;
17+
delete space.flagged;
18+
delete space.verified;
19+
delete space.turbo;
20+
delete space.hibernated;
21+
delete space.id;
22+
23+
if (space.parent && space.parent === originalSpace.id) {
24+
return Promise.reject('space cannot be its own parent');
25+
}
26+
27+
if (
28+
space.children &&
29+
Array.isArray(space.children) &&
30+
space.children.includes(originalSpace.id)
31+
) {
32+
return Promise.reject('space cannot be its own child');
33+
}
34+
35+
const schemaIsValid: any = snapshot.utils.validateSchema(snapshot.schemas.space, space, {
36+
spaceType,
37+
snapshotEnv
38+
});
39+
40+
if (schemaIsValid !== true) {
41+
log.warn('[writer] Wrong space format', schemaIsValid);
42+
const firstErrorObject: any = Object.values(schemaIsValid)[0];
43+
if (firstErrorObject.message === 'network not allowed') {
44+
return Promise.reject(firstErrorObject.message);
45+
}
46+
return Promise.reject('wrong space format');
47+
}
48+
49+
const strategiesIds: string[] = space.strategies.map((strategy: any) => strategy.name);
50+
if (snapshotEnv !== 'testnet') {
51+
const hasTicket = strategiesIds.includes('ticket');
52+
const hasVotingValidation =
53+
space.voteValidation?.name && !['any'].includes(space.voteValidation.name);
54+
55+
if (hasTicket && !hasVotingValidation) {
56+
return Promise.reject('space with ticket requires voting validation');
57+
}
58+
59+
const hasProposalValidation =
60+
(space.validation?.name && space.validation.name !== 'any') ||
61+
space.filters?.minScore ||
62+
space.filters?.onlyMembers;
63+
64+
if (!hasProposalValidation) {
65+
return Promise.reject('space missing proposal validation');
66+
}
67+
}
68+
69+
for (const id of strategiesIds) {
70+
const strategy = getStrategies()[id];
71+
72+
if (!strategy) {
73+
return Promise.reject(`strategy '${id}' is not a valid strategy`);
74+
}
75+
76+
if (strategy.disabled) {
77+
return Promise.reject(`strategy '${id}' is not available anymore`);
78+
}
79+
80+
if (strategy.override && spaceType !== 'turbo') {
81+
return Promise.reject(`strategy '${id}' is only available for pro spaces`);
82+
}
83+
}
84+
}

src/helpers/strategies.ts

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import { URL } from 'url';
2+
import { capture } from '@snapshot-labs/snapshot-sentry';
3+
import snapshot from '@snapshot-labs/snapshot.js';
4+
import log from './log';
5+
6+
type Strategy = {
7+
id: string;
8+
override: boolean;
9+
disabled: boolean;
10+
};
11+
12+
const RUN_INTERVAL = 60e3 * 5; // 5 minutes
13+
const MAX_CONSECUTIVE_FAILS = 3;
14+
const URI = new URL(
15+
'/api/strategies',
16+
process.env.SCORE_API_URL ?? 'https://score.snapshot.org'
17+
).toString();
18+
19+
let consecutiveFailsCount = 0;
20+
let shouldStop = false;
21+
let strategies: Record<Strategy['id'], Strategy> = {};
22+
23+
async function loadStrategies() {
24+
const res = await snapshot.utils.getJSON(URI);
25+
26+
if ('error' in res) {
27+
const error = new Error(
28+
`Failed to load strategies: ${res.error.message || JSON.stringify(res.error)}`
29+
);
30+
capture(error, {
31+
contexts: { input: { uri: URI }, res }
32+
});
33+
throw error;
34+
}
35+
36+
const strategiesList = Object.values(res).map((strategy: any) => ({
37+
id: strategy.key,
38+
override: strategy.dependOnOtherAddress || false,
39+
disabled: strategy.disabled || false
40+
}));
41+
42+
strategies = Object.fromEntries(strategiesList.map(strategy => [strategy.id, strategy]));
43+
}
44+
45+
// Using a getter to avoid potential reference initialization issues
46+
export function getStrategies(): Record<Strategy['id'], Strategy> {
47+
return strategies;
48+
}
49+
50+
export async function initialize() {
51+
log.info('[strategies] Initial strategies load');
52+
await loadStrategies();
53+
log.info('[strategies] Initial strategies load complete');
54+
}
55+
56+
export async function run() {
57+
log.info('[strategies] Start strategies refresh loop');
58+
59+
while (!shouldStop) {
60+
// Delay the first run to avoid immediate execution after initialize()
61+
// if stop() has been called after sleep started,
62+
// the loop will exit only after the sleep has completed
63+
await snapshot.utils.sleep(RUN_INTERVAL);
64+
try {
65+
log.info('[strategies] Start strategies refresh');
66+
await loadStrategies();
67+
consecutiveFailsCount = 0;
68+
log.info('[strategies] End strategies refresh');
69+
} catch (e: any) {
70+
consecutiveFailsCount++;
71+
72+
if (consecutiveFailsCount >= MAX_CONSECUTIVE_FAILS) {
73+
capture(e);
74+
}
75+
log.error(`[strategies] failed to load ${JSON.stringify(e)}`);
76+
}
77+
}
78+
}
79+
80+
export function stop() {
81+
log.info('[strategies] Stopping strategies refresh');
82+
shouldStop = true;
83+
}

src/index.ts

Lines changed: 52 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,62 @@ import initMetrics from './helpers/metrics';
88
import refreshModeration from './helpers/moderation';
99
import rateLimit from './helpers/rateLimit';
1010
import shutter from './helpers/shutter';
11+
import {
12+
initialize as initializeStrategies,
13+
run as refreshStrategies,
14+
stop as stopStrategies
15+
} from './helpers/strategies';
1116
import { trackTurboStatuses } from './helpers/turbo';
1217

1318
const app = express();
1419

15-
initLogger(app);
16-
refreshModeration();
17-
initMetrics(app);
18-
trackTurboStatuses();
20+
async function startServer() {
21+
initLogger(app);
22+
refreshModeration();
1923

20-
app.disable('x-powered-by');
21-
app.use(express.json({ limit: '20mb' }));
22-
app.use(express.urlencoded({ limit: '20mb', extended: false }));
23-
app.use(cors({ maxAge: 86400 }));
24-
app.use(rateLimit);
25-
app.set('trust proxy', 1);
26-
app.use('/', api);
27-
app.use('/shutter', shutter);
24+
await initializeStrategies();
25+
refreshStrategies();
2826

29-
fallbackLogger(app);
27+
initMetrics(app);
28+
trackTurboStatuses();
3029

31-
const PORT = process.env.PORT || 3001;
32-
app.listen(PORT, () => log.info(`Started on: http://localhost:${PORT}`));
30+
app.disable('x-powered-by');
31+
app.use(express.json({ limit: '20mb' }));
32+
app.use(express.urlencoded({ limit: '20mb', extended: false }));
33+
app.use(cors({ maxAge: 86400 }));
34+
app.use(rateLimit);
35+
app.set('trust proxy', 1);
36+
app.use('/', api);
37+
app.use('/shutter', shutter);
38+
39+
fallbackLogger(app);
40+
41+
const PORT = process.env.PORT || 3001;
42+
return app.listen(PORT, () => log.info(`Started on: http://localhost:${PORT}`));
43+
}
44+
45+
startServer()
46+
.then(server => {
47+
const gracefulShutdown = (signal: string) => {
48+
log.info(`Received ${signal}, shutting down gracefully...`);
49+
50+
stopStrategies();
51+
52+
server.close(() => {
53+
log.info('Server closed');
54+
process.exit(0);
55+
});
56+
57+
setTimeout(() => {
58+
log.error('Could not close connections in time, forcefully shutting down');
59+
process.exit(1);
60+
}, 10000);
61+
};
62+
63+
process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
64+
process.on('SIGINT', () => gracefulShutdown('SIGINT'));
65+
})
66+
.catch(error => {
67+
log.error('Failed to start server:', error);
68+
process.exit(1);
69+
});

src/writer/proposal.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ import { capture } from '@snapshot-labs/snapshot-sentry';
22
import snapshot from '@snapshot-labs/snapshot.js';
33
import networks from '@snapshot-labs/snapshot.js/src/networks.json';
44
import { uniq } from 'lodash';
5-
import { validateSpaceSettings } from './settings';
65
import { getPremiumNetworkIds, getSpace } from '../helpers/actions';
76
import log from '../helpers/log';
87
import { containsFlaggedLinks, flaggedAddresses } from '../helpers/moderation';
98
import { isMalicious } from '../helpers/monitoring';
109
import db from '../helpers/mysql';
1110
import { getLimits, getSpaceType } from '../helpers/options';
11+
import { validateSpaceSettings } from '../helpers/spaceValidation';
1212
import { captureError, getQuorum, jsonParse, validateChoices } from '../helpers/utils';
1313

1414
const scoreAPIUrl = process.env.SCORE_API_URL || 'https://score.snapshot.org';
@@ -65,11 +65,7 @@ async function validateSpace(space: any) {
6565
return Promise.reject('space hibernated');
6666
}
6767

68-
try {
69-
await validateSpaceSettings(space);
70-
} catch (e) {
71-
return Promise.reject(e);
72-
}
68+
await validateSpaceSettings(space);
7369
}
7470

7571
export async function verify(body): Promise<any> {

src/writer/settings.ts

Lines changed: 1 addition & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { capture } from '@snapshot-labs/snapshot-sentry';
2-
import snapshot from '@snapshot-labs/snapshot.js';
32
import isEqual from 'lodash/isEqual';
43
import { addOrUpdateSpace, getSpace } from '../helpers/actions';
54
import log from '../helpers/log';
65
import db from '../helpers/mysql';
76
import { getLimit, getSpaceType } from '../helpers/options';
7+
import { validateSpaceSettings } from '../helpers/spaceValidation';
88
import {
99
addToWalletConnectWhitelist,
1010
clearStampCache,
@@ -15,65 +15,6 @@ import {
1515

1616
const SNAPSHOT_ENV = process.env.NETWORK || 'testnet';
1717

18-
export async function validateSpaceSettings(originalSpace: any) {
19-
const spaceType = originalSpace.turbo ? 'turbo' : 'default';
20-
const space = snapshot.utils.clone(originalSpace);
21-
22-
if (space?.deleted) return Promise.reject('space deleted, contact admin');
23-
24-
delete space.deleted;
25-
delete space.flagged;
26-
delete space.verified;
27-
delete space.turbo;
28-
delete space.hibernated;
29-
delete space.id;
30-
31-
if (space.parent && space.parent === originalSpace.id) {
32-
return Promise.reject('space cannot be its own parent');
33-
}
34-
35-
if (
36-
space.children &&
37-
Array.isArray(space.children) &&
38-
space.children.includes(originalSpace.id)
39-
) {
40-
return Promise.reject('space cannot be its own child');
41-
}
42-
43-
const schemaIsValid: any = snapshot.utils.validateSchema(snapshot.schemas.space, space, {
44-
spaceType,
45-
snapshotEnv: SNAPSHOT_ENV
46-
});
47-
48-
if (schemaIsValid !== true) {
49-
log.warn('[writer] Wrong space format', schemaIsValid);
50-
const firstErrorObject: any = Object.values(schemaIsValid)[0];
51-
if (firstErrorObject.message === 'network not allowed') {
52-
return Promise.reject(firstErrorObject.message);
53-
}
54-
return Promise.reject('wrong space format');
55-
}
56-
57-
if (SNAPSHOT_ENV !== 'testnet') {
58-
const hasTicket = space.strategies.some(strategy => strategy.name === 'ticket');
59-
const hasVotingValidation =
60-
space.voteValidation?.name && !['any'].includes(space.voteValidation.name);
61-
62-
if (hasTicket && !hasVotingValidation) {
63-
return Promise.reject('space with ticket requires voting validation');
64-
}
65-
66-
const hasProposalValidation =
67-
(space.validation?.name && space.validation.name !== 'any') ||
68-
space.filters?.minScore ||
69-
space.filters?.onlyMembers;
70-
71-
if (!hasProposalValidation) {
72-
return Promise.reject('space missing proposal validation');
73-
}
74-
}
75-
}
76-
7718
export async function verify(body): Promise<any> {
7819
const msg = jsonParse(body.msg);
7920
if (msg.space.length > 64) {

test/e2e/api.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ describe('POST /flag', () => {
5858
settings: JSON.stringify(space.settings)
5959
}))
6060
.map(async space => {
61-
db.queryAsync('INSERT INTO snapshot_sequencer_test.spaces SET ?', space);
61+
return db.queryAsync('INSERT INTO snapshot_sequencer_test.spaces SET ?', space);
6262
})
6363
);
6464

@@ -75,7 +75,7 @@ describe('POST /flag', () => {
7575
vp_value_by_strategy: JSON.stringify(proposal.vp_value_by_strategy || [])
7676
}))
7777
.map(async proposal => {
78-
db.queryAsync('INSERT INTO snapshot_sequencer_test.proposals SET ?', proposal);
78+
return db.queryAsync('INSERT INTO snapshot_sequencer_test.proposals SET ?', proposal);
7979
})
8080
);
8181
});

0 commit comments

Comments
 (0)