diff --git a/apps/consumers/src/services/dao/slack-dao.service.test.ts b/apps/consumers/src/services/dao/slack-dao.service.test.ts index 54dd4b96..3b313f6e 100644 --- a/apps/consumers/src/services/dao/slack-dao.service.test.ts +++ b/apps/consumers/src/services/dao/slack-dao.service.test.ts @@ -10,8 +10,8 @@ const TEST_API_URL = 'http://test-api'; const anticaptureClient = makeAnticaptureClient({ getDAOs: async () => [ - { id: 'UNI', chainId: 1, blockTime: 12, votingDelay: '0', alreadySupportCalldataReview: false, supportOffchainData: false }, - { id: 'ENS', chainId: 1, blockTime: 12, votingDelay: '0', alreadySupportCalldataReview: false, supportOffchainData: false }, + { id: 'UNI', chainId: 1, blockTime: 12, votingDelay: '0', supportsCalldataReview: false, supportsOffchainData: false }, + { id: 'ENS', chainId: 1, blockTime: 12, votingDelay: '0', supportsCalldataReview: false, supportsOffchainData: false }, ], }); diff --git a/apps/dispatcher/src/services/triggers/base-trigger.service.ts b/apps/dispatcher/src/services/triggers/base-trigger.service.ts index f7627bee..4baf7e0a 100644 --- a/apps/dispatcher/src/services/triggers/base-trigger.service.ts +++ b/apps/dispatcher/src/services/triggers/base-trigger.service.ts @@ -12,7 +12,7 @@ import { createLogger, type Logger } from '@anticapture/observability'; * @template T - Type of event data being processed */ export abstract class BaseTriggerHandler implements TriggerHandler { - private daoCache: Map = new Map(); + private daoCache: Map = new Map(); protected readonly logger: Logger; @@ -112,9 +112,9 @@ export abstract class BaseTriggerHandler implements TriggerHandler { * @throws Error if anticaptureClient is not provided */ /** - * Gets full DAO info (chainId, alreadySupportCalldataReview) with caching + * Gets full DAO info (chainId, supportsCalldataReview) with caching */ - protected async getDaoInfo(daoId: string): Promise<{ chainId: number; alreadySupportCalldataReview: boolean; supportOffchainData: boolean }> { + protected async getDaoInfo(daoId: string): Promise<{ chainId: number; supportsCalldataReview: boolean; supportsOffchainData: boolean }> { if (!this.anticaptureClient) { throw new Error('AnticaptureClient is required for getDaoInfo'); } @@ -127,12 +127,12 @@ export abstract class BaseTriggerHandler implements TriggerHandler { for (const dao of daos) { this.daoCache.set(dao.id, { chainId: dao.chainId, - alreadySupportCalldataReview: dao.alreadySupportCalldataReview, - supportOffchainData: dao.supportOffchainData + supportsCalldataReview: dao.supportsCalldataReview, + supportsOffchainData: dao.supportsOffchainData }); } - return this.daoCache.get(daoId) || { chainId: 1, alreadySupportCalldataReview: false, supportOffchainData: false }; + return this.daoCache.get(daoId) || { chainId: 1, supportsCalldataReview: false, supportsOffchainData: false }; } /** diff --git a/apps/dispatcher/src/services/triggers/helpers/test-doubles.ts b/apps/dispatcher/src/services/triggers/helpers/test-doubles.ts index b769ae2f..6fb0ad9b 100644 --- a/apps/dispatcher/src/services/triggers/helpers/test-doubles.ts +++ b/apps/dispatcher/src/services/triggers/helpers/test-doubles.ts @@ -72,8 +72,8 @@ export function makeDao(overrides: Partial = {}): DaoInfo { blockTime: 12, votingDelay: '1', chainId: 1, - alreadySupportCalldataReview: false, - supportOffchainData: false, + supportsCalldataReview: false, + supportsOffchainData: false, ...overrides, }; } diff --git a/apps/dispatcher/src/services/triggers/new-proposal-trigger.service.test.ts b/apps/dispatcher/src/services/triggers/new-proposal-trigger.service.test.ts index a5dba54c..0090692c 100644 --- a/apps/dispatcher/src/services/triggers/new-proposal-trigger.service.test.ts +++ b/apps/dispatcher/src/services/triggers/new-proposal-trigger.service.test.ts @@ -38,8 +38,8 @@ describe('NewProposalTriggerHandler', () => { const anticaptureClient = makeAnticaptureClient({ getDAOs: async () => [ - makeDao({ id: 'dao123', alreadySupportCalldataReview: false }), - makeDao({ id: 'dao456', chainId: 10, alreadySupportCalldataReview: true, supportOffchainData: true }), + makeDao({ id: 'dao123', supportsCalldataReview: false }), + makeDao({ id: 'dao456', chainId: 10, supportsCalldataReview: true, supportsOffchainData: true }), ], }); @@ -183,8 +183,8 @@ describe('NewProposalTriggerHandler - cross-DAO eventId deduplication', () => { }, makeAnticaptureClient({ getDAOs: async () => [ - { id: 'ens.eth', blockTime: 12, votingDelay: '1', chainId: 1, alreadySupportCalldataReview: true, supportOffchainData: true }, - { id: 'uniswap.eth', blockTime: 12, votingDelay: '1', chainId: 1, alreadySupportCalldataReview: false, supportOffchainData: true } + { id: 'ens.eth', blockTime: 12, votingDelay: '1', chainId: 1, supportsCalldataReview: true, supportsOffchainData: true }, + { id: 'uniswap.eth', blockTime: 12, votingDelay: '1', chainId: 1, supportsCalldataReview: false, supportsOffchainData: true } ], }) ); diff --git a/apps/dispatcher/src/services/triggers/new-proposal-trigger.service.ts b/apps/dispatcher/src/services/triggers/new-proposal-trigger.service.ts index a1855221..aae0c260 100644 --- a/apps/dispatcher/src/services/triggers/new-proposal-trigger.service.ts +++ b/apps/dispatcher/src/services/triggers/new-proposal-trigger.service.ts @@ -47,7 +47,7 @@ export class NewProposalTriggerHandler extends BaseTriggerHandler { chainId: daoInfo.chainId, daoId, proposalId, - alreadySupportCalldataReview: daoInfo.alreadySupportCalldataReview + alreadySupportCalldataReview: daoInfo.supportsCalldataReview }); await this.sendNotificationsToSubscribers( diff --git a/apps/dispatcher/src/services/triggers/vote-confirmation-trigger.service.test.ts b/apps/dispatcher/src/services/triggers/vote-confirmation-trigger.service.test.ts index 475d8beb..c02ef3cc 100644 --- a/apps/dispatcher/src/services/triggers/vote-confirmation-trigger.service.test.ts +++ b/apps/dispatcher/src/services/triggers/vote-confirmation-trigger.service.test.ts @@ -44,9 +44,9 @@ describe('VoteConfirmationTriggerHandler', () => { await handler.handleMessage({ triggerId: NotificationTypeId.VoteConfirmation, events: [ - { daoId: 'test-dao', proposalId: 'proposal-1', voterAddress: '0xVoter123', support: '1', votingPower: '1000000000000000000', timestamp: 1767225600, transactionHash: '0xSameTxHash', proposalTitle: 'Proposal 1' }, - { daoId: 'test-dao', proposalId: 'proposal-2', voterAddress: '0xVoter123', support: '0', votingPower: '1000000000000000000', timestamp: 1767225600, transactionHash: '0xSameTxHash', proposalTitle: 'Proposal 2' }, - { daoId: 'test-dao', proposalId: 'proposal-3', voterAddress: '0xVoter123', support: '2', votingPower: '1000000000000000000', timestamp: 1767225600, transactionHash: '0xSameTxHash', proposalTitle: 'Proposal 3' }, + { daoId: 'test-dao', proposalId: 'proposal-1', voterAddress: '0xVoter123', support: '1', votingPower: 1000000000000000000n, timestamp: 1767225600, transactionHash: '0xSameTxHash', proposalTitle: 'Proposal 1' }, + { daoId: 'test-dao', proposalId: 'proposal-2', voterAddress: '0xVoter123', support: '0', votingPower: 1000000000000000000n, timestamp: 1767225600, transactionHash: '0xSameTxHash', proposalTitle: 'Proposal 2' }, + { daoId: 'test-dao', proposalId: 'proposal-3', voterAddress: '0xVoter123', support: '2', votingPower: 1000000000000000000n, timestamp: 1767225600, transactionHash: '0xSameTxHash', proposalTitle: 'Proposal 3' }, ] }); diff --git a/apps/dispatcher/src/services/triggers/vote-confirmation-trigger.service.ts b/apps/dispatcher/src/services/triggers/vote-confirmation-trigger.service.ts index 3f980c15..438ade5b 100644 --- a/apps/dispatcher/src/services/triggers/vote-confirmation-trigger.service.ts +++ b/apps/dispatcher/src/services/triggers/vote-confirmation-trigger.service.ts @@ -174,7 +174,7 @@ export class VoteConfirmationTriggerHandler extends BaseTriggerHandler ('daoId' in p ? p.daoId : p.spaceId); export const daosFromItems = (items: ReadonlyArray) => { const ids = Array.from(new Set(items.map(idOf))); - return getDaosHandler({ - items: ids.map(id => ({ id, votingDelay: '0', supportOffchainData: true })), + return daosHandler({ + items: ids.map(id => ({ id, votingDelay: '0', supportsOffchainData: true })), totalCount: ids.length, }); }; @@ -90,11 +90,11 @@ const emptyThreshold = { threshold: 0 }; const testDaos = Object.values(testConstants.daoIds).map(id => ({ id, votingDelay: '0', - supportOffchainData: true + supportsOffchainData: true })); export const defaultHandlers = [ - getDaosHandler({ items: testDaos, totalCount: testDaos.length }), + daosHandler({ items: testDaos, totalCount: testDaos.length }), offchainProposalsHandler(emptyListEnvelope), votesOffchainHandler(emptyListEnvelope), offchainProposalNonVotersHandler(emptyListEnvelope), diff --git a/apps/integrated-tests/tests/core/duplicate-prevention.test.ts b/apps/integrated-tests/tests/core/duplicate-prevention.test.ts index 3897eb27..c4c213a4 100644 --- a/apps/integrated-tests/tests/core/duplicate-prevention.test.ts +++ b/apps/integrated-tests/tests/core/duplicate-prevention.test.ts @@ -1,5 +1,5 @@ import { describe, test, expect, beforeAll, afterEach } from 'vitest'; -import { proposalsHandler, getDaosHandler, offchainProposalsHandler } from '@anticapture/client/msw'; +import { proposalsHandler, daosHandler, offchainProposalsHandler } from '@anticapture/client/msw'; import { HttpResponse } from 'msw'; import type { OnchainProposal } from '@notification-system/anticapture-client'; import { db, TestApps } from '../../src/setup'; @@ -10,7 +10,7 @@ import { testConstants, timeouts } from '../../src/config'; const useDaoAndActiveProposal = (daoId: string, proposal: OnchainProposal) => server.use( - getDaosHandler({ items: [{ id: daoId, votingDelay: '0' }], totalCount: 1 }), + daosHandler({ items: [{ id: daoId, votingDelay: '0' }], totalCount: 1 }), offchainProposalsHandler({ items: [], totalCount: 0 }), proposalsHandler(({ request }) => { const statuses = new URL(request.url).searchParams.getAll('status').map(s => s.toLowerCase()); diff --git a/apps/logic-system/src/triggers/proposal-finished-trigger.ts b/apps/logic-system/src/triggers/proposal-finished-trigger.ts index 13d84d68..4a26aa21 100644 --- a/apps/logic-system/src/triggers/proposal-finished-trigger.ts +++ b/apps/logic-system/src/triggers/proposal-finished-trigger.ts @@ -67,9 +67,9 @@ export class ProposalFinishedTrigger extends Trigger { description: proposal?.description || '', endTimestamp: proposal?.endTimestamp ?? 0, status: proposal?.status || 'unknown', - forVotes: proposal?.forVotes || '0', - againstVotes: proposal?.againstVotes || '0', - abstainVotes: proposal?.abstainVotes || '0' + forVotes: proposal?.forVotes != null ? String(proposal.forVotes) : '0', + againstVotes: proposal?.againstVotes != null ? String(proposal.againstVotes) : '0', + abstainVotes: proposal?.abstainVotes != null ? String(proposal.abstainVotes) : '0' })); // Send all proposals in a single batch message for maximum efficiency diff --git a/apps/subscription-server/src/services/settings.service.test.ts b/apps/subscription-server/src/services/settings.service.test.ts index a4123b11..f9efd21c 100644 --- a/apps/subscription-server/src/services/settings.service.test.ts +++ b/apps/subscription-server/src/services/settings.service.test.ts @@ -64,6 +64,20 @@ describe('SettingsService', () => { expect(result).toEqual([]); }); + + test('drops rows whose trigger_type is no longer in the current enum', async () => { + stub.findByUserResult = [ + { user_id: 'user-1', trigger_type: NotificationTypeId.NewProposal, is_active: true, updated_at: FIXED_DATE }, + { user_id: 'user-1', trigger_type: 'offchain-voting-reminder-75' as NotificationTypeId, is_active: false, updated_at: FIXED_DATE }, + { user_id: 'user-1', trigger_type: 'totally-made-up' as NotificationTypeId, is_active: true, updated_at: FIXED_DATE }, + ]; + + const result = await settingsService.getUserPreferences('user-1'); + + expect(result).toEqual([ + { user_id: 'user-1', trigger_type: NotificationTypeId.NewProposal, is_active: true, updated_at: FIXED_DATE }, + ]); + }); }); describe('saveUserPreferences', () => { diff --git a/apps/subscription-server/src/services/settings.service.ts b/apps/subscription-server/src/services/settings.service.ts index e4863bdf..d19996f0 100644 --- a/apps/subscription-server/src/services/settings.service.ts +++ b/apps/subscription-server/src/services/settings.service.ts @@ -1,11 +1,13 @@ -import type { NotificationTypeId } from '@notification-system/messages'; +import { NotificationTypeId } from '@notification-system/messages'; import { IUserNotificationPreferencesRepository, UserNotificationPreference } from '../interfaces/user_subscription.interface'; export class SettingsService { constructor(private prefsRepo: IUserNotificationPreferencesRepository) {} async getUserPreferences(userId: string): Promise { - return this.prefsRepo.findByUser(userId); + const stored = await this.prefsRepo.findByUser(userId); + const validTriggerTypes = new Set(Object.values(NotificationTypeId)); + return stored.filter(p => validTriggerTypes.has(p.trigger_type)); } async saveUserPreferences( diff --git a/packages/anticapture-client/package.json b/packages/anticapture-client/package.json index 93098d32..f32cbbf6 100644 --- a/packages/anticapture-client/package.json +++ b/packages/anticapture-client/package.json @@ -35,7 +35,7 @@ "vitest": "^4.1.5" }, "dependencies": { - "@anticapture/client": "^1.1.0", + "@anticapture/client": "^1.2.0", "viem": "^2.34.0" } } diff --git a/packages/anticapture-client/src/anticapture-client.ts b/packages/anticapture-client/src/anticapture-client.ts index 604fc342..1f054468 100644 --- a/packages/anticapture-client/src/anticapture-client.ts +++ b/packages/anticapture-client/src/anticapture-client.ts @@ -1,5 +1,5 @@ import { - getDaos, + daos, proposal, proposals, getEventRelevanceThreshold, @@ -54,6 +54,9 @@ function processVotingPowerHistory( .map(item => ({ ...item, daoId, + timestamp: String(item.timestamp), + votingPower: String(item.votingPower), + delta: String(item.delta), changeType: item.delegation ? 'delegation' : item.transfer ? 'transfer' : 'other', sourceAccountId: item.transfer?.from || item.delegation?.from || '', targetAccountId: item.accountId, @@ -73,7 +76,7 @@ export interface AnticaptureClientConfig { export type VoteWithDaoId = OnchainVote & { daoId: string }; export type OffchainVoteWithDaoId = OffchainVote & { daoId: string }; -export type DaoInfo = { id: string; blockTime: number; votingDelay: string; chainId: number; alreadySupportCalldataReview: boolean; supportOffchainData: boolean }; +export type DaoInfo = { id: string; blockTime: number; votingDelay: string; chainId: number; supportsCalldataReview: boolean; supportsOffchainData: boolean }; /** * Public surface of AnticaptureClient — used for dependency injection and mocking. @@ -129,17 +132,17 @@ export class AnticaptureClient implements IAnticaptureClient { private toChecksum(o: T): T { return this.normalizeAddressesInObject(o, getAddress); } private toLowercase(o: T): T { return this.normalizeAddressesInObject(o, a => a.toLowerCase()); } - async getDAOs(): Promise> { + async getDAOs(): Promise> { try { - const res = await this.call(() => getDaos(this.sdkConfig)); + const res = await this.call(() => daos(this.sdkConfig)); const items = res.items ?? []; return items.map(d => ({ id: d.id, blockTime: 12, votingDelay: d.votingDelay ?? '0', chainId: d.chainId ?? 1, - alreadySupportCalldataReview: d.alreadySupportCalldataReview ?? false, - supportOffchainData: d.supportOffchainData ?? false, + supportsCalldataReview: d.supportsCalldataReview ?? false, + supportsOffchainData: d.supportsOffchainData ?? false, })); } catch (err) { console.warn('Returning empty DAO list due to API error:', err instanceof Error ? err.message : err); @@ -152,7 +155,7 @@ export class AnticaptureClient implements IAnticaptureClient { for (const dao of allDaos) { try { // SDK dao param is a string-literal enum; DAO IDs come from runtime /daos response, so we cast - const res = await this.call(() => proposal(dao.id as any, id, this.sdkConfig)); + const res = await this.call(() => proposal(dao.id as any, id, undefined, this.sdkConfig)); if (res) return this.toLowercase(res); } catch (err) { const e = err as { status?: number; response?: { status?: number } }; @@ -280,7 +283,7 @@ export class AnticaptureClient implements IAnticaptureClient { try { // SDK dao param is a string-literal enum; DAO IDs come from runtime /daos response, so we cast const res = await this.call(() => getEventRelevanceThreshold(daoId as any, { type, relevance }, this.sdkConfig)); - return res?.threshold ?? null; + return res?.threshold != null ? String(res.threshold) : null; } catch (err) { console.warn(`[AnticaptureClient] Error fetching threshold for ${daoId}/${type}:`, err instanceof Error ? err.message : err); return null; @@ -302,7 +305,7 @@ export class AnticaptureClient implements IAnticaptureClient { const allDaos = await this.getDAOs(); const all: (OffchainProposalItem & { daoId: string })[] = []; for (const dao of allDaos) { - if (!dao.supportOffchainData) continue; + if (!dao.supportsOffchainData) continue; try { const res = await this.call(() => offchainProposals(dao.id as any, this.toChecksum(variables ?? {}), this.sdkConfig)); const items = (res?.items ?? []).map(i => ({ ...i, daoId: dao.id })); @@ -330,7 +333,7 @@ export class AnticaptureClient implements IAnticaptureClient { const daos = await this.getDAOs(); const voteArrays = await Promise.all( daos - .filter(dao => dao.supportOffchainData) + .filter(dao => dao.supportsOffchainData) .map(async (dao) => { const vs = await this.listOffchainVotes(dao.id, { fromDate, diff --git a/packages/anticapture-client/src/types.ts b/packages/anticapture-client/src/types.ts index d870e8e7..07bee1eb 100644 --- a/packages/anticapture-client/src/types.ts +++ b/packages/anticapture-client/src/types.ts @@ -3,7 +3,10 @@ import type { HistoricalVotingPower, OffchainProposal, OffchainVote } from '@ant export type OffchainProposalItem = OffchainProposal; export type OffchainVoteItem = OffchainVote; -export type ProcessedVotingPowerHistory = HistoricalVotingPower & { +export type ProcessedVotingPowerHistory = Omit & { + timestamp: string; + votingPower: string; + delta: string; changeType: 'delegation' | 'transfer' | 'other'; sourceAccountId: string; targetAccountId: string; diff --git a/packages/anticapture-client/tests/anticapture-client.test.ts b/packages/anticapture-client/tests/anticapture-client.test.ts index 9bd8e941..5f5e8a62 100644 --- a/packages/anticapture-client/tests/anticapture-client.test.ts +++ b/packages/anticapture-client/tests/anticapture-client.test.ts @@ -17,14 +17,14 @@ describe('getDAOs', () => { it('maps DAOs adding hardcoded blockTime: 12', async () => { server.use(http.get(`${TEST_BASE_URL}/daos`, () => HttpResponse.json( daosResponse([ - { id: 'uniswap', votingDelay: '1000', chainId: 1, alreadySupportCalldataReview: false, supportOffchainData: false }, - { id: 'ens', votingDelay: '500', chainId: 1, alreadySupportCalldataReview: false, supportOffchainData: false }, + { id: 'uniswap', votingDelay: '1000', chainId: 1, supportsCalldataReview: false, supportsOffchainData: false }, + { id: 'ens', votingDelay: '500', chainId: 1, supportsCalldataReview: false, supportsOffchainData: false }, ]) ))); const client = createTestClient(); expect(await client.getDAOs()).toEqual([ - { id: 'uniswap', blockTime: 12, votingDelay: '1000', chainId: 1, alreadySupportCalldataReview: false, supportOffchainData: false }, - { id: 'ens', blockTime: 12, votingDelay: '500', chainId: 1, alreadySupportCalldataReview: false, supportOffchainData: false }, + { id: 'uniswap', blockTime: 12, votingDelay: '1000', chainId: 1, supportsCalldataReview: false, supportsOffchainData: false }, + { id: 'ens', blockTime: 12, votingDelay: '500', chainId: 1, supportsCalldataReview: false, supportsOffchainData: false }, ]); }); @@ -40,7 +40,7 @@ describe('getProposalById', () => { server.use( http.get(`${TEST_BASE_URL}/daos`, () => HttpResponse.json( daosResponse([ - { id: 'ens', votingDelay: '0', chainId: 1, supportOffchainData: false, alreadySupportCalldataReview: false }, + { id: 'ens', votingDelay: '0', chainId: 1, supportsOffchainData: false, supportsCalldataReview: false }, ]) )), http.get(`${TEST_BASE_URL}/ens/proposals/prop-1`, () => @@ -57,8 +57,8 @@ describe('getProposalById', () => { server.use( http.get(`${TEST_BASE_URL}/daos`, () => HttpResponse.json( daosResponse([ - { id: 'uniswap', votingDelay: '0', chainId: 1, supportOffchainData: false, alreadySupportCalldataReview: false }, - { id: 'ens', votingDelay: '0', chainId: 1, supportOffchainData: false, alreadySupportCalldataReview: false }, + { id: 'uniswap', votingDelay: '0', chainId: 1, supportsOffchainData: false, supportsCalldataReview: false }, + { id: 'ens', votingDelay: '0', chainId: 1, supportsOffchainData: false, supportsCalldataReview: false }, ]) )), http.get(`${TEST_BASE_URL}/uniswap/proposals/prop-2`, () => new HttpResponse(null, { status: 404 })), @@ -76,7 +76,7 @@ describe('getProposalById', () => { server.use( http.get(`${TEST_BASE_URL}/daos`, () => HttpResponse.json( daosResponse([ - { id: 'ens', votingDelay: '0', chainId: 1, supportOffchainData: false, alreadySupportCalldataReview: false }, + { id: 'ens', votingDelay: '0', chainId: 1, supportsOffchainData: false, supportsCalldataReview: false }, ]) )), http.get(`${TEST_BASE_URL}/ens/proposals/missing-prop`, () => new HttpResponse(null, { status: 404 })), @@ -96,8 +96,8 @@ describe('getProposalById', () => { server.use( http.get(`${TEST_BASE_URL}/daos`, () => HttpResponse.json( daosResponse([ - { id: 'uniswap', votingDelay: '0', chainId: 1, supportOffchainData: false, alreadySupportCalldataReview: false }, - { id: 'ens', votingDelay: '0', chainId: 1, supportOffchainData: false, alreadySupportCalldataReview: false }, + { id: 'uniswap', votingDelay: '0', chainId: 1, supportsOffchainData: false, supportsCalldataReview: false }, + { id: 'ens', votingDelay: '0', chainId: 1, supportsOffchainData: false, supportsCalldataReview: false }, ]) )), http.get(`${TEST_BASE_URL}/uniswap/proposals/prop-500`, () => new HttpResponse(null, { status: 500 })), @@ -382,12 +382,12 @@ describe('listRecentVotesFromAllDaos', () => { }); describe('listRecentOffchainVotesFromAllDaos', () => { - it('only queries DAOs with supportOffchainData: true', async () => { + it('only queries DAOs with supportsOffchainData: true', async () => { server.use( http.get(`${TEST_BASE_URL}/daos`, () => HttpResponse.json(daosResponse([ - { id: 'dao1', supportOffchainData: true }, - { id: 'dao2', supportOffchainData: false }, - { id: 'dao3', supportOffchainData: true }, + { id: 'dao1', supportsOffchainData: true }, + { id: 'dao2', supportsOffchainData: false }, + { id: 'dao3', supportsOffchainData: true }, ]))), http.get(`${TEST_BASE_URL}/dao1/offchain/votes`, () => HttpResponse.json({ items: [{ voter: '0xaaa', created: 2000, proposalId: 'sp1', proposalTitle: 'T1' }], totalCount: 1 })), @@ -405,7 +405,7 @@ describe('listRecentOffchainVotesFromAllDaos', () => { it('returns empty array when no DAOs support offchain data', async () => { server.use( http.get(`${TEST_BASE_URL}/daos`, () => HttpResponse.json(daosResponse([ - { id: 'dao1', supportOffchainData: false } + { id: 'dao1', supportsOffchainData: false } ]))), ); const client = createTestClient(); diff --git a/packages/anticapture-client/tests/offchain-proposal.test.ts b/packages/anticapture-client/tests/offchain-proposal.test.ts index c3b44dca..42537150 100644 --- a/packages/anticapture-client/tests/offchain-proposal.test.ts +++ b/packages/anticapture-client/tests/offchain-proposal.test.ts @@ -32,7 +32,7 @@ describe('listOffchainProposals', () => { it('returns empty array when no DAOs support offchain data', async () => { server.use( http.get(`${TEST_BASE_URL}/daos`, () => HttpResponse.json( - daosResponse([{ id: 'uniswap', supportOffchainData: false }]) + daosResponse([{ id: 'uniswap', supportsOffchainData: false }]) )), ); const client = createTestClient(); @@ -42,7 +42,7 @@ describe('listOffchainProposals', () => { it('returns proposals with daoId attached', async () => { server.use( http.get(`${TEST_BASE_URL}/daos`, () => HttpResponse.json( - daosResponse([{ id: 'ens', supportOffchainData: true }]) + daosResponse([{ id: 'ens', supportsOffchainData: true }]) )), http.get(`${TEST_BASE_URL}/ens/offchain/proposals`, () => HttpResponse.json(offchainProposalsResponse([ @@ -60,8 +60,8 @@ describe('listOffchainProposals', () => { server.use( http.get(`${TEST_BASE_URL}/daos`, () => HttpResponse.json( daosResponse([ - { id: 'dao_a', supportOffchainData: true }, - { id: 'dao_b', supportOffchainData: true }, + { id: 'dao_a', supportsOffchainData: true }, + { id: 'dao_b', supportsOffchainData: true }, ]) )), http.get(`${TEST_BASE_URL}/dao_a/offchain/proposals`, () => @@ -81,12 +81,12 @@ describe('listOffchainProposals', () => { expect(result.map(p => p.id)).toEqual(['snap-b', 'snap-a']); // sorted DESC by created }); - it('skips DAOs without supportOffchainData and queries only offchain-enabled ones', async () => { + it('skips DAOs without supportsOffchainData and queries only offchain-enabled ones', async () => { server.use( http.get(`${TEST_BASE_URL}/daos`, () => HttpResponse.json( daosResponse([ - { id: 'onchain_only', supportOffchainData: false }, - { id: 'offchain_dao', supportOffchainData: true }, + { id: 'onchain_only', supportsOffchainData: false }, + { id: 'offchain_dao', supportsOffchainData: true }, ]) )), http.get(`${TEST_BASE_URL}/offchain_dao/offchain/proposals`, () => @@ -106,8 +106,8 @@ describe('listOffchainProposals', () => { server.use( http.get(`${TEST_BASE_URL}/daos`, () => HttpResponse.json( daosResponse([ - { id: 'ok_dao', supportOffchainData: true }, - { id: 'bad_dao', supportOffchainData: true }, + { id: 'ok_dao', supportsOffchainData: true }, + { id: 'bad_dao', supportsOffchainData: true }, ]) )), http.get(`${TEST_BASE_URL}/ok_dao/offchain/proposals`, () => diff --git a/packages/anticapture-client/tests/test-helpers.ts b/packages/anticapture-client/tests/test-helpers.ts index 1b436d86..6a4c7b15 100644 --- a/packages/anticapture-client/tests/test-helpers.ts +++ b/packages/anticapture-client/tests/test-helpers.ts @@ -21,16 +21,16 @@ export function daosResponse(items: Array<{ id: string; votingDelay?: string; chainId?: number; - supportOffchainData?: boolean; - alreadySupportCalldataReview?: boolean; + supportsOffchainData?: boolean; + supportsCalldataReview?: boolean; }>) { return { items: items.map(d => ({ id: d.id, votingDelay: d.votingDelay ?? '0', chainId: d.chainId ?? 1, - supportOffchainData: d.supportOffchainData ?? false, - alreadySupportCalldataReview: d.alreadySupportCalldataReview ?? false, + supportsOffchainData: d.supportsOffchainData ?? false, + supportsCalldataReview: d.supportsCalldataReview ?? false, })), }; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ba9267a1..e09dd740 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -262,8 +262,8 @@ importers: apps/integrated-tests: devDependencies: '@anticapture/client': - specifier: ^1.1.0 - version: 1.1.0(msw@2.12.10(@types/node@20.17.46)(typescript@5.8.3)) + specifier: ^1.2.0 + version: 1.2.0(msw@2.12.10(@types/node@20.17.46)(typescript@5.8.3)) '@notification-system/anticapture-client': specifier: workspace:* version: link:../../packages/anticapture-client @@ -471,8 +471,8 @@ importers: packages/anticapture-client: dependencies: '@anticapture/client': - specifier: ^1.1.0 - version: 1.1.0(msw@2.12.10(@types/node@20.17.46)(typescript@5.8.3)) + specifier: ^1.2.0 + version: 1.2.0(msw@2.12.10(@types/node@20.17.46)(typescript@5.8.3)) viem: specifier: ^2.34.0 version: 2.34.0(typescript@5.8.3)(zod@3.24.3) @@ -534,8 +534,8 @@ packages: resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} - '@anticapture/client@1.1.0': - resolution: {integrity: sha512-YEgF6RRUzxw2Jh8btzcGiuVwfI3U6WcVuVIp2qLAJ+L8uh3df0PVQB4czcgTaG3zuHHx/QxEC6sSBDVeVIEGOg==} + '@anticapture/client@1.2.0': + resolution: {integrity: sha512-x31GsUyDT1d32RoDjKkzU3F0G8XmuEESy2wZKxBbGeL0QN/3rGEPXNMDf5cR+c4mlf5jfNLqvbd8U+odKAkbyA==} peerDependencies: '@tanstack/react-query': ^5.0.0 msw: ^2.0.0 @@ -4708,6 +4708,9 @@ packages: zod@3.24.3: resolution: {integrity: sha512-HhY1oqzWCQWuUqvBFnsyrtZRhyPeR7SUGv+C4+MsisMuVfSPx8HpwWqH8tRahSlt6M3PiFAcoeFhZAqIXTxoSg==} + zod@4.4.3: + resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} + zustand@4.5.7: resolution: {integrity: sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==} engines: {node: '>=12.7.0'} @@ -4729,9 +4732,12 @@ snapshots: '@alloc/quick-lru@5.2.0': {} - '@anticapture/client@1.1.0(msw@2.12.10(@types/node@20.17.46)(typescript@5.8.3))': + '@anticapture/client@1.2.0(msw@2.12.10(@types/node@20.17.46)(typescript@5.8.3))': dependencies: '@faker-js/faker': 9.9.0 + pino: 9.14.0 + tsx: 4.19.4 + zod: 4.4.3 optionalDependencies: msw: 2.12.10(@types/node@20.17.46)(typescript@5.8.3) @@ -9346,6 +9352,8 @@ snapshots: zod@3.24.3: {} + zod@4.4.3: {} + zustand@4.5.7(@types/react@18.3.27)(react@18.3.1): dependencies: use-sync-external-store: 1.6.0(react@18.3.1)