diff --git a/package.json b/package.json index 0534f18d..c286d60d 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "@snapshot-labs/pineapple": "^1.1.0", "@snapshot-labs/snapshot-metrics": "^1.4.1", "@snapshot-labs/snapshot-sentry": "^1.5.5", - "@snapshot-labs/snapshot.js": "^0.12.45", + "@snapshot-labs/snapshot.js": "^0.12.46", "bluebird": "^3.7.2", "connection-string": "^1.0.1", "cors": "^2.8.5", diff --git a/src/helpers/limits.ts b/src/helpers/limits.ts deleted file mode 100644 index c7dcac8a..00000000 --- a/src/helpers/limits.ts +++ /dev/null @@ -1,54 +0,0 @@ -const SNAPSHOT_ENV = process.env.NETWORK || 'testnet'; - -export const FLAGGED_SPACE_PROPOSAL_DAY_LIMIT = 0; -export const FLAGGED_SPACE_PROPOSAL_MONTH_LIMIT = 0; - -export const SPACE_PROPOSAL_DAY_LIMIT = 3; -export const SPACE_PROPOSAL_MONTH_LIMIT = 15; - -export const VERIFIED_SPACE_PROPOSAL_DAY_LIMIT = 20; -export const VERIFIED_SPACE_PROPOSAL_MONTH_LIMIT = 100; - -export const TURBO_SPACE_PROPOSAL_DAY_LIMIT = 40; -export const TURBO_SPACE_PROPOSAL_MONTH_LIMIT = 200; - -export const ECOSYSTEM_SPACE_PROPOSAL_DAY_LIMIT = 150; -export const ECOSYSTEM_SPACE_PROPOSAL_MONTH_LIMIT = 750; - -export const FOLLOWS_LIMIT_PER_USER = 25; - -export const MAINNET_ECOSYSTEM_SPACES = [ - 'orbapp.eth', - 'cakevote.eth', - 'outcome.eth', - 'polls.lenster.xyz', - 'daotest.dcl.eth', - 'arbitrumfoundation.eth' -]; - -export const TESTNET_ECOSYSTEM_SPACES = ['citiesdao.eth']; - -export const ACTIVE_PROPOSAL_BY_AUTHOR_LIMIT = 20; - -export function getSpaceLimits(space): number[] { - if (space.flagged) { - return [FLAGGED_SPACE_PROPOSAL_DAY_LIMIT, FLAGGED_SPACE_PROPOSAL_MONTH_LIMIT]; - } - - const ecosystemSpaces = - SNAPSHOT_ENV === 'testnet' ? TESTNET_ECOSYSTEM_SPACES : MAINNET_ECOSYSTEM_SPACES; - - if (ecosystemSpaces.includes(space.id)) { - return [ECOSYSTEM_SPACE_PROPOSAL_DAY_LIMIT, ECOSYSTEM_SPACE_PROPOSAL_MONTH_LIMIT]; - } - - if (space.turbo) { - return [TURBO_SPACE_PROPOSAL_DAY_LIMIT, TURBO_SPACE_PROPOSAL_MONTH_LIMIT]; - } - - if (space.verified || SNAPSHOT_ENV === 'testnet') { - return [VERIFIED_SPACE_PROPOSAL_DAY_LIMIT, VERIFIED_SPACE_PROPOSAL_MONTH_LIMIT]; - } - - return [SPACE_PROPOSAL_DAY_LIMIT, SPACE_PROPOSAL_MONTH_LIMIT]; -} diff --git a/src/helpers/options.ts b/src/helpers/options.ts new file mode 100644 index 00000000..0b8ad27a --- /dev/null +++ b/src/helpers/options.ts @@ -0,0 +1,57 @@ +import db from './mysql'; + +async function getOptions( + keys: string[], + defaultValue: T, + formattingFn: (val: string) => T +): Promise> { + const results = keys.reduce((acc, key) => { + acc[key] = defaultValue; + return acc; + }, {}); + + const options = await db.queryAsync('select name, value from options where name in (?)', [keys]); + + options.forEach(result => { + results[result.name] = formattingFn(result.value); + }); + + return results; +} + +export async function getLimit(key: string): Promise { + return (await getLimits([key]))[key]; +} + +export async function getList(key: string): Promise { + return (await getLists([key]))[key]; +} + +export async function getLimits(keys: string[]): Promise> { + return await getOptions(keys, 0, val => Number(val)); +} + +export async function getLists(keys: string[]): Promise> { + return await getOptions(keys, [], val => val.split(',')); +} + +export async function getSpaceType( + space: { + verified: boolean; + turbo: boolean; + flagged: boolean; + id: string; + }, + withEcosystem = false +) { + let type = 'default'; + + if (withEcosystem && (await getList('space.ecosystem.list')).includes(space.id)) { + type = 'ecosystem'; + } + if (space.flagged) type = 'flagged'; + if (space.verified) type = 'verified'; + if (space.turbo) type = 'turbo'; + + return type; +} diff --git a/src/writer/follow.ts b/src/writer/follow.ts index 23c0eac3..d57ccf18 100644 --- a/src/writer/follow.ts +++ b/src/writer/follow.ts @@ -1,5 +1,5 @@ -import { FOLLOWS_LIMIT_PER_USER } from '../helpers/limits'; import db from '../helpers/mysql'; +import { getLimit } from '../helpers/options'; import { DEFAULT_NETWORK_ID, NETWORK_IDS } from '../helpers/utils'; export const getFollowsCount = async (follower: string): Promise => { @@ -22,9 +22,10 @@ export async function verify(message): Promise { if (follows.length !== 0) return Promise.reject('you are already following this space'); const count = await getFollowsCount(message.from); + const limit = await getLimit('user.default.follow_limit'); - if (count >= FOLLOWS_LIMIT_PER_USER) { - return Promise.reject(`you can join max ${FOLLOWS_LIMIT_PER_USER} spaces`); + if (count >= limit) { + return Promise.reject(`you can join max ${limit} spaces`); } if (message.network && !NETWORK_IDS.includes(message.network)) { diff --git a/src/writer/proposal.ts b/src/writer/proposal.ts index 43817d90..fa24477b 100644 --- a/src/writer/proposal.ts +++ b/src/writer/proposal.ts @@ -3,11 +3,11 @@ import snapshot from '@snapshot-labs/snapshot.js'; import networks from '@snapshot-labs/snapshot.js/src/networks.json'; import { validateSpaceSettings } from './settings'; import { getSpace } from '../helpers/actions'; -import { ACTIVE_PROPOSAL_BY_AUTHOR_LIMIT, getSpaceLimits } from '../helpers/limits'; import log from '../helpers/log'; import { containsFlaggedLinks, flaggedAddresses } from '../helpers/moderation'; import { isMalicious } from '../helpers/monitoring'; import db from '../helpers/mysql'; +import { getLimits, getSpaceType } from '../helpers/options'; import { captureError, getQuorum, jsonParse, validateChoices } from '../helpers/utils'; const scoreAPIUrl = process.env.SCORE_API_URL || 'https://score.snapshot.org'; @@ -57,7 +57,6 @@ export async function verify(body): Promise { const created = parseInt(msg.timestamp); const addressLC = body.address.toLowerCase(); const space = await getSpace(msg.space); - try { await validateSpace(space); } catch (e) { @@ -66,6 +65,17 @@ export async function verify(body): Promise { space.id = msg.space; + const spaceType = await getSpaceType(space); + const spaceTypeWithEcosystem = await getSpaceType(space, true); + + const limits = await getLimits([ + `space.${spaceType}.body_limit`, + `space.${spaceType}.choices_limit`, + 'space.active_proposal_limit_per_author', + `space.${spaceTypeWithEcosystem}.proposal_limit_per_day`, + `space.${spaceTypeWithEcosystem}.proposal_limit_per_month` + ]); + const schemaIsValid = snapshot.utils.validateSchema(snapshot.schemas.proposal, msg.payload, { spaceType: space.turbo ? 'turbo' : 'default' }); @@ -186,16 +196,29 @@ export async function verify(body): Promise { space.id, body.address ); - const [dayLimit, monthLimit] = getSpaceLimits(space); + + const dayLimit = limits[`space.${spaceTypeWithEcosystem}.proposal_limit_per_day`]; + const monthLimit = limits[`space.${spaceTypeWithEcosystem}.proposal_limit_per_month`]; if (dayCount >= dayLimit || monthCount >= monthLimit) return Promise.reject('proposal limit reached'); - if (!isAuthorized && activeProposalsByAuthor >= ACTIVE_PROPOSAL_BY_AUTHOR_LIMIT) + const activeProposalLimitPerAuthor = limits['space.active_proposal_limit_per_author']; + if (!isAuthorized && activeProposalsByAuthor >= activeProposalLimitPerAuthor) return Promise.reject('active proposal limit reached for author'); } catch (e) { capture(e); return Promise.reject('failed to check proposals limit'); } + + const bodyLengthLimit = limits[`space.${spaceType}.body_limit`]; + if (msg.payload.body.length > bodyLengthLimit) { + return Promise.reject(`proposal body length can not exceed ${bodyLengthLimit} characters`); + } + + const choicesLimit = limits[`space.${spaceType}.choices_limit`]; + if (msg.payload.choices.length > choicesLimit) { + return Promise.reject(`number of choices can not exceed ${choicesLimit}`); + } } export async function action(body, ipfs, receipt, id): Promise { diff --git a/src/writer/settings.ts b/src/writer/settings.ts index fce91419..625e53b8 100644 --- a/src/writer/settings.ts +++ b/src/writer/settings.ts @@ -4,6 +4,7 @@ import isEqual from 'lodash/isEqual'; import { addOrUpdateSpace, getSpace } from '../helpers/actions'; import log from '../helpers/log'; import db from '../helpers/mysql'; +import { getLimit, getSpaceType } from '../helpers/options'; import { clearStampCache, DEFAULT_NETWORK, jsonParse } from '../helpers/utils'; const SNAPSHOT_ENV = process.env.NETWORK || 'testnet'; @@ -73,6 +74,12 @@ export async function verify(body): Promise { return Promise.reject(e); } + const strategiesLimit = await getLimit(`space.${await getSpaceType(space)}.strategies_limit`); + + if (msg.payload.strategies.length > strategiesLimit) { + return Promise.reject(`max number of strategies is ${strategiesLimit}`); + } + const controller = await snapshot.utils.getSpaceController(msg.space, DEFAULT_NETWORK, { broviderUrl }); diff --git a/test/integration/ingestor.test.ts b/test/integration/ingestor.test.ts index ee9861f3..e3c6e500 100644 --- a/test/integration/ingestor.test.ts +++ b/test/integration/ingestor.test.ts @@ -1,11 +1,62 @@ -import ingestor from '../../src/ingestor'; -import proposalInput from '../fixtures/ingestor-payload/proposal.json'; -import { spacesGetSpaceFixtures } from '../fixtures/space'; -import voteInput from '../fixtures/ingestor-payload/vote.json'; import cloneDeep from 'lodash/cloneDeep'; import omit from 'lodash/omit'; import db, { sequencerDB } from '../../src/helpers/mysql'; import relayer from '../../src/helpers/relayer'; +import ingestor from '../../src/ingestor'; +import proposalInput from '../fixtures/ingestor-payload/proposal.json'; +import voteInput from '../fixtures/ingestor-payload/vote.json'; +import { spacesGetSpaceFixtures } from '../fixtures/space'; + +const LIMITS = { + 'space.active_proposal_limit_per_author': 20, + 'space.ecosystem.proposal_limit_per_day': 150, + 'space.ecosystem.proposal_limit_per_month': 750, + 'space.ecosystem.choices_limit': 20, + 'space.ecosystem.body_length': 10000, + 'space.ecosystem.strategies_limit': 8, + 'space.flagged.proposal_limit_per_day': 5, + 'space.flagged.proposal_limit_per_month': 7, + 'space.flagged.choices_limit': 20, + 'space.flagged.body_length': 10000, + 'space.flagged.strategies_limit': 8, + 'space.default.proposal_limit_per_day': 10, + 'space.default.proposal_limit_per_month': 150, + 'space.default.choices_limit': 20, + 'space.default.body_length': 10000, + 'space.default.strategies_limit': 8, + 'space.turbo.proposal_limit_per_day': 40, + 'space.turbo.proposal_limit_per_month': 200, + 'space.turbo.choices_limit': 1000, + 'space.turbo.body_length': 40000, + 'space.turbo.strategies_limit': 10, + 'space.verified.proposal_limit_per_day': 20, + 'space.verified.proposal_limit_per_month': 100, + 'space.verified.choices_limit': 20, + 'space.verified.body_length': 10000, + 'space.verified.strategies_limit': 6, + 'user.default.follow.limit': 25 +}; +const ECOSYSTEM_LIST = ['test.eth', 'snapshot.eth']; +jest.mock('../../src/helpers/options', () => { + const originalModule = jest.requireActual('../../src/helpers/options'); + + return { + __esModule: true, + ...originalModule, + getList: () => { + return ECOSYSTEM_LIST; + }, + getLimit: async (key: string) => { + return LIMITS[key]; + }, + getLimits: () => { + return LIMITS; + }, + getSpaceType: () => { + return 'default'; + } + }; +}); jest.mock('../../src/helpers/moderation', () => { const originalModule = jest.requireActual('../../src/helpers/moderation'); diff --git a/test/integration/writer/follows.test.ts b/test/integration/writer/follows.test.ts index 5c5f6299..5f498ac3 100644 --- a/test/integration/writer/follows.test.ts +++ b/test/integration/writer/follows.test.ts @@ -1,8 +1,19 @@ -import { FOLLOWS_LIMIT_PER_USER } from '../../../src/helpers/limits'; import db, { sequencerDB } from '../../../src/helpers/mysql'; import { action, verify } from '../../../src/writer/follow'; import { spacesSqlFixtures } from '../../fixtures/space'; +const LIMIT = 10; + +jest.mock('../../../src/helpers/options', () => { + const originalModule = jest.requireActual('../../../src/helpers/options'); + + return { + __esModule: true, + ...originalModule, + getLimit: () => LIMIT + }; +}); + describe('writer/follow', () => { const TEST_PREFIX = 'test-follow-'; const space = spacesSqlFixtures[1]; @@ -21,7 +32,7 @@ describe('writer/follow', () => { let i = 1; const promises: Promise[] = []; - while (i <= FOLLOWS_LIMIT_PER_USER) { + while (i <= LIMIT) { promises.push( db.queryAsync('INSERT INTO snapshot_sequencer_test.spaces SET ?', { ...space, @@ -45,7 +56,7 @@ describe('writer/follow', () => { it('rejects when the user has followed too much spaces', () => { return expect(verify({ from: followerId })).rejects.toEqual( - `you can join max ${FOLLOWS_LIMIT_PER_USER} spaces` + `you can join max ${LIMIT} spaces` ); }); diff --git a/test/unit/writer/proposal.test.ts b/test/unit/writer/proposal.test.ts index e36e938a..dd7b435a 100644 --- a/test/unit/writer/proposal.test.ts +++ b/test/unit/writer/proposal.test.ts @@ -1,24 +1,56 @@ import omit from 'lodash/omit'; -import { - ACTIVE_PROPOSAL_BY_AUTHOR_LIMIT, - ECOSYSTEM_SPACE_PROPOSAL_DAY_LIMIT, - ECOSYSTEM_SPACE_PROPOSAL_MONTH_LIMIT, - FLAGGED_SPACE_PROPOSAL_DAY_LIMIT, - FLAGGED_SPACE_PROPOSAL_MONTH_LIMIT, - MAINNET_ECOSYSTEM_SPACES, - SPACE_PROPOSAL_DAY_LIMIT, - SPACE_PROPOSAL_MONTH_LIMIT, - TURBO_SPACE_PROPOSAL_DAY_LIMIT, - TURBO_SPACE_PROPOSAL_MONTH_LIMIT, - VERIFIED_SPACE_PROPOSAL_DAY_LIMIT, - VERIFIED_SPACE_PROPOSAL_MONTH_LIMIT -} from '../../../src/helpers/limits'; import * as writer from '../../../src/writer/proposal'; import { spacesGetSpaceFixtures } from '../../fixtures/space'; import input from '../../fixtures/writer-payload/proposal.json'; const FLAGGED_ADDRESSES = ['0x0']; +const LIMITS = { + 'space.active_proposal_limit_per_author': 20, + 'space.ecosystem.proposal_limit_per_day': 150, + 'space.ecosystem.proposal_limit_per_month': 750, + 'space.ecosystem.choices_limit': 20, + 'space.ecosystem.body_length': 10000, + 'space.ecosystem.strategies_limit': 8, + 'space.flagged.proposal_limit_per_day': 5, + 'space.flagged.proposal_limit_per_month': 7, + 'space.flagged.choices_limit': 20, + 'space.flagged.body_length': 10000, + 'space.flagged.strategies_limit': 8, + 'space.default.proposal_limit_per_day': 10, + 'space.default.proposal_limit_per_month': 150, + 'space.default.choices_limit': 20, + 'space.default.body_length': 10000, + 'space.default.strategies_limit': 8, + 'space.turbo.proposal_limit_per_day': 40, + 'space.turbo.proposal_limit_per_month': 200, + 'space.turbo.choices_limit': 1000, + 'space.turbo.body_length': 40000, + 'space.turbo.strategies_limit': 8, + 'space.verified.proposal_limit_per_day': 20, + 'space.verified.proposal_limit_per_month': 100, + 'space.verified.choices_limit': 20, + 'space.verified.body_length': 10000, + 'space.verified.strategies_limit': 6, + 'user.default.follow.limit': 25 +}; +const ECOSYSTEM_LIST = ['test.eth', 'snapshot.eth']; + +jest.mock('../../../src/helpers/options', () => { + const originalModule = jest.requireActual('../../../src/helpers/options'); + + return { + __esModule: true, + ...originalModule, + getList: () => { + return ECOSYSTEM_LIST; + }, + getLimits: () => { + return LIMITS; + } + }; +}); + // eslint-disable-next-line @typescript-eslint/no-unused-vars const mockGetSpace = jest.fn((_): any => { return spacesGetSpaceFixtures; @@ -443,11 +475,11 @@ describe('writer/proposal', () => { }); it.each([ - ['flagged', FLAGGED_SPACE_PROPOSAL_DAY_LIMIT, 'flagged', true], - ['verified', VERIFIED_SPACE_PROPOSAL_DAY_LIMIT, 'verified', true], - ['ecosystem', ECOSYSTEM_SPACE_PROPOSAL_DAY_LIMIT, 'id', MAINNET_ECOSYSTEM_SPACES[0]], - ['turbo', TURBO_SPACE_PROPOSAL_DAY_LIMIT, 'turbo', true], - ['normal', SPACE_PROPOSAL_DAY_LIMIT, null, null] + ['flagged', LIMITS['space.flagged.proposal_limit_per_day'], 'flagged', true], + ['verified', LIMITS['space.verified.proposal_limit_per_day'], 'verified', true], + ['ecosystem', LIMITS['space.ecosystem.proposal_limit_per_day'], 'id', ECOSYSTEM_LIST[0]], + ['turbo', LIMITS['space.turbo.proposal_limit_per_day'], 'turbo', true], + ['normal', LIMITS['space.default.proposal_limit_per_day'], null, null] ])( 'rejects if the %s space has exceeded the proposal daily post limit', async (category, limit, key, value) => { @@ -468,11 +500,11 @@ describe('writer/proposal', () => { ); it.each([ - ['flagged', FLAGGED_SPACE_PROPOSAL_MONTH_LIMIT, 'flagged', true], - ['verified', VERIFIED_SPACE_PROPOSAL_MONTH_LIMIT, 'verified', true], - ['ecosystem', ECOSYSTEM_SPACE_PROPOSAL_MONTH_LIMIT, 'id', MAINNET_ECOSYSTEM_SPACES[0]], - ['turbo', TURBO_SPACE_PROPOSAL_MONTH_LIMIT, 'turbo', true], - ['normal', SPACE_PROPOSAL_MONTH_LIMIT, null, null] + ['flagged', LIMITS['space.flagged.proposal_limit_per_month'], 'flagged', true], + ['verified', LIMITS['space.verified.proposal_limit_per_month'], 'verified', true], + ['ecosystem', LIMITS['space.ecosystem.proposal_limit_per_month'], 'id', ECOSYSTEM_LIST[0]], + ['turbo', LIMITS['space.turbo.proposal_limit_per_month'], 'turbo', true], + ['normal', LIMITS['space.default.proposal_limit_per_month'], null, null] ])( 'rejects if the %s space has exceeded the proposal monthly post limit', async (category, limit, key, value) => { @@ -498,7 +530,7 @@ describe('writer/proposal', () => { { dayCount: 0, monthCount: 0, - activeProposalsByAuthor: ACTIVE_PROPOSAL_BY_AUTHOR_LIMIT + 1 + activeProposalsByAuthor: LIMITS['space.active_proposal_limit_per_author'] + 1 } ]); diff --git a/test/unit/writer/settings.test.ts b/test/unit/writer/settings.test.ts index 8f1627d3..f7f2e082 100644 --- a/test/unit/writer/settings.test.ts +++ b/test/unit/writer/settings.test.ts @@ -1,4 +1,3 @@ -import SpaceSchema from '@snapshot-labs/snapshot.js/src/schemas/space.json'; import { verify } from '../../../src/writer/settings'; import { spacesGetSpaceFixtures } from '../../fixtures/space'; import input from '../../fixtures/writer-payload/space.json'; @@ -18,6 +17,58 @@ function randomStrategies(count = 1) { })); } +const LIMITS = { + 'space.active_proposal_limit_per_author': 20, + 'space.ecosystem.proposal_limit_per_day': 150, + 'space.ecosystem.proposal_limit_per_month': 750, + 'space.ecosystem.choices_limit': 20, + 'space.ecosystem.body_length': 10000, + 'space.ecosystem.strategies_limit': 8, + 'space.flagged.proposal_limit_per_day': 5, + 'space.flagged.proposal_limit_per_month': 7, + 'space.flagged.choices_limit': 20, + 'space.flagged.body_length': 10000, + 'space.flagged.strategies_limit': 8, + 'space.default.proposal_limit_per_day': 10, + 'space.default.proposal_limit_per_month': 150, + 'space.default.choices_limit': 20, + 'space.default.body_length': 10000, + 'space.default.strategies_limit': 8, + 'space.turbo.proposal_limit_per_day': 40, + 'space.turbo.proposal_limit_per_month': 200, + 'space.turbo.choices_limit': 1000, + 'space.turbo.body_length': 40000, + 'space.turbo.strategies_limit': 10, + 'space.verified.proposal_limit_per_day': 20, + 'space.verified.proposal_limit_per_month': 100, + 'space.verified.choices_limit': 20, + 'space.verified.body_length': 10000, + 'space.verified.strategies_limit': 6, + 'user.default.follow.limit': 25 +}; +const ECOSYSTEM_LIST = ['test.eth', 'snapshot.eth']; + +const mockGetSpaceType = jest.fn((): any => { + return 'default'; +}); +jest.mock('../../../src/helpers/options', () => { + const originalModule = jest.requireActual('../../../src/helpers/options'); + + return { + __esModule: true, + ...originalModule, + getList: () => { + return ECOSYSTEM_LIST; + }, + getLimit: async (key: string) => { + return LIMITS[key]; + }, + getSpaceType: () => { + return mockGetSpaceType(); + } + }; +}); + // eslint-disable-next-line @typescript-eslint/no-unused-vars const mockGetSpace = jest.fn((_): any => { return spacesGetSpaceFixtures; @@ -81,10 +132,8 @@ describe('writer/settings', () => { }); it.todo('rejects if the submitter does not have permission'); it.todo('rejects if the submitter does not have permission to change admin'); - const maxStrategiesWithSpaceType = - SpaceSchema.definitions.Space.properties.strategies.maxItemsWithSpaceType; - const maxStrategiesForNormalSpace = maxStrategiesWithSpaceType['default']; - const maxStrategiesForTurboSpace = maxStrategiesWithSpaceType['turbo']; + const maxStrategiesForNormalSpace = LIMITS['space.default.strategies_limit']; + const maxStrategiesForTurboSpace = LIMITS['space.turbo.strategies_limit']; it(`rejects if passing more than ${maxStrategiesForNormalSpace} strategies for normal space`, async () => { return expect( verify( @@ -92,10 +141,11 @@ describe('writer/settings', () => { strategies: randomStrategies(maxStrategiesForNormalSpace + 2) }) ) - ).rejects.toContain('wrong space format'); + ).rejects.toContain(`max number of strategies is ${maxStrategiesForNormalSpace}`); }); it(`rejects if passing more than ${maxStrategiesForTurboSpace} strategies for turbo space`, async () => { + mockGetSpaceType.mockResolvedValueOnce('turbo'); mockGetSpace.mockResolvedValueOnce({ ...spacesGetSpaceFixtures, turbo: true }); return expect( verify( @@ -103,7 +153,7 @@ describe('writer/settings', () => { strategies: randomStrategies(maxStrategiesForTurboSpace + 2) }) ) - ).rejects.toContain('wrong space format'); + ).rejects.toContain(`max number of strategies is ${maxStrategiesForTurboSpace}`); }); describe('when the space has an existing custom domain', () => { @@ -220,6 +270,7 @@ describe('writer/settings', () => { describe('with correct number of strategies for turbo spaces', () => { it('returns a Promise resolve', async () => { + mockGetSpaceType.mockResolvedValueOnce('turbo'); mockGetSpace.mockResolvedValueOnce({ ...spacesGetSpaceFixtures, turbo: true }); return expect( verify( diff --git a/yarn.lock b/yarn.lock index ca8c27a1..9d2405cb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1350,10 +1350,10 @@ dependencies: "@sentry/node" "^7.81.1" -"@snapshot-labs/snapshot.js@^0.12.45": - version "0.12.45" - resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.45.tgz#24dd99c7fdf4fab22d16410e384c16ac4ea2d5bc" - integrity sha512-Wt9EbqBvZG1KVTKYPLQwj9XY1dy0WnFycOKoHq+9u/oICoddnudhqj7fUhPvoUw+PFlAGZN161U3gx7yvf6EkQ== +"@snapshot-labs/snapshot.js@^0.12.46": + version "0.12.46" + resolved "https://registry.yarnpkg.com/@snapshot-labs/snapshot.js/-/snapshot.js-0.12.46.tgz#fe0ab1eade4e46d068ee5094ae07b05cdbf53213" + integrity sha512-lcLKDnwXDYNdx6tpCI181ezhTyTulk6NcbidDhsjFTFwec0m5tXnOKAkb/zjDkBRqeBWrruX7NH9Mf4YH3haBg== dependencies: "@ensdomains/eth-ens-namehash" "^2.0.15" "@ethersproject/abi" "^5.6.4"