From 3e4b0e791a232c69c289fc3dc861ac76af80fc01 Mon Sep 17 00:00:00 2001 From: Leonardo Vieira Date: Thu, 26 Feb 2026 11:16:59 -0300 Subject: [PATCH 01/42] feat: generated files --- .../dist/anticapture-client.d.ts | 23 ++ .../dist/anticapture-client.js | 76 +++++++ packages/anticapture-client/dist/index.d.ts | 2 +- packages/anticapture-client/dist/schemas.d.ts | 214 ++++++++++++++++++ packages/anticapture-client/dist/schemas.js | 35 ++- 5 files changed, 348 insertions(+), 2 deletions(-) diff --git a/packages/anticapture-client/dist/anticapture-client.d.ts b/packages/anticapture-client/dist/anticapture-client.d.ts index d38e0f5b..fff29777 100644 --- a/packages/anticapture-client/dist/anticapture-client.d.ts +++ b/packages/anticapture-client/dist/anticapture-client.d.ts @@ -2,6 +2,7 @@ import { AxiosInstance } from 'axios'; import { z } from 'zod'; import type { GetProposalByIdQuery, ListProposalsQuery, ListProposalsQueryVariables, ListHistoricalVotingPowerQueryVariables, ListVotesQuery, ListVotesQueryVariables } from './gql/graphql'; import { SafeProposalNonVotersResponseSchema, ProcessedVotingPowerHistory } from './schemas'; +import type { OffchainProposalItem } from './schemas'; type ProposalItems = NonNullable['items']; type VotingPowerHistoryItems = ProcessedVotingPowerHistory[]; type ProposalNonVoter = z.infer['proposalNonVoters']['items'][0]; @@ -28,6 +29,11 @@ export declare class AnticaptureClient { */ private toLowercase; private query; + /** + * Executes a raw GraphQL query string (for queries not yet in codegen) + * Same as query() but accepts a string instead of a TypedDocumentNode + */ + private queryRaw; private buildHeaders; /** * Fetches all DAOs from the anticapture GraphQL API with full type safety @@ -74,5 +80,22 @@ export declare class AnticaptureClient { * @returns Array of votes from all DAOs with daoId included */ listRecentVotesFromAllDaos(timestampGt: string, limit?: number): Promise; + /** + * Lists offchain (Snapshot) proposals from all DAOs or a specific DAO + * Uses raw query string since codegen hasn't been run against the updated gateway yet. + * TODO: Switch to typed document after running codegen with offchain proposals in the gateway schema + * @param variables Query variables (skip, limit, orderDirection, status, fromDate) + * @param daoId Optional specific DAO ID. If not provided, queries all DAOs + * @returns Array of offchain proposal items with daoId attached + */ + listOffchainProposals(variables?: { + skip?: number; + limit?: number; + orderDirection?: string; + status?: string | string[]; + fromDate?: number; + }, daoId?: string): Promise<(OffchainProposalItem & { + daoId: string; + })[]>; } export {}; diff --git a/packages/anticapture-client/dist/anticapture-client.js b/packages/anticapture-client/dist/anticapture-client.js index 3a6327f4..0d166a19 100644 --- a/packages/anticapture-client/dist/anticapture-client.js +++ b/packages/anticapture-client/dist/anticapture-client.js @@ -105,6 +105,22 @@ class AnticaptureClient { } return schema.parse(this.toLowercase(response.data.data)); } + /** + * Executes a raw GraphQL query string (for queries not yet in codegen) + * Same as query() but accepts a string instead of a TypedDocumentNode + */ + async queryRaw(queryString, schema, variables, daoId) { + const headers = this.buildHeaders(daoId); + const checksummedVariables = variables ? this.toChecksum(variables) : variables; + const response = await this.httpClient.post('', { + query: queryString, + variables: checksummedVariables, + }, { headers }); + if (response.data.errors) { + throw new Error(JSON.stringify(response.data.errors)); + } + return schema.parse(this.toLowercase(response.data.data)); + } buildHeaders(daoId) { const headers = { 'Content-Type': 'application/json', @@ -291,5 +307,65 @@ class AnticaptureClient { }); return allVotes; } + /** + * Lists offchain (Snapshot) proposals from all DAOs or a specific DAO + * Uses raw query string since codegen hasn't been run against the updated gateway yet. + * TODO: Switch to typed document after running codegen with offchain proposals in the gateway schema + * @param variables Query variables (skip, limit, orderDirection, status, fromDate) + * @param daoId Optional specific DAO ID. If not provided, queries all DAOs + * @returns Array of offchain proposal items with daoId attached + */ + async listOffchainProposals(variables, daoId) { + const query = ` + query ListOffchainProposals($skip: NonNegativeInt, $limit: PositiveInt, $orderDirection: queryInput_offchainProposals_orderDirection, $status: JSON, $fromDate: Float) { + offchainProposals(skip: $skip, limit: $limit, orderDirection: $orderDirection, status: $status, fromDate: $fromDate) { + items { + id + spaceId + author + title + body + discussion + type + start + end + state + created + updated + link + flagged + } + totalCount + } + } + `; + if (!daoId) { + const allDAOs = await this.getDAOs(); + const allProposals = []; + for (const dao of allDAOs) { + try { + const validated = await this.queryRaw(query, schemas_1.SafeOffchainProposalsResponseSchema, variables, dao.id); + const items = validated.offchainProposals.items.map(item => ({ ...item, daoId: dao.id })); + if (items.length > 0) { + allProposals.push(...items); + } + } + catch (error) { + console.warn(`Skipping offchain proposals for ${dao.id} due to API error: ${error instanceof Error ? error.message : error}`); + } + } + // Sort by created timestamp desc (most recent first) + allProposals.sort((a, b) => b.created - a.created); + return allProposals; + } + try { + const validated = await this.queryRaw(query, schemas_1.SafeOffchainProposalsResponseSchema, variables, daoId); + return validated.offchainProposals.items.map(item => ({ ...item, daoId })); + } + catch (error) { + console.warn(`Error querying offchain proposals for DAO ${daoId}: ${error instanceof Error ? error.message : error}`); + return []; + } + } } exports.AnticaptureClient = AnticaptureClient; diff --git a/packages/anticapture-client/dist/index.d.ts b/packages/anticapture-client/dist/index.d.ts index 0adeebe1..37ca6054 100644 --- a/packages/anticapture-client/dist/index.d.ts +++ b/packages/anticapture-client/dist/index.d.ts @@ -2,4 +2,4 @@ export { AnticaptureClient } from './anticapture-client'; export type { VoteWithDaoId } from './anticapture-client'; export type { GetDaOsQuery, GetProposalByIdQuery, GetProposalByIdQueryVariables, ListProposalsQuery, ListProposalsQueryVariables, ListVotesQuery, ListVotesQueryVariables, ListHistoricalVotingPowerQuery, ListHistoricalVotingPowerQueryVariables } from './gql/graphql'; export { QueryInput_Proposals_OrderDirection, QueryInput_HistoricalVotingPower_OrderBy, QueryInput_HistoricalVotingPower_OrderDirection, QueryInput_Votes_OrderBy, QueryInput_Votes_OrderDirection } from './gql/graphql'; -export type { ProcessedVotingPowerHistory } from './schemas'; +export type { ProcessedVotingPowerHistory, OffchainProposalItem } from './schemas'; diff --git a/packages/anticapture-client/dist/schemas.d.ts b/packages/anticapture-client/dist/schemas.d.ts index ca577146..43994da9 100644 --- a/packages/anticapture-client/dist/schemas.d.ts +++ b/packages/anticapture-client/dist/schemas.d.ts @@ -559,6 +559,220 @@ export declare const SafeProposalNonVotersResponseSchema: z.ZodEffects; +export declare const OffchainProposalItemSchema: z.ZodObject<{ + id: z.ZodString; + spaceId: z.ZodString; + author: z.ZodString; + title: z.ZodString; + body: z.ZodString; + discussion: z.ZodString; + type: z.ZodString; + start: z.ZodNumber; + end: z.ZodNumber; + state: z.ZodString; + created: z.ZodNumber; + updated: z.ZodNumber; + link: z.ZodString; + flagged: z.ZodBoolean; +}, "strip", z.ZodTypeAny, { + link: string; + id: string; + type: string; + title: string; + spaceId: string; + author: string; + body: string; + discussion: string; + start: number; + end: number; + state: string; + created: number; + updated: number; + flagged: boolean; +}, { + link: string; + id: string; + type: string; + title: string; + spaceId: string; + author: string; + body: string; + discussion: string; + start: number; + end: number; + state: string; + created: number; + updated: number; + flagged: boolean; +}>; +export type OffchainProposalItem = z.infer; +export declare const SafeOffchainProposalsResponseSchema: z.ZodEffects>, "many">; + totalCount: z.ZodNumber; + }, "strip", z.ZodTypeAny, { + items: ({ + link: string; + id: string; + type: string; + title: string; + spaceId: string; + author: string; + body: string; + discussion: string; + start: number; + end: number; + state: string; + created: number; + updated: number; + flagged: boolean; + } | null)[]; + totalCount: number; + }, { + items: ({ + link: string; + id: string; + type: string; + title: string; + spaceId: string; + author: string; + body: string; + discussion: string; + start: number; + end: number; + state: string; + created: number; + updated: number; + flagged: boolean; + } | null)[]; + totalCount: number; + }>>; +}, "strip", z.ZodTypeAny, { + offchainProposals: { + items: ({ + link: string; + id: string; + type: string; + title: string; + spaceId: string; + author: string; + body: string; + discussion: string; + start: number; + end: number; + state: string; + created: number; + updated: number; + flagged: boolean; + } | null)[]; + totalCount: number; + } | null; +}, { + offchainProposals: { + items: ({ + link: string; + id: string; + type: string; + title: string; + spaceId: string; + author: string; + body: string; + discussion: string; + start: number; + end: number; + state: string; + created: number; + updated: number; + flagged: boolean; + } | null)[]; + totalCount: number; + } | null; +}>, { + offchainProposals: { + items: { + link: string; + id: string; + type: string; + title: string; + spaceId: string; + author: string; + body: string; + discussion: string; + start: number; + end: number; + state: string; + created: number; + updated: number; + flagged: boolean; + }[]; + totalCount: number; + }; +}, { + offchainProposals: { + items: ({ + link: string; + id: string; + type: string; + title: string; + spaceId: string; + author: string; + body: string; + discussion: string; + start: number; + end: number; + state: string; + created: number; + updated: number; + flagged: boolean; + } | null)[]; + totalCount: number; + } | null; +}>; type SafeProposalsResponse = z.infer; type SafeHistoricalVotingPowerResponse = z.infer; export type ProcessedVotingPowerHistory = z.infer & { diff --git a/packages/anticapture-client/dist/schemas.js b/packages/anticapture-client/dist/schemas.js index affb1c0a..3e9c4932 100644 --- a/packages/anticapture-client/dist/schemas.js +++ b/packages/anticapture-client/dist/schemas.js @@ -1,6 +1,6 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -exports.SafeProposalNonVotersResponseSchema = exports.SafeVotesResponseSchema = exports.SafeHistoricalVotingPowerResponseSchema = exports.SafeProposalByIdResponseSchema = exports.SafeProposalsResponseSchema = exports.SafeDaosResponseSchema = void 0; +exports.SafeOffchainProposalsResponseSchema = exports.OffchainProposalItemSchema = exports.SafeProposalNonVotersResponseSchema = exports.SafeVotesResponseSchema = exports.SafeHistoricalVotingPowerResponseSchema = exports.SafeProposalByIdResponseSchema = exports.SafeProposalsResponseSchema = exports.SafeDaosResponseSchema = void 0; exports.processProposals = processProposals; exports.processVotingPowerHistory = processVotingPowerHistory; const zod_1 = require("zod"); @@ -116,6 +116,39 @@ exports.SafeProposalNonVotersResponseSchema = zod_1.z.object({ } }; }); +exports.OffchainProposalItemSchema = zod_1.z.object({ + id: zod_1.z.string(), + spaceId: zod_1.z.string(), + author: zod_1.z.string(), + title: zod_1.z.string(), + body: zod_1.z.string(), + discussion: zod_1.z.string(), + type: zod_1.z.string(), + start: zod_1.z.number(), + end: zod_1.z.number(), + state: zod_1.z.string(), + created: zod_1.z.number(), + updated: zod_1.z.number(), + link: zod_1.z.string(), + flagged: zod_1.z.boolean(), +}); +exports.SafeOffchainProposalsResponseSchema = zod_1.z.object({ + offchainProposals: zod_1.z.object({ + items: zod_1.z.array(exports.OffchainProposalItemSchema.nullable()), + totalCount: zod_1.z.number(), + }).nullable(), +}).transform((data) => { + if (!data.offchainProposals) { + console.warn('OffchainProposalsResponse has null offchainProposals:', data); + return { offchainProposals: { items: [], totalCount: 0 } }; + } + return { + offchainProposals: { + ...data.offchainProposals, + items: data.offchainProposals.items.filter((item) => item !== null), + }, + }; +}); // Internal helper function to process validated proposals function processProposals(validated, daoId) { return validated.proposals.items.reduce((acc, proposal) => { From 2901dd2534703be9a2e1d8de3fc10828925f6f71 Mon Sep 17 00:00:00 2001 From: Leonardo Vieira Date: Thu, 26 Feb 2026 11:22:58 -0300 Subject: [PATCH 02/42] feat: massages for the snapshot proposal case --- packages/messages/src/index.ts | 1 + packages/messages/src/triggers/buttons.ts | 15 +++++++++++++++ .../src/triggers/new-offchain-proposal.ts | 3 +++ 3 files changed, 19 insertions(+) create mode 100644 packages/messages/src/triggers/new-offchain-proposal.ts diff --git a/packages/messages/src/index.ts b/packages/messages/src/index.ts index 7b463702..26b0cd7c 100644 --- a/packages/messages/src/index.ts +++ b/packages/messages/src/index.ts @@ -4,6 +4,7 @@ // Export trigger messages export * from './triggers/new-proposal'; +export * from './triggers/new-offchain-proposal'; export * from './triggers/vote-confirmation'; export * from './triggers/voting-reminder'; export * from './triggers/proposal-finished'; diff --git a/packages/messages/src/triggers/buttons.ts b/packages/messages/src/triggers/buttons.ts index 1a9902b0..29374947 100644 --- a/packages/messages/src/triggers/buttons.ts +++ b/packages/messages/src/triggers/buttons.ts @@ -38,6 +38,10 @@ export const callToActionButtons = { votingReminder: { text: 'Check about the delegates and proposal information', url: 'https://anticapture.com/' + }, + newOffchainProposal: { + text: 'Review DAO data before voting', + url: 'https://anticapture.com/' } } as const; @@ -46,6 +50,11 @@ export const callToActionButtons = { */ export const scanButtonText = 'View Transaction'; +/** + * Text for forum discussion button + */ +export const discussionButtonText = 'View Discussion'; + /** * Parameters for building notification buttons */ @@ -53,6 +62,7 @@ export interface BuildButtonsParams { triggerType: keyof typeof callToActionButtons; txHash?: string; chainId?: number; + discussionUrl?: string; } const explorerService = new ExplorerService(); @@ -67,6 +77,11 @@ export function buildButtons(params: BuildButtonsParams): Button[] { // Always add CTA button buttons.push(callToActionButtons[params.triggerType]); + // Add discussion button if forum URL is available + if (params.discussionUrl) { + buttons.push({ text: discussionButtonText, url: params.discussionUrl }); + } + // Add scan button if transaction info is available if (params.txHash && params.chainId) { const scanUrl = explorerService.getTransactionLink(params.chainId, params.txHash); diff --git a/packages/messages/src/triggers/new-offchain-proposal.ts b/packages/messages/src/triggers/new-offchain-proposal.ts new file mode 100644 index 00000000..f692a16f --- /dev/null +++ b/packages/messages/src/triggers/new-offchain-proposal.ts @@ -0,0 +1,3 @@ +export const newOffchainProposalMessages = { + notification: '📋 New Snapshot proposal in {{daoId}}: "{{title}}"' +}; From eb39c32bb8ac53e844943d1d90c44aa605f225c5 Mon Sep 17 00:00:00 2001 From: Leonardo Vieira Date: Thu, 26 Feb 2026 11:36:37 -0300 Subject: [PATCH 03/42] feat: update anticapture client to query offchain proposals --- .../dist/anticapture-client.d.ts | 17 +- .../dist/anticapture-client.js | 45 +- packages/anticapture-client/dist/gql/gql.d.ts | 5 + packages/anticapture-client/dist/gql/gql.js | 1 + .../anticapture-client/dist/gql/graphql.d.ts | 351 ++++++++++++++++ .../anticapture-client/dist/gql/graphql.js | 96 ++++- packages/anticapture-client/dist/schemas.d.ts | 204 +++------ packages/anticapture-client/dist/schemas.js | 9 - .../queries/offchain-proposals.graphql | 12 + packages/anticapture-client/src/gql/gql.ts | 6 + .../anticapture-client/src/gql/graphql.ts | 397 ++++++++++++++++++ packages/anticapture-client/src/index.ts | 2 +- packages/anticapture-client/src/schemas.ts | 30 ++ 13 files changed, 949 insertions(+), 226 deletions(-) create mode 100644 packages/anticapture-client/queries/offchain-proposals.graphql diff --git a/packages/anticapture-client/dist/anticapture-client.d.ts b/packages/anticapture-client/dist/anticapture-client.d.ts index fff29777..7538f872 100644 --- a/packages/anticapture-client/dist/anticapture-client.d.ts +++ b/packages/anticapture-client/dist/anticapture-client.d.ts @@ -1,6 +1,6 @@ import { AxiosInstance } from 'axios'; import { z } from 'zod'; -import type { GetProposalByIdQuery, ListProposalsQuery, ListProposalsQueryVariables, ListHistoricalVotingPowerQueryVariables, ListVotesQuery, ListVotesQueryVariables } from './gql/graphql'; +import type { GetProposalByIdQuery, ListProposalsQuery, ListProposalsQueryVariables, ListHistoricalVotingPowerQueryVariables, ListVotesQuery, ListVotesQueryVariables, ListOffchainProposalsQueryVariables } from './gql/graphql'; import { SafeProposalNonVotersResponseSchema, ProcessedVotingPowerHistory } from './schemas'; import type { OffchainProposalItem } from './schemas'; type ProposalItems = NonNullable['items']; @@ -29,11 +29,6 @@ export declare class AnticaptureClient { */ private toLowercase; private query; - /** - * Executes a raw GraphQL query string (for queries not yet in codegen) - * Same as query() but accepts a string instead of a TypedDocumentNode - */ - private queryRaw; private buildHeaders; /** * Fetches all DAOs from the anticapture GraphQL API with full type safety @@ -82,19 +77,11 @@ export declare class AnticaptureClient { listRecentVotesFromAllDaos(timestampGt: string, limit?: number): Promise; /** * Lists offchain (Snapshot) proposals from all DAOs or a specific DAO - * Uses raw query string since codegen hasn't been run against the updated gateway yet. - * TODO: Switch to typed document after running codegen with offchain proposals in the gateway schema * @param variables Query variables (skip, limit, orderDirection, status, fromDate) * @param daoId Optional specific DAO ID. If not provided, queries all DAOs * @returns Array of offchain proposal items with daoId attached */ - listOffchainProposals(variables?: { - skip?: number; - limit?: number; - orderDirection?: string; - status?: string | string[]; - fromDate?: number; - }, daoId?: string): Promise<(OffchainProposalItem & { + listOffchainProposals(variables?: ListOffchainProposalsQueryVariables, daoId?: string): Promise<(OffchainProposalItem & { daoId: string; })[]>; } diff --git a/packages/anticapture-client/dist/anticapture-client.js b/packages/anticapture-client/dist/anticapture-client.js index 0d166a19..edce5364 100644 --- a/packages/anticapture-client/dist/anticapture-client.js +++ b/packages/anticapture-client/dist/anticapture-client.js @@ -105,22 +105,6 @@ class AnticaptureClient { } return schema.parse(this.toLowercase(response.data.data)); } - /** - * Executes a raw GraphQL query string (for queries not yet in codegen) - * Same as query() but accepts a string instead of a TypedDocumentNode - */ - async queryRaw(queryString, schema, variables, daoId) { - const headers = this.buildHeaders(daoId); - const checksummedVariables = variables ? this.toChecksum(variables) : variables; - const response = await this.httpClient.post('', { - query: queryString, - variables: checksummedVariables, - }, { headers }); - if (response.data.errors) { - throw new Error(JSON.stringify(response.data.errors)); - } - return schema.parse(this.toLowercase(response.data.data)); - } buildHeaders(daoId) { const headers = { 'Content-Type': 'application/json', @@ -309,42 +293,17 @@ class AnticaptureClient { } /** * Lists offchain (Snapshot) proposals from all DAOs or a specific DAO - * Uses raw query string since codegen hasn't been run against the updated gateway yet. - * TODO: Switch to typed document after running codegen with offchain proposals in the gateway schema * @param variables Query variables (skip, limit, orderDirection, status, fromDate) * @param daoId Optional specific DAO ID. If not provided, queries all DAOs * @returns Array of offchain proposal items with daoId attached */ async listOffchainProposals(variables, daoId) { - const query = ` - query ListOffchainProposals($skip: NonNegativeInt, $limit: PositiveInt, $orderDirection: queryInput_offchainProposals_orderDirection, $status: JSON, $fromDate: Float) { - offchainProposals(skip: $skip, limit: $limit, orderDirection: $orderDirection, status: $status, fromDate: $fromDate) { - items { - id - spaceId - author - title - body - discussion - type - start - end - state - created - updated - link - flagged - } - totalCount - } - } - `; if (!daoId) { const allDAOs = await this.getDAOs(); const allProposals = []; for (const dao of allDAOs) { try { - const validated = await this.queryRaw(query, schemas_1.SafeOffchainProposalsResponseSchema, variables, dao.id); + const validated = await this.query(graphql_2.ListOffchainProposalsDocument, schemas_1.SafeOffchainProposalsResponseSchema, variables, dao.id); const items = validated.offchainProposals.items.map(item => ({ ...item, daoId: dao.id })); if (items.length > 0) { allProposals.push(...items); @@ -359,7 +318,7 @@ class AnticaptureClient { return allProposals; } try { - const validated = await this.queryRaw(query, schemas_1.SafeOffchainProposalsResponseSchema, variables, daoId); + const validated = await this.query(graphql_2.ListOffchainProposalsDocument, schemas_1.SafeOffchainProposalsResponseSchema, variables, daoId); return validated.offchainProposals.items.map(item => ({ ...item, daoId })); } catch (error) { diff --git a/packages/anticapture-client/dist/gql/gql.d.ts b/packages/anticapture-client/dist/gql/gql.d.ts index 25771ff3..8df8eec4 100644 --- a/packages/anticapture-client/dist/gql/gql.d.ts +++ b/packages/anticapture-client/dist/gql/gql.d.ts @@ -13,6 +13,7 @@ import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document- */ type Documents = { "query GetDAOs {\n daos {\n items {\n id\n votingDelay\n chainId\n }\n }\n}": typeof types.GetDaOsDocument; + "query ListOffchainProposals($skip: NonNegativeInt, $limit: PositiveInt, $orderDirection: queryInput_offchainProposals_orderDirection, $status: JSON, $fromDate: Float) {\n offchainProposals(\n skip: $skip\n limit: $limit\n orderDirection: $orderDirection\n status: $status\n fromDate: $fromDate\n ) {\n items {\n id\n title\n discussion\n state\n created\n }\n totalCount\n }\n}": typeof types.ListOffchainProposalsDocument; "query ProposalNonVoters($id: String!, $addresses: JSON) {\n proposalNonVoters(id: $id, addresses: $addresses) {\n items {\n voter\n }\n }\n}": typeof types.ProposalNonVotersDocument; "query GetProposalById($id: String!) {\n proposal(id: $id) {\n id\n daoId\n proposerAccountId\n title\n description\n startBlock\n endBlock\n endTimestamp\n timestamp\n status\n forVotes\n againstVotes\n abstainVotes\n txHash\n }\n}\n\nquery ListProposals($skip: NonNegativeInt, $limit: PositiveInt, $orderDirection: queryInput_proposals_orderDirection, $status: JSON, $fromDate: Float, $fromEndDate: Float, $includeOptimisticProposals: queryInput_proposals_includeOptimisticProposals) {\n proposals(\n skip: $skip\n limit: $limit\n orderDirection: $orderDirection\n status: $status\n fromDate: $fromDate\n fromEndDate: $fromEndDate\n includeOptimisticProposals: $includeOptimisticProposals\n ) {\n items {\n id\n daoId\n proposerAccountId\n title\n description\n startBlock\n endBlock\n endTimestamp\n timestamp\n status\n forVotes\n againstVotes\n abstainVotes\n txHash\n }\n totalCount\n }\n}": typeof types.GetProposalByIdDocument; "query ListVotes($voterAddressIn: JSON, $fromDate: Float, $toDate: Float, $limit: Float, $skip: NonNegativeInt, $orderBy: queryInput_votes_orderBy, $orderDirection: queryInput_votes_orderDirection, $support: Float) {\n votes(\n voterAddressIn: $voterAddressIn\n fromDate: $fromDate\n toDate: $toDate\n limit: $limit\n skip: $skip\n orderBy: $orderBy\n orderDirection: $orderDirection\n support: $support\n ) {\n items {\n transactionHash\n proposalId\n voterAddress\n support\n votingPower\n timestamp\n reason\n proposalTitle\n }\n totalCount\n }\n}": typeof types.ListVotesDocument; @@ -36,6 +37,10 @@ export declare function graphql(source: string): unknown; * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export declare function graphql(source: "query GetDAOs {\n daos {\n items {\n id\n votingDelay\n chainId\n }\n }\n}"): (typeof documents)["query GetDAOs {\n daos {\n items {\n id\n votingDelay\n chainId\n }\n }\n}"]; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export declare function graphql(source: "query ListOffchainProposals($skip: NonNegativeInt, $limit: PositiveInt, $orderDirection: queryInput_offchainProposals_orderDirection, $status: JSON, $fromDate: Float) {\n offchainProposals(\n skip: $skip\n limit: $limit\n orderDirection: $orderDirection\n status: $status\n fromDate: $fromDate\n ) {\n items {\n id\n title\n discussion\n state\n created\n }\n totalCount\n }\n}"): (typeof documents)["query ListOffchainProposals($skip: NonNegativeInt, $limit: PositiveInt, $orderDirection: queryInput_offchainProposals_orderDirection, $status: JSON, $fromDate: Float) {\n offchainProposals(\n skip: $skip\n limit: $limit\n orderDirection: $orderDirection\n status: $status\n fromDate: $fromDate\n ) {\n items {\n id\n title\n discussion\n state\n created\n }\n totalCount\n }\n}"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/packages/anticapture-client/dist/gql/gql.js b/packages/anticapture-client/dist/gql/gql.js index 5a989ed0..3cc6078a 100644 --- a/packages/anticapture-client/dist/gql/gql.js +++ b/packages/anticapture-client/dist/gql/gql.js @@ -38,6 +38,7 @@ exports.graphql = graphql; const types = __importStar(require("./graphql")); const documents = { "query GetDAOs {\n daos {\n items {\n id\n votingDelay\n chainId\n }\n }\n}": types.GetDaOsDocument, + "query ListOffchainProposals($skip: NonNegativeInt, $limit: PositiveInt, $orderDirection: queryInput_offchainProposals_orderDirection, $status: JSON, $fromDate: Float) {\n offchainProposals(\n skip: $skip\n limit: $limit\n orderDirection: $orderDirection\n status: $status\n fromDate: $fromDate\n ) {\n items {\n id\n title\n discussion\n state\n created\n }\n totalCount\n }\n}": types.ListOffchainProposalsDocument, "query ProposalNonVoters($id: String!, $addresses: JSON) {\n proposalNonVoters(id: $id, addresses: $addresses) {\n items {\n voter\n }\n }\n}": types.ProposalNonVotersDocument, "query GetProposalById($id: String!) {\n proposal(id: $id) {\n id\n daoId\n proposerAccountId\n title\n description\n startBlock\n endBlock\n endTimestamp\n timestamp\n status\n forVotes\n againstVotes\n abstainVotes\n txHash\n }\n}\n\nquery ListProposals($skip: NonNegativeInt, $limit: PositiveInt, $orderDirection: queryInput_proposals_orderDirection, $status: JSON, $fromDate: Float, $fromEndDate: Float, $includeOptimisticProposals: queryInput_proposals_includeOptimisticProposals) {\n proposals(\n skip: $skip\n limit: $limit\n orderDirection: $orderDirection\n status: $status\n fromDate: $fromDate\n fromEndDate: $fromEndDate\n includeOptimisticProposals: $includeOptimisticProposals\n ) {\n items {\n id\n daoId\n proposerAccountId\n title\n description\n startBlock\n endBlock\n endTimestamp\n timestamp\n status\n forVotes\n againstVotes\n abstainVotes\n txHash\n }\n totalCount\n }\n}": types.GetProposalByIdDocument, "query ListVotes($voterAddressIn: JSON, $fromDate: Float, $toDate: Float, $limit: Float, $skip: NonNegativeInt, $orderBy: queryInput_votes_orderBy, $orderDirection: queryInput_votes_orderDirection, $support: Float) {\n votes(\n voterAddressIn: $voterAddressIn\n fromDate: $fromDate\n toDate: $toDate\n limit: $limit\n skip: $skip\n orderBy: $orderBy\n orderDirection: $orderDirection\n support: $support\n ) {\n items {\n transactionHash\n proposalId\n voterAddress\n support\n votingPower\n timestamp\n reason\n proposalTitle\n }\n totalCount\n }\n}": types.ListVotesDocument, diff --git a/packages/anticapture-client/dist/gql/graphql.d.ts b/packages/anticapture-client/dist/gql/graphql.d.ts index 7e9fc76b..f32a3d12 100644 --- a/packages/anticapture-client/dist/gql/graphql.d.ts +++ b/packages/anticapture-client/dist/gql/graphql.d.ts @@ -151,6 +151,14 @@ export type Query = { delegationPercentageByDay?: Maybe; /** Get current delegators of an account */ delegations?: Maybe; + /** Get current delegators of an account with voting power */ + delegators?: Maybe; + /** Get feed events */ + feedEvents?: Maybe; + /** Returns label information from Arkham, ENS data, and whether the address is an EOA or contract. Arkham data is stored permanently. ENS data is cached with a configurable TTL. */ + getAddress?: Maybe; + /** Returns label information from Arkham, ENS data, and address type for multiple addresses. Maximum 100 addresses per request. Arkham data is stored permanently. ENS data is cached with a configurable TTL. */ + getAddresses?: Maybe; /** Get historical DAO Token Treasury value (governance token quantity × token price) */ getDaoTokenTreasury?: Maybe; /** Get historical Liquid Treasury (treasury without DAO tokens) from external providers (DefiLlama/Dune) */ @@ -169,6 +177,10 @@ export type Query = { historicalVotingPowerByAccountId?: Maybe; /** Get the last update time */ lastUpdate?: Maybe; + /** Returns a single offchain (Snapshot) proposal by its ID */ + offchainProposalById?: Maybe; + /** Returns a list of offchain (Snapshot) proposals */ + offchainProposals?: Maybe; /** Returns a single proposal by its ID */ proposal?: Maybe; /** Returns the active delegates that did not vote on a given proposal */ @@ -189,6 +201,10 @@ export type Query = { votes?: Maybe; /** Returns a paginated list of votes cast on a specific proposal */ votesByProposalId?: Maybe; + /** Returns a list of offchain (Snapshot) votes */ + votesOffchain?: Maybe; + /** Returns a paginated list of offchain (Snapshot) votes for a specific proposal */ + votesOffchainByProposalId?: Maybe; /** Returns voting power information for a specific address (account) */ votingPowerByAccountId?: Maybe; /** Returns a mapping of the voting power changes within a time frame for the given addresses */ @@ -287,6 +303,29 @@ export type QueryDelegationPercentageByDayArgs = { export type QueryDelegationsArgs = { address: Scalars['String']['input']; }; +export type QueryDelegatorsArgs = { + address: Scalars['String']['input']; + limit?: InputMaybe; + orderBy?: InputMaybe; + orderDirection?: InputMaybe; + skip?: InputMaybe; +}; +export type QueryFeedEventsArgs = { + fromDate?: InputMaybe; + limit?: InputMaybe; + orderBy?: InputMaybe; + orderDirection?: InputMaybe; + relevance?: InputMaybe; + skip?: InputMaybe; + toDate?: InputMaybe; + type?: InputMaybe; +}; +export type QueryGetAddressArgs = { + address: Scalars['String']['input']; +}; +export type QueryGetAddressesArgs = { + addresses: Scalars['JSON']['input']; +}; export type QueryGetDaoTokenTreasuryArgs = { days?: InputMaybe; order?: InputMaybe; @@ -348,6 +387,16 @@ export type QueryHistoricalVotingPowerByAccountIdArgs = { export type QueryLastUpdateArgs = { chart: QueryInput_LastUpdate_Chart; }; +export type QueryOffchainProposalByIdArgs = { + id: Scalars['String']['input']; +}; +export type QueryOffchainProposalsArgs = { + fromDate?: InputMaybe; + limit?: InputMaybe; + orderDirection?: InputMaybe; + skip?: InputMaybe; + status?: InputMaybe; +}; export type QueryProposalArgs = { id: Scalars['String']['input']; }; @@ -435,6 +484,25 @@ export type QueryVotesByProposalIdArgs = { toDate?: InputMaybe; voterAddressIn?: InputMaybe; }; +export type QueryVotesOffchainArgs = { + fromDate?: InputMaybe; + limit?: InputMaybe; + orderBy?: InputMaybe; + orderDirection?: InputMaybe; + skip?: InputMaybe; + toDate?: InputMaybe; + voterAddresses?: InputMaybe; +}; +export type QueryVotesOffchainByProposalIdArgs = { + fromDate?: InputMaybe; + id: Scalars['String']['input']; + limit?: InputMaybe; + orderBy?: InputMaybe; + orderDirection?: InputMaybe; + skip?: InputMaybe; + toDate?: InputMaybe; + voterAddresses?: InputMaybe; +}; export type QueryVotingPowerByAccountIdArgs = { accountId: Scalars['String']['input']; }; @@ -464,7 +532,9 @@ export type AccountBalanceByAccountId_200_Response = { __typename?: 'accountBalanceByAccountId_200_response'; address: Scalars['String']['output']; balance: Scalars['String']['output']; + data: Query_AccountBalanceByAccountId_Data; delegate: Scalars['String']['output']; + period: Query_AccountBalanceByAccountId_Period; tokenId: Scalars['String']['output']; }; export type AccountBalanceVariationsByAccountId_200_Response = { @@ -480,6 +550,7 @@ export type AccountBalanceVariations_200_Response = { export type AccountBalances_200_Response = { __typename?: 'accountBalances_200_response'; items: Array>; + period: Query_AccountBalances_Period; totalCount: Scalars['Float']['output']; }; export type AccountInteractions_200_Response = { @@ -573,6 +644,27 @@ export type Delegations_200_Response = { items: Array>; totalCount: Scalars['Float']['output']; }; +export type Delegators_200_Response = { + __typename?: 'delegators_200_response'; + items: Array>; + totalCount: Scalars['Float']['output']; +}; +export type FeedEvents_200_Response = { + __typename?: 'feedEvents_200_response'; + items: Array>; + totalCount: Scalars['Float']['output']; +}; +export type GetAddress_200_Response = { + __typename?: 'getAddress_200_response'; + address: Scalars['String']['output']; + arkham?: Maybe; + ens?: Maybe; + isContract: Scalars['Boolean']['output']; +}; +export type GetAddresses_200_Response = { + __typename?: 'getAddresses_200_response'; + results: Array>; +}; export type GetDaoTokenTreasury_200_Response = { __typename?: 'getDaoTokenTreasury_200_response'; items: Array>; @@ -615,6 +707,28 @@ export type LastUpdate_200_Response = { __typename?: 'lastUpdate_200_response'; lastUpdate: Scalars['String']['output']; }; +export type OffchainProposalById_200_Response = { + __typename?: 'offchainProposalById_200_response'; + author: Scalars['String']['output']; + body: Scalars['String']['output']; + created: Scalars['Float']['output']; + discussion: Scalars['String']['output']; + end: Scalars['Float']['output']; + flagged: Scalars['Boolean']['output']; + id: Scalars['String']['output']; + link: Scalars['String']['output']; + spaceId: Scalars['String']['output']; + start: Scalars['Float']['output']; + state: Scalars['String']['output']; + title: Scalars['String']['output']; + type: Scalars['String']['output']; + updated: Scalars['Float']['output']; +}; +export type OffchainProposals_200_Response = { + __typename?: 'offchainProposals_200_response'; + items: Array>; + totalCount: Scalars['Float']['output']; +}; export type ProposalNonVoters_200_Response = { __typename?: 'proposalNonVoters_200_response'; items: Array>; @@ -663,6 +777,10 @@ export declare enum QueryInput_AccountBalanceVariations_OrderDirection { Asc = "asc", Desc = "desc" } +export declare enum QueryInput_AccountBalances_OrderBy { + Balance = "balance", + Variation = "variation" +} export declare enum QueryInput_AccountBalances_OrderDirection { Asc = "asc", Desc = "desc" @@ -756,6 +874,43 @@ export declare enum QueryInput_DelegationPercentageByDay_OrderDirection { Asc = "asc", Desc = "desc" } +export declare enum QueryInput_Delegations_OrderBy { + Amount = "amount", + Timestamp = "timestamp" +} +export declare enum QueryInput_Delegations_OrderDirection { + Asc = "asc", + Desc = "desc" +} +export declare enum QueryInput_Delegators_OrderBy { + Amount = "amount", + Timestamp = "timestamp" +} +export declare enum QueryInput_Delegators_OrderDirection { + Asc = "asc", + Desc = "desc" +} +export declare enum QueryInput_FeedEvents_OrderBy { + Timestamp = "timestamp", + Value = "value" +} +export declare enum QueryInput_FeedEvents_OrderDirection { + Asc = "asc", + Desc = "desc" +} +export declare enum QueryInput_FeedEvents_Relevance { + High = "HIGH", + Low = "LOW", + Medium = "MEDIUM" +} +export declare enum QueryInput_FeedEvents_Type { + Delegation = "DELEGATION", + DelegationVotesChanged = "DELEGATION_VOTES_CHANGED", + Proposal = "PROPOSAL", + ProposalExtended = "PROPOSAL_EXTENDED", + Transfer = "TRANSFER", + Vote = "VOTE" +} export declare enum QueryInput_GetDaoTokenTreasury_Days { '7d' = "_7d", '30d' = "_30d", @@ -822,6 +977,10 @@ export declare enum QueryInput_LastUpdate_Chart { CostComparison = "cost_comparison", TokenDistribution = "token_distribution" } +export declare enum QueryInput_OffchainProposals_OrderDirection { + Asc = "asc", + Desc = "desc" +} export declare enum QueryInput_ProposalNonVoters_OrderDirection { Asc = "asc", Desc = "desc" @@ -887,6 +1046,22 @@ export declare enum QueryInput_VotesByProposalId_OrderDirection { Asc = "asc", Desc = "desc" } +export declare enum QueryInput_VotesOffchainByProposalId_OrderBy { + Created = "created", + Vp = "vp" +} +export declare enum QueryInput_VotesOffchainByProposalId_OrderDirection { + Asc = "asc", + Desc = "desc" +} +export declare enum QueryInput_VotesOffchain_OrderBy { + Created = "created", + Vp = "vp" +} +export declare enum QueryInput_VotesOffchain_OrderDirection { + Asc = "asc", + Desc = "desc" +} export declare enum QueryInput_Votes_OrderBy { Timestamp = "timestamp", VotingPower = "votingPower" @@ -901,12 +1076,32 @@ export declare enum QueryInput_VotingPowerVariations_OrderDirection { } export declare enum QueryInput_VotingPowers_OrderBy { DelegationsCount = "delegationsCount", + Variation = "variation", VotingPower = "votingPower" } export declare enum QueryInput_VotingPowers_OrderDirection { Asc = "asc", Desc = "desc" } +export type Query_AccountBalanceByAccountId_Data = { + __typename?: 'query_accountBalanceByAccountId_data'; + address: Scalars['String']['output']; + balance: Scalars['String']['output']; + delegate: Scalars['String']['output']; + tokenId: Scalars['String']['output']; + variation: Query_AccountBalanceByAccountId_Data_Variation; +}; +export type Query_AccountBalanceByAccountId_Data_Variation = { + __typename?: 'query_accountBalanceByAccountId_data_variation'; + absoluteChange: Scalars['String']['output']; + percentageChange: Scalars['String']['output']; + previousBalance: Scalars['String']['output']; +}; +export type Query_AccountBalanceByAccountId_Period = { + __typename?: 'query_accountBalanceByAccountId_period'; + endTimestamp: Scalars['String']['output']; + startTimestamp: Scalars['String']['output']; +}; export type Query_AccountBalanceVariationsByAccountId_Data = { __typename?: 'query_accountBalanceVariationsByAccountId_data'; absoluteChange: Scalars['String']['output']; @@ -939,6 +1134,18 @@ export type Query_AccountBalances_Items_Items = { balance: Scalars['String']['output']; delegate: Scalars['String']['output']; tokenId: Scalars['String']['output']; + variation: Query_AccountBalances_Items_Items_Variation; +}; +export type Query_AccountBalances_Items_Items_Variation = { + __typename?: 'query_accountBalances_items_items_variation'; + absoluteChange: Scalars['String']['output']; + percentageChange: Scalars['String']['output']; + previousBalance: Scalars['String']['output']; +}; +export type Query_AccountBalances_Period = { + __typename?: 'query_accountBalances_period'; + endTimestamp: Scalars['String']['output']; + startTimestamp: Scalars['String']['output']; }; export type Query_AccountInteractions_Items_Items = { __typename?: 'query_accountInteractions_items_items'; @@ -971,6 +1178,68 @@ export type Query_Delegations_Items_Items = { timestamp: Scalars['String']['output']; transactionHash: Scalars['String']['output']; }; +export type Query_Delegators_Items_Items = { + __typename?: 'query_delegators_items_items'; + amount: Scalars['String']['output']; + delegatorAddress: Scalars['String']['output']; + timestamp: Scalars['String']['output']; +}; +export type Query_FeedEvents_Items_Items = { + __typename?: 'query_feedEvents_items_items'; + logIndex: Scalars['Float']['output']; + metadata?: Maybe; + relevance: Query_FeedEvents_Items_Items_Relevance; + timestamp: Scalars['Float']['output']; + txHash: Scalars['String']['output']; + type: Query_FeedEvents_Items_Items_Type; + value?: Maybe; +}; +export declare enum Query_FeedEvents_Items_Items_Relevance { + High = "HIGH", + Low = "LOW", + Medium = "MEDIUM" +} +export declare enum Query_FeedEvents_Items_Items_Type { + Delegation = "DELEGATION", + DelegationVotesChanged = "DELEGATION_VOTES_CHANGED", + Proposal = "PROPOSAL", + ProposalExtended = "PROPOSAL_EXTENDED", + Transfer = "TRANSFER", + Vote = "VOTE" +} +export type Query_GetAddress_Arkham = { + __typename?: 'query_getAddress_arkham'; + entity?: Maybe; + entityType?: Maybe; + label?: Maybe; + twitter?: Maybe; +}; +export type Query_GetAddress_Ens = { + __typename?: 'query_getAddress_ens'; + avatar?: Maybe; + banner?: Maybe; + name?: Maybe; +}; +export type Query_GetAddresses_Results_Items = { + __typename?: 'query_getAddresses_results_items'; + address: Scalars['String']['output']; + arkham?: Maybe; + ens?: Maybe; + isContract: Scalars['Boolean']['output']; +}; +export type Query_GetAddresses_Results_Items_Arkham = { + __typename?: 'query_getAddresses_results_items_arkham'; + entity?: Maybe; + entityType?: Maybe; + label?: Maybe; + twitter?: Maybe; +}; +export type Query_GetAddresses_Results_Items_Ens = { + __typename?: 'query_getAddresses_results_items_ens'; + avatar?: Maybe; + banner?: Maybe; + name?: Maybe; +}; export type Query_GetDaoTokenTreasury_Items_Items = { __typename?: 'query_getDaoTokenTreasury_items_items'; /** Unix timestamp in milliseconds */ @@ -1072,6 +1341,23 @@ export type Query_HistoricalVotingPower_Items_Items_Transfer = { to: Scalars['String']['output']; value: Scalars['String']['output']; }; +export type Query_OffchainProposals_Items_Items = { + __typename?: 'query_offchainProposals_items_items'; + author: Scalars['String']['output']; + body: Scalars['String']['output']; + created: Scalars['Float']['output']; + discussion: Scalars['String']['output']; + end: Scalars['Float']['output']; + flagged: Scalars['Boolean']['output']; + id: Scalars['String']['output']; + link: Scalars['String']['output']; + spaceId: Scalars['String']['output']; + start: Scalars['Float']['output']; + state: Scalars['String']['output']; + title: Scalars['String']['output']; + type: Scalars['String']['output']; + updated: Scalars['Float']['output']; +}; export type Query_ProposalNonVoters_Items_Items = { __typename?: 'query_proposalNonVoters_items_items'; lastVoteTimestamp: Scalars['Float']['output']; @@ -1212,6 +1498,26 @@ export type Query_VotesByProposalId_Items_Items = { voterAddress: Scalars['String']['output']; votingPower: Scalars['String']['output']; }; +export type Query_VotesOffchainByProposalId_Items_Items = { + __typename?: 'query_votesOffchainByProposalId_items_items'; + choice?: Maybe; + created: Scalars['Float']['output']; + proposalId: Scalars['String']['output']; + proposalTitle: Scalars['String']['output']; + reason: Scalars['String']['output']; + voter: Scalars['String']['output']; + vp: Scalars['Float']['output']; +}; +export type Query_VotesOffchain_Items_Items = { + __typename?: 'query_votesOffchain_items_items'; + choice?: Maybe; + created: Scalars['Float']['output']; + proposalId: Scalars['String']['output']; + proposalTitle: Scalars['String']['output']; + reason: Scalars['String']['output']; + voter: Scalars['String']['output']; + vp: Scalars['Float']['output']; +}; export type Query_Votes_Items_Items = { __typename?: 'query_votes_items_items'; proposalId: Scalars['String']['output']; @@ -1223,6 +1529,11 @@ export type Query_Votes_Items_Items = { voterAddress: Scalars['String']['output']; votingPower: Scalars['String']['output']; }; +export type Query_VotingPowerByAccountId_Variation = { + __typename?: 'query_votingPowerByAccountId_variation'; + absoluteChange: Scalars['String']['output']; + percentageChange: Scalars['Float']['output']; +}; export type Query_VotingPowerVariationsByAccountId_Data = { __typename?: 'query_votingPowerVariationsByAccountId_data'; absoluteChange: Scalars['String']['output']; @@ -1254,9 +1565,15 @@ export type Query_VotingPowers_Items_Items = { accountId: Scalars['String']['output']; delegationsCount: Scalars['Float']['output']; proposalsCount: Scalars['Float']['output']; + variation: Query_VotingPowers_Items_Items_Variation; votesCount: Scalars['Float']['output']; votingPower: Scalars['String']['output']; }; +export type Query_VotingPowers_Items_Items_Variation = { + __typename?: 'query_votingPowers_items_items_variation'; + absoluteChange: Scalars['String']['output']; + percentageChange: Scalars['Float']['output']; +}; export declare enum Timestamp_Const { Timestamp = "timestamp" } @@ -1294,6 +1611,16 @@ export type VotesByProposalId_200_Response = { items: Array>; totalCount: Scalars['Float']['output']; }; +export type VotesOffchainByProposalId_200_Response = { + __typename?: 'votesOffchainByProposalId_200_response'; + items: Array>; + totalCount: Scalars['Float']['output']; +}; +export type VotesOffchain_200_Response = { + __typename?: 'votesOffchain_200_response'; + items: Array>; + totalCount: Scalars['Float']['output']; +}; export type Votes_200_Response = { __typename?: 'votes_200_response'; items: Array>; @@ -1304,6 +1631,7 @@ export type VotingPowerByAccountId_200_Response = { accountId: Scalars['String']['output']; delegationsCount: Scalars['Float']['output']; proposalsCount: Scalars['Float']['output']; + variation: Query_VotingPowerByAccountId_Variation; votesCount: Scalars['Float']['output']; votingPower: Scalars['String']['output']; }; @@ -1337,6 +1665,28 @@ export type GetDaOsQuery = { }>; }; }; +export type ListOffchainProposalsQueryVariables = Exact<{ + skip?: InputMaybe; + limit?: InputMaybe; + orderDirection?: InputMaybe; + status?: InputMaybe; + fromDate?: InputMaybe; +}>; +export type ListOffchainProposalsQuery = { + __typename?: 'Query'; + offchainProposals?: { + __typename?: 'offchainProposals_200_response'; + totalCount: number; + items: Array<{ + __typename?: 'query_offchainProposals_items_items'; + id: string; + title: string; + discussion: string; + state: string; + created: number; + } | null>; + } | null; +}; export type ProposalNonVotersQueryVariables = Exact<{ id: Scalars['String']['input']; addresses?: InputMaybe; @@ -1474,6 +1824,7 @@ export type ListHistoricalVotingPowerQuery = { } | null; }; export declare const GetDaOsDocument: DocumentNode; +export declare const ListOffchainProposalsDocument: DocumentNode; export declare const ProposalNonVotersDocument: DocumentNode; export declare const GetProposalByIdDocument: DocumentNode; export declare const ListProposalsDocument: DocumentNode; diff --git a/packages/anticapture-client/dist/gql/graphql.js b/packages/anticapture-client/dist/gql/graphql.js index e4b06321..20d2c665 100644 --- a/packages/anticapture-client/dist/gql/graphql.js +++ b/packages/anticapture-client/dist/gql/graphql.js @@ -1,7 +1,7 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -exports.QueryInput_VotingPowers_OrderDirection = exports.QueryInput_VotingPowers_OrderBy = exports.QueryInput_VotingPowerVariations_OrderDirection = exports.QueryInput_Votes_OrderDirection = exports.QueryInput_Votes_OrderBy = exports.QueryInput_VotesByProposalId_OrderDirection = exports.QueryInput_VotesByProposalId_OrderBy = exports.QueryInput_Transfers_SortOrder = exports.QueryInput_Transfers_SortBy = exports.QueryInput_Transactions_SortOrder = exports.QueryInput_Token_Currency = exports.QueryInput_TokenMetrics_OrderDirection = exports.QueryInput_TokenMetrics_MetricType = exports.QueryInput_Proposals_OrderDirection = exports.QueryInput_Proposals_IncludeOptimisticProposals = exports.QueryInput_ProposalsActivity_UserVoteFilter = exports.QueryInput_ProposalsActivity_OrderDirection = exports.QueryInput_ProposalsActivity_OrderBy = exports.QueryInput_ProposalNonVoters_OrderDirection = exports.QueryInput_LastUpdate_Chart = exports.QueryInput_HistoricalVotingPower_OrderDirection = exports.QueryInput_HistoricalVotingPower_OrderBy = exports.QueryInput_HistoricalVotingPowerByAccountId_OrderDirection = exports.QueryInput_HistoricalVotingPowerByAccountId_OrderBy = exports.QueryInput_HistoricalDelegations_OrderDirection = exports.QueryInput_HistoricalBalances_OrderDirection = exports.QueryInput_HistoricalBalances_OrderBy = exports.QueryInput_GetTotalTreasury_Order = exports.QueryInput_GetTotalTreasury_Days = exports.QueryInput_GetLiquidTreasury_Order = exports.QueryInput_GetLiquidTreasury_Days = exports.QueryInput_GetDaoTokenTreasury_Order = exports.QueryInput_GetDaoTokenTreasury_Days = exports.QueryInput_DelegationPercentageByDay_OrderDirection = exports.QueryInput_CompareVotes_Days = exports.QueryInput_CompareTreasury_Days = exports.QueryInput_CompareTotalSupply_Days = exports.QueryInput_CompareProposals_Days = exports.QueryInput_CompareLendingSupply_Days = exports.QueryInput_CompareDexSupply_Days = exports.QueryInput_CompareDelegatedSupply_Days = exports.QueryInput_CompareCirculatingSupply_Days = exports.QueryInput_CompareCexSupply_Days = exports.QueryInput_CompareAverageTurnout_Days = exports.QueryInput_CompareActiveSupply_Days = exports.QueryInput_AccountInteractions_OrderDirection = exports.QueryInput_AccountInteractions_OrderBy = exports.QueryInput_AccountBalances_OrderDirection = exports.QueryInput_AccountBalanceVariations_OrderDirection = exports.HttpMethod = void 0; -exports.ListHistoricalVotingPowerDocument = exports.ListVotesDocument = exports.ListProposalsDocument = exports.GetProposalByIdDocument = exports.ProposalNonVotersDocument = exports.GetDaOsDocument = exports.Timestamp_Const = void 0; +exports.QueryInput_Token_Currency = exports.QueryInput_TokenMetrics_OrderDirection = exports.QueryInput_TokenMetrics_MetricType = exports.QueryInput_Proposals_OrderDirection = exports.QueryInput_Proposals_IncludeOptimisticProposals = exports.QueryInput_ProposalsActivity_UserVoteFilter = exports.QueryInput_ProposalsActivity_OrderDirection = exports.QueryInput_ProposalsActivity_OrderBy = exports.QueryInput_ProposalNonVoters_OrderDirection = exports.QueryInput_OffchainProposals_OrderDirection = exports.QueryInput_LastUpdate_Chart = exports.QueryInput_HistoricalVotingPower_OrderDirection = exports.QueryInput_HistoricalVotingPower_OrderBy = exports.QueryInput_HistoricalVotingPowerByAccountId_OrderDirection = exports.QueryInput_HistoricalVotingPowerByAccountId_OrderBy = exports.QueryInput_HistoricalDelegations_OrderDirection = exports.QueryInput_HistoricalBalances_OrderDirection = exports.QueryInput_HistoricalBalances_OrderBy = exports.QueryInput_GetTotalTreasury_Order = exports.QueryInput_GetTotalTreasury_Days = exports.QueryInput_GetLiquidTreasury_Order = exports.QueryInput_GetLiquidTreasury_Days = exports.QueryInput_GetDaoTokenTreasury_Order = exports.QueryInput_GetDaoTokenTreasury_Days = exports.QueryInput_FeedEvents_Type = exports.QueryInput_FeedEvents_Relevance = exports.QueryInput_FeedEvents_OrderDirection = exports.QueryInput_FeedEvents_OrderBy = exports.QueryInput_Delegators_OrderDirection = exports.QueryInput_Delegators_OrderBy = exports.QueryInput_Delegations_OrderDirection = exports.QueryInput_Delegations_OrderBy = exports.QueryInput_DelegationPercentageByDay_OrderDirection = exports.QueryInput_CompareVotes_Days = exports.QueryInput_CompareTreasury_Days = exports.QueryInput_CompareTotalSupply_Days = exports.QueryInput_CompareProposals_Days = exports.QueryInput_CompareLendingSupply_Days = exports.QueryInput_CompareDexSupply_Days = exports.QueryInput_CompareDelegatedSupply_Days = exports.QueryInput_CompareCirculatingSupply_Days = exports.QueryInput_CompareCexSupply_Days = exports.QueryInput_CompareAverageTurnout_Days = exports.QueryInput_CompareActiveSupply_Days = exports.QueryInput_AccountInteractions_OrderDirection = exports.QueryInput_AccountInteractions_OrderBy = exports.QueryInput_AccountBalances_OrderDirection = exports.QueryInput_AccountBalances_OrderBy = exports.QueryInput_AccountBalanceVariations_OrderDirection = exports.HttpMethod = void 0; +exports.ListHistoricalVotingPowerDocument = exports.ListVotesDocument = exports.ListProposalsDocument = exports.GetProposalByIdDocument = exports.ProposalNonVotersDocument = exports.ListOffchainProposalsDocument = exports.GetDaOsDocument = exports.Timestamp_Const = exports.Query_FeedEvents_Items_Items_Type = exports.Query_FeedEvents_Items_Items_Relevance = exports.QueryInput_VotingPowers_OrderDirection = exports.QueryInput_VotingPowers_OrderBy = exports.QueryInput_VotingPowerVariations_OrderDirection = exports.QueryInput_Votes_OrderDirection = exports.QueryInput_Votes_OrderBy = exports.QueryInput_VotesOffchain_OrderDirection = exports.QueryInput_VotesOffchain_OrderBy = exports.QueryInput_VotesOffchainByProposalId_OrderDirection = exports.QueryInput_VotesOffchainByProposalId_OrderBy = exports.QueryInput_VotesByProposalId_OrderDirection = exports.QueryInput_VotesByProposalId_OrderBy = exports.QueryInput_Transfers_SortOrder = exports.QueryInput_Transfers_SortBy = exports.QueryInput_Transactions_SortOrder = void 0; var HttpMethod; (function (HttpMethod) { HttpMethod["Connect"] = "CONNECT"; @@ -19,6 +19,11 @@ var QueryInput_AccountBalanceVariations_OrderDirection; QueryInput_AccountBalanceVariations_OrderDirection["Asc"] = "asc"; QueryInput_AccountBalanceVariations_OrderDirection["Desc"] = "desc"; })(QueryInput_AccountBalanceVariations_OrderDirection || (exports.QueryInput_AccountBalanceVariations_OrderDirection = QueryInput_AccountBalanceVariations_OrderDirection = {})); +var QueryInput_AccountBalances_OrderBy; +(function (QueryInput_AccountBalances_OrderBy) { + QueryInput_AccountBalances_OrderBy["Balance"] = "balance"; + QueryInput_AccountBalances_OrderBy["Variation"] = "variation"; +})(QueryInput_AccountBalances_OrderBy || (exports.QueryInput_AccountBalances_OrderBy = QueryInput_AccountBalances_OrderBy = {})); var QueryInput_AccountBalances_OrderDirection; (function (QueryInput_AccountBalances_OrderDirection) { QueryInput_AccountBalances_OrderDirection["Asc"] = "asc"; @@ -127,6 +132,51 @@ var QueryInput_DelegationPercentageByDay_OrderDirection; QueryInput_DelegationPercentageByDay_OrderDirection["Asc"] = "asc"; QueryInput_DelegationPercentageByDay_OrderDirection["Desc"] = "desc"; })(QueryInput_DelegationPercentageByDay_OrderDirection || (exports.QueryInput_DelegationPercentageByDay_OrderDirection = QueryInput_DelegationPercentageByDay_OrderDirection = {})); +var QueryInput_Delegations_OrderBy; +(function (QueryInput_Delegations_OrderBy) { + QueryInput_Delegations_OrderBy["Amount"] = "amount"; + QueryInput_Delegations_OrderBy["Timestamp"] = "timestamp"; +})(QueryInput_Delegations_OrderBy || (exports.QueryInput_Delegations_OrderBy = QueryInput_Delegations_OrderBy = {})); +var QueryInput_Delegations_OrderDirection; +(function (QueryInput_Delegations_OrderDirection) { + QueryInput_Delegations_OrderDirection["Asc"] = "asc"; + QueryInput_Delegations_OrderDirection["Desc"] = "desc"; +})(QueryInput_Delegations_OrderDirection || (exports.QueryInput_Delegations_OrderDirection = QueryInput_Delegations_OrderDirection = {})); +var QueryInput_Delegators_OrderBy; +(function (QueryInput_Delegators_OrderBy) { + QueryInput_Delegators_OrderBy["Amount"] = "amount"; + QueryInput_Delegators_OrderBy["Timestamp"] = "timestamp"; +})(QueryInput_Delegators_OrderBy || (exports.QueryInput_Delegators_OrderBy = QueryInput_Delegators_OrderBy = {})); +var QueryInput_Delegators_OrderDirection; +(function (QueryInput_Delegators_OrderDirection) { + QueryInput_Delegators_OrderDirection["Asc"] = "asc"; + QueryInput_Delegators_OrderDirection["Desc"] = "desc"; +})(QueryInput_Delegators_OrderDirection || (exports.QueryInput_Delegators_OrderDirection = QueryInput_Delegators_OrderDirection = {})); +var QueryInput_FeedEvents_OrderBy; +(function (QueryInput_FeedEvents_OrderBy) { + QueryInput_FeedEvents_OrderBy["Timestamp"] = "timestamp"; + QueryInput_FeedEvents_OrderBy["Value"] = "value"; +})(QueryInput_FeedEvents_OrderBy || (exports.QueryInput_FeedEvents_OrderBy = QueryInput_FeedEvents_OrderBy = {})); +var QueryInput_FeedEvents_OrderDirection; +(function (QueryInput_FeedEvents_OrderDirection) { + QueryInput_FeedEvents_OrderDirection["Asc"] = "asc"; + QueryInput_FeedEvents_OrderDirection["Desc"] = "desc"; +})(QueryInput_FeedEvents_OrderDirection || (exports.QueryInput_FeedEvents_OrderDirection = QueryInput_FeedEvents_OrderDirection = {})); +var QueryInput_FeedEvents_Relevance; +(function (QueryInput_FeedEvents_Relevance) { + QueryInput_FeedEvents_Relevance["High"] = "HIGH"; + QueryInput_FeedEvents_Relevance["Low"] = "LOW"; + QueryInput_FeedEvents_Relevance["Medium"] = "MEDIUM"; +})(QueryInput_FeedEvents_Relevance || (exports.QueryInput_FeedEvents_Relevance = QueryInput_FeedEvents_Relevance = {})); +var QueryInput_FeedEvents_Type; +(function (QueryInput_FeedEvents_Type) { + QueryInput_FeedEvents_Type["Delegation"] = "DELEGATION"; + QueryInput_FeedEvents_Type["DelegationVotesChanged"] = "DELEGATION_VOTES_CHANGED"; + QueryInput_FeedEvents_Type["Proposal"] = "PROPOSAL"; + QueryInput_FeedEvents_Type["ProposalExtended"] = "PROPOSAL_EXTENDED"; + QueryInput_FeedEvents_Type["Transfer"] = "TRANSFER"; + QueryInput_FeedEvents_Type["Vote"] = "VOTE"; +})(QueryInput_FeedEvents_Type || (exports.QueryInput_FeedEvents_Type = QueryInput_FeedEvents_Type = {})); var QueryInput_GetDaoTokenTreasury_Days; (function (QueryInput_GetDaoTokenTreasury_Days) { QueryInput_GetDaoTokenTreasury_Days["7d"] = "_7d"; @@ -207,6 +257,11 @@ var QueryInput_LastUpdate_Chart; QueryInput_LastUpdate_Chart["CostComparison"] = "cost_comparison"; QueryInput_LastUpdate_Chart["TokenDistribution"] = "token_distribution"; })(QueryInput_LastUpdate_Chart || (exports.QueryInput_LastUpdate_Chart = QueryInput_LastUpdate_Chart = {})); +var QueryInput_OffchainProposals_OrderDirection; +(function (QueryInput_OffchainProposals_OrderDirection) { + QueryInput_OffchainProposals_OrderDirection["Asc"] = "asc"; + QueryInput_OffchainProposals_OrderDirection["Desc"] = "desc"; +})(QueryInput_OffchainProposals_OrderDirection || (exports.QueryInput_OffchainProposals_OrderDirection = QueryInput_OffchainProposals_OrderDirection = {})); var QueryInput_ProposalNonVoters_OrderDirection; (function (QueryInput_ProposalNonVoters_OrderDirection) { QueryInput_ProposalNonVoters_OrderDirection["Asc"] = "asc"; @@ -286,6 +341,26 @@ var QueryInput_VotesByProposalId_OrderDirection; QueryInput_VotesByProposalId_OrderDirection["Asc"] = "asc"; QueryInput_VotesByProposalId_OrderDirection["Desc"] = "desc"; })(QueryInput_VotesByProposalId_OrderDirection || (exports.QueryInput_VotesByProposalId_OrderDirection = QueryInput_VotesByProposalId_OrderDirection = {})); +var QueryInput_VotesOffchainByProposalId_OrderBy; +(function (QueryInput_VotesOffchainByProposalId_OrderBy) { + QueryInput_VotesOffchainByProposalId_OrderBy["Created"] = "created"; + QueryInput_VotesOffchainByProposalId_OrderBy["Vp"] = "vp"; +})(QueryInput_VotesOffchainByProposalId_OrderBy || (exports.QueryInput_VotesOffchainByProposalId_OrderBy = QueryInput_VotesOffchainByProposalId_OrderBy = {})); +var QueryInput_VotesOffchainByProposalId_OrderDirection; +(function (QueryInput_VotesOffchainByProposalId_OrderDirection) { + QueryInput_VotesOffchainByProposalId_OrderDirection["Asc"] = "asc"; + QueryInput_VotesOffchainByProposalId_OrderDirection["Desc"] = "desc"; +})(QueryInput_VotesOffchainByProposalId_OrderDirection || (exports.QueryInput_VotesOffchainByProposalId_OrderDirection = QueryInput_VotesOffchainByProposalId_OrderDirection = {})); +var QueryInput_VotesOffchain_OrderBy; +(function (QueryInput_VotesOffchain_OrderBy) { + QueryInput_VotesOffchain_OrderBy["Created"] = "created"; + QueryInput_VotesOffchain_OrderBy["Vp"] = "vp"; +})(QueryInput_VotesOffchain_OrderBy || (exports.QueryInput_VotesOffchain_OrderBy = QueryInput_VotesOffchain_OrderBy = {})); +var QueryInput_VotesOffchain_OrderDirection; +(function (QueryInput_VotesOffchain_OrderDirection) { + QueryInput_VotesOffchain_OrderDirection["Asc"] = "asc"; + QueryInput_VotesOffchain_OrderDirection["Desc"] = "desc"; +})(QueryInput_VotesOffchain_OrderDirection || (exports.QueryInput_VotesOffchain_OrderDirection = QueryInput_VotesOffchain_OrderDirection = {})); var QueryInput_Votes_OrderBy; (function (QueryInput_Votes_OrderBy) { QueryInput_Votes_OrderBy["Timestamp"] = "timestamp"; @@ -304,6 +379,7 @@ var QueryInput_VotingPowerVariations_OrderDirection; var QueryInput_VotingPowers_OrderBy; (function (QueryInput_VotingPowers_OrderBy) { QueryInput_VotingPowers_OrderBy["DelegationsCount"] = "delegationsCount"; + QueryInput_VotingPowers_OrderBy["Variation"] = "variation"; QueryInput_VotingPowers_OrderBy["VotingPower"] = "votingPower"; })(QueryInput_VotingPowers_OrderBy || (exports.QueryInput_VotingPowers_OrderBy = QueryInput_VotingPowers_OrderBy = {})); var QueryInput_VotingPowers_OrderDirection; @@ -311,11 +387,27 @@ var QueryInput_VotingPowers_OrderDirection; QueryInput_VotingPowers_OrderDirection["Asc"] = "asc"; QueryInput_VotingPowers_OrderDirection["Desc"] = "desc"; })(QueryInput_VotingPowers_OrderDirection || (exports.QueryInput_VotingPowers_OrderDirection = QueryInput_VotingPowers_OrderDirection = {})); +var Query_FeedEvents_Items_Items_Relevance; +(function (Query_FeedEvents_Items_Items_Relevance) { + Query_FeedEvents_Items_Items_Relevance["High"] = "HIGH"; + Query_FeedEvents_Items_Items_Relevance["Low"] = "LOW"; + Query_FeedEvents_Items_Items_Relevance["Medium"] = "MEDIUM"; +})(Query_FeedEvents_Items_Items_Relevance || (exports.Query_FeedEvents_Items_Items_Relevance = Query_FeedEvents_Items_Items_Relevance = {})); +var Query_FeedEvents_Items_Items_Type; +(function (Query_FeedEvents_Items_Items_Type) { + Query_FeedEvents_Items_Items_Type["Delegation"] = "DELEGATION"; + Query_FeedEvents_Items_Items_Type["DelegationVotesChanged"] = "DELEGATION_VOTES_CHANGED"; + Query_FeedEvents_Items_Items_Type["Proposal"] = "PROPOSAL"; + Query_FeedEvents_Items_Items_Type["ProposalExtended"] = "PROPOSAL_EXTENDED"; + Query_FeedEvents_Items_Items_Type["Transfer"] = "TRANSFER"; + Query_FeedEvents_Items_Items_Type["Vote"] = "VOTE"; +})(Query_FeedEvents_Items_Items_Type || (exports.Query_FeedEvents_Items_Items_Type = Query_FeedEvents_Items_Items_Type = {})); var Timestamp_Const; (function (Timestamp_Const) { Timestamp_Const["Timestamp"] = "timestamp"; })(Timestamp_Const || (exports.Timestamp_Const = Timestamp_Const = {})); exports.GetDaOsDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "GetDAOs" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "daos" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "items" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "votingDelay" } }, { "kind": "Field", "name": { "kind": "Name", "value": "chainId" } }] } }] } }] } }] }; +exports.ListOffchainProposalsDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "ListOffchainProposals" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "skip" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "NonNegativeInt" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "limit" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "PositiveInt" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "orderDirection" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "queryInput_offchainProposals_orderDirection" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "status" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "JSON" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "fromDate" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Float" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "offchainProposals" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "skip" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "skip" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "limit" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "limit" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "orderDirection" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "orderDirection" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "status" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "status" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "fromDate" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "fromDate" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "items" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "title" } }, { "kind": "Field", "name": { "kind": "Name", "value": "discussion" } }, { "kind": "Field", "name": { "kind": "Name", "value": "state" } }, { "kind": "Field", "name": { "kind": "Name", "value": "created" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "totalCount" } }] } }] } }] }; exports.ProposalNonVotersDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "ProposalNonVoters" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "id" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "String" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "addresses" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "JSON" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "proposalNonVoters" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "id" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "id" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "addresses" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "addresses" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "items" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "voter" } }] } }] } }] } }] }; exports.GetProposalByIdDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "GetProposalById" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "id" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "String" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "proposal" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "id" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "id" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "daoId" } }, { "kind": "Field", "name": { "kind": "Name", "value": "proposerAccountId" } }, { "kind": "Field", "name": { "kind": "Name", "value": "title" } }, { "kind": "Field", "name": { "kind": "Name", "value": "description" } }, { "kind": "Field", "name": { "kind": "Name", "value": "startBlock" } }, { "kind": "Field", "name": { "kind": "Name", "value": "endBlock" } }, { "kind": "Field", "name": { "kind": "Name", "value": "endTimestamp" } }, { "kind": "Field", "name": { "kind": "Name", "value": "timestamp" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }, { "kind": "Field", "name": { "kind": "Name", "value": "forVotes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "againstVotes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "abstainVotes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "txHash" } }] } }] } }] }; exports.ListProposalsDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "ListProposals" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "skip" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "NonNegativeInt" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "limit" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "PositiveInt" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "orderDirection" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "queryInput_proposals_orderDirection" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "status" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "JSON" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "fromDate" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Float" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "fromEndDate" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Float" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "includeOptimisticProposals" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "queryInput_proposals_includeOptimisticProposals" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "proposals" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "skip" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "skip" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "limit" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "limit" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "orderDirection" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "orderDirection" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "status" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "status" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "fromDate" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "fromDate" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "fromEndDate" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "fromEndDate" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "includeOptimisticProposals" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "includeOptimisticProposals" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "items" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "daoId" } }, { "kind": "Field", "name": { "kind": "Name", "value": "proposerAccountId" } }, { "kind": "Field", "name": { "kind": "Name", "value": "title" } }, { "kind": "Field", "name": { "kind": "Name", "value": "description" } }, { "kind": "Field", "name": { "kind": "Name", "value": "startBlock" } }, { "kind": "Field", "name": { "kind": "Name", "value": "endBlock" } }, { "kind": "Field", "name": { "kind": "Name", "value": "endTimestamp" } }, { "kind": "Field", "name": { "kind": "Name", "value": "timestamp" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }, { "kind": "Field", "name": { "kind": "Name", "value": "forVotes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "againstVotes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "abstainVotes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "txHash" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "totalCount" } }] } }] } }] }; diff --git a/packages/anticapture-client/dist/schemas.d.ts b/packages/anticapture-client/dist/schemas.d.ts index 43994da9..542e6374 100644 --- a/packages/anticapture-client/dist/schemas.d.ts +++ b/packages/anticapture-client/dist/schemas.d.ts @@ -113,14 +113,14 @@ declare const HistoricalVotingPowerItemSchema: z.ZodObject<{ value: z.ZodString; previousDelegate: z.ZodNullable; }, "strip", z.ZodTypeAny, { + value: string; from: string; to: string; - value: string; previousDelegate: string | null; }, { + value: string; from: string; to: string; - value: string; previousDelegate: string | null; }>>; transfer: z.ZodNullable>; }, "strip", z.ZodTypeAny, { - delta: string; timestamp: string; + delta: string; votingPower: string; daoId: string; transactionHash: string; accountId: string; logIndex: number; delegation: { + value: string; from: string; to: string; - value: string; previousDelegate: string | null; } | null; transfer: { + value: string; from: string; to: string; - value: string; } | null; }, { - delta: string; timestamp: string; + delta: string; votingPower: string; daoId: string; transactionHash: string; accountId: string; logIndex: number; delegation: { + value: string; from: string; to: string; - value: string; previousDelegate: string | null; } | null; transfer: { + value: string; from: string; to: string; - value: string; } | null; }>; export declare const SafeHistoricalVotingPowerResponseSchema: z.ZodEffects; }, "strip", z.ZodTypeAny, { + value: string; from: string; to: string; - value: string; previousDelegate: string | null; }, { + value: string; from: string; to: string; - value: string; previousDelegate: string | null; }>>; transfer: z.ZodNullable>; }, "strip", z.ZodTypeAny, { - delta: string; timestamp: string; + delta: string; votingPower: string; daoId: string; transactionHash: string; accountId: string; logIndex: number; delegation: { + value: string; from: string; to: string; - value: string; previousDelegate: string | null; } | null; transfer: { + value: string; from: string; to: string; - value: string; } | null; }, { - delta: string; timestamp: string; + delta: string; votingPower: string; daoId: string; transactionHash: string; accountId: string; logIndex: number; delegation: { + value: string; from: string; to: string; - value: string; previousDelegate: string | null; } | null; transfer: { + value: string; from: string; to: string; - value: string; } | null; }>>, "many">; totalCount: z.ZodNumber; }, "strip", z.ZodTypeAny, { items: ({ - delta: string; timestamp: string; + delta: string; votingPower: string; daoId: string; transactionHash: string; accountId: string; logIndex: number; delegation: { + value: string; from: string; to: string; - value: string; previousDelegate: string | null; } | null; transfer: { + value: string; from: string; to: string; - value: string; } | null; } | null)[]; totalCount: number; }, { items: ({ - delta: string; timestamp: string; + delta: string; votingPower: string; daoId: string; transactionHash: string; accountId: string; logIndex: number; delegation: { + value: string; from: string; to: string; - value: string; previousDelegate: string | null; } | null; transfer: { + value: string; from: string; to: string; - value: string; } | null; } | null)[]; totalCount: number; @@ -302,23 +302,23 @@ export declare const SafeHistoricalVotingPowerResponseSchema: z.ZodEffects, { historicalVotingPower: { items: { - delta: string; timestamp: string; + delta: string; votingPower: string; daoId: string; transactionHash: string; accountId: string; logIndex: number; delegation: { + value: string; from: string; to: string; - value: string; previousDelegate: string | null; } | null; transfer: { + value: string; from: string; to: string; - value: string; } | null; }[]; totalCount: number; @@ -374,23 +374,23 @@ export declare const SafeHistoricalVotingPowerResponseSchema: z.ZodEffects; export declare const OffchainProposalItemSchema: z.ZodObject<{ id: z.ZodString; - spaceId: z.ZodString; - author: z.ZodString; title: z.ZodString; - body: z.ZodString; discussion: z.ZodString; - type: z.ZodString; - start: z.ZodNumber; - end: z.ZodNumber; state: z.ZodString; created: z.ZodNumber; - updated: z.ZodNumber; - link: z.ZodString; - flagged: z.ZodBoolean; }, "strip", z.ZodTypeAny, { - link: string; + created: number; id: string; - type: string; title: string; - spaceId: string; - author: string; - body: string; discussion: string; - start: number; - end: number; state: string; - created: number; - updated: number; - flagged: boolean; }, { - link: string; + created: number; id: string; - type: string; title: string; - spaceId: string; - author: string; - body: string; discussion: string; - start: number; - end: number; state: string; - created: number; - updated: number; - flagged: boolean; }>; export type OffchainProposalItem = z.infer; export declare const SafeOffchainProposalsResponseSchema: z.ZodEffects>, "many">; totalCount: z.ZodNumber; }, "strip", z.ZodTypeAny, { items: ({ - link: string; + created: number; id: string; - type: string; title: string; - spaceId: string; - author: string; - body: string; discussion: string; - start: number; - end: number; state: string; - created: number; - updated: number; - flagged: boolean; } | null)[]; totalCount: number; }, { items: ({ - link: string; + created: number; id: string; - type: string; title: string; - spaceId: string; - author: string; - body: string; discussion: string; - start: number; - end: number; state: string; - created: number; - updated: number; - flagged: boolean; } | null)[]; totalCount: number; }>>; }, "strip", z.ZodTypeAny, { offchainProposals: { items: ({ - link: string; + created: number; id: string; - type: string; title: string; - spaceId: string; - author: string; - body: string; discussion: string; - start: number; - end: number; state: string; - created: number; - updated: number; - flagged: boolean; } | null)[]; totalCount: number; } | null; }, { offchainProposals: { items: ({ - link: string; + created: number; id: string; - type: string; title: string; - spaceId: string; - author: string; - body: string; discussion: string; - start: number; - end: number; state: string; - created: number; - updated: number; - flagged: boolean; } | null)[]; totalCount: number; } | null; }>, { offchainProposals: { items: { - link: string; + created: number; id: string; - type: string; title: string; - spaceId: string; - author: string; - body: string; discussion: string; - start: number; - end: number; state: string; - created: number; - updated: number; - flagged: boolean; }[]; totalCount: number; }; }, { offchainProposals: { items: ({ - link: string; + created: number; id: string; - type: string; title: string; - spaceId: string; - author: string; - body: string; discussion: string; - start: number; - end: number; state: string; - created: number; - updated: number; - flagged: boolean; } | null)[]; totalCount: number; } | null; diff --git a/packages/anticapture-client/dist/schemas.js b/packages/anticapture-client/dist/schemas.js index 3e9c4932..9af376a3 100644 --- a/packages/anticapture-client/dist/schemas.js +++ b/packages/anticapture-client/dist/schemas.js @@ -118,19 +118,10 @@ exports.SafeProposalNonVotersResponseSchema = zod_1.z.object({ }); exports.OffchainProposalItemSchema = zod_1.z.object({ id: zod_1.z.string(), - spaceId: zod_1.z.string(), - author: zod_1.z.string(), title: zod_1.z.string(), - body: zod_1.z.string(), discussion: zod_1.z.string(), - type: zod_1.z.string(), - start: zod_1.z.number(), - end: zod_1.z.number(), state: zod_1.z.string(), created: zod_1.z.number(), - updated: zod_1.z.number(), - link: zod_1.z.string(), - flagged: zod_1.z.boolean(), }); exports.SafeOffchainProposalsResponseSchema = zod_1.z.object({ offchainProposals: zod_1.z.object({ diff --git a/packages/anticapture-client/queries/offchain-proposals.graphql b/packages/anticapture-client/queries/offchain-proposals.graphql new file mode 100644 index 00000000..66036c20 --- /dev/null +++ b/packages/anticapture-client/queries/offchain-proposals.graphql @@ -0,0 +1,12 @@ +query ListOffchainProposals($skip: NonNegativeInt, $limit: PositiveInt, $orderDirection: queryInput_offchainProposals_orderDirection, $status: JSON, $fromDate: Float) { + offchainProposals(skip: $skip, limit: $limit, orderDirection: $orderDirection, status: $status, fromDate: $fromDate) { + items { + id + title + discussion + state + created + } + totalCount + } +} diff --git a/packages/anticapture-client/src/gql/gql.ts b/packages/anticapture-client/src/gql/gql.ts index 23ec75f5..10593d42 100644 --- a/packages/anticapture-client/src/gql/gql.ts +++ b/packages/anticapture-client/src/gql/gql.ts @@ -15,6 +15,7 @@ import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document- */ type Documents = { "query GetDAOs {\n daos {\n items {\n id\n votingDelay\n chainId\n }\n }\n}": typeof types.GetDaOsDocument, + "query ListOffchainProposals($skip: NonNegativeInt, $limit: PositiveInt, $orderDirection: queryInput_offchainProposals_orderDirection, $status: JSON, $fromDate: Float) {\n offchainProposals(\n skip: $skip\n limit: $limit\n orderDirection: $orderDirection\n status: $status\n fromDate: $fromDate\n ) {\n items {\n id\n title\n discussion\n state\n created\n }\n totalCount\n }\n}": typeof types.ListOffchainProposalsDocument, "query ProposalNonVoters($id: String!, $addresses: JSON) {\n proposalNonVoters(id: $id, addresses: $addresses) {\n items {\n voter\n }\n }\n}": typeof types.ProposalNonVotersDocument, "query GetProposalById($id: String!) {\n proposal(id: $id) {\n id\n daoId\n proposerAccountId\n title\n description\n startBlock\n endBlock\n endTimestamp\n timestamp\n status\n forVotes\n againstVotes\n abstainVotes\n txHash\n }\n}\n\nquery ListProposals($skip: NonNegativeInt, $limit: PositiveInt, $orderDirection: queryInput_proposals_orderDirection, $status: JSON, $fromDate: Float, $fromEndDate: Float, $includeOptimisticProposals: queryInput_proposals_includeOptimisticProposals) {\n proposals(\n skip: $skip\n limit: $limit\n orderDirection: $orderDirection\n status: $status\n fromDate: $fromDate\n fromEndDate: $fromEndDate\n includeOptimisticProposals: $includeOptimisticProposals\n ) {\n items {\n id\n daoId\n proposerAccountId\n title\n description\n startBlock\n endBlock\n endTimestamp\n timestamp\n status\n forVotes\n againstVotes\n abstainVotes\n txHash\n }\n totalCount\n }\n}": typeof types.GetProposalByIdDocument, "query ListVotes($voterAddressIn: JSON, $fromDate: Float, $toDate: Float, $limit: Float, $skip: NonNegativeInt, $orderBy: queryInput_votes_orderBy, $orderDirection: queryInput_votes_orderDirection, $support: Float) {\n votes(\n voterAddressIn: $voterAddressIn\n fromDate: $fromDate\n toDate: $toDate\n limit: $limit\n skip: $skip\n orderBy: $orderBy\n orderDirection: $orderDirection\n support: $support\n ) {\n items {\n transactionHash\n proposalId\n voterAddress\n support\n votingPower\n timestamp\n reason\n proposalTitle\n }\n totalCount\n }\n}": typeof types.ListVotesDocument, @@ -22,6 +23,7 @@ type Documents = { }; const documents: Documents = { "query GetDAOs {\n daos {\n items {\n id\n votingDelay\n chainId\n }\n }\n}": types.GetDaOsDocument, + "query ListOffchainProposals($skip: NonNegativeInt, $limit: PositiveInt, $orderDirection: queryInput_offchainProposals_orderDirection, $status: JSON, $fromDate: Float) {\n offchainProposals(\n skip: $skip\n limit: $limit\n orderDirection: $orderDirection\n status: $status\n fromDate: $fromDate\n ) {\n items {\n id\n title\n discussion\n state\n created\n }\n totalCount\n }\n}": types.ListOffchainProposalsDocument, "query ProposalNonVoters($id: String!, $addresses: JSON) {\n proposalNonVoters(id: $id, addresses: $addresses) {\n items {\n voter\n }\n }\n}": types.ProposalNonVotersDocument, "query GetProposalById($id: String!) {\n proposal(id: $id) {\n id\n daoId\n proposerAccountId\n title\n description\n startBlock\n endBlock\n endTimestamp\n timestamp\n status\n forVotes\n againstVotes\n abstainVotes\n txHash\n }\n}\n\nquery ListProposals($skip: NonNegativeInt, $limit: PositiveInt, $orderDirection: queryInput_proposals_orderDirection, $status: JSON, $fromDate: Float, $fromEndDate: Float, $includeOptimisticProposals: queryInput_proposals_includeOptimisticProposals) {\n proposals(\n skip: $skip\n limit: $limit\n orderDirection: $orderDirection\n status: $status\n fromDate: $fromDate\n fromEndDate: $fromEndDate\n includeOptimisticProposals: $includeOptimisticProposals\n ) {\n items {\n id\n daoId\n proposerAccountId\n title\n description\n startBlock\n endBlock\n endTimestamp\n timestamp\n status\n forVotes\n againstVotes\n abstainVotes\n txHash\n }\n totalCount\n }\n}": types.GetProposalByIdDocument, "query ListVotes($voterAddressIn: JSON, $fromDate: Float, $toDate: Float, $limit: Float, $skip: NonNegativeInt, $orderBy: queryInput_votes_orderBy, $orderDirection: queryInput_votes_orderDirection, $support: Float) {\n votes(\n voterAddressIn: $voterAddressIn\n fromDate: $fromDate\n toDate: $toDate\n limit: $limit\n skip: $skip\n orderBy: $orderBy\n orderDirection: $orderDirection\n support: $support\n ) {\n items {\n transactionHash\n proposalId\n voterAddress\n support\n votingPower\n timestamp\n reason\n proposalTitle\n }\n totalCount\n }\n}": types.ListVotesDocument, @@ -46,6 +48,10 @@ export function graphql(source: string): unknown; * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "query GetDAOs {\n daos {\n items {\n id\n votingDelay\n chainId\n }\n }\n}"): (typeof documents)["query GetDAOs {\n daos {\n items {\n id\n votingDelay\n chainId\n }\n }\n}"]; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function graphql(source: "query ListOffchainProposals($skip: NonNegativeInt, $limit: PositiveInt, $orderDirection: queryInput_offchainProposals_orderDirection, $status: JSON, $fromDate: Float) {\n offchainProposals(\n skip: $skip\n limit: $limit\n orderDirection: $orderDirection\n status: $status\n fromDate: $fromDate\n ) {\n items {\n id\n title\n discussion\n state\n created\n }\n totalCount\n }\n}"): (typeof documents)["query ListOffchainProposals($skip: NonNegativeInt, $limit: PositiveInt, $orderDirection: queryInput_offchainProposals_orderDirection, $status: JSON, $fromDate: Float) {\n offchainProposals(\n skip: $skip\n limit: $limit\n orderDirection: $orderDirection\n status: $status\n fromDate: $fromDate\n ) {\n items {\n id\n title\n discussion\n state\n created\n }\n totalCount\n }\n}"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/packages/anticapture-client/src/gql/graphql.ts b/packages/anticapture-client/src/gql/graphql.ts index d2f56ebc..16d2221c 100644 --- a/packages/anticapture-client/src/gql/graphql.ts +++ b/packages/anticapture-client/src/gql/graphql.ts @@ -117,6 +117,14 @@ export type Query = { delegationPercentageByDay?: Maybe; /** Get current delegators of an account */ delegations?: Maybe; + /** Get current delegators of an account with voting power */ + delegators?: Maybe; + /** Get feed events */ + feedEvents?: Maybe; + /** Returns label information from Arkham, ENS data, and whether the address is an EOA or contract. Arkham data is stored permanently. ENS data is cached with a configurable TTL. */ + getAddress?: Maybe; + /** Returns label information from Arkham, ENS data, and address type for multiple addresses. Maximum 100 addresses per request. Arkham data is stored permanently. ENS data is cached with a configurable TTL. */ + getAddresses?: Maybe; /** Get historical DAO Token Treasury value (governance token quantity × token price) */ getDaoTokenTreasury?: Maybe; /** Get historical Liquid Treasury (treasury without DAO tokens) from external providers (DefiLlama/Dune) */ @@ -135,6 +143,10 @@ export type Query = { historicalVotingPowerByAccountId?: Maybe; /** Get the last update time */ lastUpdate?: Maybe; + /** Returns a single offchain (Snapshot) proposal by its ID */ + offchainProposalById?: Maybe; + /** Returns a list of offchain (Snapshot) proposals */ + offchainProposals?: Maybe; /** Returns a single proposal by its ID */ proposal?: Maybe; /** Returns the active delegates that did not vote on a given proposal */ @@ -155,6 +167,10 @@ export type Query = { votes?: Maybe; /** Returns a paginated list of votes cast on a specific proposal */ votesByProposalId?: Maybe; + /** Returns a list of offchain (Snapshot) votes */ + votesOffchain?: Maybe; + /** Returns a paginated list of offchain (Snapshot) votes for a specific proposal */ + votesOffchainByProposalId?: Maybe; /** Returns voting power information for a specific address (account) */ votingPowerByAccountId?: Maybe; /** Returns a mapping of the voting power changes within a time frame for the given addresses */ @@ -293,6 +309,37 @@ export type QueryDelegationsArgs = { }; +export type QueryDelegatorsArgs = { + address: Scalars['String']['input']; + limit?: InputMaybe; + orderBy?: InputMaybe; + orderDirection?: InputMaybe; + skip?: InputMaybe; +}; + + +export type QueryFeedEventsArgs = { + fromDate?: InputMaybe; + limit?: InputMaybe; + orderBy?: InputMaybe; + orderDirection?: InputMaybe; + relevance?: InputMaybe; + skip?: InputMaybe; + toDate?: InputMaybe; + type?: InputMaybe; +}; + + +export type QueryGetAddressArgs = { + address: Scalars['String']['input']; +}; + + +export type QueryGetAddressesArgs = { + addresses: Scalars['JSON']['input']; +}; + + export type QueryGetDaoTokenTreasuryArgs = { days?: InputMaybe; order?: InputMaybe; @@ -372,6 +419,20 @@ export type QueryLastUpdateArgs = { }; +export type QueryOffchainProposalByIdArgs = { + id: Scalars['String']['input']; +}; + + +export type QueryOffchainProposalsArgs = { + fromDate?: InputMaybe; + limit?: InputMaybe; + orderDirection?: InputMaybe; + skip?: InputMaybe; + status?: InputMaybe; +}; + + export type QueryProposalArgs = { id: Scalars['String']['input']; }; @@ -479,6 +540,29 @@ export type QueryVotesByProposalIdArgs = { }; +export type QueryVotesOffchainArgs = { + fromDate?: InputMaybe; + limit?: InputMaybe; + orderBy?: InputMaybe; + orderDirection?: InputMaybe; + skip?: InputMaybe; + toDate?: InputMaybe; + voterAddresses?: InputMaybe; +}; + + +export type QueryVotesOffchainByProposalIdArgs = { + fromDate?: InputMaybe; + id: Scalars['String']['input']; + limit?: InputMaybe; + orderBy?: InputMaybe; + orderDirection?: InputMaybe; + skip?: InputMaybe; + toDate?: InputMaybe; + voterAddresses?: InputMaybe; +}; + + export type QueryVotingPowerByAccountIdArgs = { accountId: Scalars['String']['input']; }; @@ -515,7 +599,9 @@ export type AccountBalanceByAccountId_200_Response = { __typename?: 'accountBalanceByAccountId_200_response'; address: Scalars['String']['output']; balance: Scalars['String']['output']; + data: Query_AccountBalanceByAccountId_Data; delegate: Scalars['String']['output']; + period: Query_AccountBalanceByAccountId_Period; tokenId: Scalars['String']['output']; }; @@ -534,6 +620,7 @@ export type AccountBalanceVariations_200_Response = { export type AccountBalances_200_Response = { __typename?: 'accountBalances_200_response'; items: Array>; + period: Query_AccountBalances_Period; totalCount: Scalars['Float']['output']; }; @@ -643,6 +730,31 @@ export type Delegations_200_Response = { totalCount: Scalars['Float']['output']; }; +export type Delegators_200_Response = { + __typename?: 'delegators_200_response'; + items: Array>; + totalCount: Scalars['Float']['output']; +}; + +export type FeedEvents_200_Response = { + __typename?: 'feedEvents_200_response'; + items: Array>; + totalCount: Scalars['Float']['output']; +}; + +export type GetAddress_200_Response = { + __typename?: 'getAddress_200_response'; + address: Scalars['String']['output']; + arkham?: Maybe; + ens?: Maybe; + isContract: Scalars['Boolean']['output']; +}; + +export type GetAddresses_200_Response = { + __typename?: 'getAddresses_200_response'; + results: Array>; +}; + export type GetDaoTokenTreasury_200_Response = { __typename?: 'getDaoTokenTreasury_200_response'; items: Array>; @@ -693,6 +805,30 @@ export type LastUpdate_200_Response = { lastUpdate: Scalars['String']['output']; }; +export type OffchainProposalById_200_Response = { + __typename?: 'offchainProposalById_200_response'; + author: Scalars['String']['output']; + body: Scalars['String']['output']; + created: Scalars['Float']['output']; + discussion: Scalars['String']['output']; + end: Scalars['Float']['output']; + flagged: Scalars['Boolean']['output']; + id: Scalars['String']['output']; + link: Scalars['String']['output']; + spaceId: Scalars['String']['output']; + start: Scalars['Float']['output']; + state: Scalars['String']['output']; + title: Scalars['String']['output']; + type: Scalars['String']['output']; + updated: Scalars['Float']['output']; +}; + +export type OffchainProposals_200_Response = { + __typename?: 'offchainProposals_200_response'; + items: Array>; + totalCount: Scalars['Float']['output']; +}; + export type ProposalNonVoters_200_Response = { __typename?: 'proposalNonVoters_200_response'; items: Array>; @@ -746,6 +882,11 @@ export enum QueryInput_AccountBalanceVariations_OrderDirection { Desc = 'desc' } +export enum QueryInput_AccountBalances_OrderBy { + Balance = 'balance', + Variation = 'variation' +} + export enum QueryInput_AccountBalances_OrderDirection { Asc = 'asc', Desc = 'desc' @@ -854,6 +995,51 @@ export enum QueryInput_DelegationPercentageByDay_OrderDirection { Desc = 'desc' } +export enum QueryInput_Delegations_OrderBy { + Amount = 'amount', + Timestamp = 'timestamp' +} + +export enum QueryInput_Delegations_OrderDirection { + Asc = 'asc', + Desc = 'desc' +} + +export enum QueryInput_Delegators_OrderBy { + Amount = 'amount', + Timestamp = 'timestamp' +} + +export enum QueryInput_Delegators_OrderDirection { + Asc = 'asc', + Desc = 'desc' +} + +export enum QueryInput_FeedEvents_OrderBy { + Timestamp = 'timestamp', + Value = 'value' +} + +export enum QueryInput_FeedEvents_OrderDirection { + Asc = 'asc', + Desc = 'desc' +} + +export enum QueryInput_FeedEvents_Relevance { + High = 'HIGH', + Low = 'LOW', + Medium = 'MEDIUM' +} + +export enum QueryInput_FeedEvents_Type { + Delegation = 'DELEGATION', + DelegationVotesChanged = 'DELEGATION_VOTES_CHANGED', + Proposal = 'PROPOSAL', + ProposalExtended = 'PROPOSAL_EXTENDED', + Transfer = 'TRANSFER', + Vote = 'VOTE' +} + export enum QueryInput_GetDaoTokenTreasury_Days { '7d' = '_7d', '30d' = '_30d', @@ -934,6 +1120,11 @@ export enum QueryInput_LastUpdate_Chart { TokenDistribution = 'token_distribution' } +export enum QueryInput_OffchainProposals_OrderDirection { + Asc = 'asc', + Desc = 'desc' +} + export enum QueryInput_ProposalNonVoters_OrderDirection { Asc = 'asc', Desc = 'desc' @@ -1013,6 +1204,26 @@ export enum QueryInput_VotesByProposalId_OrderDirection { Desc = 'desc' } +export enum QueryInput_VotesOffchainByProposalId_OrderBy { + Created = 'created', + Vp = 'vp' +} + +export enum QueryInput_VotesOffchainByProposalId_OrderDirection { + Asc = 'asc', + Desc = 'desc' +} + +export enum QueryInput_VotesOffchain_OrderBy { + Created = 'created', + Vp = 'vp' +} + +export enum QueryInput_VotesOffchain_OrderDirection { + Asc = 'asc', + Desc = 'desc' +} + export enum QueryInput_Votes_OrderBy { Timestamp = 'timestamp', VotingPower = 'votingPower' @@ -1030,6 +1241,7 @@ export enum QueryInput_VotingPowerVariations_OrderDirection { export enum QueryInput_VotingPowers_OrderBy { DelegationsCount = 'delegationsCount', + Variation = 'variation', VotingPower = 'votingPower' } @@ -1038,6 +1250,28 @@ export enum QueryInput_VotingPowers_OrderDirection { Desc = 'desc' } +export type Query_AccountBalanceByAccountId_Data = { + __typename?: 'query_accountBalanceByAccountId_data'; + address: Scalars['String']['output']; + balance: Scalars['String']['output']; + delegate: Scalars['String']['output']; + tokenId: Scalars['String']['output']; + variation: Query_AccountBalanceByAccountId_Data_Variation; +}; + +export type Query_AccountBalanceByAccountId_Data_Variation = { + __typename?: 'query_accountBalanceByAccountId_data_variation'; + absoluteChange: Scalars['String']['output']; + percentageChange: Scalars['String']['output']; + previousBalance: Scalars['String']['output']; +}; + +export type Query_AccountBalanceByAccountId_Period = { + __typename?: 'query_accountBalanceByAccountId_period'; + endTimestamp: Scalars['String']['output']; + startTimestamp: Scalars['String']['output']; +}; + export type Query_AccountBalanceVariationsByAccountId_Data = { __typename?: 'query_accountBalanceVariationsByAccountId_data'; absoluteChange: Scalars['String']['output']; @@ -1074,6 +1308,20 @@ export type Query_AccountBalances_Items_Items = { balance: Scalars['String']['output']; delegate: Scalars['String']['output']; tokenId: Scalars['String']['output']; + variation: Query_AccountBalances_Items_Items_Variation; +}; + +export type Query_AccountBalances_Items_Items_Variation = { + __typename?: 'query_accountBalances_items_items_variation'; + absoluteChange: Scalars['String']['output']; + percentageChange: Scalars['String']['output']; + previousBalance: Scalars['String']['output']; +}; + +export type Query_AccountBalances_Period = { + __typename?: 'query_accountBalances_period'; + endTimestamp: Scalars['String']['output']; + startTimestamp: Scalars['String']['output']; }; export type Query_AccountInteractions_Items_Items = { @@ -1112,6 +1360,77 @@ export type Query_Delegations_Items_Items = { transactionHash: Scalars['String']['output']; }; +export type Query_Delegators_Items_Items = { + __typename?: 'query_delegators_items_items'; + amount: Scalars['String']['output']; + delegatorAddress: Scalars['String']['output']; + timestamp: Scalars['String']['output']; +}; + +export type Query_FeedEvents_Items_Items = { + __typename?: 'query_feedEvents_items_items'; + logIndex: Scalars['Float']['output']; + metadata?: Maybe; + relevance: Query_FeedEvents_Items_Items_Relevance; + timestamp: Scalars['Float']['output']; + txHash: Scalars['String']['output']; + type: Query_FeedEvents_Items_Items_Type; + value?: Maybe; +}; + +export enum Query_FeedEvents_Items_Items_Relevance { + High = 'HIGH', + Low = 'LOW', + Medium = 'MEDIUM' +} + +export enum Query_FeedEvents_Items_Items_Type { + Delegation = 'DELEGATION', + DelegationVotesChanged = 'DELEGATION_VOTES_CHANGED', + Proposal = 'PROPOSAL', + ProposalExtended = 'PROPOSAL_EXTENDED', + Transfer = 'TRANSFER', + Vote = 'VOTE' +} + +export type Query_GetAddress_Arkham = { + __typename?: 'query_getAddress_arkham'; + entity?: Maybe; + entityType?: Maybe; + label?: Maybe; + twitter?: Maybe; +}; + +export type Query_GetAddress_Ens = { + __typename?: 'query_getAddress_ens'; + avatar?: Maybe; + banner?: Maybe; + name?: Maybe; +}; + +export type Query_GetAddresses_Results_Items = { + __typename?: 'query_getAddresses_results_items'; + address: Scalars['String']['output']; + arkham?: Maybe; + ens?: Maybe; + isContract: Scalars['Boolean']['output']; +}; + +export type Query_GetAddresses_Results_Items_Arkham = { + __typename?: 'query_getAddresses_results_items_arkham'; + entity?: Maybe; + entityType?: Maybe; + label?: Maybe; + twitter?: Maybe; +}; + +export type Query_GetAddresses_Results_Items_Ens = { + __typename?: 'query_getAddresses_results_items_ens'; + avatar?: Maybe; + banner?: Maybe; + name?: Maybe; +}; + export type Query_GetDaoTokenTreasury_Items_Items = { __typename?: 'query_getDaoTokenTreasury_items_items'; /** Unix timestamp in milliseconds */ @@ -1226,6 +1545,24 @@ export type Query_HistoricalVotingPower_Items_Items_Transfer = { value: Scalars['String']['output']; }; +export type Query_OffchainProposals_Items_Items = { + __typename?: 'query_offchainProposals_items_items'; + author: Scalars['String']['output']; + body: Scalars['String']['output']; + created: Scalars['Float']['output']; + discussion: Scalars['String']['output']; + end: Scalars['Float']['output']; + flagged: Scalars['Boolean']['output']; + id: Scalars['String']['output']; + link: Scalars['String']['output']; + spaceId: Scalars['String']['output']; + start: Scalars['Float']['output']; + state: Scalars['String']['output']; + title: Scalars['String']['output']; + type: Scalars['String']['output']; + updated: Scalars['Float']['output']; +}; + export type Query_ProposalNonVoters_Items_Items = { __typename?: 'query_proposalNonVoters_items_items'; lastVoteTimestamp: Scalars['Float']['output']; @@ -1378,6 +1715,28 @@ export type Query_VotesByProposalId_Items_Items = { votingPower: Scalars['String']['output']; }; +export type Query_VotesOffchainByProposalId_Items_Items = { + __typename?: 'query_votesOffchainByProposalId_items_items'; + choice?: Maybe; + created: Scalars['Float']['output']; + proposalId: Scalars['String']['output']; + proposalTitle: Scalars['String']['output']; + reason: Scalars['String']['output']; + voter: Scalars['String']['output']; + vp: Scalars['Float']['output']; +}; + +export type Query_VotesOffchain_Items_Items = { + __typename?: 'query_votesOffchain_items_items'; + choice?: Maybe; + created: Scalars['Float']['output']; + proposalId: Scalars['String']['output']; + proposalTitle: Scalars['String']['output']; + reason: Scalars['String']['output']; + voter: Scalars['String']['output']; + vp: Scalars['Float']['output']; +}; + export type Query_Votes_Items_Items = { __typename?: 'query_votes_items_items'; proposalId: Scalars['String']['output']; @@ -1390,6 +1749,12 @@ export type Query_Votes_Items_Items = { votingPower: Scalars['String']['output']; }; +export type Query_VotingPowerByAccountId_Variation = { + __typename?: 'query_votingPowerByAccountId_variation'; + absoluteChange: Scalars['String']['output']; + percentageChange: Scalars['Float']['output']; +}; + export type Query_VotingPowerVariationsByAccountId_Data = { __typename?: 'query_votingPowerVariationsByAccountId_data'; absoluteChange: Scalars['String']['output']; @@ -1425,10 +1790,17 @@ export type Query_VotingPowers_Items_Items = { accountId: Scalars['String']['output']; delegationsCount: Scalars['Float']['output']; proposalsCount: Scalars['Float']['output']; + variation: Query_VotingPowers_Items_Items_Variation; votesCount: Scalars['Float']['output']; votingPower: Scalars['String']['output']; }; +export type Query_VotingPowers_Items_Items_Variation = { + __typename?: 'query_votingPowers_items_items_variation'; + absoluteChange: Scalars['String']['output']; + percentageChange: Scalars['Float']['output']; +}; + export enum Timestamp_Const { Timestamp = 'timestamp' } @@ -1472,6 +1844,18 @@ export type VotesByProposalId_200_Response = { totalCount: Scalars['Float']['output']; }; +export type VotesOffchainByProposalId_200_Response = { + __typename?: 'votesOffchainByProposalId_200_response'; + items: Array>; + totalCount: Scalars['Float']['output']; +}; + +export type VotesOffchain_200_Response = { + __typename?: 'votesOffchain_200_response'; + items: Array>; + totalCount: Scalars['Float']['output']; +}; + export type Votes_200_Response = { __typename?: 'votes_200_response'; items: Array>; @@ -1483,6 +1867,7 @@ export type VotingPowerByAccountId_200_Response = { accountId: Scalars['String']['output']; delegationsCount: Scalars['Float']['output']; proposalsCount: Scalars['Float']['output']; + variation: Query_VotingPowerByAccountId_Variation; votesCount: Scalars['Float']['output']; votingPower: Scalars['String']['output']; }; @@ -1510,6 +1895,17 @@ export type GetDaOsQueryVariables = Exact<{ [key: string]: never; }>; export type GetDaOsQuery = { __typename?: 'Query', daos: { __typename?: 'DAOList', items: Array<{ __typename?: 'dao_200_response', id: string, votingDelay: string, chainId: number }> } }; +export type ListOffchainProposalsQueryVariables = Exact<{ + skip?: InputMaybe; + limit?: InputMaybe; + orderDirection?: InputMaybe; + status?: InputMaybe; + fromDate?: InputMaybe; +}>; + + +export type ListOffchainProposalsQuery = { __typename?: 'Query', offchainProposals?: { __typename?: 'offchainProposals_200_response', totalCount: number, items: Array<{ __typename?: 'query_offchainProposals_items_items', id: string, title: string, discussion: string, state: string, created: number } | null> } | null }; + export type ProposalNonVotersQueryVariables = Exact<{ id: Scalars['String']['input']; addresses?: InputMaybe; @@ -1566,6 +1962,7 @@ export type ListHistoricalVotingPowerQuery = { __typename?: 'Query', historicalV export const GetDaOsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetDAOs"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"daos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"votingDelay"}},{"kind":"Field","name":{"kind":"Name","value":"chainId"}}]}}]}}]}}]} as unknown as DocumentNode; +export const ListOffchainProposalsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ListOffchainProposals"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"skip"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"NonNegativeInt"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"limit"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PositiveInt"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"orderDirection"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"queryInput_offchainProposals_orderDirection"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"status"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"fromDate"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"offchainProposals"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"skip"},"value":{"kind":"Variable","name":{"kind":"Name","value":"skip"}}},{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"Variable","name":{"kind":"Name","value":"limit"}}},{"kind":"Argument","name":{"kind":"Name","value":"orderDirection"},"value":{"kind":"Variable","name":{"kind":"Name","value":"orderDirection"}}},{"kind":"Argument","name":{"kind":"Name","value":"status"},"value":{"kind":"Variable","name":{"kind":"Name","value":"status"}}},{"kind":"Argument","name":{"kind":"Name","value":"fromDate"},"value":{"kind":"Variable","name":{"kind":"Name","value":"fromDate"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"discussion"}},{"kind":"Field","name":{"kind":"Name","value":"state"}},{"kind":"Field","name":{"kind":"Name","value":"created"}}]}},{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}}]}}]} as unknown as DocumentNode; export const ProposalNonVotersDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ProposalNonVoters"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"addresses"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"proposalNonVoters"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}},{"kind":"Argument","name":{"kind":"Name","value":"addresses"},"value":{"kind":"Variable","name":{"kind":"Name","value":"addresses"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"voter"}}]}}]}}]}}]} as unknown as DocumentNode; export const GetProposalByIdDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetProposalById"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"proposal"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"daoId"}},{"kind":"Field","name":{"kind":"Name","value":"proposerAccountId"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"startBlock"}},{"kind":"Field","name":{"kind":"Name","value":"endBlock"}},{"kind":"Field","name":{"kind":"Name","value":"endTimestamp"}},{"kind":"Field","name":{"kind":"Name","value":"timestamp"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"forVotes"}},{"kind":"Field","name":{"kind":"Name","value":"againstVotes"}},{"kind":"Field","name":{"kind":"Name","value":"abstainVotes"}},{"kind":"Field","name":{"kind":"Name","value":"txHash"}}]}}]}}]} as unknown as DocumentNode; export const ListProposalsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ListProposals"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"skip"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"NonNegativeInt"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"limit"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PositiveInt"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"orderDirection"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"queryInput_proposals_orderDirection"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"status"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"fromDate"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"fromEndDate"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"includeOptimisticProposals"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"queryInput_proposals_includeOptimisticProposals"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"proposals"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"skip"},"value":{"kind":"Variable","name":{"kind":"Name","value":"skip"}}},{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"Variable","name":{"kind":"Name","value":"limit"}}},{"kind":"Argument","name":{"kind":"Name","value":"orderDirection"},"value":{"kind":"Variable","name":{"kind":"Name","value":"orderDirection"}}},{"kind":"Argument","name":{"kind":"Name","value":"status"},"value":{"kind":"Variable","name":{"kind":"Name","value":"status"}}},{"kind":"Argument","name":{"kind":"Name","value":"fromDate"},"value":{"kind":"Variable","name":{"kind":"Name","value":"fromDate"}}},{"kind":"Argument","name":{"kind":"Name","value":"fromEndDate"},"value":{"kind":"Variable","name":{"kind":"Name","value":"fromEndDate"}}},{"kind":"Argument","name":{"kind":"Name","value":"includeOptimisticProposals"},"value":{"kind":"Variable","name":{"kind":"Name","value":"includeOptimisticProposals"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"daoId"}},{"kind":"Field","name":{"kind":"Name","value":"proposerAccountId"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"startBlock"}},{"kind":"Field","name":{"kind":"Name","value":"endBlock"}},{"kind":"Field","name":{"kind":"Name","value":"endTimestamp"}},{"kind":"Field","name":{"kind":"Name","value":"timestamp"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"forVotes"}},{"kind":"Field","name":{"kind":"Name","value":"againstVotes"}},{"kind":"Field","name":{"kind":"Name","value":"abstainVotes"}},{"kind":"Field","name":{"kind":"Name","value":"txHash"}}]}},{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}}]}}]} as unknown as DocumentNode; diff --git a/packages/anticapture-client/src/index.ts b/packages/anticapture-client/src/index.ts index ea29719c..dcde5707 100644 --- a/packages/anticapture-client/src/index.ts +++ b/packages/anticapture-client/src/index.ts @@ -25,4 +25,4 @@ export { QueryInput_Votes_OrderDirection } from './gql/graphql'; -export type { ProcessedVotingPowerHistory } from './schemas'; \ No newline at end of file +export type { ProcessedVotingPowerHistory, OffchainProposalItem } from './schemas'; \ No newline at end of file diff --git a/packages/anticapture-client/src/schemas.ts b/packages/anticapture-client/src/schemas.ts index 3a09c7f3..b28e8835 100644 --- a/packages/anticapture-client/src/schemas.ts +++ b/packages/anticapture-client/src/schemas.ts @@ -121,6 +121,36 @@ export const SafeProposalNonVotersResponseSchema = z.object({ }); +export const OffchainProposalItemSchema = z.object({ + id: z.string(), + title: z.string(), + discussion: z.string(), + state: z.string(), + created: z.number(), +}); + +export type OffchainProposalItem = z.infer; + +export const SafeOffchainProposalsResponseSchema = z.object({ + offchainProposals: z.object({ + items: z.array(OffchainProposalItemSchema.nullable()), + totalCount: z.number(), + }).nullable(), +}).transform((data) => { + if (!data.offchainProposals) { + console.warn('OffchainProposalsResponse has null offchainProposals:', data); + return { offchainProposals: { items: [], totalCount: 0 } }; + } + return { + offchainProposals: { + ...data.offchainProposals, + items: data.offchainProposals.items.filter( + (item): item is OffchainProposalItem => item !== null + ), + }, + }; +}); + // Internal types for schema validation type SafeProposalsResponse = z.infer; type SafeHistoricalVotingPowerResponse = z.infer; From 35d69783bb2b5efa50b107b09b10d7732d64461f Mon Sep 17 00:00:00 2001 From: Leonardo Vieira Date: Thu, 26 Feb 2026 11:36:48 -0300 Subject: [PATCH 04/42] feat: listOffchainProposals function --- .../src/anticapture-client.ts | 48 +++++++++++++++++-- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/packages/anticapture-client/src/anticapture-client.ts b/packages/anticapture-client/src/anticapture-client.ts index 1fe23c3a..a473a094 100644 --- a/packages/anticapture-client/src/anticapture-client.ts +++ b/packages/anticapture-client/src/anticapture-client.ts @@ -12,10 +12,12 @@ import type { ListHistoricalVotingPowerQueryVariables, ListVotesQuery, ListVotesQueryVariables, - ProposalNonVotersQueryVariables + ProposalNonVotersQueryVariables, + ListOffchainProposalsQueryVariables } from './gql/graphql'; -import { GetDaOsDocument, GetProposalByIdDocument, ListProposalsDocument, ListHistoricalVotingPowerDocument, ListVotesDocument, ProposalNonVotersDocument, QueryInput_Votes_OrderBy, QueryInput_Votes_OrderDirection } from './gql/graphql'; -import { SafeDaosResponseSchema, SafeProposalByIdResponseSchema, SafeProposalsResponseSchema, SafeHistoricalVotingPowerResponseSchema, SafeVotesResponseSchema, SafeProposalNonVotersResponseSchema, processProposals, processVotingPowerHistory, ProcessedVotingPowerHistory } from './schemas'; +import { GetDaOsDocument, GetProposalByIdDocument, ListProposalsDocument, ListHistoricalVotingPowerDocument, ListVotesDocument, ProposalNonVotersDocument, ListOffchainProposalsDocument, QueryInput_Votes_OrderBy, QueryInput_Votes_OrderDirection } from './gql/graphql'; +import { SafeDaosResponseSchema, SafeProposalByIdResponseSchema, SafeProposalsResponseSchema, SafeHistoricalVotingPowerResponseSchema, SafeVotesResponseSchema, SafeProposalNonVotersResponseSchema, SafeOffchainProposalsResponseSchema, processProposals, processVotingPowerHistory, ProcessedVotingPowerHistory } from './schemas'; +import type { OffchainProposalItem } from './schemas'; type ProposalItems = NonNullable['items']; type VotingPowerHistoryItems = ProcessedVotingPowerHistory[]; @@ -329,4 +331,44 @@ export class AnticaptureClient { return allVotes; } + + /** + * Lists offchain (Snapshot) proposals from all DAOs or a specific DAO + * @param variables Query variables (skip, limit, orderDirection, status, fromDate) + * @param daoId Optional specific DAO ID. If not provided, queries all DAOs + * @returns Array of offchain proposal items with daoId attached + */ + async listOffchainProposals( + variables?: ListOffchainProposalsQueryVariables, + daoId?: string + ): Promise<(OffchainProposalItem & { daoId: string })[]> { + if (!daoId) { + const allDAOs = await this.getDAOs(); + const allProposals: (OffchainProposalItem & { daoId: string })[] = []; + + for (const dao of allDAOs) { + try { + const validated = await this.query(ListOffchainProposalsDocument, SafeOffchainProposalsResponseSchema, variables, dao.id); + const items = validated.offchainProposals.items.map(item => ({ ...item, daoId: dao.id })); + if (items.length > 0) { + allProposals.push(...items); + } + } catch (error) { + console.warn(`Skipping offchain proposals for ${dao.id} due to API error: ${error instanceof Error ? error.message : error}`); + } + } + + // Sort by created timestamp desc (most recent first) + allProposals.sort((a, b) => b.created - a.created); + return allProposals; + } + + try { + const validated = await this.query(ListOffchainProposalsDocument, SafeOffchainProposalsResponseSchema, variables, daoId); + return validated.offchainProposals.items.map(item => ({ ...item, daoId })); + } catch (error) { + console.warn(`Error querying offchain proposals for DAO ${daoId}: ${error instanceof Error ? error.message : error}`); + return []; + } + } } \ No newline at end of file From 99c30fad543e9ed2ea6757c659d562839fc26e01 Mon Sep 17 00:00:00 2001 From: Leonardo Vieira Date: Thu, 26 Feb 2026 11:37:31 -0300 Subject: [PATCH 05/42] feat: NewOffchainProposalTrigger instance on app.ts --- apps/logic-system/src/app.ts | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/apps/logic-system/src/app.ts b/apps/logic-system/src/app.ts index 809a5d1d..fd7d1d36 100644 --- a/apps/logic-system/src/app.ts +++ b/apps/logic-system/src/app.ts @@ -1,9 +1,11 @@ import { NewProposalTrigger } from './triggers/new-proposal-trigger'; +import { NewOffchainProposalTrigger } from './triggers/new-offchain-proposal-trigger'; import { VotingPowerChangedTrigger } from './triggers/voting-power-changed-trigger'; import { ProposalFinishedTrigger } from './triggers/proposal-finished-trigger'; import { VoteConfirmationTrigger } from './triggers/vote-confirmation-trigger'; import { VotingReminderTrigger } from './triggers/voting-reminder-trigger'; import { ProposalRepository } from './repositories/proposal.repository'; +import { OffchainProposalRepository } from './repositories/offchain-proposal.repository'; import { VotingPowerRepository } from './repositories/voting-power.repository'; import { VotesRepository } from './repositories/votes.repository'; import { RabbitMQDispatcherService } from './api-clients/rabbitmq-dispatcher.service'; @@ -14,6 +16,7 @@ import { AxiosInstance } from 'axios'; export class App { private trigger!: NewProposalTrigger; + private offchainProposalTrigger!: NewOffchainProposalTrigger; private votingPowerTrigger!: VotingPowerChangedTrigger; private proposalFinishedTrigger!: ProposalFinishedTrigger; private voteConfirmationTrigger!: VoteConfirmationTrigger; @@ -36,15 +39,17 @@ export class App { const anticaptureClient = new AnticaptureClient(anticaptureHttpClient); const proposalRepository = new ProposalRepository(anticaptureClient); + const offchainProposalRepository = new OffchainProposalRepository(anticaptureClient); const votingPowerRepository = new VotingPowerRepository(anticaptureClient); const votesRepository = new VotesRepository(anticaptureClient); - this.initPromise = this.initializeRabbitMQ(rabbitmqUrl, proposalRepository, votingPowerRepository, votesRepository, triggerInterval, initialTimestamp); + this.initPromise = this.initializeRabbitMQ(rabbitmqUrl, proposalRepository, offchainProposalRepository, votingPowerRepository, votesRepository, triggerInterval, initialTimestamp); } private async initializeRabbitMQ( - rabbitmqUrl: string, + rabbitmqUrl: string, proposalRepository: ProposalRepository, + offchainProposalRepository: OffchainProposalRepository, votingPowerRepository: VotingPowerRepository, votesRepository: VotesRepository, triggerInterval: number, @@ -63,6 +68,13 @@ export class App { initialTimestamp ); + this.offchainProposalTrigger = new NewOffchainProposalTrigger( + dispatcherService, + offchainProposalRepository, + triggerInterval, + initialTimestamp + ); + this.votingPowerTrigger = new VotingPowerChangedTrigger( dispatcherService, votingPowerRepository, @@ -108,6 +120,7 @@ export class App { async start(): Promise { await this.initPromise; this.trigger.start({ status: this.proposalStatus }); + this.offchainProposalTrigger.start({ status: ['active', 'pending'] }); this.votingPowerTrigger.start(); this.proposalFinishedTrigger.start(); this.voteConfirmationTrigger.start(); @@ -139,10 +152,14 @@ export class App { if (this.voteConfirmationTrigger) { this.voteConfirmationTrigger.reset(initialTimestamp); } + if (this.offchainProposalTrigger) { + this.offchainProposalTrigger.reset(initialTimestamp); + } } async stop(): Promise { await this.trigger.stop(); + await this.offchainProposalTrigger.stop(); await this.votingPowerTrigger.stop(); await this.proposalFinishedTrigger.stop(); await this.voteConfirmationTrigger.stop(); From 5c28466a8d7767d231907fa068471fc294f34c3d Mon Sep 17 00:00:00 2001 From: Leonardo Vieira Date: Thu, 26 Feb 2026 11:39:47 -0300 Subject: [PATCH 06/42] feat: offchain proposal interface --- .../interfaces/offchain-proposal.interface.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 apps/logic-system/src/interfaces/offchain-proposal.interface.ts diff --git a/apps/logic-system/src/interfaces/offchain-proposal.interface.ts b/apps/logic-system/src/interfaces/offchain-proposal.interface.ts new file mode 100644 index 00000000..1766412c --- /dev/null +++ b/apps/logic-system/src/interfaces/offchain-proposal.interface.ts @@ -0,0 +1,18 @@ +import type { OffchainProposalItem } from '@notification-system/anticapture-client'; + +export type OffchainProposal = OffchainProposalItem & { daoId: string }; + +export interface ListOffchainProposalsOptions { + /** Filter by state (e.g., "active", "pending") */ + status?: string | string[]; + /** Filter proposals created after this date (timestamp in seconds) */ + fromDate?: number; + /** Maximum number of proposals to return */ + limit?: number; + /** Order direction - asc or desc */ + orderDirection?: string; +} + +export interface OffchainProposalDataSource { + listAll(options?: ListOffchainProposalsOptions): Promise; +} From aa72541aba5ae6d6f016df36cc88efc511a3bb52 Mon Sep 17 00:00:00 2001 From: Leonardo Vieira Date: Thu, 26 Feb 2026 11:40:58 -0300 Subject: [PATCH 07/42] feat: repository to call the client for offchain proposals --- .../offchain-proposal.repository.ts | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 apps/logic-system/src/repositories/offchain-proposal.repository.ts diff --git a/apps/logic-system/src/repositories/offchain-proposal.repository.ts b/apps/logic-system/src/repositories/offchain-proposal.repository.ts new file mode 100644 index 00000000..c371f366 --- /dev/null +++ b/apps/logic-system/src/repositories/offchain-proposal.repository.ts @@ -0,0 +1,32 @@ +import { AnticaptureClient } from '@notification-system/anticapture-client'; +import { OffchainProposalDataSource, OffchainProposal, ListOffchainProposalsOptions } from '../interfaces/offchain-proposal.interface'; + +export class OffchainProposalRepository implements OffchainProposalDataSource { + private anticaptureClient: AnticaptureClient; + + constructor(anticaptureClient: AnticaptureClient) { + this.anticaptureClient = anticaptureClient; + } + + async listAll(options?: ListOffchainProposalsOptions): Promise { + const variables: Record = {}; + + if (options?.status) { + variables.status = options.status; + } + + if (options?.fromDate) { + variables.fromDate = options.fromDate; + } + + if (options?.limit) { + variables.limit = options.limit; + } + + if (options?.orderDirection) { + variables.orderDirection = options.orderDirection; + } + + return await this.anticaptureClient.listOffchainProposals(variables); + } +} From b772f3c5a6228e292f3a8902fa0b4c8e58c5f61d Mon Sep 17 00:00:00 2001 From: Leonardo Vieira Date: Thu, 26 Feb 2026 11:51:42 -0300 Subject: [PATCH 08/42] feat: new trigger on logic-system --- .../triggers/new-offchain-proposal-trigger.ts | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 apps/logic-system/src/triggers/new-offchain-proposal-trigger.ts diff --git a/apps/logic-system/src/triggers/new-offchain-proposal-trigger.ts b/apps/logic-system/src/triggers/new-offchain-proposal-trigger.ts new file mode 100644 index 00000000..be674b59 --- /dev/null +++ b/apps/logic-system/src/triggers/new-offchain-proposal-trigger.ts @@ -0,0 +1,71 @@ +/** + * @fileoverview Trigger logic for handling new offchain (Snapshot) proposals. + * Monitors for active/pending Snapshot proposals and sends them to the Dispatcher. + */ + +import { Trigger } from './base-trigger'; +import { OffchainProposal, OffchainProposalDataSource, ListOffchainProposalsOptions } from '../interfaces/offchain-proposal.interface'; +import { DispatcherService, DispatcherMessage } from '../interfaces/dispatcher.interface'; + +const triggerId = 'new-offchain-proposal'; + +export class NewOffchainProposalTrigger extends Trigger { + private timestampCursor: number; + + constructor( + private readonly dispatcherService: DispatcherService, + private readonly offchainProposalRepository: OffchainProposalDataSource, + interval: number, + initialTimestamp?: string + ) { + super(triggerId, interval); + if (initialTimestamp) { + this.timestampCursor = parseInt(initialTimestamp, 10); + } else { + this.timestampCursor = Math.floor((Date.now() - 24 * 60 * 60 * 1000) / 1000); // 24 hours ago + } + } + + /** + * Resets the trigger state to initial timestamp + * @param timestamp Optional timestamp to reset to, defaults to 24 hours ago + * @todo This method will be removed when we migrate to Redis for state management + */ + public reset(timestamp?: string): void { + if (timestamp) { + this.timestampCursor = parseInt(timestamp, 10); + } else { + this.timestampCursor = Math.floor((Date.now() - 24 * 60 * 60 * 1000) / 1000); + } + } + + async process(data: OffchainProposal[]) { + if (data.length === 0) { + return; + } + + const message: DispatcherMessage = { + triggerId: this.id, + events: data + }; + await this.dispatcherService.sendMessage(message); + + // Update cursor to the most recent proposal's created timestamp + 1 + // Data comes sorted by created desc, so the first item has the latest timestamp + if (data[0]?.created) { + this.timestampCursor = data[0].created + 1; + } + } + + /** + * Fetches offchain proposals from the API + * @returns Array of offchain proposals + */ + protected async fetchData(options: ListOffchainProposalsOptions): Promise { + return await this.offchainProposalRepository.listAll({ + ...options, + status: options.status, + fromDate: this.timestampCursor + }); + } +} From ce321958057d9ed4c192f05990c1d8b953bb6b08 Mon Sep 17 00:00:00 2001 From: Leonardo Vieira Date: Thu, 26 Feb 2026 11:56:17 -0300 Subject: [PATCH 09/42] add: new trigger handler on dispatcher --- .../new-offchain-proposal-trigger.service.ts | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 apps/dispatcher/src/services/triggers/new-offchain-proposal-trigger.service.ts diff --git a/apps/dispatcher/src/services/triggers/new-offchain-proposal-trigger.service.ts b/apps/dispatcher/src/services/triggers/new-offchain-proposal-trigger.service.ts new file mode 100644 index 00000000..693cef95 --- /dev/null +++ b/apps/dispatcher/src/services/triggers/new-offchain-proposal-trigger.service.ts @@ -0,0 +1,56 @@ +import { DispatcherMessage, MessageProcessingResult } from "../../interfaces/dispatcher-message.interface"; +import { ISubscriptionClient } from "../../interfaces/subscription-client.interface"; +import { NotificationClientFactory } from "../notification/notification-factory.service"; +import { BaseTriggerHandler } from "./base-trigger.service"; +import { newOffchainProposalMessages, replacePlaceholders, buildButtons } from '@notification-system/messages'; +import crypto from 'crypto'; + +/** + * Handler for processing "new-offchain-proposal" trigger messages (Snapshot proposals) + */ +export class NewOffchainProposalTriggerHandler extends BaseTriggerHandler { + constructor( + subscriptionClient: ISubscriptionClient, + notificationFactory: NotificationClientFactory, + ) { + super(subscriptionClient, notificationFactory); + } + + /** + * Handle a new offchain proposal message + * @param message The message containing offchain proposal data + */ + async handleMessage(message: DispatcherMessage): Promise { + for (const proposal of message.events) { + const { daoId, id: proposalId, title, created, discussion } = proposal; + const eventId = `offchain-${proposalId}`; + const proposalTimestamp = String(created); + + const subscribers = await this.getSubscribers(daoId, eventId, proposalTimestamp); + const notificationMessage = replacePlaceholders(newOffchainProposalMessages.notification, { + daoId, + title: title || 'Untitled Proposal' + }); + + // Build buttons — include discussion link if available, no txHash for offchain + const buttons = buildButtons({ + triggerType: 'newOffchainProposal', + discussionUrl: discussion || undefined, + }); + + await this.sendNotificationsToSubscribers( + subscribers, + notificationMessage, + eventId, + daoId, + undefined, + buttons + ); + } + + return { + messageId: crypto.randomUUID(), + timestamp: new Date().toISOString() + }; + } +} From ddfd801d3b40bc83d937d7df3ff89542e407009b Mon Sep 17 00:00:00 2001 From: Leonardo Vieira Date: Thu, 26 Feb 2026 11:56:44 -0300 Subject: [PATCH 10/42] feat: new handler instance on dispatcher --- apps/dispatcher/src/app.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/dispatcher/src/app.ts b/apps/dispatcher/src/app.ts index a3157920..eb5e932a 100644 --- a/apps/dispatcher/src/app.ts +++ b/apps/dispatcher/src/app.ts @@ -5,6 +5,7 @@ import { SubscriptionClient } from './services/subscription-client.service'; import { NotificationClientFactory } from './services/notification/notification-factory.service'; import { RabbitMQNotificationService } from './services/notification/rabbitmq-notification.service'; import { NewProposalTriggerHandler } from './services/triggers/new-proposal-trigger.service'; +import { NewOffchainProposalTriggerHandler } from './services/triggers/new-offchain-proposal-trigger.service'; import { VotingPowerTriggerHandler } from './services/triggers/voting-power-trigger.service'; import { ProposalFinishedTriggerHandler } from './services/triggers/proposal-finished-trigger.service'; import { NonVotingHandler } from './services/triggers/non-voting-handler.service'; @@ -59,6 +60,11 @@ export class App { new NewProposalTriggerHandler(subscriptionClient, notificationFactory, anticaptureClient) ); + triggerProcessorService.addHandler( + 'new-offchain-proposal', + new NewOffchainProposalTriggerHandler(subscriptionClient, notificationFactory) + ); + triggerProcessorService.addHandler( 'voting-power-changed', new VotingPowerTriggerHandler(subscriptionClient, notificationFactory) From 21aee2baa7b12e861c1594735efc7ffb2ee082a1 Mon Sep 17 00:00:00 2001 From: Leonardo Vieira Date: Thu, 26 Feb 2026 12:57:50 -0300 Subject: [PATCH 11/42] feat: MSW lib --- packages/anticapture-client/jest.config.js | 7 + packages/anticapture-client/package.json | 1 + pnpm-lock.yaml | 489 +++++++++++++++++++-- 3 files changed, 464 insertions(+), 33 deletions(-) diff --git a/packages/anticapture-client/jest.config.js b/packages/anticapture-client/jest.config.js index 7439fe3d..79ceb218 100644 --- a/packages/anticapture-client/jest.config.js +++ b/packages/anticapture-client/jest.config.js @@ -3,6 +3,13 @@ module.exports = { testEnvironment: 'node', roots: ['/tests'], testMatch: ['**/*.test.ts'], + transformIgnorePatterns: [ + '/node_modules/.pnpm/(?!(msw|@mswjs|until-async|@bundled-es-modules)[@+])', + ], + transform: { + '^.+\\.tsx?$': 'ts-jest', + '^.+\\.jsx?$': ['ts-jest', { tsconfig: { allowJs: true } }], + }, collectCoverageFrom: [ 'src/**/*.{ts,js}', '!src/**/*.d.ts', diff --git a/packages/anticapture-client/package.json b/packages/anticapture-client/package.json index 4c2cdc83..5ed78f54 100644 --- a/packages/anticapture-client/package.json +++ b/packages/anticapture-client/package.json @@ -29,6 +29,7 @@ "@types/node": "^20.17.46", "dotenv-cli": "^8.0.0", "jest": "^29.0.0", + "msw": "^2.12.10", "ts-jest": "^29.0.0", "typescript": "^5.8.3" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 99ad685f..928e561b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -160,10 +160,10 @@ importers: version: 20.17.46 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.2)) + version: 29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@20.17.46)(typescript@5.8.2)) ts-jest: specifier: ^29.3.2 - version: 29.3.2(@babel/core@7.27.1)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.1))(jest@29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.2)))(typescript@5.8.2) + version: 29.3.2(@babel/core@7.27.1)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.1))(jest@29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@20.17.46)(typescript@5.8.2)))(typescript@5.8.2) tsx: specifier: ^4.19.4 version: 4.19.4 @@ -284,7 +284,7 @@ importers: version: 16.5.0 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.2)) + version: 29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@20.17.46)(typescript@5.8.3)) knex: specifier: ^3.1.0 version: 3.1.0(pg@8.16.3)(sqlite3@5.1.7) @@ -296,7 +296,7 @@ importers: version: 5.1.7 ts-jest: specifier: ^29.3.2 - version: 29.3.2(@babel/core@7.27.1)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.1))(jest@29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.2)))(typescript@5.8.3) + version: 29.3.2(@babel/core@7.27.1)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.1))(jest@29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@20.17.46)(typescript@5.8.3)))(typescript@5.8.3) typescript: specifier: ^5.8.3 version: 5.8.3 @@ -430,13 +430,13 @@ importers: version: 8.15.2 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@20.17.46)(typescript@5.8.3)) + version: 29.7.0(@types/node@24.3.1)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.3)) ts-jest: specifier: ^29.3.2 - version: 29.3.2(@babel/core@7.27.1)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.1))(jest@29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@20.17.46)(typescript@5.8.3)))(typescript@5.8.3) + version: 29.3.2(@babel/core@7.27.1)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.1))(jest@29.7.0(@types/node@24.3.1)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.3)))(typescript@5.8.3) ts-node: specifier: ^10.9.2 - version: 10.9.2(@swc/core@1.11.24)(@types/node@20.17.46)(typescript@5.8.3) + version: 10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.3) tsx: specifier: ^4.19.4 version: 4.19.4 @@ -488,10 +488,13 @@ importers: version: 8.0.0 jest: specifier: ^29.0.0 - version: 29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.2)) + version: 29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@20.17.46)(typescript@5.8.3)) + msw: + specifier: ^2.12.10 + version: 2.12.10(@types/node@20.17.46)(typescript@5.8.3) ts-jest: specifier: ^29.0.0 - version: 29.3.2(@babel/core@7.27.1)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.1))(jest@29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.2)))(typescript@5.8.3) + version: 29.3.2(@babel/core@7.27.1)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.1))(jest@29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@20.17.46)(typescript@5.8.3)))(typescript@5.8.3) typescript: specifier: ^5.8.3 version: 5.8.3 @@ -510,10 +513,10 @@ importers: version: 20.17.46 jest: specifier: ^29.0.0 - version: 29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.2)) + version: 29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@20.17.46)(typescript@5.8.3)) ts-jest: specifier: ^29.0.0 - version: 29.3.2(@babel/core@7.27.1)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.1))(jest@29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.2)))(typescript@5.8.3) + version: 29.3.2(@babel/core@7.27.1)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.1))(jest@29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@20.17.46)(typescript@5.8.3)))(typescript@5.8.3) typescript: specifier: ^5.0.0 version: 5.8.3 @@ -1222,6 +1225,41 @@ packages: resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} deprecated: Use @eslint/object-schema instead + '@inquirer/ansi@1.0.2': + resolution: {integrity: sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==} + engines: {node: '>=18'} + + '@inquirer/confirm@5.1.21': + resolution: {integrity: sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/core@10.3.2': + resolution: {integrity: sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/figures@1.0.15': + resolution: {integrity: sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==} + engines: {node: '>=18'} + + '@inquirer/type@3.0.10': + resolution: {integrity: sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} @@ -1332,6 +1370,10 @@ packages: resolution: {integrity: sha512-9I2Zn6+NJLfaGoz9jN3lpwDgAYvfGeNYdbAIjJOqzs4Tpc+VU3Jqq4IofSUBKajiDS8k9fZIg18/z13mpk1bsA==} engines: {node: '>=8'} + '@mswjs/interceptors@0.41.3': + resolution: {integrity: sha512-cXu86tF4VQVfwz8W1SPbhoRyHJkti6mjH/XJIxp40jhO4j2k1m4KYrEykxqWPkFF3vrK4rgQppBh//AwyGSXPA==} + engines: {node: '>=18'} + '@next/env@14.2.35': resolution: {integrity: sha512-DuhvCtj4t9Gwrx80dmz2F4t/zKQ4ktN8WrMwOuVzkJfBilwAwGr6v16M5eI8yCuZ63H9TTuEU09Iu2HqkzFPVQ==} @@ -1421,6 +1463,15 @@ packages: engines: {node: '>=10'} deprecated: This functionality has been moved to @npmcli/fs + '@open-draft/deferred-promise@2.2.0': + resolution: {integrity: sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==} + + '@open-draft/logger@0.3.0': + resolution: {integrity: sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==} + + '@open-draft/until@2.1.0': + resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==} + '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -1922,6 +1973,9 @@ packages: '@types/stack-utils@2.0.3': resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + '@types/statuses@2.0.6': + resolution: {integrity: sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==} + '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} @@ -2465,6 +2519,10 @@ packages: resolution: {integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==} engines: {node: '>= 10'} + cli-width@4.1.0: + resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} + engines: {node: '>= 12'} + client-only@0.0.1: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} @@ -3249,16 +3307,18 @@ packages: glob@10.4.5: resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me hasBin: true glob@11.0.2: resolution: {integrity: sha512-YT7U7Vye+t5fZ/QMkBFrTJ7ZQxInIUjwyAjVj84CYXqgBdv30MFUPGnBR6sQaVq6Is15wYJUsnzTuWaGRBhBAQ==} engines: {node: 20 || >=22} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me hasBin: true glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me globals@11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} @@ -3326,6 +3386,10 @@ packages: resolution: {integrity: sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw==} engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} + graphql@16.13.0: + resolution: {integrity: sha512-uSisMYERbaB9bkA9M4/4dnqyktaEkf1kMHNKq/7DHyxVeWqHQ2mBmVqm5u6/FVHwF3iCNalKcg82Zfl+tffWoA==} + engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} + has-flag@3.0.0: resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} engines: {node: '>=4'} @@ -3352,6 +3416,9 @@ packages: header-case@2.0.4: resolution: {integrity: sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==} + headers-polyfill@4.0.3: + resolution: {integrity: sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==} + html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} @@ -3523,6 +3590,9 @@ packages: is-lower-case@2.0.2: resolution: {integrity: sha512-bVcMJy4X5Og6VZfdOZstSexlEy20Sr0k/p/b2IlQJlfdKAQuMpiv5w2Ccxb8sKdRUNAG1PnHVHjFSdRDVS6NlQ==} + is-node-process@1.2.0: + resolution: {integrity: sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==} + is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} @@ -4124,9 +4194,23 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + msw@2.12.10: + resolution: {integrity: sha512-G3VUymSE0/iegFnuipujpwyTM2GuZAKXNeerUSrG2+Eg391wW63xFs5ixWsK9MWzr1AGoSkYGmyAzNgbR3+urw==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + typescript: '>= 4.8.x' + peerDependenciesMeta: + typescript: + optional: true + mute-stream@0.0.8: resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} + mute-stream@2.0.0: + resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==} + engines: {node: ^18.17.0 || >=20.5.0} + mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} @@ -4287,6 +4371,9 @@ packages: resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} engines: {node: '>=0.10.0'} + outvariant@1.4.3: + resolution: {integrity: sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==} + ox@0.8.7: resolution: {integrity: sha512-W1f0FiMf9NZqtHPEDEAEkyzZDwbIKfmH2qmQx8NNiQ/9JhxrSblmtLJsSfTtQG5YKowLOnBlLVguCyxm/7ztxw==} peerDependencies: @@ -4401,6 +4488,9 @@ packages: resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} engines: {node: 20 || >=22} + path-to-regexp@6.3.0: + resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} + path-to-regexp@8.3.0: resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} @@ -4835,6 +4925,9 @@ packages: resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} engines: {node: '>= 4'} + rettime@0.10.1: + resolution: {integrity: sha512-uyDrIlUEH37cinabq0AX4QbgV4HbFZ/gqoiunWQ1UqBtRvTTytwhNYjE++pO/MjPTZL5KQCf2bEoJ/BJNVQ5Kw==} + reusify@1.1.0: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} @@ -5063,6 +5156,10 @@ packages: resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} engines: {node: '>= 0.8'} + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} + streamsearch@1.1.0: resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} engines: {node: '>=10.0.0'} @@ -5070,6 +5167,9 @@ packages: streamx@2.22.1: resolution: {integrity: sha512-znKXEBxfatz2GBNK02kRnCXjV+AA4kjZIUxeWSr3UGirZMJfTE9uiwKHobnbgxWyL/JWro8tTq+vOqAK1/qbSA==} + strict-event-emitter@0.5.1: + resolution: {integrity: sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==} + string-env-interpolation@1.0.1: resolution: {integrity: sha512-78lwMoCcn0nNu8LszbP1UA7g55OeE4v7rCeWnM5B453rnNr4aq+5it3FEYtZrSEiMvHZOZ9Jlqb0OD0M2VInqg==} @@ -5160,6 +5260,10 @@ packages: resolution: {integrity: sha512-c7AfkZ9udatCuAy9RSfiGPpeOKKUAUK5e1cXadLOGUjasdxqYqAK0jTNkM/FSEyJ3a5Ra27j/tw/PS0qLmaF/A==} engines: {node: '>=18'} + tagged-tag@1.0.0: + resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} + engines: {node: '>=20'} + tailwind-merge@3.4.1: resolution: {integrity: sha512-2OA0rFqWOkITEAOFWSBSApYkDeH9t2B3XSJuI4YztKBzK3mX0737A2qtxDZ7xkw9Zfh0bWl+r34sF3HXV+Ig7Q==} @@ -5247,6 +5351,13 @@ packages: title-case@3.0.3: resolution: {integrity: sha512-e1zGYRvbffpcHIrnuqT0Dh+gEJtDaxDSoG4JAIpq4oDFyooziLBIiYQv0GBT4FUAnUop5uZ1hiIAj7oAF6sOCA==} + tldts-core@7.0.23: + resolution: {integrity: sha512-0g9vrtDQLrNIiCj22HSe9d4mLVG3g5ph5DZ8zCKBr4OtrspmNB6ss7hVyzArAeE88ceZocIEGkyW1Ime7fxPtQ==} + + tldts@7.0.23: + resolution: {integrity: sha512-ASdhgQIBSay0R/eXggAkQ53G4nTJqTXqC2kbaBbdDwM7SkjyZyO0OaaN1/FH7U/yCeqOHDwFO5j8+Os/IS1dXw==} + hasBin: true + tmp@0.0.33: resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} engines: {node: '>=0.6.0'} @@ -5274,6 +5385,10 @@ packages: resolution: {integrity: sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==} hasBin: true + tough-cookie@6.0.0: + resolution: {integrity: sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==} + engines: {node: '>=16'} + tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} @@ -5419,6 +5534,10 @@ packages: resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} engines: {node: '>=16'} + type-fest@5.4.4: + resolution: {integrity: sha512-JnTrzGu+zPV3aXIUhnyWJj4z/wigMsdYajGLIYakqyOW1nPllzXEJee0QQbHj+CTIQtXGlAjuK0UY+2xTyjVAw==} + engines: {node: '>=20'} + type-is@2.0.1: resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} engines: {node: '>= 0.6'} @@ -5476,6 +5595,9 @@ packages: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} + until-async@3.0.2: + resolution: {integrity: sha512-IiSk4HlzAMqTUseHHe3VhIGyuFmN90zMTpD3Z3y8jeQbzLIq500MVM7Jq2vUAnTKAFPJrqwkzr6PoTcPhGcOiw==} + update-browserslist-db@1.2.3: resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} hasBin: true @@ -5636,6 +5758,10 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + yoctocolors-cjs@2.1.3: + resolution: {integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==} + engines: {node: '>=18'} + zip-stream@6.0.1: resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==} engines: {node: '>= 14'} @@ -6545,6 +6671,34 @@ snapshots: '@humanwhocodes/object-schema@2.0.3': {} + '@inquirer/ansi@1.0.2': {} + + '@inquirer/confirm@5.1.21(@types/node@20.17.46)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@20.17.46) + '@inquirer/type': 3.0.10(@types/node@20.17.46) + optionalDependencies: + '@types/node': 20.17.46 + + '@inquirer/core@10.3.2(@types/node@20.17.46)': + dependencies: + '@inquirer/ansi': 1.0.2 + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10(@types/node@20.17.46) + cli-width: 4.1.0 + mute-stream: 2.0.0 + signal-exit: 4.1.0 + wrap-ansi: 6.2.0 + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 20.17.46 + + '@inquirer/figures@1.0.15': {} + + '@inquirer/type@3.0.10(@types/node@20.17.46)': + optionalDependencies: + '@types/node': 20.17.46 + '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 @@ -6608,6 +6762,41 @@ snapshots: - supports-color - ts-node + '@jest/core@29.7.0(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@20.17.46)(typescript@5.8.2))': + dependencies: + '@jest/console': 29.7.0 + '@jest/reporters': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.17.46 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + ci-info: 3.9.0 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-changed-files: 29.7.0 + jest-config: 29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@20.17.46)(typescript@5.8.2)) + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-resolve-dependencies: 29.7.0 + jest-runner: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + jest-watcher: 29.7.0 + micromatch: 4.0.8 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + - ts-node + '@jest/core@29.7.0(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@20.17.46)(typescript@5.8.3))': dependencies: '@jest/console': 29.7.0 @@ -6643,7 +6832,7 @@ snapshots: - supports-color - ts-node - '@jest/core@29.7.0(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.2))': + '@jest/core@29.7.0(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.3))': dependencies: '@jest/console': 29.7.0 '@jest/reporters': 29.7.0 @@ -6657,7 +6846,7 @@ snapshots: exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.2)) + jest-config: 29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.3)) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -6826,6 +7015,15 @@ snapshots: '@lukeed/ms@2.0.2': {} + '@mswjs/interceptors@0.41.3': + dependencies: + '@open-draft/deferred-promise': 2.2.0 + '@open-draft/logger': 0.3.0 + '@open-draft/until': 2.1.0 + is-node-process: 1.2.0 + outvariant: 1.4.3 + strict-event-emitter: 0.5.1 + '@next/env@14.2.35': {} '@next/swc-darwin-arm64@14.2.33': @@ -6887,6 +7085,15 @@ snapshots: rimraf: 3.0.2 optional: true + '@open-draft/deferred-promise@2.2.0': {} + + '@open-draft/logger@0.3.0': + dependencies: + is-node-process: 1.2.0 + outvariant: 1.4.3 + + '@open-draft/until@2.1.0': {} + '@pkgjs/parseargs@0.11.0': optional: true @@ -7435,6 +7642,8 @@ snapshots: '@types/stack-utils@2.0.3': {} + '@types/statuses@2.0.6': {} + '@types/trusted-types@2.0.7': optional: true @@ -8107,6 +8316,8 @@ snapshots: cli-width@3.0.0: {} + cli-width@4.1.0: {} + client-only@0.0.1: {} cliui@8.0.1: @@ -8223,6 +8434,21 @@ snapshots: - supports-color - ts-node + create-jest@29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@20.17.46)(typescript@5.8.2)): + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-config: 29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@20.17.46)(typescript@5.8.2)) + jest-util: 29.7.0 + prompts: 2.4.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + create-jest@29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@20.17.46)(typescript@5.8.3)): dependencies: '@jest/types': 29.6.3 @@ -8238,13 +8464,13 @@ snapshots: - supports-color - ts-node - create-jest@29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.2)): + create-jest@29.7.0(@types/node@24.3.1)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.3)): dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.2)) + jest-config: 29.7.0(@types/node@24.3.1)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.3)) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -9076,6 +9302,8 @@ snapshots: graphql@16.11.0: {} + graphql@16.13.0: {} + has-flag@3.0.0: {} has-flag@4.0.0: {} @@ -9098,6 +9326,8 @@ snapshots: capital-case: 1.0.4 tslib: 2.8.1 + headers-polyfill@4.0.3: {} + html-escaper@2.0.2: {} html2canvas@1.4.1: @@ -9276,6 +9506,8 @@ snapshots: dependencies: tslib: 2.8.1 + is-node-process@1.2.0: {} + is-number@7.0.0: {} is-path-inside@3.0.3: {} @@ -9425,6 +9657,25 @@ snapshots: - supports-color - ts-node + jest-cli@29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@20.17.46)(typescript@5.8.2)): + dependencies: + '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@20.17.46)(typescript@5.8.2)) + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + chalk: 4.1.2 + create-jest: 29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@20.17.46)(typescript@5.8.2)) + exit: 0.1.2 + import-local: 3.2.0 + jest-config: 29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@20.17.46)(typescript@5.8.2)) + jest-util: 29.7.0 + jest-validate: 29.7.0 + yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + jest-cli@29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@20.17.46)(typescript@5.8.3)): dependencies: '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@20.17.46)(typescript@5.8.3)) @@ -9444,16 +9695,16 @@ snapshots: - supports-color - ts-node - jest-cli@29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.2)): + jest-cli@29.7.0(@types/node@24.3.1)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.3)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.2)) + '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.3)) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.2)) + create-jest: 29.7.0(@types/node@24.3.1)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.3)) exit: 0.1.2 import-local: 3.2.0 - jest-config: 29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.2)) + jest-config: 29.7.0(@types/node@24.3.1)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.3)) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -9525,6 +9776,37 @@ snapshots: - babel-plugin-macros - supports-color + jest-config@29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@20.17.46)(typescript@5.8.2)): + dependencies: + '@babel/core': 7.27.1 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.27.1) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0 + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.8 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 20.17.46 + ts-node: 10.9.2(@swc/core@1.11.24)(@types/node@20.17.46)(typescript@5.8.2) + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + jest-config@29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@20.17.46)(typescript@5.8.3)): dependencies: '@babel/core': 7.27.1 @@ -9556,7 +9838,7 @@ snapshots: - babel-plugin-macros - supports-color - jest-config@29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.2)): + jest-config@29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.3)): dependencies: '@babel/core': 7.27.1 '@jest/test-sequencer': 29.7.0 @@ -9582,7 +9864,38 @@ snapshots: strip-json-comments: 3.1.1 optionalDependencies: '@types/node': 20.17.46 - ts-node: 10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.2) + ts-node: 10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.3) + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + jest-config@29.7.0(@types/node@24.3.1)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.3)): + dependencies: + '@babel/core': 7.27.1 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.27.1) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0 + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.8 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 24.3.1 + ts-node: 10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.3) transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -9814,6 +10127,18 @@ snapshots: - supports-color - ts-node + jest@29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@20.17.46)(typescript@5.8.2)): + dependencies: + '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@20.17.46)(typescript@5.8.2)) + '@jest/types': 29.6.3 + import-local: 3.2.0 + jest-cli: 29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@20.17.46)(typescript@5.8.2)) + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + jest@29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@20.17.46)(typescript@5.8.3)): dependencies: '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@20.17.46)(typescript@5.8.3)) @@ -9826,12 +10151,12 @@ snapshots: - supports-color - ts-node - jest@29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.2)): + jest@29.7.0(@types/node@24.3.1)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.3)): dependencies: - '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.2)) + '@jest/core': 29.7.0(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.3)) '@jest/types': 29.6.3 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.2)) + jest-cli: 29.7.0(@types/node@24.3.1)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.3)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -10224,8 +10549,35 @@ snapshots: ms@2.1.3: {} + msw@2.12.10(@types/node@20.17.46)(typescript@5.8.3): + dependencies: + '@inquirer/confirm': 5.1.21(@types/node@20.17.46) + '@mswjs/interceptors': 0.41.3 + '@open-draft/deferred-promise': 2.2.0 + '@types/statuses': 2.0.6 + cookie: 1.0.2 + graphql: 16.13.0 + headers-polyfill: 4.0.3 + is-node-process: 1.2.0 + outvariant: 1.4.3 + path-to-regexp: 6.3.0 + picocolors: 1.1.1 + rettime: 0.10.1 + statuses: 2.0.2 + strict-event-emitter: 0.5.1 + tough-cookie: 6.0.0 + type-fest: 5.4.4 + until-async: 3.0.2 + yargs: 17.7.2 + optionalDependencies: + typescript: 5.8.3 + transitivePeerDependencies: + - '@types/node' + mute-stream@0.0.8: {} + mute-stream@2.0.0: {} + mz@2.7.0: dependencies: any-promise: 1.3.0 @@ -10404,6 +10756,8 @@ snapshots: os-tmpdir@1.0.2: {} + outvariant@1.4.3: {} + ox@0.8.7(typescript@4.9.5)(zod@3.24.3): dependencies: '@adraffy/ens-normalize': 1.11.0 @@ -10551,6 +10905,8 @@ snapshots: lru-cache: 11.1.0 minipass: 7.1.2 + path-to-regexp@6.3.0: {} + path-to-regexp@8.3.0: {} path-type@4.0.0: {} @@ -10998,6 +11354,8 @@ snapshots: retry@0.13.1: {} + rettime@0.10.1: {} + reusify@1.1.0: {} rfdc@1.4.1: {} @@ -11257,6 +11615,8 @@ snapshots: statuses@2.0.1: {} + statuses@2.0.2: {} + streamsearch@1.1.0: {} streamx@2.22.1: @@ -11266,6 +11626,8 @@ snapshots: optionalDependencies: bare-events: 2.5.4 + strict-event-emitter@0.5.1: {} + string-env-interpolation@1.0.1: {} string-length@4.0.2: @@ -11351,6 +11713,8 @@ snapshots: timeout-signal: 2.0.0 whatwg-mimetype: 4.0.0 + tagged-tag@1.0.0: {} + tailwind-merge@3.4.1: {} tailwindcss-animate@1.0.7(tailwindcss@3.4.19(tsx@4.19.4)(yaml@2.7.1)): @@ -11507,6 +11871,12 @@ snapshots: dependencies: tslib: 2.8.1 + tldts-core@7.0.23: {} + + tldts@7.0.23: + dependencies: + tldts-core: 7.0.23 + tmp@0.0.33: dependencies: os-tmpdir: 1.0.2 @@ -11525,6 +11895,10 @@ snapshots: touch@3.1.1: {} + tough-cookie@6.0.0: + dependencies: + tldts: 7.0.23 + tr46@0.0.3: {} ts-interface-checker@0.1.13: {} @@ -11549,19 +11923,19 @@ snapshots: '@jest/types': 29.6.3 babel-jest: 29.7.0(@babel/core@7.27.1) - ts-jest@29.3.2(@babel/core@7.27.1)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.1))(jest@29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@20.17.46)(typescript@5.8.3)))(typescript@5.8.3): + ts-jest@29.3.2(@babel/core@7.27.1)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.1))(jest@29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@20.17.46)(typescript@5.8.2)))(typescript@5.8.2): dependencies: bs-logger: 0.2.6 ejs: 3.1.10 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@20.17.46)(typescript@5.8.3)) + jest: 29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@20.17.46)(typescript@5.8.2)) jest-util: 29.7.0 json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 semver: 7.7.1 type-fest: 4.41.0 - typescript: 5.8.3 + typescript: 5.8.2 yargs-parser: 21.1.1 optionalDependencies: '@babel/core': 7.27.1 @@ -11569,19 +11943,19 @@ snapshots: '@jest/types': 29.6.3 babel-jest: 29.7.0(@babel/core@7.27.1) - ts-jest@29.3.2(@babel/core@7.27.1)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.1))(jest@29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.2)))(typescript@5.8.2): + ts-jest@29.3.2(@babel/core@7.27.1)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.1))(jest@29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@20.17.46)(typescript@5.8.3)))(typescript@5.8.3): dependencies: bs-logger: 0.2.6 ejs: 3.1.10 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.2)) + jest: 29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@20.17.46)(typescript@5.8.3)) jest-util: 29.7.0 json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 semver: 7.7.1 type-fest: 4.41.0 - typescript: 5.8.2 + typescript: 5.8.3 yargs-parser: 21.1.1 optionalDependencies: '@babel/core': 7.27.1 @@ -11589,12 +11963,12 @@ snapshots: '@jest/types': 29.6.3 babel-jest: 29.7.0(@babel/core@7.27.1) - ts-jest@29.3.2(@babel/core@7.27.1)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.1))(jest@29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.2)))(typescript@5.8.3): + ts-jest@29.3.2(@babel/core@7.27.1)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.1))(jest@29.7.0(@types/node@24.3.1)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.3)))(typescript@5.8.3): dependencies: bs-logger: 0.2.6 ejs: 3.1.10 fast-json-stable-stringify: 2.1.0 - jest: 29.7.0(@types/node@20.17.46)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.2)) + jest: 29.7.0(@types/node@24.3.1)(ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.3)) jest-util: 29.7.0 json5: 2.2.3 lodash.memoize: 4.1.2 @@ -11631,6 +12005,27 @@ snapshots: optionalDependencies: '@swc/core': 1.11.24 + ts-node@10.9.2(@swc/core@1.11.24)(@types/node@20.17.46)(typescript@5.8.2): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 20.17.46 + acorn: 8.15.0 + acorn-walk: 8.3.4 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.8.2 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + optionalDependencies: + '@swc/core': 1.11.24 + optional: true + ts-node@10.9.2(@swc/core@1.11.24)(@types/node@20.17.46)(typescript@5.8.3): dependencies: '@cspotcode/source-map-support': 0.8.1 @@ -11671,6 +12066,26 @@ snapshots: optionalDependencies: '@swc/core': 1.11.24 + ts-node@10.9.2(@swc/core@1.11.24)(@types/node@24.3.1)(typescript@5.8.3): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 24.3.1 + acorn: 8.15.0 + acorn-walk: 8.3.4 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.8.3 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + optionalDependencies: + '@swc/core': 1.11.24 + tslib@1.14.1: {} tslib@2.6.3: {} @@ -11736,6 +12151,10 @@ snapshots: type-fest@4.41.0: {} + type-fest@5.4.4: + dependencies: + tagged-tag: 1.0.0 + type-is@2.0.1: dependencies: content-type: 1.0.5 @@ -11780,6 +12199,8 @@ snapshots: unpipe@1.0.0: {} + until-async@3.0.2: {} + update-browserslist-db@1.2.3(browserslist@4.28.1): dependencies: browserslist: 4.28.1 @@ -11977,6 +12398,8 @@ snapshots: yocto-queue@0.1.0: {} + yoctocolors-cjs@2.1.3: {} + zip-stream@6.0.1: dependencies: archiver-utils: 5.0.2 From 850e889797a33b6e410f28c285442416b6217022 Mon Sep 17 00:00:00 2001 From: Leonardo Vieira Date: Thu, 26 Feb 2026 12:58:08 -0300 Subject: [PATCH 12/42] feat: unit tests --- ...-offchain-proposal-trigger.service.test.ts | 224 ++++++++++++++++++ .../new-offchain-proposal-trigger.test.ts | 175 ++++++++++++++ .../tests/offchain-proposal.test.ts | 128 ++++++++++ 3 files changed, 527 insertions(+) create mode 100644 apps/dispatcher/src/services/triggers/new-offchain-proposal-trigger.service.test.ts create mode 100644 apps/logic-system/tests/new-offchain-proposal-trigger.test.ts create mode 100644 packages/anticapture-client/tests/offchain-proposal.test.ts diff --git a/apps/dispatcher/src/services/triggers/new-offchain-proposal-trigger.service.test.ts b/apps/dispatcher/src/services/triggers/new-offchain-proposal-trigger.service.test.ts new file mode 100644 index 00000000..5a31193e --- /dev/null +++ b/apps/dispatcher/src/services/triggers/new-offchain-proposal-trigger.service.test.ts @@ -0,0 +1,224 @@ +import { describe, it, expect, beforeEach } from '@jest/globals'; +import { NewOffchainProposalTriggerHandler } from './new-offchain-proposal-trigger.service'; +import { ISubscriptionClient, User, Notification } from '../../interfaces/subscription-client.interface'; +import { NotificationClientFactory } from '../notification/notification-factory.service'; +import { INotificationClient, NotificationPayload } from '../../interfaces/notification-client.interface'; +import { DispatcherMessage } from '../../interfaces/dispatcher-message.interface'; + +class SimpleSubscriptionClient implements ISubscriptionClient { + subscribers: Map = new Map(); + sentNotifications: Notification[] = []; + + async getDaoSubscribers(daoId: string): Promise { + return this.subscribers.get(daoId) || []; + } + + async shouldSend(subscribers: User[], eventId: string, daoId: string): Promise { + return subscribers.map(s => ({ user_id: s.id, event_id: eventId, dao_id: daoId })); + } + + async shouldSendBatch(): Promise { return []; } + + async markAsSent(notifications: Notification[]): Promise { + this.sentNotifications.push(...notifications); + } + + async getWalletOwners(): Promise { return []; } + async getWalletOwnersBatch(): Promise> { return {}; } + async getFollowedAddresses(): Promise { return []; } +} + +class SimpleNotificationClient implements INotificationClient { + sentPayloads: NotificationPayload[] = []; + + async sendNotification(payload: NotificationPayload): Promise { + this.sentPayloads.push(payload); + } +} + +function createHandler( + subscriptionClient: SimpleSubscriptionClient, + notificationClient: SimpleNotificationClient, +) { + const factory = new NotificationClientFactory(); + factory.addClient('telegram', notificationClient); + factory.addClient('slack', notificationClient); + return new NewOffchainProposalTriggerHandler(subscriptionClient, factory); +} + +describe('NewOffchainProposalTriggerHandler', () => { + let subscriptionClient: SimpleSubscriptionClient; + let notificationClient: SimpleNotificationClient; + let handler: NewOffchainProposalTriggerHandler; + + const testUser: User = { + id: 'user-1', + channel: 'telegram', + channel_user_id: '123', + created_at: new Date(), + }; + + beforeEach(() => { + subscriptionClient = new SimpleSubscriptionClient(); + notificationClient = new SimpleNotificationClient(); + handler = createHandler(subscriptionClient, notificationClient); + }); + + describe('handleMessage', () => { + it('should produce correct message text for single proposal', async () => { + subscriptionClient.subscribers.set('test-dao', [testUser]); + + const message: DispatcherMessage = { + triggerId: 'new-offchain-proposal', + events: [{ + daoId: 'test-dao', id: 'snap-1', title: 'Grant Program', + created: 1700000000, discussion: '', state: 'active', + }], + }; + + await handler.handleMessage(message); + + expect(notificationClient.sentPayloads).toHaveLength(1); + expect(notificationClient.sentPayloads[0].message).toContain("Grant Program"); + }); + + it('should use "Untitled Proposal" when title is empty', async () => { + subscriptionClient.subscribers.set('test-dao', [testUser]); + + const message: DispatcherMessage = { + triggerId: 'new-offchain-proposal', + events: [{ + daoId: 'test-dao', id: 'snap-1', title: '', + created: 1700000000, discussion: '', state: 'active', + }], + }; + + await handler.handleMessage(message); + + expect(notificationClient.sentPayloads[0].message).toContain('Untitled Proposal'); + }); + + it('should set correct eventId as offchain-{proposalId}', async () => { + subscriptionClient.subscribers.set('test-dao', [testUser]); + + const message: DispatcherMessage = { + triggerId: 'new-offchain-proposal', + events: [{ + daoId: 'test-dao', id: 'snap-123', title: 'Test', + created: 1700000000, discussion: '', state: 'active', + }], + }; + + await handler.handleMessage(message); + + expect(subscriptionClient.sentNotifications[0].event_id).toBe('offchain-snap-123'); + }); + + it('should always include CTA button "Review DAO data before voting"', async () => { + subscriptionClient.subscribers.set('test-dao', [testUser]); + + const message: DispatcherMessage = { + triggerId: 'new-offchain-proposal', + events: [{ + daoId: 'test-dao', id: 'snap-1', title: 'Test', + created: 1700000000, discussion: '', state: 'active', + }], + }; + + await handler.handleMessage(message); + + const buttons = notificationClient.sentPayloads[0].metadata?.buttons; + expect(buttons).toBeDefined(); + expect(buttons[0].text).toBe('Review DAO data before voting'); + }); + + it('should include "View Discussion" button when discussion URL is provided', async () => { + subscriptionClient.subscribers.set('test-dao', [testUser]); + + const message: DispatcherMessage = { + triggerId: 'new-offchain-proposal', + events: [{ + daoId: 'test-dao', id: 'snap-1', title: 'Test', + created: 1700000000, discussion: 'https://forum.example.com/123', state: 'active', + }], + }; + + await handler.handleMessage(message); + + const buttons = notificationClient.sentPayloads[0].metadata?.buttons; + expect(buttons).toHaveLength(2); + expect(buttons[1].text).toBe('View Discussion'); + expect(buttons[1].url).toBe('https://forum.example.com/123'); + }); + + it('should omit "View Discussion" button when discussion is empty', async () => { + subscriptionClient.subscribers.set('test-dao', [testUser]); + + const message: DispatcherMessage = { + triggerId: 'new-offchain-proposal', + events: [{ + daoId: 'test-dao', id: 'snap-1', title: 'Test', + created: 1700000000, discussion: '', state: 'active', + }], + }; + + await handler.handleMessage(message); + + const buttons = notificationClient.sentPayloads[0].metadata?.buttons; + expect(buttons).toHaveLength(1); + }); + + it('should process multiple proposals and notify all subscribers', async () => { + const user2: User = { id: 'user-2', channel: 'telegram', channel_user_id: '456', created_at: new Date() }; + subscriptionClient.subscribers.set('dao-a', [testUser, user2]); + subscriptionClient.subscribers.set('dao-b', [testUser]); + + const message: DispatcherMessage = { + triggerId: 'new-offchain-proposal', + events: [ + { daoId: 'dao-a', id: 'snap-1', title: 'Proposal A', created: 1700000000, discussion: '', state: 'active' }, + { daoId: 'dao-b', id: 'snap-2', title: 'Proposal B', created: 1700000100, discussion: '', state: 'active' }, + ], + }; + + await handler.handleMessage(message); + + expect(notificationClient.sentPayloads).toHaveLength(3); + }); + + it('should not perform lookups when events array is empty', async () => { + subscriptionClient.subscribers.set('test-dao', [testUser]); + + const message: DispatcherMessage = { + triggerId: 'new-offchain-proposal', + events: [], + }; + + await handler.handleMessage(message); + + expect(notificationClient.sentPayloads).toHaveLength(0); + expect(subscriptionClient.sentNotifications).toHaveLength(0); + }); + + it('should mark notifications as sent after successful delivery', async () => { + subscriptionClient.subscribers.set('test-dao', [testUser]); + + const message: DispatcherMessage = { + triggerId: 'new-offchain-proposal', + events: [{ + daoId: 'test-dao', id: 'snap-1', title: 'Test', + created: 1700000000, discussion: '', state: 'active', + }], + }; + + await handler.handleMessage(message); + + expect(subscriptionClient.sentNotifications).toHaveLength(1); + expect(subscriptionClient.sentNotifications[0]).toEqual({ + user_id: 'user-1', + event_id: 'offchain-snap-1', + dao_id: 'test-dao', + }); + }); + }); +}); diff --git a/apps/logic-system/tests/new-offchain-proposal-trigger.test.ts b/apps/logic-system/tests/new-offchain-proposal-trigger.test.ts new file mode 100644 index 00000000..2cb79fee --- /dev/null +++ b/apps/logic-system/tests/new-offchain-proposal-trigger.test.ts @@ -0,0 +1,175 @@ +import { describe, it, expect, jest, beforeEach, afterEach } from '@jest/globals'; +import { NewOffchainProposalTrigger } from '../src/triggers/new-offchain-proposal-trigger'; +import { + OffchainProposal, + OffchainProposalDataSource, + ListOffchainProposalsOptions +} from '../src/interfaces/offchain-proposal.interface'; +import { DispatcherService, DispatcherMessage } from '../src/interfaces/dispatcher.interface'; + +function createOffchainProposal(overrides?: Partial): OffchainProposal { + return { + id: 'snap-proposal-1', + title: 'Test Snapshot Proposal', + discussion: 'https://forum.example.com/proposal-1', + state: 'active', + created: 1700000000, + daoId: 'test-dao', + ...overrides, + }; +} + +class SimpleOffchainProposalDataSource implements OffchainProposalDataSource { + proposals: OffchainProposal[] = []; + lastOptions?: ListOffchainProposalsOptions; + + async listAll(options?: ListOffchainProposalsOptions): Promise { + this.lastOptions = options; + return this.proposals; + } +} + +class SimpleDispatcherService implements DispatcherService { + sentMessages: DispatcherMessage[] = []; + shouldFail = false; + + async sendMessage(message: DispatcherMessage): Promise { + if (this.shouldFail) throw new Error('Dispatcher failed'); + this.sentMessages.push(message); + } +} + +describe('NewOffchainProposalTrigger', () => { + let dataSource: SimpleOffchainProposalDataSource; + let dispatcher: SimpleDispatcherService; + let trigger: NewOffchainProposalTrigger; + + beforeEach(() => { + dataSource = new SimpleOffchainProposalDataSource(); + dispatcher = new SimpleDispatcherService(); + trigger = new NewOffchainProposalTrigger(dispatcher, dataSource, 60000); + }); + + describe('process()', () => { + it('should not send message when array is empty', async () => { + await trigger.process([]); + + expect(dispatcher.sentMessages).toHaveLength(0); + }); + + it('should send single proposal with correct triggerId and events', async () => { + const proposal = createOffchainProposal(); + + await trigger.process([proposal]); + + expect(dispatcher.sentMessages).toHaveLength(1); + expect(dispatcher.sentMessages[0]).toEqual({ + triggerId: 'new-offchain-proposal', + events: [proposal], + }); + }); + + it('should update timestampCursor to data[0].created + 1', async () => { + const proposal = createOffchainProposal({ created: 1700000000 }); + + await trigger.process([proposal]); + + expect(trigger['timestampCursor']).toBe(1700000001); + }); + + it('should include all proposals in events array', async () => { + const proposals = [ + createOffchainProposal({ id: 'snap-1', created: 1700000200 }), + createOffchainProposal({ id: 'snap-2', created: 1700000100 }), + ]; + + await trigger.process(proposals); + + expect(dispatcher.sentMessages).toHaveLength(1); + expect(dispatcher.sentMessages[0].events).toHaveLength(2); + expect(trigger['timestampCursor']).toBe(1700000201); + }); + + it('should propagate dispatcher errors', async () => { + dispatcher.shouldFail = true; + const proposal = createOffchainProposal(); + + await expect(trigger.process([proposal])).rejects.toThrow('Dispatcher failed'); + }); + }); + + describe('start/stop', () => { + beforeEach(() => { + jest.useFakeTimers(); + dataSource.proposals = [createOffchainProposal()]; + }); + + afterEach(() => { + jest.useRealTimers(); + }); + + it('should start interval, fetch data, and process it', () => { + trigger.start({ status: ['active', 'pending'] }); + jest.advanceTimersByTime(60000); + + expect(dataSource.lastOptions).toBeDefined(); + expect(dataSource.lastOptions!.status).toEqual(['active', 'pending']); + }); + + it('should stop and clear timer', async () => { + trigger.start({ status: ['active', 'pending'] }); + await trigger.stop(); + + expect(trigger['timer']).toBeNull(); + + jest.advanceTimersByTime(120000); + expect(dataSource.lastOptions).toBeUndefined(); + }); + }); + + describe('initialTimestamp & reset', () => { + it('should use custom initialTimestamp', () => { + const customTrigger = new NewOffchainProposalTrigger( + dispatcher, dataSource, 60000, '1234567890' + ); + + expect(customTrigger['timestampCursor']).toBe(1234567890); + }); + + it('should reset to specific timestamp', () => { + trigger.reset('9999999999'); + + expect(trigger['timestampCursor']).toBe(9999999999); + }); + + it('should reset to 24h ago when no argument', () => { + jest.useFakeTimers(); + jest.setSystemTime(new Date('2025-01-15T12:00:00Z')); + + trigger.reset(); + + const expected = Math.floor((Date.now() - 24 * 60 * 60 * 1000) / 1000); + expect(trigger['timestampCursor']).toBe(expected); + + jest.useRealTimers(); + }); + }); + + describe('fetchData', () => { + it('should pass fromDate as current cursor to data source', async () => { + const customTrigger = new NewOffchainProposalTrigger( + dispatcher, dataSource, 60000, '1700000000' + ); + + await customTrigger['fetchData']({ status: ['active'] }); + + expect(dataSource.lastOptions?.fromDate).toBe(1700000000); + }); + + it('should pass status from options', async () => { + await trigger['fetchData']({ status: ['active', 'pending'] }); + + expect(dataSource.lastOptions?.status).toEqual(['active', 'pending']); + }); + }); +}); diff --git a/packages/anticapture-client/tests/offchain-proposal.test.ts b/packages/anticapture-client/tests/offchain-proposal.test.ts new file mode 100644 index 00000000..b4be4489 --- /dev/null +++ b/packages/anticapture-client/tests/offchain-proposal.test.ts @@ -0,0 +1,128 @@ +import { describe, it, expect, afterEach, beforeAll, afterAll } from '@jest/globals'; +import { AnticaptureClient } from '../src/anticapture-client'; +import { setupServer } from 'msw/node'; +import { http, HttpResponse } from 'msw'; +import axios from 'axios'; + +const TEST_API_URL = 'http://test-api/graphql'; + +interface OffchainProposalStub { + id: string; + title: string; + discussion: string; + state: string; + created: number; +} + +interface GraphQLScenario { + daos: Array<{ id: string; votingDelay?: string; chainId?: number }>; + proposals?: Record; + errors?: Record; +} + +function handleGraphQL(scenario: GraphQLScenario) { + return http.post(TEST_API_URL, async ({ request }) => { + const body = await request.json() as { query: string }; + + if (body.query.includes('daos')) { + return HttpResponse.json({ + data: { + daos: { + items: scenario.daos.map(d => ({ + id: d.id, + votingDelay: d.votingDelay ?? '0', + chainId: d.chainId ?? 1, + })), + }, + }, + }); + } + + const daoId = request.headers.get('anticapture-dao-id'); + + if (daoId && scenario.errors?.[daoId]) { + return HttpResponse.json({ + data: null, + errors: [{ message: scenario.errors[daoId] }], + }); + } + + const items = (daoId && scenario.proposals?.[daoId]) || []; + return HttpResponse.json({ + data: { + offchainProposals: { items, totalCount: items.length }, + }, + }); + }); +} + +describe('listOffchainProposals', () => { + const server = setupServer(); + + beforeAll(() => server.listen({ onUnhandledRequest: 'bypass' })); + afterEach(() => server.resetHandlers()); + afterAll(() => server.close()); + + function createRealClient() { + const httpClient = axios.create({ baseURL: TEST_API_URL }); + return new AnticaptureClient(httpClient, 0, 5000); + } + + it('returns empty array when no DAOs exist', async () => { + server.use(handleGraphQL({ daos: [] })); + + const client = createRealClient(); + const result = await client.listOffchainProposals(); + + expect(result).toEqual([]); + }); + + it('returns proposals with daoId attached', async () => { + server.use(handleGraphQL({ + daos: [{ id: 'ENS' }], + proposals: { + ENS: [{ id: 'snap-1', title: 'Test Proposal', discussion: 'https://forum.example.com', state: 'active', created: 1700000000 }], + }, + })); + + const client = createRealClient(); + const result = await client.listOffchainProposals(); + + expect(result).toHaveLength(1); + expect(result[0]).toMatchObject({ id: 'snap-1', daoId: 'ENS' }); + }); + + it('aggregates proposals from multiple DAOs', async () => { + server.use(handleGraphQL({ + daos: [{ id: 'DAO_A' }, { id: 'DAO_B' }], + proposals: { + DAO_A: [{ id: 'snap-a', title: 'From A', discussion: '', state: 'active', created: 1700000100 }], + DAO_B: [{ id: 'snap-b', title: 'From B', discussion: '', state: 'pending', created: 1700000200 }], + }, + })); + + const client = createRealClient(); + const result = await client.listOffchainProposals(); + + expect(result).toHaveLength(2); + expect(result.map(p => p.id)).toEqual(['snap-b', 'snap-a']); + }); + + it('skips DAO on API error and continues with others', async () => { + server.use(handleGraphQL({ + daos: [{ id: 'OK_DAO' }, { id: 'BAD_DAO' }], + proposals: { + OK_DAO: [{ id: 'snap-ok', title: 'OK', discussion: '', state: 'active', created: 1700000000 }], + }, + errors: { + BAD_DAO: 'API exploded', + }, + })); + + const client = createRealClient(); + const result = await client.listOffchainProposals(); + + expect(result).toHaveLength(1); + expect(result[0].id).toBe('snap-ok'); + }); +}); \ No newline at end of file From 2bd2b972e3fe394632c01a0cf1d49ef6287e12cf Mon Sep 17 00:00:00 2001 From: Leonardo Vieira Date: Thu, 26 Feb 2026 13:18:02 -0300 Subject: [PATCH 13/42] feat: factory to offchain proposals --- .../factories/offchain-proposal-factory.ts | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 apps/integrated-tests/src/fixtures/factories/offchain-proposal-factory.ts diff --git a/apps/integrated-tests/src/fixtures/factories/offchain-proposal-factory.ts b/apps/integrated-tests/src/fixtures/factories/offchain-proposal-factory.ts new file mode 100644 index 00000000..566fc370 --- /dev/null +++ b/apps/integrated-tests/src/fixtures/factories/offchain-proposal-factory.ts @@ -0,0 +1,63 @@ +/** + * @notice Data structure for offchain (Snapshot) proposals in integration tests + * @dev Matches the shape returned by AnticaptureClient.listOffchainProposals + */ +export interface OffchainProposalData { + id: string; + daoId: string; + title: string; + discussion: string; + state: string; + created: number; +} + +/** + * @notice Factory class for creating test offchain proposal data + * @dev Provides methods to generate Snapshot-style proposal objects for integration testing + */ +export class OffchainProposalFactory { + /** + * @notice Creates a single offchain proposal with default or custom data + * @param daoId The DAO ID this proposal belongs to + * @param proposalId Unique identifier for the proposal + * @param overrides Optional partial data to override defaults + * @return Complete OffchainProposalData object ready for testing + */ + static createProposal( + daoId: string, + proposalId: string, + overrides?: Partial, + ): OffchainProposalData { + const futureTimestamp = Math.floor(Date.now() / 1000) + 5; + + return { + id: proposalId, + daoId, + title: `Test Snapshot Proposal ${proposalId}`, + discussion: '', + state: 'active', + created: futureTimestamp, + ...overrides, + }; + } + + /** + * @notice Creates multiple offchain proposals for the same DAO + * @param daoId The DAO ID all proposals belong to + * @param count Number of proposals to create + * @param baseId Base string for proposal IDs (will append -1, -2, etc.) + * @return Array of OffchainProposalData objects with sequential IDs + */ + static createMultipleProposals( + daoId: string, + count: number, + baseId: string = 'snap-proposal', + ): OffchainProposalData[] { + const baseTime = Math.floor(Date.now() / 1000) + 100; + return Array.from({ length: count }, (_, index) => + this.createProposal(daoId, `${baseId}-${index + 1}`, { + created: baseTime + index * 10, + }), + ); + } +} From e37ffe88a884c3727d92b6e595c0f53269b8cf72 Mon Sep 17 00:00:00 2001 From: Leonardo Vieira Date: Thu, 26 Feb 2026 13:18:45 -0300 Subject: [PATCH 14/42] feat: offchain proposal event support on createMockImplementation --- .../src/mocks/graphql-mock-setup.ts | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/apps/integrated-tests/src/mocks/graphql-mock-setup.ts b/apps/integrated-tests/src/mocks/graphql-mock-setup.ts index f7e45b3b..3dac31fd 100644 --- a/apps/integrated-tests/src/mocks/graphql-mock-setup.ts +++ b/apps/integrated-tests/src/mocks/graphql-mock-setup.ts @@ -1,4 +1,4 @@ -import { ProposalData } from '../fixtures'; +import { ProposalData, OffchainProposalData } from '../fixtures'; import { ProcessedVotingPowerHistory } from '@notification-system/anticapture-client'; import { getAddress, isAddressEqual } from 'viem'; @@ -39,7 +39,7 @@ export class GraphQLMockSetup { /** * @notice Generic mock implementation that handles all query types */ - private static createMockImplementation(proposals: ProposalData[] = [], votingPowerData: ProcessedVotingPowerHistory[] = [], daoChainMapping: Record = {}, votesData: any[] = []) { + private static createMockImplementation(proposals: ProposalData[] = [], votingPowerData: ProcessedVotingPowerHistory[] = [], daoChainMapping: Record = {}, votesData: any[] = [], offchainProposalsData: OffchainProposalData[] = []) { return (url: string, data: any, config: any) => { // Handle proposals if (data.query?.includes('ListProposals')) { @@ -69,6 +69,20 @@ export class GraphQLMockSetup { }); } + // Handle offchain proposals + if (data.query?.includes('ListOffchainProposals')) { + let filtered = offchainProposalsData; + if (data.variables?.fromDate) { + filtered = filtered.filter(p => p.created >= data.variables.fromDate); + } + if (config?.headers?.['anticapture-dao-id']) { + filtered = filtered.filter(p => p.daoId === config.headers['anticapture-dao-id']); + } + return Promise.resolve({ + data: { data: { offchainProposals: { items: filtered.map(p => ({ id: p.id, title: p.title, discussion: p.discussion, state: p.state, created: p.created })), totalCount: filtered.length } } } + }); + } + // Handle single proposal if (data.query?.includes('GetProposalById')) { const proposalId = data.variables?.id; @@ -170,7 +184,8 @@ export class GraphQLMockSetup { const uniqueDaoIds = [...new Set([ ...proposals.map(p => p.daoId).filter(Boolean), ...votingPowerData.map(vp => vp.daoId).filter(Boolean), - ...votesData.map((v: any) => v.daoId).filter(Boolean) + ...votesData.map((v: any) => v.daoId).filter(Boolean), + ...offchainProposalsData.map(p => p.daoId).filter(Boolean) ])]; return Promise.resolve({ data: { data: { daos: { items: uniqueDaoIds.map(id => ({ @@ -201,15 +216,17 @@ export class GraphQLMockSetup { * @param votingPowerData Array of voting power history data * @param daoChainMapping Optional mapping of DAO IDs to chain IDs * @param votesData Array of vote data + * @param offchainProposalsData Array of offchain (Snapshot) proposal data */ static setupMock( mockHttpClient: any, proposals: ProposalData[] = [], votingPowerData: ProcessedVotingPowerHistory[] = [], daoChainMapping: Record = {}, - votesData: any[] = [] + votesData: any[] = [], + offchainProposalsData: OffchainProposalData[] = [] ): void { - mockHttpClient.post.mockImplementation(this.createMockImplementation(proposals, votingPowerData, daoChainMapping, votesData)); + mockHttpClient.post.mockImplementation(this.createMockImplementation(proposals, votingPowerData, daoChainMapping, votesData, offchainProposalsData)); } /** From 91351a06b006dd4c1d167237025aa3e732a42335 Mon Sep 17 00:00:00 2001 From: Leonardo Vieira Date: Thu, 26 Feb 2026 13:18:56 -0300 Subject: [PATCH 15/42] feat: imports --- apps/integrated-tests/src/fixtures/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/integrated-tests/src/fixtures/index.ts b/apps/integrated-tests/src/fixtures/index.ts index 67c6b146..51e995ed 100644 --- a/apps/integrated-tests/src/fixtures/index.ts +++ b/apps/integrated-tests/src/fixtures/index.ts @@ -6,4 +6,5 @@ export * from './factories/user-factory'; export * from './factories/proposal-factory'; export * from './factories/voting-power-factory'; export * from './factories/vote-factory'; -export * from './factories/workspace-factory'; \ No newline at end of file +export * from './factories/workspace-factory'; +export * from './factories/offchain-proposal-factory'; \ No newline at end of file From 0ef24e76c5668bb71483ec8950ae5c533cdf66d3 Mon Sep 17 00:00:00 2001 From: Leonardo Vieira Date: Thu, 26 Feb 2026 14:36:21 -0300 Subject: [PATCH 16/42] feat: integration test --- .../slack/slack-new-offchain-proposal.test.ts | 141 ++++++++++++++ .../new-offchain-proposal-trigger.test.ts | 179 ++++++++++++++++++ 2 files changed, 320 insertions(+) create mode 100644 apps/integrated-tests/tests/slack/slack-new-offchain-proposal.test.ts create mode 100644 apps/integrated-tests/tests/telegram/new-offchain-proposal-trigger.test.ts diff --git a/apps/integrated-tests/tests/slack/slack-new-offchain-proposal.test.ts b/apps/integrated-tests/tests/slack/slack-new-offchain-proposal.test.ts new file mode 100644 index 00000000..c4c86c3d --- /dev/null +++ b/apps/integrated-tests/tests/slack/slack-new-offchain-proposal.test.ts @@ -0,0 +1,141 @@ +/** + * Slack New Offchain Proposal Integration Test + * Tests that Snapshot proposal notifications are correctly delivered via Slack + */ + +import { describe, test, expect, beforeEach, beforeAll } from '@jest/globals'; +import { db, TestApps } from '../../src/setup'; +import { HttpClientMockSetup, GraphQLMockSetup } from '../../src/mocks'; +import { UserFactory, OffchainProposalFactory, WorkspaceFactory } from '../../src/fixtures'; +import { SlackTestHelper, DatabaseTestHelper, TestCleanup } from '../../src/helpers'; +import { SlackTestClient } from '../../src/test-clients/slack-test.client'; +import { testConstants, timeouts } from '../../src/config'; + +describe('Slack New Offchain Proposal - Integration Test', () => { + let apps: TestApps; + let httpMockSetup: HttpClientMockSetup; + let slackHelper: SlackTestHelper; + let slackClient: SlackTestClient; + let dbHelper: DatabaseTestHelper; + + const testDaoId = testConstants.daoIds.ens; + + beforeAll(async () => { + apps = TestCleanup.getGlobalApps(); + httpMockSetup = TestCleanup.getGlobalHttpMockSetup(); + + slackClient = new SlackTestClient(global.mockSlackSendMessage); + slackHelper = new SlackTestHelper(global.mockSlackSendMessage, slackClient); + + dbHelper = new DatabaseTestHelper(db); + }); + + beforeEach(async () => { + await TestCleanup.cleanupBetweenTests(); + }); + + test('should send offchain proposal notification to Slack user', async () => { + const channelId = 'C_OFFCHAIN_01'; + const workspaceId = WorkspaceFactory.getWorkspaceId(); + const slackUserId = `${workspaceId}:${channelId}`; + + const { user } = await UserFactory.createUserWithFullSetup( + slackUserId, + `slack_offchain_${channelId}`, + testDaoId, + true, + undefined, + 'slack', + ); + + const proposal = OffchainProposalFactory.createProposal(testDaoId, `snap-slack-${Date.now()}`, { + title: 'Slack Snapshot Proposal', + }); + + GraphQLMockSetup.setupMock( + httpMockSetup.getMockClient(), + [], + [], + {}, + [], + [proposal], + ); + + const message = await slackHelper.waitForMessage( + msg => + msg.text.includes('New Snapshot proposal') && + msg.text.includes(proposal.title) && + msg.channel === channelId, + { + timeout: timeouts.notification.delivery, + errorMessage: 'Slack offchain proposal notification not received', + }, + ); + + expect(message.channel).toBe(channelId); + expect(message.text).toContain('New Snapshot proposal'); + expect(message.text).toContain(proposal.title); + expect(message.text).toContain(testDaoId); + + if (message.text.includes('http')) { + expect(message.text).toMatch(/]+>/); + } + + const notifications = await dbHelper.getNotifications(); + const slackNotification = notifications.find( + n => n.user_id === user.id && n.event_id.includes(proposal.id), + ); + expect(slackNotification).toBeDefined(); + }); + + test('should deliver notification to multiple Slack users subscribed to the same DAO', async () => { + const channel1 = 'C_OFFCHAIN_M1'; + const channel2 = 'C_OFFCHAIN_M2'; + const workspaceId = WorkspaceFactory.getWorkspaceId(); + + await UserFactory.createUserWithFullSetup( + `${workspaceId}:${channel1}`, + `slack_offchain_${channel1}`, + testDaoId, + true, + undefined, + 'slack', + ); + + await UserFactory.createUserWithFullSetup( + `${workspaceId}:${channel2}`, + `slack_offchain_${channel2}`, + testDaoId, + true, + undefined, + 'slack', + ); + + const proposal = OffchainProposalFactory.createProposal(testDaoId, `snap-multi-${Date.now()}`, { + title: 'Multi-User Offchain Proposal', + }); + + GraphQLMockSetup.setupMock( + httpMockSetup.getMockClient(), + [], + [], + {}, + [], + [proposal], + ); + + const messages = await slackHelper.waitForMessageCount(2, { + timeout: timeouts.notification.delivery, + containing: proposal.title, + }); + + const channels = messages.map(m => m.channel); + expect(channels).toContain(channel1); + expect(channels).toContain(channel2); + + messages.forEach(message => { + expect(message.text).toContain('New Snapshot proposal'); + expect(message.text).toContain(proposal.title); + }); + }); +}); diff --git a/apps/integrated-tests/tests/telegram/new-offchain-proposal-trigger.test.ts b/apps/integrated-tests/tests/telegram/new-offchain-proposal-trigger.test.ts new file mode 100644 index 00000000..532f3086 --- /dev/null +++ b/apps/integrated-tests/tests/telegram/new-offchain-proposal-trigger.test.ts @@ -0,0 +1,179 @@ +import { describe, test, expect, beforeEach, beforeAll } from '@jest/globals'; +import { db, TestApps } from '../../src/setup'; +import { HttpClientMockSetup, GraphQLMockSetup } from '../../src/mocks'; +import { UserFactory, OffchainProposalFactory } from '../../src/fixtures'; +import { TelegramTestHelper, DatabaseTestHelper, TestCleanup } from '../../src/helpers'; +import { testConstants, timeouts } from '../../src/config'; + +describe('New Offchain Proposal Trigger - Integration Test', () => { + let apps: TestApps; + let httpMockSetup: HttpClientMockSetup; + let telegramHelper: TelegramTestHelper; + let dbHelper: DatabaseTestHelper; + + const testDaoId = testConstants.daoIds.ens; + + beforeAll(async () => { + apps = TestCleanup.getGlobalApps(); + httpMockSetup = TestCleanup.getGlobalHttpMockSetup(); + telegramHelper = new TelegramTestHelper(global.mockTelegramSendMessage); + dbHelper = new DatabaseTestHelper(db); + }); + + beforeEach(async () => { + await TestCleanup.cleanupBetweenTests(); + }); + + test('should send notification when new offchain proposal is created', async () => { + const testUser = testConstants.profiles.p1; + const pastTimestamp = new Date(Date.now() - timeouts.wait.long).toISOString(); + + await UserFactory.createUserWithFullSetup( + testUser.chatId, + 'offchain-user-basic', + testDaoId, + true, + pastTimestamp, + ); + + const proposal = OffchainProposalFactory.createProposal(testDaoId, `snap-basic-${Date.now()}`, { + title: 'Community Treasury Allocation', + }); + + GraphQLMockSetup.setupMock( + httpMockSetup.getMockClient(), + [], + [], + {}, + [], + [proposal], + ); + + const message = await telegramHelper.waitForMessage( + msg => msg.text.includes('New Snapshot proposal') && msg.text.includes(proposal.title), + { timeout: timeouts.notification.delivery }, + ); + + expect(message.text).toContain('📋'); + expect(message.text).toContain('New Snapshot proposal'); + expect(message.text).toContain(testDaoId); + expect(message.text).toContain(proposal.title); + expect(message.chatId).toBe(testUser.chatId); + }); + + test('should include discussion link when discussion URL is present', async () => { + const testUser = testConstants.profiles.p2; + const pastTimestamp = new Date(Date.now() - timeouts.wait.long).toISOString(); + + await UserFactory.createUserWithFullSetup( + testUser.chatId, + 'offchain-user-discussion', + testDaoId, + true, + pastTimestamp, + ); + + const discussionUrl = 'https://forum.example.com/proposal-discussion'; + const proposal = OffchainProposalFactory.createProposal(testDaoId, `snap-discuss-${Date.now()}`, { + title: 'Proposal With Discussion', + discussion: discussionUrl, + }); + + GraphQLMockSetup.setupMock( + httpMockSetup.getMockClient(), + [], + [], + {}, + [], + [proposal], + ); + + const message = await telegramHelper.waitForMessage( + msg => msg.text.includes('Proposal With Discussion'), + { timeout: timeouts.notification.delivery }, + ); + + expect(message.text).toContain('New Snapshot proposal'); + expect(message.chatId).toBe(testUser.chatId); + + const buttons = message.reply_markup?.inline_keyboard?.flat() ?? []; + const discussionButton = buttons.find((btn: any) => btn.url === discussionUrl); + expect(discussionButton).toBeDefined(); + expect(discussionButton.text).toBe('View Discussion'); + }); + + test('should NOT notify users not subscribed to the DAO', async () => { + const testUser = testConstants.profiles.p3; + const pastTimestamp = new Date(Date.now() - timeouts.wait.long).toISOString(); + + await UserFactory.createUserWithFullSetup( + testUser.chatId, + 'offchain-user-wrong-dao', + 'different-dao', + true, + pastTimestamp, + ); + + const proposal = OffchainProposalFactory.createProposal(testDaoId, `snap-nosub-${Date.now()}`, { + title: 'Proposal For Other DAO', + }); + + GraphQLMockSetup.setupMock( + httpMockSetup.getMockClient(), + [], + [], + {}, + [], + [proposal], + ); + + const messagePromise = telegramHelper.waitForMessage( + msg => msg.text.includes('Proposal For Other DAO'), + { timeout: timeouts.wait.short }, + ); + + await expect(messagePromise).rejects.toThrow('Telegram message not received'); + }); + + test('should NOT send duplicate notifications for the same proposal', async () => { + const testUser = testConstants.profiles.p4; + const pastTimestamp = new Date(Date.now() - timeouts.wait.long).toISOString(); + + await UserFactory.createUserWithFullSetup( + testUser.chatId, + 'offchain-user-dup', + testDaoId, + true, + pastTimestamp, + ); + + const proposal = OffchainProposalFactory.createProposal(testDaoId, `snap-dup-${Date.now()}`, { + title: 'Duplicate Prevention Proposal', + }); + + GraphQLMockSetup.setupMock( + httpMockSetup.getMockClient(), + [], + [], + {}, + [], + [proposal], + ); + + const firstMessage = await telegramHelper.waitForMessage( + msg => msg.text.includes('Duplicate Prevention Proposal'), + { timeout: timeouts.notification.delivery }, + ); + + expect(firstMessage).toBeDefined(); + + apps.logicSystemApp.resetTriggers(); + + const duplicatePromise = telegramHelper.waitForMessage( + msg => msg.text.includes('Duplicate Prevention Proposal'), + { timeout: timeouts.wait.short }, + ); + + await expect(duplicatePromise).rejects.toThrow('Telegram message not received'); + }); +}); From 391e3e5e833b0faefc741a1dfd734902f6fc6d9a Mon Sep 17 00:00:00 2001 From: "Alexandro T. Netto" Date: Tue, 3 Mar 2026 18:25:54 -0300 Subject: [PATCH 17/42] feat: add Bearer token auth for AntiCapture API Gateway AntiCapture PR #1680 adds BLOCKFUL_API_TOKEN-based auth to the API Gateway. Wire the optional token into all three services (logic-system, dispatcher, consumers) so requests include the Authorization header when the env var is set. --- .env.example | 1 + apps/consumers/example.env | 1 + apps/consumers/src/config/env.ts | 2 ++ apps/consumers/src/index.ts | 9 ++++++++- apps/dispatcher/src/app.ts | 6 +++++- apps/dispatcher/src/envConfig.ts | 2 ++ apps/dispatcher/src/index.ts | 4 +++- apps/logic-system/.env.example | 1 + apps/logic-system/src/config/env.ts | 1 + apps/logic-system/src/index.ts | 9 ++++++++- docker-compose.yml | 3 +++ 11 files changed, 35 insertions(+), 4 deletions(-) diff --git a/.env.example b/.env.example index 8bc4343a..172ee3f1 100644 --- a/.env.example +++ b/.env.example @@ -3,6 +3,7 @@ # === REQUIRED CONFIGURATION === ANTICAPTURE_GRAPHQL_ENDPOINT=https://api-gateway-production-0879.up.railway.app/graphql +BLOCKFUL_API_TOKEN= # === NOTIFICATION PLATFORMS === TELEGRAM_BOT_TOKEN= diff --git a/apps/consumers/example.env b/apps/consumers/example.env index 9fc11959..d77bd031 100644 --- a/apps/consumers/example.env +++ b/apps/consumers/example.env @@ -1,4 +1,5 @@ TELEGRAM_BOT_TOKEN=your_telegram_bot_token ANTICAPTURE_GRAPHQL_ENDPOINT=https://api-gateway/graphql +BLOCKFUL_API_TOKEN= SUBSCRIPTION_SERVER_URL=http://localhost:3001 API_PORT=3000 \ No newline at end of file diff --git a/apps/consumers/src/config/env.ts b/apps/consumers/src/config/env.ts index 9d23df2b..361d9f30 100644 --- a/apps/consumers/src/config/env.ts +++ b/apps/consumers/src/config/env.ts @@ -10,6 +10,7 @@ const envSchema = z.object({ SLACK_SIGNING_SECRET: z.string(), TOKEN_ENCRYPTION_KEY: z.string(), ANTICAPTURE_GRAPHQL_ENDPOINT: z.string().url("ANTICAPTURE_GRAPHQL_ENDPOINT must be a valid URL"), + BLOCKFUL_API_TOKEN: z.string().optional(), SUBSCRIPTION_SERVER_URL: z.string(), RABBITMQ_URL: z.string().url(), PORT: z.coerce.number().positive().optional().default(3002), @@ -24,6 +25,7 @@ export function loadConfig() { slackSigningSecret: env.SLACK_SIGNING_SECRET, tokenEncryptionKey: env.TOKEN_ENCRYPTION_KEY, anticaptureGraphqlEndpoint: env.ANTICAPTURE_GRAPHQL_ENDPOINT, + blockfulApiToken: env.BLOCKFUL_API_TOKEN, subscriptionServerUrl: env.SUBSCRIPTION_SERVER_URL, rabbitmqUrl: env.RABBITMQ_URL, port: env.PORT, diff --git a/apps/consumers/src/index.ts b/apps/consumers/src/index.ts index 7ad7a7c1..296a5920 100644 --- a/apps/consumers/src/index.ts +++ b/apps/consumers/src/index.ts @@ -35,7 +35,14 @@ const slackClient = new SlackClient( // Create and start the application const app = new App( config.subscriptionServerUrl, - axios.create({ baseURL: config.anticaptureGraphqlEndpoint }), + axios.create({ + baseURL: config.anticaptureGraphqlEndpoint, + headers: { + ...(config.blockfulApiToken && { + Authorization: `Bearer ${config.blockfulApiToken}`, + }), + }, + }), config.rabbitmqUrl, ensResolver, telegramClient, diff --git a/apps/dispatcher/src/app.ts b/apps/dispatcher/src/app.ts index a3157920..cb45e975 100644 --- a/apps/dispatcher/src/app.ts +++ b/apps/dispatcher/src/app.ts @@ -23,7 +23,8 @@ export class App { private subscriptionServerUrl: string, private rabbitmqUrl: string, private anticaptureGraphqlEndpoint: string, - private anticaptureHttpClient?: any + private anticaptureHttpClient?: any, + private blockfulApiToken?: string ) {} private async setupServices(): Promise { @@ -42,6 +43,9 @@ export class App { baseURL: this.anticaptureGraphqlEndpoint, headers: { 'Content-Type': 'application/json', + ...(this.blockfulApiToken && { + Authorization: `Bearer ${this.blockfulApiToken}`, + }), }, }); const anticaptureClient = new AnticaptureClient(anticaptureAxiosClient); diff --git a/apps/dispatcher/src/envConfig.ts b/apps/dispatcher/src/envConfig.ts index 80774155..d5c581c6 100644 --- a/apps/dispatcher/src/envConfig.ts +++ b/apps/dispatcher/src/envConfig.ts @@ -11,6 +11,7 @@ const envSchema = z.object({ SUBSCRIPTION_SERVER_URL: z.string().url(), RABBITMQ_URL: z.string().url(), ANTICAPTURE_GRAPHQL_ENDPOINT: z.string().url(), + BLOCKFUL_API_TOKEN: z.string().optional(), }); export function loadConfig() { @@ -21,5 +22,6 @@ export function loadConfig() { subscriptionServerUrl: env.SUBSCRIPTION_SERVER_URL, rabbitmqUrl: env.RABBITMQ_URL, anticaptureGraphqlEndpoint: env.ANTICAPTURE_GRAPHQL_ENDPOINT, + blockfulApiToken: env.BLOCKFUL_API_TOKEN, } as const; } \ No newline at end of file diff --git a/apps/dispatcher/src/index.ts b/apps/dispatcher/src/index.ts index cb6c03ea..534d00ce 100644 --- a/apps/dispatcher/src/index.ts +++ b/apps/dispatcher/src/index.ts @@ -5,7 +5,9 @@ const config = loadConfig(); const app = new App( config.subscriptionServerUrl, config.rabbitmqUrl, - config.anticaptureGraphqlEndpoint + config.anticaptureGraphqlEndpoint, + undefined, + config.blockfulApiToken ); (async () => { diff --git a/apps/logic-system/.env.example b/apps/logic-system/.env.example index 9dbe82cb..190afd8c 100644 --- a/apps/logic-system/.env.example +++ b/apps/logic-system/.env.example @@ -1,5 +1,6 @@ # Anticapture GraphQL API ANTICAPTURE_GRAPHQL_ENDPOINT="https://api-gateway/graphql" +BLOCKFUL_API_TOKEN= # Dispatcher service configuration DISPATCHER_ENDPOINT="http://localhost:3000/api/dispatch" diff --git a/apps/logic-system/src/config/env.ts b/apps/logic-system/src/config/env.ts index 25990105..76ffa70e 100644 --- a/apps/logic-system/src/config/env.ts +++ b/apps/logic-system/src/config/env.ts @@ -13,6 +13,7 @@ const validProposalStatuses = [ // Define environment variables schema with validation const envSchema = z.object({ ANTICAPTURE_GRAPHQL_ENDPOINT: z.string().url('ANTICAPTURE_GRAPHQL_ENDPOINT must be a valid URL'), + BLOCKFUL_API_TOKEN: z.string().optional(), RABBITMQ_URL: z.string().url(), TRIGGER_INTERVAL: z.coerce.number().optional().default(60000), PROPOSAL_STATUS: z.enum(validProposalStatuses), diff --git a/apps/logic-system/src/index.ts b/apps/logic-system/src/index.ts index 8eef19d2..63a2b882 100644 --- a/apps/logic-system/src/index.ts +++ b/apps/logic-system/src/index.ts @@ -5,7 +5,14 @@ import { env } from './config/env'; const app = new App( env.TRIGGER_INTERVAL, env.PROPOSAL_STATUS, - axios.create({ baseURL: env.ANTICAPTURE_GRAPHQL_ENDPOINT }), + axios.create({ + baseURL: env.ANTICAPTURE_GRAPHQL_ENDPOINT, + headers: { + ...(env.BLOCKFUL_API_TOKEN && { + Authorization: `Bearer ${env.BLOCKFUL_API_TOKEN}`, + }), + }, + }), env.RABBITMQ_URL, ); diff --git a/docker-compose.yml b/docker-compose.yml index b3df4149..2fbb8999 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -67,6 +67,7 @@ services: environment: TELEGRAM_BOT_TOKEN: ${TELEGRAM_BOT_TOKEN} ANTICAPTURE_GRAPHQL_ENDPOINT: ${ANTICAPTURE_GRAPHQL_ENDPOINT} + BLOCKFUL_API_TOKEN: ${BLOCKFUL_API_TOKEN:-} SLACK_SIGNING_SECRET: ${SLACK_SIGNING_SECRET} SLACK_CHANNEL_ID: ${SLACK_CHANNEL_ID:-} SUBSCRIPTION_SERVER_URL: http://subscription-server:3003 @@ -90,6 +91,7 @@ services: container_name: dispatcher environment: ANTICAPTURE_GRAPHQL_ENDPOINT: ${ANTICAPTURE_GRAPHQL_ENDPOINT} + BLOCKFUL_API_TOKEN: ${BLOCKFUL_API_TOKEN:-} RABBITMQ_URL: amqp://admin:admin@rabbitmq:5672 SUBSCRIPTION_SERVER_URL: http://subscription-server:3003 depends_on: @@ -109,6 +111,7 @@ services: container_name: logic-system environment: ANTICAPTURE_GRAPHQL_ENDPOINT: ${ANTICAPTURE_GRAPHQL_ENDPOINT} + BLOCKFUL_API_TOKEN: ${BLOCKFUL_API_TOKEN:-} RABBITMQ_URL: amqp://admin:admin@rabbitmq:5672 TRIGGER_INTERVAL: 10000 PROPOSAL_STATUS: ACTIVE From 75db667b35ecb1382203a72fbe092b1cdc9ba686 Mon Sep 17 00:00:00 2001 From: Leonardo Vieira Date: Wed, 4 Mar 2026 10:32:34 -0300 Subject: [PATCH 18/42] feat: generated files --- .../dist/anticapture-client.d.ts | 8 +- .../dist/anticapture-client.js | 26 ++- packages/anticapture-client/dist/gql/gql.d.ts | 5 + packages/anticapture-client/dist/gql/gql.js | 1 + .../anticapture-client/dist/gql/graphql.d.ts | 211 ++++++++++++++++-- .../anticapture-client/dist/gql/graphql.js | 73 +++++- packages/anticapture-client/dist/index.d.ts | 1 + packages/anticapture-client/dist/index.js | 5 +- packages/anticapture-client/dist/schemas.d.ts | 95 ++++---- packages/anticapture-client/dist/schemas.js | 10 +- 10 files changed, 373 insertions(+), 62 deletions(-) diff --git a/packages/anticapture-client/dist/anticapture-client.d.ts b/packages/anticapture-client/dist/anticapture-client.d.ts index d38e0f5b..14061e9b 100644 --- a/packages/anticapture-client/dist/anticapture-client.d.ts +++ b/packages/anticapture-client/dist/anticapture-client.d.ts @@ -1,7 +1,7 @@ import { AxiosInstance } from 'axios'; import { z } from 'zod'; import type { GetProposalByIdQuery, ListProposalsQuery, ListProposalsQueryVariables, ListHistoricalVotingPowerQueryVariables, ListVotesQuery, ListVotesQueryVariables } from './gql/graphql'; -import { SafeProposalNonVotersResponseSchema, ProcessedVotingPowerHistory } from './schemas'; +import { SafeProposalNonVotersResponseSchema, ProcessedVotingPowerHistory, FeedEventType, FeedRelevance } from './schemas'; type ProposalItems = NonNullable['items']; type VotingPowerHistoryItems = ProcessedVotingPowerHistory[]; type ProposalNonVoter = z.infer['proposalNonVoters']['items'][0]; @@ -74,5 +74,11 @@ export declare class AnticaptureClient { * @returns Array of votes from all DAOs with daoId included */ listRecentVotesFromAllDaos(timestampGt: string, limit?: number): Promise; + /** + * Fetches the event relevance threshold for a given DAO, event type, and relevance level. + * Used to filter out low-impact events (e.g., small delegation changes). + * @returns Threshold as a numeric string, or null if unavailable (fail-open) + */ + getEventThreshold(daoId: string, type: FeedEventType, relevance: FeedRelevance): Promise; } export {}; diff --git a/packages/anticapture-client/dist/anticapture-client.js b/packages/anticapture-client/dist/anticapture-client.js index 3a6327f4..1a9e0f99 100644 --- a/packages/anticapture-client/dist/anticapture-client.js +++ b/packages/anticapture-client/dist/anticapture-client.js @@ -225,7 +225,7 @@ class AnticaptureClient { async listVotes(daoId, variables) { try { const validated = await this.query(graphql_2.ListVotesDocument, schemas_1.SafeVotesResponseSchema, variables, daoId); - return validated.votes.items.filter((item) => item !== null); + return validated.votes.items.filter(item => item !== null); } catch (error) { console.warn(`Error fetching votes for DAO ${daoId}:`, error); @@ -291,5 +291,29 @@ class AnticaptureClient { }); return allVotes; } + /** + * Fetches the event relevance threshold for a given DAO, event type, and relevance level. + * Used to filter out low-impact events (e.g., small delegation changes). + * @returns Threshold as a numeric string, or null if unavailable (fail-open) + */ + async getEventThreshold(daoId, type, relevance) { + try { + const headers = this.buildHeaders(daoId); + const response = await this.httpClient.post('', { + query: (0, graphql_1.print)(graphql_2.GetEventRelevanceThresholdDocument), + variables: { type, relevance }, + }, { headers }); + if (response.data.errors) { + console.warn('[AnticaptureClient] Threshold query errors:', response.data.errors); + return null; + } + const validated = schemas_1.EventThresholdResponseSchema.parse(response.data.data); + return validated.getEventRelevanceThreshold.threshold; + } + catch (error) { + console.warn(`[AnticaptureClient] Error fetching threshold for ${daoId}/${type}:`, error instanceof Error ? error.message : error); + return null; + } + } } exports.AnticaptureClient = AnticaptureClient; diff --git a/packages/anticapture-client/dist/gql/gql.d.ts b/packages/anticapture-client/dist/gql/gql.d.ts index 25771ff3..17720a4a 100644 --- a/packages/anticapture-client/dist/gql/gql.d.ts +++ b/packages/anticapture-client/dist/gql/gql.d.ts @@ -15,6 +15,7 @@ type Documents = { "query GetDAOs {\n daos {\n items {\n id\n votingDelay\n chainId\n }\n }\n}": typeof types.GetDaOsDocument; "query ProposalNonVoters($id: String!, $addresses: JSON) {\n proposalNonVoters(id: $id, addresses: $addresses) {\n items {\n voter\n }\n }\n}": typeof types.ProposalNonVotersDocument; "query GetProposalById($id: String!) {\n proposal(id: $id) {\n id\n daoId\n proposerAccountId\n title\n description\n startBlock\n endBlock\n endTimestamp\n timestamp\n status\n forVotes\n againstVotes\n abstainVotes\n txHash\n }\n}\n\nquery ListProposals($skip: NonNegativeInt, $limit: PositiveInt, $orderDirection: queryInput_proposals_orderDirection, $status: JSON, $fromDate: Float, $fromEndDate: Float, $includeOptimisticProposals: queryInput_proposals_includeOptimisticProposals) {\n proposals(\n skip: $skip\n limit: $limit\n orderDirection: $orderDirection\n status: $status\n fromDate: $fromDate\n fromEndDate: $fromEndDate\n includeOptimisticProposals: $includeOptimisticProposals\n ) {\n items {\n id\n daoId\n proposerAccountId\n title\n description\n startBlock\n endBlock\n endTimestamp\n timestamp\n status\n forVotes\n againstVotes\n abstainVotes\n txHash\n }\n totalCount\n }\n}": typeof types.GetProposalByIdDocument; + "query GetEventRelevanceThreshold($relevance: queryInput_getEventRelevanceThreshold_relevance!, $type: queryInput_getEventRelevanceThreshold_type!) {\n getEventRelevanceThreshold(relevance: $relevance, type: $type) {\n threshold\n }\n}": typeof types.GetEventRelevanceThresholdDocument; "query ListVotes($voterAddressIn: JSON, $fromDate: Float, $toDate: Float, $limit: Float, $skip: NonNegativeInt, $orderBy: queryInput_votes_orderBy, $orderDirection: queryInput_votes_orderDirection, $support: Float) {\n votes(\n voterAddressIn: $voterAddressIn\n fromDate: $fromDate\n toDate: $toDate\n limit: $limit\n skip: $skip\n orderBy: $orderBy\n orderDirection: $orderDirection\n support: $support\n ) {\n items {\n transactionHash\n proposalId\n voterAddress\n support\n votingPower\n timestamp\n reason\n proposalTitle\n }\n totalCount\n }\n}": typeof types.ListVotesDocument; "query ListHistoricalVotingPower($limit: PositiveInt, $skip: NonNegativeInt, $orderBy: queryInput_historicalVotingPower_orderBy, $orderDirection: queryInput_historicalVotingPower_orderDirection, $fromDate: String, $address: String) {\n historicalVotingPower(\n limit: $limit\n skip: $skip\n orderBy: $orderBy\n orderDirection: $orderDirection\n fromDate: $fromDate\n address: $address\n ) {\n items {\n accountId\n timestamp\n votingPower\n delta\n daoId\n transactionHash\n logIndex\n delegation {\n from\n to\n value\n previousDelegate\n }\n transfer {\n from\n to\n value\n }\n }\n totalCount\n }\n}": typeof types.ListHistoricalVotingPowerDocument; }; @@ -44,6 +45,10 @@ export declare function graphql(source: "query ProposalNonVoters($id: String!, $ * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export declare function graphql(source: "query GetProposalById($id: String!) {\n proposal(id: $id) {\n id\n daoId\n proposerAccountId\n title\n description\n startBlock\n endBlock\n endTimestamp\n timestamp\n status\n forVotes\n againstVotes\n abstainVotes\n txHash\n }\n}\n\nquery ListProposals($skip: NonNegativeInt, $limit: PositiveInt, $orderDirection: queryInput_proposals_orderDirection, $status: JSON, $fromDate: Float, $fromEndDate: Float, $includeOptimisticProposals: queryInput_proposals_includeOptimisticProposals) {\n proposals(\n skip: $skip\n limit: $limit\n orderDirection: $orderDirection\n status: $status\n fromDate: $fromDate\n fromEndDate: $fromEndDate\n includeOptimisticProposals: $includeOptimisticProposals\n ) {\n items {\n id\n daoId\n proposerAccountId\n title\n description\n startBlock\n endBlock\n endTimestamp\n timestamp\n status\n forVotes\n againstVotes\n abstainVotes\n txHash\n }\n totalCount\n }\n}"): (typeof documents)["query GetProposalById($id: String!) {\n proposal(id: $id) {\n id\n daoId\n proposerAccountId\n title\n description\n startBlock\n endBlock\n endTimestamp\n timestamp\n status\n forVotes\n againstVotes\n abstainVotes\n txHash\n }\n}\n\nquery ListProposals($skip: NonNegativeInt, $limit: PositiveInt, $orderDirection: queryInput_proposals_orderDirection, $status: JSON, $fromDate: Float, $fromEndDate: Float, $includeOptimisticProposals: queryInput_proposals_includeOptimisticProposals) {\n proposals(\n skip: $skip\n limit: $limit\n orderDirection: $orderDirection\n status: $status\n fromDate: $fromDate\n fromEndDate: $fromEndDate\n includeOptimisticProposals: $includeOptimisticProposals\n ) {\n items {\n id\n daoId\n proposerAccountId\n title\n description\n startBlock\n endBlock\n endTimestamp\n timestamp\n status\n forVotes\n againstVotes\n abstainVotes\n txHash\n }\n totalCount\n }\n}"]; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export declare function graphql(source: "query GetEventRelevanceThreshold($relevance: queryInput_getEventRelevanceThreshold_relevance!, $type: queryInput_getEventRelevanceThreshold_type!) {\n getEventRelevanceThreshold(relevance: $relevance, type: $type) {\n threshold\n }\n}"): (typeof documents)["query GetEventRelevanceThreshold($relevance: queryInput_getEventRelevanceThreshold_relevance!, $type: queryInput_getEventRelevanceThreshold_type!) {\n getEventRelevanceThreshold(relevance: $relevance, type: $type) {\n threshold\n }\n}"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/packages/anticapture-client/dist/gql/gql.js b/packages/anticapture-client/dist/gql/gql.js index 5a989ed0..563a7b9a 100644 --- a/packages/anticapture-client/dist/gql/gql.js +++ b/packages/anticapture-client/dist/gql/gql.js @@ -40,6 +40,7 @@ const documents = { "query GetDAOs {\n daos {\n items {\n id\n votingDelay\n chainId\n }\n }\n}": types.GetDaOsDocument, "query ProposalNonVoters($id: String!, $addresses: JSON) {\n proposalNonVoters(id: $id, addresses: $addresses) {\n items {\n voter\n }\n }\n}": types.ProposalNonVotersDocument, "query GetProposalById($id: String!) {\n proposal(id: $id) {\n id\n daoId\n proposerAccountId\n title\n description\n startBlock\n endBlock\n endTimestamp\n timestamp\n status\n forVotes\n againstVotes\n abstainVotes\n txHash\n }\n}\n\nquery ListProposals($skip: NonNegativeInt, $limit: PositiveInt, $orderDirection: queryInput_proposals_orderDirection, $status: JSON, $fromDate: Float, $fromEndDate: Float, $includeOptimisticProposals: queryInput_proposals_includeOptimisticProposals) {\n proposals(\n skip: $skip\n limit: $limit\n orderDirection: $orderDirection\n status: $status\n fromDate: $fromDate\n fromEndDate: $fromEndDate\n includeOptimisticProposals: $includeOptimisticProposals\n ) {\n items {\n id\n daoId\n proposerAccountId\n title\n description\n startBlock\n endBlock\n endTimestamp\n timestamp\n status\n forVotes\n againstVotes\n abstainVotes\n txHash\n }\n totalCount\n }\n}": types.GetProposalByIdDocument, + "query GetEventRelevanceThreshold($relevance: queryInput_getEventRelevanceThreshold_relevance!, $type: queryInput_getEventRelevanceThreshold_type!) {\n getEventRelevanceThreshold(relevance: $relevance, type: $type) {\n threshold\n }\n}": types.GetEventRelevanceThresholdDocument, "query ListVotes($voterAddressIn: JSON, $fromDate: Float, $toDate: Float, $limit: Float, $skip: NonNegativeInt, $orderBy: queryInput_votes_orderBy, $orderDirection: queryInput_votes_orderDirection, $support: Float) {\n votes(\n voterAddressIn: $voterAddressIn\n fromDate: $fromDate\n toDate: $toDate\n limit: $limit\n skip: $skip\n orderBy: $orderBy\n orderDirection: $orderDirection\n support: $support\n ) {\n items {\n transactionHash\n proposalId\n voterAddress\n support\n votingPower\n timestamp\n reason\n proposalTitle\n }\n totalCount\n }\n}": types.ListVotesDocument, "query ListHistoricalVotingPower($limit: PositiveInt, $skip: NonNegativeInt, $orderBy: queryInput_historicalVotingPower_orderBy, $orderDirection: queryInput_historicalVotingPower_orderDirection, $fromDate: String, $address: String) {\n historicalVotingPower(\n limit: $limit\n skip: $skip\n orderBy: $orderBy\n orderDirection: $orderDirection\n fromDate: $fromDate\n address: $address\n ) {\n items {\n accountId\n timestamp\n votingPower\n delta\n daoId\n transactionHash\n logIndex\n delegation {\n from\n to\n value\n previousDelegate\n }\n transfer {\n from\n to\n value\n }\n }\n totalCount\n }\n}": types.ListHistoricalVotingPowerDocument, }; diff --git a/packages/anticapture-client/dist/gql/graphql.d.ts b/packages/anticapture-client/dist/gql/graphql.d.ts index 7e9fc76b..ec3753f2 100644 --- a/packages/anticapture-client/dist/gql/graphql.d.ts +++ b/packages/anticapture-client/dist/gql/graphql.d.ts @@ -149,10 +149,16 @@ export type Query = { daos: DaoList; /** Get delegation percentage day buckets with forward-fill */ delegationPercentageByDay?: Maybe; - /** Get current delegators of an account */ + /** Get current delegations for an account */ delegations?: Maybe; + /** Get current delegators of an account with voting power */ + delegators?: Maybe; + /** Get feed events */ + feedEvents?: Maybe; /** Get historical DAO Token Treasury value (governance token quantity × token price) */ getDaoTokenTreasury?: Maybe; + /** Get event relevance threshold */ + getEventRelevanceThreshold?: Maybe; /** Get historical Liquid Treasury (treasury without DAO tokens) from external providers (DefiLlama/Dune) */ getLiquidTreasury?: Maybe; /** Get historical Total Treasury (liquid treasury + DAO token treasury) */ @@ -200,6 +206,8 @@ export type Query = { }; export type QueryAccountBalanceByAccountIdArgs = { address: Scalars['String']['input']; + fromDate?: InputMaybe; + toDate?: InputMaybe; }; export type QueryAccountBalanceVariationsArgs = { addresses?: InputMaybe; @@ -217,10 +225,13 @@ export type QueryAccountBalanceVariationsByAccountIdArgs = { export type QueryAccountBalancesArgs = { addresses?: InputMaybe; delegates?: InputMaybe; + fromDate?: InputMaybe; fromValue?: InputMaybe; limit?: InputMaybe; + orderBy?: InputMaybe; orderDirection?: InputMaybe; skip?: InputMaybe; + toDate?: InputMaybe; toValue?: InputMaybe; }; export type QueryAccountInteractionsArgs = { @@ -287,10 +298,31 @@ export type QueryDelegationPercentageByDayArgs = { export type QueryDelegationsArgs = { address: Scalars['String']['input']; }; +export type QueryDelegatorsArgs = { + address: Scalars['String']['input']; + limit?: InputMaybe; + orderBy?: InputMaybe; + orderDirection?: InputMaybe; + skip?: InputMaybe; +}; +export type QueryFeedEventsArgs = { + fromDate?: InputMaybe; + limit?: InputMaybe; + orderBy?: InputMaybe; + orderDirection?: InputMaybe; + relevance?: InputMaybe; + skip?: InputMaybe; + toDate?: InputMaybe; + type?: InputMaybe; +}; export type QueryGetDaoTokenTreasuryArgs = { days?: InputMaybe; order?: InputMaybe; }; +export type QueryGetEventRelevanceThresholdArgs = { + relevance: QueryInput_GetEventRelevanceThreshold_Relevance; + type: QueryInput_GetEventRelevanceThreshold_Type; +}; export type QueryGetLiquidTreasuryArgs = { days?: InputMaybe; order?: InputMaybe; @@ -437,6 +469,8 @@ export type QueryVotesByProposalIdArgs = { }; export type QueryVotingPowerByAccountIdArgs = { accountId: Scalars['String']['input']; + fromDate?: InputMaybe; + toDate?: InputMaybe; }; export type QueryVotingPowerVariationsArgs = { addresses?: InputMaybe; @@ -453,19 +487,19 @@ export type QueryVotingPowerVariationsByAccountIdArgs = { }; export type QueryVotingPowersArgs = { addresses?: InputMaybe; + fromDate?: InputMaybe; fromValue?: InputMaybe; limit?: InputMaybe; orderBy?: InputMaybe; orderDirection?: InputMaybe; skip?: InputMaybe; + toDate?: InputMaybe; toValue?: InputMaybe; }; export type AccountBalanceByAccountId_200_Response = { __typename?: 'accountBalanceByAccountId_200_response'; - address: Scalars['String']['output']; - balance: Scalars['String']['output']; - delegate: Scalars['String']['output']; - tokenId: Scalars['String']['output']; + data: Query_AccountBalanceByAccountId_Data; + period: Query_AccountBalanceByAccountId_Period; }; export type AccountBalanceVariationsByAccountId_200_Response = { __typename?: 'accountBalanceVariationsByAccountId_200_response'; @@ -480,6 +514,7 @@ export type AccountBalanceVariations_200_Response = { export type AccountBalances_200_Response = { __typename?: 'accountBalances_200_response'; items: Array>; + period: Query_AccountBalances_Period; totalCount: Scalars['Float']['output']; }; export type AccountInteractions_200_Response = { @@ -573,12 +608,26 @@ export type Delegations_200_Response = { items: Array>; totalCount: Scalars['Float']['output']; }; +export type Delegators_200_Response = { + __typename?: 'delegators_200_response'; + items: Array>; + totalCount: Scalars['Float']['output']; +}; +export type FeedEvents_200_Response = { + __typename?: 'feedEvents_200_response'; + items: Array>; + totalCount: Scalars['Float']['output']; +}; export type GetDaoTokenTreasury_200_Response = { __typename?: 'getDaoTokenTreasury_200_response'; items: Array>; /** Total number of items */ totalCount: Scalars['Float']['output']; }; +export type GetEventRelevanceThreshold_200_Response = { + __typename?: 'getEventRelevanceThreshold_200_response'; + threshold: Scalars['String']['output']; +}; export type GetLiquidTreasury_200_Response = { __typename?: 'getLiquidTreasury_200_response'; items: Array>; @@ -639,7 +688,7 @@ export type Proposal_200_Response = { status: Scalars['String']['output']; targets: Array>; timestamp: Scalars['String']['output']; - title: Scalars['String']['output']; + title?: Maybe; txHash: Scalars['String']['output']; values: Array>; }; @@ -663,6 +712,10 @@ export declare enum QueryInput_AccountBalanceVariations_OrderDirection { Asc = "asc", Desc = "desc" } +export declare enum QueryInput_AccountBalances_OrderBy { + Balance = "balance", + Variation = "variation" +} export declare enum QueryInput_AccountBalances_OrderDirection { Asc = "asc", Desc = "desc" @@ -756,6 +809,34 @@ export declare enum QueryInput_DelegationPercentageByDay_OrderDirection { Asc = "asc", Desc = "desc" } +export declare enum QueryInput_Delegators_OrderBy { + Amount = "amount", + Timestamp = "timestamp" +} +export declare enum QueryInput_Delegators_OrderDirection { + Asc = "asc", + Desc = "desc" +} +export declare enum QueryInput_FeedEvents_OrderBy { + Timestamp = "timestamp", + Value = "value" +} +export declare enum QueryInput_FeedEvents_OrderDirection { + Asc = "asc", + Desc = "desc" +} +export declare enum QueryInput_FeedEvents_Relevance { + High = "HIGH", + Low = "LOW", + Medium = "MEDIUM" +} +export declare enum QueryInput_FeedEvents_Type { + Delegation = "DELEGATION", + Proposal = "PROPOSAL", + ProposalExtended = "PROPOSAL_EXTENDED", + Transfer = "TRANSFER", + Vote = "VOTE" +} export declare enum QueryInput_GetDaoTokenTreasury_Days { '7d' = "_7d", '30d' = "_30d", @@ -767,6 +848,18 @@ export declare enum QueryInput_GetDaoTokenTreasury_Order { Asc = "asc", Desc = "desc" } +export declare enum QueryInput_GetEventRelevanceThreshold_Relevance { + High = "HIGH", + Low = "LOW", + Medium = "MEDIUM" +} +export declare enum QueryInput_GetEventRelevanceThreshold_Type { + Delegation = "DELEGATION", + Proposal = "PROPOSAL", + ProposalExtended = "PROPOSAL_EXTENDED", + Transfer = "TRANSFER", + Vote = "VOTE" +} export declare enum QueryInput_GetLiquidTreasury_Days { '7d' = "_7d", '30d' = "_30d", @@ -901,12 +994,32 @@ export declare enum QueryInput_VotingPowerVariations_OrderDirection { } export declare enum QueryInput_VotingPowers_OrderBy { DelegationsCount = "delegationsCount", + Variation = "variation", VotingPower = "votingPower" } export declare enum QueryInput_VotingPowers_OrderDirection { Asc = "asc", Desc = "desc" } +export type Query_AccountBalanceByAccountId_Data = { + __typename?: 'query_accountBalanceByAccountId_data'; + address: Scalars['String']['output']; + balance: Scalars['String']['output']; + delegate: Scalars['String']['output']; + tokenId: Scalars['String']['output']; + variation: Query_AccountBalanceByAccountId_Data_Variation; +}; +export type Query_AccountBalanceByAccountId_Data_Variation = { + __typename?: 'query_accountBalanceByAccountId_data_variation'; + absoluteChange: Scalars['String']['output']; + percentageChange: Scalars['String']['output']; + previousBalance: Scalars['String']['output']; +}; +export type Query_AccountBalanceByAccountId_Period = { + __typename?: 'query_accountBalanceByAccountId_period'; + endTimestamp: Scalars['String']['output']; + startTimestamp: Scalars['String']['output']; +}; export type Query_AccountBalanceVariationsByAccountId_Data = { __typename?: 'query_accountBalanceVariationsByAccountId_data'; absoluteChange: Scalars['String']['output']; @@ -939,6 +1052,18 @@ export type Query_AccountBalances_Items_Items = { balance: Scalars['String']['output']; delegate: Scalars['String']['output']; tokenId: Scalars['String']['output']; + variation: Query_AccountBalances_Items_Items_Variation; +}; +export type Query_AccountBalances_Items_Items_Variation = { + __typename?: 'query_accountBalances_items_items_variation'; + absoluteChange: Scalars['String']['output']; + percentageChange: Scalars['String']['output']; + previousBalance: Scalars['String']['output']; +}; +export type Query_AccountBalances_Period = { + __typename?: 'query_accountBalances_period'; + endTimestamp: Scalars['String']['output']; + startTimestamp: Scalars['String']['output']; }; export type Query_AccountInteractions_Items_Items = { __typename?: 'query_accountInteractions_items_items'; @@ -971,6 +1096,34 @@ export type Query_Delegations_Items_Items = { timestamp: Scalars['String']['output']; transactionHash: Scalars['String']['output']; }; +export type Query_Delegators_Items_Items = { + __typename?: 'query_delegators_items_items'; + amount: Scalars['String']['output']; + delegatorAddress: Scalars['String']['output']; + timestamp: Scalars['String']['output']; +}; +export type Query_FeedEvents_Items_Items = { + __typename?: 'query_feedEvents_items_items'; + logIndex: Scalars['Float']['output']; + metadata?: Maybe; + relevance: Query_FeedEvents_Items_Items_Relevance; + timestamp: Scalars['Float']['output']; + txHash: Scalars['String']['output']; + type: Query_FeedEvents_Items_Items_Type; + value?: Maybe; +}; +export declare enum Query_FeedEvents_Items_Items_Relevance { + High = "HIGH", + Low = "LOW", + Medium = "MEDIUM" +} +export declare enum Query_FeedEvents_Items_Items_Type { + Delegation = "DELEGATION", + Proposal = "PROPOSAL", + ProposalExtended = "PROPOSAL_EXTENDED", + Transfer = "TRANSFER", + Vote = "VOTE" +} export type Query_GetDaoTokenTreasury_Items_Items = { __typename?: 'query_getDaoTokenTreasury_items_items'; /** Unix timestamp in milliseconds */ @@ -1127,7 +1280,7 @@ export type Query_Proposals_Items_Items = { status: Scalars['String']['output']; targets: Array>; timestamp: Scalars['String']['output']; - title: Scalars['String']['output']; + title?: Maybe; txHash: Scalars['String']['output']; values: Array>; }; @@ -1204,10 +1357,10 @@ export type Query_Transfers_Items_Items = { export type Query_VotesByProposalId_Items_Items = { __typename?: 'query_votesByProposalId_items_items'; proposalId: Scalars['String']['output']; - proposalTitle: Scalars['String']['output']; + proposalTitle?: Maybe; reason?: Maybe; - support: Scalars['Float']['output']; - timestamp: Scalars['Float']['output']; + support?: Maybe; + timestamp: Scalars['Int']['output']; transactionHash: Scalars['String']['output']; voterAddress: Scalars['String']['output']; votingPower: Scalars['String']['output']; @@ -1215,14 +1368,19 @@ export type Query_VotesByProposalId_Items_Items = { export type Query_Votes_Items_Items = { __typename?: 'query_votes_items_items'; proposalId: Scalars['String']['output']; - proposalTitle: Scalars['String']['output']; + proposalTitle?: Maybe; reason?: Maybe; - support: Scalars['Float']['output']; - timestamp: Scalars['Float']['output']; + support?: Maybe; + timestamp: Scalars['Int']['output']; transactionHash: Scalars['String']['output']; voterAddress: Scalars['String']['output']; votingPower: Scalars['String']['output']; }; +export type Query_VotingPowerByAccountId_Variation = { + __typename?: 'query_votingPowerByAccountId_variation'; + absoluteChange: Scalars['String']['output']; + percentageChange: Scalars['String']['output']; +}; export type Query_VotingPowerVariationsByAccountId_Data = { __typename?: 'query_votingPowerVariationsByAccountId_data'; absoluteChange: Scalars['String']['output']; @@ -1254,9 +1412,15 @@ export type Query_VotingPowers_Items_Items = { accountId: Scalars['String']['output']; delegationsCount: Scalars['Float']['output']; proposalsCount: Scalars['Float']['output']; + variation: Query_VotingPowers_Items_Items_Variation; votesCount: Scalars['Float']['output']; votingPower: Scalars['String']['output']; }; +export type Query_VotingPowers_Items_Items_Variation = { + __typename?: 'query_votingPowers_items_items_variation'; + absoluteChange: Scalars['String']['output']; + percentageChange: Scalars['String']['output']; +}; export declare enum Timestamp_Const { Timestamp = "timestamp" } @@ -1304,6 +1468,7 @@ export type VotingPowerByAccountId_200_Response = { accountId: Scalars['String']['output']; delegationsCount: Scalars['Float']['output']; proposalsCount: Scalars['Float']['output']; + variation: Query_VotingPowerByAccountId_Variation; votesCount: Scalars['Float']['output']; votingPower: Scalars['String']['output']; }; @@ -1361,7 +1526,7 @@ export type GetProposalByIdQuery = { id: string; daoId: string; proposerAccountId: string; - title: string; + title?: string | null; description: string; startBlock: number; endBlock: number; @@ -1393,7 +1558,7 @@ export type ListProposalsQuery = { id: string; daoId: string; proposerAccountId: string; - title: string; + title?: string | null; description: string; startBlock: number; endBlock: number; @@ -1407,6 +1572,17 @@ export type ListProposalsQuery = { } | null>; } | null; }; +export type GetEventRelevanceThresholdQueryVariables = Exact<{ + relevance: QueryInput_GetEventRelevanceThreshold_Relevance; + type: QueryInput_GetEventRelevanceThreshold_Type; +}>; +export type GetEventRelevanceThresholdQuery = { + __typename?: 'Query'; + getEventRelevanceThreshold?: { + __typename?: 'getEventRelevanceThreshold_200_response'; + threshold: string; + } | null; +}; export type ListVotesQueryVariables = Exact<{ voterAddressIn?: InputMaybe; fromDate?: InputMaybe; @@ -1427,11 +1603,11 @@ export type ListVotesQuery = { transactionHash: string; proposalId: string; voterAddress: string; - support: number; + support?: number | null; votingPower: string; timestamp: number; reason?: string | null; - proposalTitle: string; + proposalTitle?: string | null; } | null>; } | null; }; @@ -1477,5 +1653,6 @@ export declare const GetDaOsDocument: DocumentNode; export declare const GetProposalByIdDocument: DocumentNode; export declare const ListProposalsDocument: DocumentNode; +export declare const GetEventRelevanceThresholdDocument: DocumentNode; export declare const ListVotesDocument: DocumentNode; export declare const ListHistoricalVotingPowerDocument: DocumentNode; diff --git a/packages/anticapture-client/dist/gql/graphql.js b/packages/anticapture-client/dist/gql/graphql.js index e4b06321..5f7c97be 100644 --- a/packages/anticapture-client/dist/gql/graphql.js +++ b/packages/anticapture-client/dist/gql/graphql.js @@ -1,7 +1,7 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -exports.QueryInput_VotingPowers_OrderDirection = exports.QueryInput_VotingPowers_OrderBy = exports.QueryInput_VotingPowerVariations_OrderDirection = exports.QueryInput_Votes_OrderDirection = exports.QueryInput_Votes_OrderBy = exports.QueryInput_VotesByProposalId_OrderDirection = exports.QueryInput_VotesByProposalId_OrderBy = exports.QueryInput_Transfers_SortOrder = exports.QueryInput_Transfers_SortBy = exports.QueryInput_Transactions_SortOrder = exports.QueryInput_Token_Currency = exports.QueryInput_TokenMetrics_OrderDirection = exports.QueryInput_TokenMetrics_MetricType = exports.QueryInput_Proposals_OrderDirection = exports.QueryInput_Proposals_IncludeOptimisticProposals = exports.QueryInput_ProposalsActivity_UserVoteFilter = exports.QueryInput_ProposalsActivity_OrderDirection = exports.QueryInput_ProposalsActivity_OrderBy = exports.QueryInput_ProposalNonVoters_OrderDirection = exports.QueryInput_LastUpdate_Chart = exports.QueryInput_HistoricalVotingPower_OrderDirection = exports.QueryInput_HistoricalVotingPower_OrderBy = exports.QueryInput_HistoricalVotingPowerByAccountId_OrderDirection = exports.QueryInput_HistoricalVotingPowerByAccountId_OrderBy = exports.QueryInput_HistoricalDelegations_OrderDirection = exports.QueryInput_HistoricalBalances_OrderDirection = exports.QueryInput_HistoricalBalances_OrderBy = exports.QueryInput_GetTotalTreasury_Order = exports.QueryInput_GetTotalTreasury_Days = exports.QueryInput_GetLiquidTreasury_Order = exports.QueryInput_GetLiquidTreasury_Days = exports.QueryInput_GetDaoTokenTreasury_Order = exports.QueryInput_GetDaoTokenTreasury_Days = exports.QueryInput_DelegationPercentageByDay_OrderDirection = exports.QueryInput_CompareVotes_Days = exports.QueryInput_CompareTreasury_Days = exports.QueryInput_CompareTotalSupply_Days = exports.QueryInput_CompareProposals_Days = exports.QueryInput_CompareLendingSupply_Days = exports.QueryInput_CompareDexSupply_Days = exports.QueryInput_CompareDelegatedSupply_Days = exports.QueryInput_CompareCirculatingSupply_Days = exports.QueryInput_CompareCexSupply_Days = exports.QueryInput_CompareAverageTurnout_Days = exports.QueryInput_CompareActiveSupply_Days = exports.QueryInput_AccountInteractions_OrderDirection = exports.QueryInput_AccountInteractions_OrderBy = exports.QueryInput_AccountBalances_OrderDirection = exports.QueryInput_AccountBalanceVariations_OrderDirection = exports.HttpMethod = void 0; -exports.ListHistoricalVotingPowerDocument = exports.ListVotesDocument = exports.ListProposalsDocument = exports.GetProposalByIdDocument = exports.ProposalNonVotersDocument = exports.GetDaOsDocument = exports.Timestamp_Const = void 0; +exports.QueryInput_Transactions_SortOrder = exports.QueryInput_Token_Currency = exports.QueryInput_TokenMetrics_OrderDirection = exports.QueryInput_TokenMetrics_MetricType = exports.QueryInput_Proposals_OrderDirection = exports.QueryInput_Proposals_IncludeOptimisticProposals = exports.QueryInput_ProposalsActivity_UserVoteFilter = exports.QueryInput_ProposalsActivity_OrderDirection = exports.QueryInput_ProposalsActivity_OrderBy = exports.QueryInput_ProposalNonVoters_OrderDirection = exports.QueryInput_LastUpdate_Chart = exports.QueryInput_HistoricalVotingPower_OrderDirection = exports.QueryInput_HistoricalVotingPower_OrderBy = exports.QueryInput_HistoricalVotingPowerByAccountId_OrderDirection = exports.QueryInput_HistoricalVotingPowerByAccountId_OrderBy = exports.QueryInput_HistoricalDelegations_OrderDirection = exports.QueryInput_HistoricalBalances_OrderDirection = exports.QueryInput_HistoricalBalances_OrderBy = exports.QueryInput_GetTotalTreasury_Order = exports.QueryInput_GetTotalTreasury_Days = exports.QueryInput_GetLiquidTreasury_Order = exports.QueryInput_GetLiquidTreasury_Days = exports.QueryInput_GetEventRelevanceThreshold_Type = exports.QueryInput_GetEventRelevanceThreshold_Relevance = exports.QueryInput_GetDaoTokenTreasury_Order = exports.QueryInput_GetDaoTokenTreasury_Days = exports.QueryInput_FeedEvents_Type = exports.QueryInput_FeedEvents_Relevance = exports.QueryInput_FeedEvents_OrderDirection = exports.QueryInput_FeedEvents_OrderBy = exports.QueryInput_Delegators_OrderDirection = exports.QueryInput_Delegators_OrderBy = exports.QueryInput_DelegationPercentageByDay_OrderDirection = exports.QueryInput_CompareVotes_Days = exports.QueryInput_CompareTreasury_Days = exports.QueryInput_CompareTotalSupply_Days = exports.QueryInput_CompareProposals_Days = exports.QueryInput_CompareLendingSupply_Days = exports.QueryInput_CompareDexSupply_Days = exports.QueryInput_CompareDelegatedSupply_Days = exports.QueryInput_CompareCirculatingSupply_Days = exports.QueryInput_CompareCexSupply_Days = exports.QueryInput_CompareAverageTurnout_Days = exports.QueryInput_CompareActiveSupply_Days = exports.QueryInput_AccountInteractions_OrderDirection = exports.QueryInput_AccountInteractions_OrderBy = exports.QueryInput_AccountBalances_OrderDirection = exports.QueryInput_AccountBalances_OrderBy = exports.QueryInput_AccountBalanceVariations_OrderDirection = exports.HttpMethod = void 0; +exports.ListHistoricalVotingPowerDocument = exports.ListVotesDocument = exports.GetEventRelevanceThresholdDocument = exports.ListProposalsDocument = exports.GetProposalByIdDocument = exports.ProposalNonVotersDocument = exports.GetDaOsDocument = exports.Timestamp_Const = exports.Query_FeedEvents_Items_Items_Type = exports.Query_FeedEvents_Items_Items_Relevance = exports.QueryInput_VotingPowers_OrderDirection = exports.QueryInput_VotingPowers_OrderBy = exports.QueryInput_VotingPowerVariations_OrderDirection = exports.QueryInput_Votes_OrderDirection = exports.QueryInput_Votes_OrderBy = exports.QueryInput_VotesByProposalId_OrderDirection = exports.QueryInput_VotesByProposalId_OrderBy = exports.QueryInput_Transfers_SortOrder = exports.QueryInput_Transfers_SortBy = void 0; var HttpMethod; (function (HttpMethod) { HttpMethod["Connect"] = "CONNECT"; @@ -19,6 +19,11 @@ var QueryInput_AccountBalanceVariations_OrderDirection; QueryInput_AccountBalanceVariations_OrderDirection["Asc"] = "asc"; QueryInput_AccountBalanceVariations_OrderDirection["Desc"] = "desc"; })(QueryInput_AccountBalanceVariations_OrderDirection || (exports.QueryInput_AccountBalanceVariations_OrderDirection = QueryInput_AccountBalanceVariations_OrderDirection = {})); +var QueryInput_AccountBalances_OrderBy; +(function (QueryInput_AccountBalances_OrderBy) { + QueryInput_AccountBalances_OrderBy["Balance"] = "balance"; + QueryInput_AccountBalances_OrderBy["Variation"] = "variation"; +})(QueryInput_AccountBalances_OrderBy || (exports.QueryInput_AccountBalances_OrderBy = QueryInput_AccountBalances_OrderBy = {})); var QueryInput_AccountBalances_OrderDirection; (function (QueryInput_AccountBalances_OrderDirection) { QueryInput_AccountBalances_OrderDirection["Asc"] = "asc"; @@ -127,6 +132,40 @@ var QueryInput_DelegationPercentageByDay_OrderDirection; QueryInput_DelegationPercentageByDay_OrderDirection["Asc"] = "asc"; QueryInput_DelegationPercentageByDay_OrderDirection["Desc"] = "desc"; })(QueryInput_DelegationPercentageByDay_OrderDirection || (exports.QueryInput_DelegationPercentageByDay_OrderDirection = QueryInput_DelegationPercentageByDay_OrderDirection = {})); +var QueryInput_Delegators_OrderBy; +(function (QueryInput_Delegators_OrderBy) { + QueryInput_Delegators_OrderBy["Amount"] = "amount"; + QueryInput_Delegators_OrderBy["Timestamp"] = "timestamp"; +})(QueryInput_Delegators_OrderBy || (exports.QueryInput_Delegators_OrderBy = QueryInput_Delegators_OrderBy = {})); +var QueryInput_Delegators_OrderDirection; +(function (QueryInput_Delegators_OrderDirection) { + QueryInput_Delegators_OrderDirection["Asc"] = "asc"; + QueryInput_Delegators_OrderDirection["Desc"] = "desc"; +})(QueryInput_Delegators_OrderDirection || (exports.QueryInput_Delegators_OrderDirection = QueryInput_Delegators_OrderDirection = {})); +var QueryInput_FeedEvents_OrderBy; +(function (QueryInput_FeedEvents_OrderBy) { + QueryInput_FeedEvents_OrderBy["Timestamp"] = "timestamp"; + QueryInput_FeedEvents_OrderBy["Value"] = "value"; +})(QueryInput_FeedEvents_OrderBy || (exports.QueryInput_FeedEvents_OrderBy = QueryInput_FeedEvents_OrderBy = {})); +var QueryInput_FeedEvents_OrderDirection; +(function (QueryInput_FeedEvents_OrderDirection) { + QueryInput_FeedEvents_OrderDirection["Asc"] = "asc"; + QueryInput_FeedEvents_OrderDirection["Desc"] = "desc"; +})(QueryInput_FeedEvents_OrderDirection || (exports.QueryInput_FeedEvents_OrderDirection = QueryInput_FeedEvents_OrderDirection = {})); +var QueryInput_FeedEvents_Relevance; +(function (QueryInput_FeedEvents_Relevance) { + QueryInput_FeedEvents_Relevance["High"] = "HIGH"; + QueryInput_FeedEvents_Relevance["Low"] = "LOW"; + QueryInput_FeedEvents_Relevance["Medium"] = "MEDIUM"; +})(QueryInput_FeedEvents_Relevance || (exports.QueryInput_FeedEvents_Relevance = QueryInput_FeedEvents_Relevance = {})); +var QueryInput_FeedEvents_Type; +(function (QueryInput_FeedEvents_Type) { + QueryInput_FeedEvents_Type["Delegation"] = "DELEGATION"; + QueryInput_FeedEvents_Type["Proposal"] = "PROPOSAL"; + QueryInput_FeedEvents_Type["ProposalExtended"] = "PROPOSAL_EXTENDED"; + QueryInput_FeedEvents_Type["Transfer"] = "TRANSFER"; + QueryInput_FeedEvents_Type["Vote"] = "VOTE"; +})(QueryInput_FeedEvents_Type || (exports.QueryInput_FeedEvents_Type = QueryInput_FeedEvents_Type = {})); var QueryInput_GetDaoTokenTreasury_Days; (function (QueryInput_GetDaoTokenTreasury_Days) { QueryInput_GetDaoTokenTreasury_Days["7d"] = "_7d"; @@ -140,6 +179,20 @@ var QueryInput_GetDaoTokenTreasury_Order; QueryInput_GetDaoTokenTreasury_Order["Asc"] = "asc"; QueryInput_GetDaoTokenTreasury_Order["Desc"] = "desc"; })(QueryInput_GetDaoTokenTreasury_Order || (exports.QueryInput_GetDaoTokenTreasury_Order = QueryInput_GetDaoTokenTreasury_Order = {})); +var QueryInput_GetEventRelevanceThreshold_Relevance; +(function (QueryInput_GetEventRelevanceThreshold_Relevance) { + QueryInput_GetEventRelevanceThreshold_Relevance["High"] = "HIGH"; + QueryInput_GetEventRelevanceThreshold_Relevance["Low"] = "LOW"; + QueryInput_GetEventRelevanceThreshold_Relevance["Medium"] = "MEDIUM"; +})(QueryInput_GetEventRelevanceThreshold_Relevance || (exports.QueryInput_GetEventRelevanceThreshold_Relevance = QueryInput_GetEventRelevanceThreshold_Relevance = {})); +var QueryInput_GetEventRelevanceThreshold_Type; +(function (QueryInput_GetEventRelevanceThreshold_Type) { + QueryInput_GetEventRelevanceThreshold_Type["Delegation"] = "DELEGATION"; + QueryInput_GetEventRelevanceThreshold_Type["Proposal"] = "PROPOSAL"; + QueryInput_GetEventRelevanceThreshold_Type["ProposalExtended"] = "PROPOSAL_EXTENDED"; + QueryInput_GetEventRelevanceThreshold_Type["Transfer"] = "TRANSFER"; + QueryInput_GetEventRelevanceThreshold_Type["Vote"] = "VOTE"; +})(QueryInput_GetEventRelevanceThreshold_Type || (exports.QueryInput_GetEventRelevanceThreshold_Type = QueryInput_GetEventRelevanceThreshold_Type = {})); var QueryInput_GetLiquidTreasury_Days; (function (QueryInput_GetLiquidTreasury_Days) { QueryInput_GetLiquidTreasury_Days["7d"] = "_7d"; @@ -304,6 +357,7 @@ var QueryInput_VotingPowerVariations_OrderDirection; var QueryInput_VotingPowers_OrderBy; (function (QueryInput_VotingPowers_OrderBy) { QueryInput_VotingPowers_OrderBy["DelegationsCount"] = "delegationsCount"; + QueryInput_VotingPowers_OrderBy["Variation"] = "variation"; QueryInput_VotingPowers_OrderBy["VotingPower"] = "votingPower"; })(QueryInput_VotingPowers_OrderBy || (exports.QueryInput_VotingPowers_OrderBy = QueryInput_VotingPowers_OrderBy = {})); var QueryInput_VotingPowers_OrderDirection; @@ -311,6 +365,20 @@ var QueryInput_VotingPowers_OrderDirection; QueryInput_VotingPowers_OrderDirection["Asc"] = "asc"; QueryInput_VotingPowers_OrderDirection["Desc"] = "desc"; })(QueryInput_VotingPowers_OrderDirection || (exports.QueryInput_VotingPowers_OrderDirection = QueryInput_VotingPowers_OrderDirection = {})); +var Query_FeedEvents_Items_Items_Relevance; +(function (Query_FeedEvents_Items_Items_Relevance) { + Query_FeedEvents_Items_Items_Relevance["High"] = "HIGH"; + Query_FeedEvents_Items_Items_Relevance["Low"] = "LOW"; + Query_FeedEvents_Items_Items_Relevance["Medium"] = "MEDIUM"; +})(Query_FeedEvents_Items_Items_Relevance || (exports.Query_FeedEvents_Items_Items_Relevance = Query_FeedEvents_Items_Items_Relevance = {})); +var Query_FeedEvents_Items_Items_Type; +(function (Query_FeedEvents_Items_Items_Type) { + Query_FeedEvents_Items_Items_Type["Delegation"] = "DELEGATION"; + Query_FeedEvents_Items_Items_Type["Proposal"] = "PROPOSAL"; + Query_FeedEvents_Items_Items_Type["ProposalExtended"] = "PROPOSAL_EXTENDED"; + Query_FeedEvents_Items_Items_Type["Transfer"] = "TRANSFER"; + Query_FeedEvents_Items_Items_Type["Vote"] = "VOTE"; +})(Query_FeedEvents_Items_Items_Type || (exports.Query_FeedEvents_Items_Items_Type = Query_FeedEvents_Items_Items_Type = {})); var Timestamp_Const; (function (Timestamp_Const) { Timestamp_Const["Timestamp"] = "timestamp"; @@ -319,5 +387,6 @@ exports.GetDaOsDocument = { "kind": "Document", "definitions": [{ "kind": "Opera exports.ProposalNonVotersDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "ProposalNonVoters" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "id" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "String" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "addresses" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "JSON" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "proposalNonVoters" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "id" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "id" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "addresses" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "addresses" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "items" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "voter" } }] } }] } }] } }] }; exports.GetProposalByIdDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "GetProposalById" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "id" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "String" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "proposal" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "id" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "id" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "daoId" } }, { "kind": "Field", "name": { "kind": "Name", "value": "proposerAccountId" } }, { "kind": "Field", "name": { "kind": "Name", "value": "title" } }, { "kind": "Field", "name": { "kind": "Name", "value": "description" } }, { "kind": "Field", "name": { "kind": "Name", "value": "startBlock" } }, { "kind": "Field", "name": { "kind": "Name", "value": "endBlock" } }, { "kind": "Field", "name": { "kind": "Name", "value": "endTimestamp" } }, { "kind": "Field", "name": { "kind": "Name", "value": "timestamp" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }, { "kind": "Field", "name": { "kind": "Name", "value": "forVotes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "againstVotes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "abstainVotes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "txHash" } }] } }] } }] }; exports.ListProposalsDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "ListProposals" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "skip" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "NonNegativeInt" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "limit" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "PositiveInt" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "orderDirection" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "queryInput_proposals_orderDirection" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "status" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "JSON" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "fromDate" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Float" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "fromEndDate" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Float" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "includeOptimisticProposals" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "queryInput_proposals_includeOptimisticProposals" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "proposals" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "skip" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "skip" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "limit" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "limit" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "orderDirection" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "orderDirection" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "status" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "status" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "fromDate" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "fromDate" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "fromEndDate" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "fromEndDate" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "includeOptimisticProposals" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "includeOptimisticProposals" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "items" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "daoId" } }, { "kind": "Field", "name": { "kind": "Name", "value": "proposerAccountId" } }, { "kind": "Field", "name": { "kind": "Name", "value": "title" } }, { "kind": "Field", "name": { "kind": "Name", "value": "description" } }, { "kind": "Field", "name": { "kind": "Name", "value": "startBlock" } }, { "kind": "Field", "name": { "kind": "Name", "value": "endBlock" } }, { "kind": "Field", "name": { "kind": "Name", "value": "endTimestamp" } }, { "kind": "Field", "name": { "kind": "Name", "value": "timestamp" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }, { "kind": "Field", "name": { "kind": "Name", "value": "forVotes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "againstVotes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "abstainVotes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "txHash" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "totalCount" } }] } }] } }] }; +exports.GetEventRelevanceThresholdDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "GetEventRelevanceThreshold" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "relevance" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "queryInput_getEventRelevanceThreshold_relevance" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "type" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "queryInput_getEventRelevanceThreshold_type" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "getEventRelevanceThreshold" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "relevance" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "relevance" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "type" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "type" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "threshold" } }] } }] } }] }; exports.ListVotesDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "ListVotes" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "voterAddressIn" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "JSON" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "fromDate" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Float" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "toDate" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Float" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "limit" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Float" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "skip" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "NonNegativeInt" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "orderBy" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "queryInput_votes_orderBy" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "orderDirection" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "queryInput_votes_orderDirection" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "support" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Float" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "votes" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "voterAddressIn" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "voterAddressIn" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "fromDate" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "fromDate" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "toDate" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "toDate" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "limit" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "limit" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "skip" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "skip" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "orderBy" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "orderBy" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "orderDirection" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "orderDirection" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "support" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "support" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "items" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "transactionHash" } }, { "kind": "Field", "name": { "kind": "Name", "value": "proposalId" } }, { "kind": "Field", "name": { "kind": "Name", "value": "voterAddress" } }, { "kind": "Field", "name": { "kind": "Name", "value": "support" } }, { "kind": "Field", "name": { "kind": "Name", "value": "votingPower" } }, { "kind": "Field", "name": { "kind": "Name", "value": "timestamp" } }, { "kind": "Field", "name": { "kind": "Name", "value": "reason" } }, { "kind": "Field", "name": { "kind": "Name", "value": "proposalTitle" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "totalCount" } }] } }] } }] }; exports.ListHistoricalVotingPowerDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "ListHistoricalVotingPower" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "limit" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "PositiveInt" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "skip" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "NonNegativeInt" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "orderBy" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "queryInput_historicalVotingPower_orderBy" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "orderDirection" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "queryInput_historicalVotingPower_orderDirection" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "fromDate" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "String" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "address" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "String" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "historicalVotingPower" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "limit" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "limit" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "skip" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "skip" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "orderBy" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "orderBy" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "orderDirection" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "orderDirection" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "fromDate" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "fromDate" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "address" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "address" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "items" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "accountId" } }, { "kind": "Field", "name": { "kind": "Name", "value": "timestamp" } }, { "kind": "Field", "name": { "kind": "Name", "value": "votingPower" } }, { "kind": "Field", "name": { "kind": "Name", "value": "delta" } }, { "kind": "Field", "name": { "kind": "Name", "value": "daoId" } }, { "kind": "Field", "name": { "kind": "Name", "value": "transactionHash" } }, { "kind": "Field", "name": { "kind": "Name", "value": "logIndex" } }, { "kind": "Field", "name": { "kind": "Name", "value": "delegation" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "from" } }, { "kind": "Field", "name": { "kind": "Name", "value": "to" } }, { "kind": "Field", "name": { "kind": "Name", "value": "value" } }, { "kind": "Field", "name": { "kind": "Name", "value": "previousDelegate" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "transfer" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "from" } }, { "kind": "Field", "name": { "kind": "Name", "value": "to" } }, { "kind": "Field", "name": { "kind": "Name", "value": "value" } }] } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "totalCount" } }] } }] } }] }; diff --git a/packages/anticapture-client/dist/index.d.ts b/packages/anticapture-client/dist/index.d.ts index 0adeebe1..0ad05ea7 100644 --- a/packages/anticapture-client/dist/index.d.ts +++ b/packages/anticapture-client/dist/index.d.ts @@ -3,3 +3,4 @@ export type { VoteWithDaoId } from './anticapture-client'; export type { GetDaOsQuery, GetProposalByIdQuery, GetProposalByIdQueryVariables, ListProposalsQuery, ListProposalsQueryVariables, ListVotesQuery, ListVotesQueryVariables, ListHistoricalVotingPowerQuery, ListHistoricalVotingPowerQueryVariables } from './gql/graphql'; export { QueryInput_Proposals_OrderDirection, QueryInput_HistoricalVotingPower_OrderBy, QueryInput_HistoricalVotingPower_OrderDirection, QueryInput_Votes_OrderBy, QueryInput_Votes_OrderDirection } from './gql/graphql'; export type { ProcessedVotingPowerHistory } from './schemas'; +export { FeedEventType, FeedRelevance } from './schemas'; diff --git a/packages/anticapture-client/dist/index.js b/packages/anticapture-client/dist/index.js index 21152cc1..bd19ec5f 100644 --- a/packages/anticapture-client/dist/index.js +++ b/packages/anticapture-client/dist/index.js @@ -1,6 +1,6 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -exports.QueryInput_Votes_OrderDirection = exports.QueryInput_Votes_OrderBy = exports.QueryInput_HistoricalVotingPower_OrderDirection = exports.QueryInput_HistoricalVotingPower_OrderBy = exports.QueryInput_Proposals_OrderDirection = exports.AnticaptureClient = void 0; +exports.FeedRelevance = exports.FeedEventType = exports.QueryInput_Votes_OrderDirection = exports.QueryInput_Votes_OrderBy = exports.QueryInput_HistoricalVotingPower_OrderDirection = exports.QueryInput_HistoricalVotingPower_OrderBy = exports.QueryInput_Proposals_OrderDirection = exports.AnticaptureClient = void 0; var anticapture_client_1 = require("./anticapture-client"); Object.defineProperty(exports, "AnticaptureClient", { enumerable: true, get: function () { return anticapture_client_1.AnticaptureClient; } }); // Export GraphQL enums @@ -10,3 +10,6 @@ Object.defineProperty(exports, "QueryInput_HistoricalVotingPower_OrderBy", { enu Object.defineProperty(exports, "QueryInput_HistoricalVotingPower_OrderDirection", { enumerable: true, get: function () { return graphql_1.QueryInput_HistoricalVotingPower_OrderDirection; } }); Object.defineProperty(exports, "QueryInput_Votes_OrderBy", { enumerable: true, get: function () { return graphql_1.QueryInput_Votes_OrderBy; } }); Object.defineProperty(exports, "QueryInput_Votes_OrderDirection", { enumerable: true, get: function () { return graphql_1.QueryInput_Votes_OrderDirection; } }); +var schemas_1 = require("./schemas"); +Object.defineProperty(exports, "FeedEventType", { enumerable: true, get: function () { return schemas_1.FeedEventType; } }); +Object.defineProperty(exports, "FeedRelevance", { enumerable: true, get: function () { return schemas_1.FeedRelevance; } }); diff --git a/packages/anticapture-client/dist/schemas.d.ts b/packages/anticapture-client/dist/schemas.d.ts index ca577146..f890d762 100644 --- a/packages/anticapture-client/dist/schemas.d.ts +++ b/packages/anticapture-client/dist/schemas.d.ts @@ -1,4 +1,5 @@ import { z } from 'zod'; +export { QueryInput_GetEventRelevanceThreshold_Type as FeedEventType, QueryInput_GetEventRelevanceThreshold_Relevance as FeedRelevance, } from './gql/graphql'; export declare const SafeDaosResponseSchema: z.ZodEffects; }, "strip", z.ZodTypeAny, { + value: string; from: string; to: string; - value: string; previousDelegate: string | null; }, { + value: string; from: string; to: string; - value: string; previousDelegate: string | null; }>>; transfer: z.ZodNullable>; }, "strip", z.ZodTypeAny, { - delta: string; timestamp: string; + delta: string; votingPower: string; daoId: string; transactionHash: string; accountId: string; logIndex: number; delegation: { + value: string; from: string; to: string; - value: string; previousDelegate: string | null; } | null; transfer: { + value: string; from: string; to: string; - value: string; } | null; }, { - delta: string; timestamp: string; + delta: string; votingPower: string; daoId: string; transactionHash: string; accountId: string; logIndex: number; delegation: { + value: string; from: string; to: string; - value: string; previousDelegate: string | null; } | null; transfer: { + value: string; from: string; to: string; - value: string; } | null; }>; export declare const SafeHistoricalVotingPowerResponseSchema: z.ZodEffects; }, "strip", z.ZodTypeAny, { + value: string; from: string; to: string; - value: string; previousDelegate: string | null; }, { + value: string; from: string; to: string; - value: string; previousDelegate: string | null; }>>; transfer: z.ZodNullable>; }, "strip", z.ZodTypeAny, { - delta: string; timestamp: string; + delta: string; votingPower: string; daoId: string; transactionHash: string; accountId: string; logIndex: number; delegation: { + value: string; from: string; to: string; - value: string; previousDelegate: string | null; } | null; transfer: { + value: string; from: string; to: string; - value: string; } | null; }, { - delta: string; timestamp: string; + delta: string; votingPower: string; daoId: string; transactionHash: string; accountId: string; logIndex: number; delegation: { + value: string; from: string; to: string; - value: string; previousDelegate: string | null; } | null; transfer: { + value: string; from: string; to: string; - value: string; } | null; }>>, "many">; totalCount: z.ZodNumber; }, "strip", z.ZodTypeAny, { items: ({ - delta: string; timestamp: string; + delta: string; votingPower: string; daoId: string; transactionHash: string; accountId: string; logIndex: number; delegation: { + value: string; from: string; to: string; - value: string; previousDelegate: string | null; } | null; transfer: { + value: string; from: string; to: string; - value: string; } | null; } | null)[]; totalCount: number; }, { items: ({ - delta: string; timestamp: string; + delta: string; votingPower: string; daoId: string; transactionHash: string; accountId: string; logIndex: number; delegation: { + value: string; from: string; to: string; - value: string; previousDelegate: string | null; } | null; transfer: { + value: string; from: string; to: string; - value: string; } | null; } | null)[]; totalCount: number; @@ -302,23 +303,23 @@ export declare const SafeHistoricalVotingPowerResponseSchema: z.ZodEffects, { historicalVotingPower: { items: { - delta: string; timestamp: string; + delta: string; votingPower: string; daoId: string; transactionHash: string; accountId: string; logIndex: number; delegation: { + value: string; from: string; to: string; - value: string; previousDelegate: string | null; } | null; transfer: { + value: string; from: string; to: string; - value: string; } | null; }[]; totalCount: number; @@ -374,23 +375,23 @@ export declare const SafeHistoricalVotingPowerResponseSchema: z.ZodEffects; +export declare const EventThresholdResponseSchema: z.ZodObject<{ + getEventRelevanceThreshold: z.ZodObject<{ + threshold: z.ZodString; + }, "strip", z.ZodTypeAny, { + threshold: string; + }, { + threshold: string; + }>; +}, "strip", z.ZodTypeAny, { + getEventRelevanceThreshold: { + threshold: string; + }; +}, { + getEventRelevanceThreshold: { + threshold: string; + }; +}>; type SafeProposalsResponse = z.infer; type SafeHistoricalVotingPowerResponse = z.infer; export type ProcessedVotingPowerHistory = z.infer & { @@ -571,4 +589,3 @@ export type ProcessedVotingPowerHistory = z.infer { From 203e29f0f55db02140eb55958518bcccc3449029 Mon Sep 17 00:00:00 2001 From: Leonardo Vieira Date: Wed, 4 Mar 2026 10:33:08 -0300 Subject: [PATCH 19/42] feat: gql files --- packages/anticapture-client/src/gql/gql.ts | 6 + .../anticapture-client/src/gql/graphql.ts | 235 ++++++++++++++++-- 2 files changed, 225 insertions(+), 16 deletions(-) diff --git a/packages/anticapture-client/src/gql/gql.ts b/packages/anticapture-client/src/gql/gql.ts index 23ec75f5..8c125009 100644 --- a/packages/anticapture-client/src/gql/gql.ts +++ b/packages/anticapture-client/src/gql/gql.ts @@ -17,6 +17,7 @@ type Documents = { "query GetDAOs {\n daos {\n items {\n id\n votingDelay\n chainId\n }\n }\n}": typeof types.GetDaOsDocument, "query ProposalNonVoters($id: String!, $addresses: JSON) {\n proposalNonVoters(id: $id, addresses: $addresses) {\n items {\n voter\n }\n }\n}": typeof types.ProposalNonVotersDocument, "query GetProposalById($id: String!) {\n proposal(id: $id) {\n id\n daoId\n proposerAccountId\n title\n description\n startBlock\n endBlock\n endTimestamp\n timestamp\n status\n forVotes\n againstVotes\n abstainVotes\n txHash\n }\n}\n\nquery ListProposals($skip: NonNegativeInt, $limit: PositiveInt, $orderDirection: queryInput_proposals_orderDirection, $status: JSON, $fromDate: Float, $fromEndDate: Float, $includeOptimisticProposals: queryInput_proposals_includeOptimisticProposals) {\n proposals(\n skip: $skip\n limit: $limit\n orderDirection: $orderDirection\n status: $status\n fromDate: $fromDate\n fromEndDate: $fromEndDate\n includeOptimisticProposals: $includeOptimisticProposals\n ) {\n items {\n id\n daoId\n proposerAccountId\n title\n description\n startBlock\n endBlock\n endTimestamp\n timestamp\n status\n forVotes\n againstVotes\n abstainVotes\n txHash\n }\n totalCount\n }\n}": typeof types.GetProposalByIdDocument, + "query GetEventRelevanceThreshold($relevance: queryInput_getEventRelevanceThreshold_relevance!, $type: queryInput_getEventRelevanceThreshold_type!) {\n getEventRelevanceThreshold(relevance: $relevance, type: $type) {\n threshold\n }\n}": typeof types.GetEventRelevanceThresholdDocument, "query ListVotes($voterAddressIn: JSON, $fromDate: Float, $toDate: Float, $limit: Float, $skip: NonNegativeInt, $orderBy: queryInput_votes_orderBy, $orderDirection: queryInput_votes_orderDirection, $support: Float) {\n votes(\n voterAddressIn: $voterAddressIn\n fromDate: $fromDate\n toDate: $toDate\n limit: $limit\n skip: $skip\n orderBy: $orderBy\n orderDirection: $orderDirection\n support: $support\n ) {\n items {\n transactionHash\n proposalId\n voterAddress\n support\n votingPower\n timestamp\n reason\n proposalTitle\n }\n totalCount\n }\n}": typeof types.ListVotesDocument, "query ListHistoricalVotingPower($limit: PositiveInt, $skip: NonNegativeInt, $orderBy: queryInput_historicalVotingPower_orderBy, $orderDirection: queryInput_historicalVotingPower_orderDirection, $fromDate: String, $address: String) {\n historicalVotingPower(\n limit: $limit\n skip: $skip\n orderBy: $orderBy\n orderDirection: $orderDirection\n fromDate: $fromDate\n address: $address\n ) {\n items {\n accountId\n timestamp\n votingPower\n delta\n daoId\n transactionHash\n logIndex\n delegation {\n from\n to\n value\n previousDelegate\n }\n transfer {\n from\n to\n value\n }\n }\n totalCount\n }\n}": typeof types.ListHistoricalVotingPowerDocument, }; @@ -24,6 +25,7 @@ const documents: Documents = { "query GetDAOs {\n daos {\n items {\n id\n votingDelay\n chainId\n }\n }\n}": types.GetDaOsDocument, "query ProposalNonVoters($id: String!, $addresses: JSON) {\n proposalNonVoters(id: $id, addresses: $addresses) {\n items {\n voter\n }\n }\n}": types.ProposalNonVotersDocument, "query GetProposalById($id: String!) {\n proposal(id: $id) {\n id\n daoId\n proposerAccountId\n title\n description\n startBlock\n endBlock\n endTimestamp\n timestamp\n status\n forVotes\n againstVotes\n abstainVotes\n txHash\n }\n}\n\nquery ListProposals($skip: NonNegativeInt, $limit: PositiveInt, $orderDirection: queryInput_proposals_orderDirection, $status: JSON, $fromDate: Float, $fromEndDate: Float, $includeOptimisticProposals: queryInput_proposals_includeOptimisticProposals) {\n proposals(\n skip: $skip\n limit: $limit\n orderDirection: $orderDirection\n status: $status\n fromDate: $fromDate\n fromEndDate: $fromEndDate\n includeOptimisticProposals: $includeOptimisticProposals\n ) {\n items {\n id\n daoId\n proposerAccountId\n title\n description\n startBlock\n endBlock\n endTimestamp\n timestamp\n status\n forVotes\n againstVotes\n abstainVotes\n txHash\n }\n totalCount\n }\n}": types.GetProposalByIdDocument, + "query GetEventRelevanceThreshold($relevance: queryInput_getEventRelevanceThreshold_relevance!, $type: queryInput_getEventRelevanceThreshold_type!) {\n getEventRelevanceThreshold(relevance: $relevance, type: $type) {\n threshold\n }\n}": types.GetEventRelevanceThresholdDocument, "query ListVotes($voterAddressIn: JSON, $fromDate: Float, $toDate: Float, $limit: Float, $skip: NonNegativeInt, $orderBy: queryInput_votes_orderBy, $orderDirection: queryInput_votes_orderDirection, $support: Float) {\n votes(\n voterAddressIn: $voterAddressIn\n fromDate: $fromDate\n toDate: $toDate\n limit: $limit\n skip: $skip\n orderBy: $orderBy\n orderDirection: $orderDirection\n support: $support\n ) {\n items {\n transactionHash\n proposalId\n voterAddress\n support\n votingPower\n timestamp\n reason\n proposalTitle\n }\n totalCount\n }\n}": types.ListVotesDocument, "query ListHistoricalVotingPower($limit: PositiveInt, $skip: NonNegativeInt, $orderBy: queryInput_historicalVotingPower_orderBy, $orderDirection: queryInput_historicalVotingPower_orderDirection, $fromDate: String, $address: String) {\n historicalVotingPower(\n limit: $limit\n skip: $skip\n orderBy: $orderBy\n orderDirection: $orderDirection\n fromDate: $fromDate\n address: $address\n ) {\n items {\n accountId\n timestamp\n votingPower\n delta\n daoId\n transactionHash\n logIndex\n delegation {\n from\n to\n value\n previousDelegate\n }\n transfer {\n from\n to\n value\n }\n }\n totalCount\n }\n}": types.ListHistoricalVotingPowerDocument, }; @@ -54,6 +56,10 @@ export function graphql(source: "query ProposalNonVoters($id: String!, $addresse * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "query GetProposalById($id: String!) {\n proposal(id: $id) {\n id\n daoId\n proposerAccountId\n title\n description\n startBlock\n endBlock\n endTimestamp\n timestamp\n status\n forVotes\n againstVotes\n abstainVotes\n txHash\n }\n}\n\nquery ListProposals($skip: NonNegativeInt, $limit: PositiveInt, $orderDirection: queryInput_proposals_orderDirection, $status: JSON, $fromDate: Float, $fromEndDate: Float, $includeOptimisticProposals: queryInput_proposals_includeOptimisticProposals) {\n proposals(\n skip: $skip\n limit: $limit\n orderDirection: $orderDirection\n status: $status\n fromDate: $fromDate\n fromEndDate: $fromEndDate\n includeOptimisticProposals: $includeOptimisticProposals\n ) {\n items {\n id\n daoId\n proposerAccountId\n title\n description\n startBlock\n endBlock\n endTimestamp\n timestamp\n status\n forVotes\n againstVotes\n abstainVotes\n txHash\n }\n totalCount\n }\n}"): (typeof documents)["query GetProposalById($id: String!) {\n proposal(id: $id) {\n id\n daoId\n proposerAccountId\n title\n description\n startBlock\n endBlock\n endTimestamp\n timestamp\n status\n forVotes\n againstVotes\n abstainVotes\n txHash\n }\n}\n\nquery ListProposals($skip: NonNegativeInt, $limit: PositiveInt, $orderDirection: queryInput_proposals_orderDirection, $status: JSON, $fromDate: Float, $fromEndDate: Float, $includeOptimisticProposals: queryInput_proposals_includeOptimisticProposals) {\n proposals(\n skip: $skip\n limit: $limit\n orderDirection: $orderDirection\n status: $status\n fromDate: $fromDate\n fromEndDate: $fromEndDate\n includeOptimisticProposals: $includeOptimisticProposals\n ) {\n items {\n id\n daoId\n proposerAccountId\n title\n description\n startBlock\n endBlock\n endTimestamp\n timestamp\n status\n forVotes\n againstVotes\n abstainVotes\n txHash\n }\n totalCount\n }\n}"]; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function graphql(source: "query GetEventRelevanceThreshold($relevance: queryInput_getEventRelevanceThreshold_relevance!, $type: queryInput_getEventRelevanceThreshold_type!) {\n getEventRelevanceThreshold(relevance: $relevance, type: $type) {\n threshold\n }\n}"): (typeof documents)["query GetEventRelevanceThreshold($relevance: queryInput_getEventRelevanceThreshold_relevance!, $type: queryInput_getEventRelevanceThreshold_type!) {\n getEventRelevanceThreshold(relevance: $relevance, type: $type) {\n threshold\n }\n}"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/packages/anticapture-client/src/gql/graphql.ts b/packages/anticapture-client/src/gql/graphql.ts index d2f56ebc..a79e86c5 100644 --- a/packages/anticapture-client/src/gql/graphql.ts +++ b/packages/anticapture-client/src/gql/graphql.ts @@ -115,10 +115,16 @@ export type Query = { daos: DaoList; /** Get delegation percentage day buckets with forward-fill */ delegationPercentageByDay?: Maybe; - /** Get current delegators of an account */ + /** Get current delegations for an account */ delegations?: Maybe; + /** Get current delegators of an account with voting power */ + delegators?: Maybe; + /** Get feed events */ + feedEvents?: Maybe; /** Get historical DAO Token Treasury value (governance token quantity × token price) */ getDaoTokenTreasury?: Maybe; + /** Get event relevance threshold */ + getEventRelevanceThreshold?: Maybe; /** Get historical Liquid Treasury (treasury without DAO tokens) from external providers (DefiLlama/Dune) */ getLiquidTreasury?: Maybe; /** Get historical Total Treasury (liquid treasury + DAO token treasury) */ @@ -168,6 +174,8 @@ export type Query = { export type QueryAccountBalanceByAccountIdArgs = { address: Scalars['String']['input']; + fromDate?: InputMaybe; + toDate?: InputMaybe; }; @@ -191,10 +199,13 @@ export type QueryAccountBalanceVariationsByAccountIdArgs = { export type QueryAccountBalancesArgs = { addresses?: InputMaybe; delegates?: InputMaybe; + fromDate?: InputMaybe; fromValue?: InputMaybe; limit?: InputMaybe; + orderBy?: InputMaybe; orderDirection?: InputMaybe; skip?: InputMaybe; + toDate?: InputMaybe; toValue?: InputMaybe; }; @@ -293,12 +304,39 @@ export type QueryDelegationsArgs = { }; +export type QueryDelegatorsArgs = { + address: Scalars['String']['input']; + limit?: InputMaybe; + orderBy?: InputMaybe; + orderDirection?: InputMaybe; + skip?: InputMaybe; +}; + + +export type QueryFeedEventsArgs = { + fromDate?: InputMaybe; + limit?: InputMaybe; + orderBy?: InputMaybe; + orderDirection?: InputMaybe; + relevance?: InputMaybe; + skip?: InputMaybe; + toDate?: InputMaybe; + type?: InputMaybe; +}; + + export type QueryGetDaoTokenTreasuryArgs = { days?: InputMaybe; order?: InputMaybe; }; +export type QueryGetEventRelevanceThresholdArgs = { + relevance: QueryInput_GetEventRelevanceThreshold_Relevance; + type: QueryInput_GetEventRelevanceThreshold_Type; +}; + + export type QueryGetLiquidTreasuryArgs = { days?: InputMaybe; order?: InputMaybe; @@ -481,6 +519,8 @@ export type QueryVotesByProposalIdArgs = { export type QueryVotingPowerByAccountIdArgs = { accountId: Scalars['String']['input']; + fromDate?: InputMaybe; + toDate?: InputMaybe; }; @@ -503,20 +543,20 @@ export type QueryVotingPowerVariationsByAccountIdArgs = { export type QueryVotingPowersArgs = { addresses?: InputMaybe; + fromDate?: InputMaybe; fromValue?: InputMaybe; limit?: InputMaybe; orderBy?: InputMaybe; orderDirection?: InputMaybe; skip?: InputMaybe; + toDate?: InputMaybe; toValue?: InputMaybe; }; export type AccountBalanceByAccountId_200_Response = { __typename?: 'accountBalanceByAccountId_200_response'; - address: Scalars['String']['output']; - balance: Scalars['String']['output']; - delegate: Scalars['String']['output']; - tokenId: Scalars['String']['output']; + data: Query_AccountBalanceByAccountId_Data; + period: Query_AccountBalanceByAccountId_Period; }; export type AccountBalanceVariationsByAccountId_200_Response = { @@ -534,6 +574,7 @@ export type AccountBalanceVariations_200_Response = { export type AccountBalances_200_Response = { __typename?: 'accountBalances_200_response'; items: Array>; + period: Query_AccountBalances_Period; totalCount: Scalars['Float']['output']; }; @@ -643,6 +684,18 @@ export type Delegations_200_Response = { totalCount: Scalars['Float']['output']; }; +export type Delegators_200_Response = { + __typename?: 'delegators_200_response'; + items: Array>; + totalCount: Scalars['Float']['output']; +}; + +export type FeedEvents_200_Response = { + __typename?: 'feedEvents_200_response'; + items: Array>; + totalCount: Scalars['Float']['output']; +}; + export type GetDaoTokenTreasury_200_Response = { __typename?: 'getDaoTokenTreasury_200_response'; items: Array>; @@ -650,6 +703,11 @@ export type GetDaoTokenTreasury_200_Response = { totalCount: Scalars['Float']['output']; }; +export type GetEventRelevanceThreshold_200_Response = { + __typename?: 'getEventRelevanceThreshold_200_response'; + threshold: Scalars['String']['output']; +}; + export type GetLiquidTreasury_200_Response = { __typename?: 'getLiquidTreasury_200_response'; items: Array>; @@ -718,7 +776,7 @@ export type Proposal_200_Response = { status: Scalars['String']['output']; targets: Array>; timestamp: Scalars['String']['output']; - title: Scalars['String']['output']; + title?: Maybe; txHash: Scalars['String']['output']; values: Array>; }; @@ -746,6 +804,11 @@ export enum QueryInput_AccountBalanceVariations_OrderDirection { Desc = 'desc' } +export enum QueryInput_AccountBalances_OrderBy { + Balance = 'balance', + Variation = 'variation' +} + export enum QueryInput_AccountBalances_OrderDirection { Asc = 'asc', Desc = 'desc' @@ -854,6 +917,40 @@ export enum QueryInput_DelegationPercentageByDay_OrderDirection { Desc = 'desc' } +export enum QueryInput_Delegators_OrderBy { + Amount = 'amount', + Timestamp = 'timestamp' +} + +export enum QueryInput_Delegators_OrderDirection { + Asc = 'asc', + Desc = 'desc' +} + +export enum QueryInput_FeedEvents_OrderBy { + Timestamp = 'timestamp', + Value = 'value' +} + +export enum QueryInput_FeedEvents_OrderDirection { + Asc = 'asc', + Desc = 'desc' +} + +export enum QueryInput_FeedEvents_Relevance { + High = 'HIGH', + Low = 'LOW', + Medium = 'MEDIUM' +} + +export enum QueryInput_FeedEvents_Type { + Delegation = 'DELEGATION', + Proposal = 'PROPOSAL', + ProposalExtended = 'PROPOSAL_EXTENDED', + Transfer = 'TRANSFER', + Vote = 'VOTE' +} + export enum QueryInput_GetDaoTokenTreasury_Days { '7d' = '_7d', '30d' = '_30d', @@ -867,6 +964,20 @@ export enum QueryInput_GetDaoTokenTreasury_Order { Desc = 'desc' } +export enum QueryInput_GetEventRelevanceThreshold_Relevance { + High = 'HIGH', + Low = 'LOW', + Medium = 'MEDIUM' +} + +export enum QueryInput_GetEventRelevanceThreshold_Type { + Delegation = 'DELEGATION', + Proposal = 'PROPOSAL', + ProposalExtended = 'PROPOSAL_EXTENDED', + Transfer = 'TRANSFER', + Vote = 'VOTE' +} + export enum QueryInput_GetLiquidTreasury_Days { '7d' = '_7d', '30d' = '_30d', @@ -1030,6 +1141,7 @@ export enum QueryInput_VotingPowerVariations_OrderDirection { export enum QueryInput_VotingPowers_OrderBy { DelegationsCount = 'delegationsCount', + Variation = 'variation', VotingPower = 'votingPower' } @@ -1038,6 +1150,28 @@ export enum QueryInput_VotingPowers_OrderDirection { Desc = 'desc' } +export type Query_AccountBalanceByAccountId_Data = { + __typename?: 'query_accountBalanceByAccountId_data'; + address: Scalars['String']['output']; + balance: Scalars['String']['output']; + delegate: Scalars['String']['output']; + tokenId: Scalars['String']['output']; + variation: Query_AccountBalanceByAccountId_Data_Variation; +}; + +export type Query_AccountBalanceByAccountId_Data_Variation = { + __typename?: 'query_accountBalanceByAccountId_data_variation'; + absoluteChange: Scalars['String']['output']; + percentageChange: Scalars['String']['output']; + previousBalance: Scalars['String']['output']; +}; + +export type Query_AccountBalanceByAccountId_Period = { + __typename?: 'query_accountBalanceByAccountId_period'; + endTimestamp: Scalars['String']['output']; + startTimestamp: Scalars['String']['output']; +}; + export type Query_AccountBalanceVariationsByAccountId_Data = { __typename?: 'query_accountBalanceVariationsByAccountId_data'; absoluteChange: Scalars['String']['output']; @@ -1074,6 +1208,20 @@ export type Query_AccountBalances_Items_Items = { balance: Scalars['String']['output']; delegate: Scalars['String']['output']; tokenId: Scalars['String']['output']; + variation: Query_AccountBalances_Items_Items_Variation; +}; + +export type Query_AccountBalances_Items_Items_Variation = { + __typename?: 'query_accountBalances_items_items_variation'; + absoluteChange: Scalars['String']['output']; + percentageChange: Scalars['String']['output']; + previousBalance: Scalars['String']['output']; +}; + +export type Query_AccountBalances_Period = { + __typename?: 'query_accountBalances_period'; + endTimestamp: Scalars['String']['output']; + startTimestamp: Scalars['String']['output']; }; export type Query_AccountInteractions_Items_Items = { @@ -1112,6 +1260,38 @@ export type Query_Delegations_Items_Items = { transactionHash: Scalars['String']['output']; }; +export type Query_Delegators_Items_Items = { + __typename?: 'query_delegators_items_items'; + amount: Scalars['String']['output']; + delegatorAddress: Scalars['String']['output']; + timestamp: Scalars['String']['output']; +}; + +export type Query_FeedEvents_Items_Items = { + __typename?: 'query_feedEvents_items_items'; + logIndex: Scalars['Float']['output']; + metadata?: Maybe; + relevance: Query_FeedEvents_Items_Items_Relevance; + timestamp: Scalars['Float']['output']; + txHash: Scalars['String']['output']; + type: Query_FeedEvents_Items_Items_Type; + value?: Maybe; +}; + +export enum Query_FeedEvents_Items_Items_Relevance { + High = 'HIGH', + Low = 'LOW', + Medium = 'MEDIUM' +} + +export enum Query_FeedEvents_Items_Items_Type { + Delegation = 'DELEGATION', + Proposal = 'PROPOSAL', + ProposalExtended = 'PROPOSAL_EXTENDED', + Transfer = 'TRANSFER', + Vote = 'VOTE' +} + export type Query_GetDaoTokenTreasury_Items_Items = { __typename?: 'query_getDaoTokenTreasury_items_items'; /** Unix timestamp in milliseconds */ @@ -1285,7 +1465,7 @@ export type Query_Proposals_Items_Items = { status: Scalars['String']['output']; targets: Array>; timestamp: Scalars['String']['output']; - title: Scalars['String']['output']; + title?: Maybe; txHash: Scalars['String']['output']; values: Array>; }; @@ -1369,10 +1549,10 @@ export type Query_Transfers_Items_Items = { export type Query_VotesByProposalId_Items_Items = { __typename?: 'query_votesByProposalId_items_items'; proposalId: Scalars['String']['output']; - proposalTitle: Scalars['String']['output']; + proposalTitle?: Maybe; reason?: Maybe; - support: Scalars['Float']['output']; - timestamp: Scalars['Float']['output']; + support?: Maybe; + timestamp: Scalars['Int']['output']; transactionHash: Scalars['String']['output']; voterAddress: Scalars['String']['output']; votingPower: Scalars['String']['output']; @@ -1381,15 +1561,21 @@ export type Query_VotesByProposalId_Items_Items = { export type Query_Votes_Items_Items = { __typename?: 'query_votes_items_items'; proposalId: Scalars['String']['output']; - proposalTitle: Scalars['String']['output']; + proposalTitle?: Maybe; reason?: Maybe; - support: Scalars['Float']['output']; - timestamp: Scalars['Float']['output']; + support?: Maybe; + timestamp: Scalars['Int']['output']; transactionHash: Scalars['String']['output']; voterAddress: Scalars['String']['output']; votingPower: Scalars['String']['output']; }; +export type Query_VotingPowerByAccountId_Variation = { + __typename?: 'query_votingPowerByAccountId_variation'; + absoluteChange: Scalars['String']['output']; + percentageChange: Scalars['String']['output']; +}; + export type Query_VotingPowerVariationsByAccountId_Data = { __typename?: 'query_votingPowerVariationsByAccountId_data'; absoluteChange: Scalars['String']['output']; @@ -1425,10 +1611,17 @@ export type Query_VotingPowers_Items_Items = { accountId: Scalars['String']['output']; delegationsCount: Scalars['Float']['output']; proposalsCount: Scalars['Float']['output']; + variation: Query_VotingPowers_Items_Items_Variation; votesCount: Scalars['Float']['output']; votingPower: Scalars['String']['output']; }; +export type Query_VotingPowers_Items_Items_Variation = { + __typename?: 'query_votingPowers_items_items_variation'; + absoluteChange: Scalars['String']['output']; + percentageChange: Scalars['String']['output']; +}; + export enum Timestamp_Const { Timestamp = 'timestamp' } @@ -1483,6 +1676,7 @@ export type VotingPowerByAccountId_200_Response = { accountId: Scalars['String']['output']; delegationsCount: Scalars['Float']['output']; proposalsCount: Scalars['Float']['output']; + variation: Query_VotingPowerByAccountId_Variation; votesCount: Scalars['Float']['output']; votingPower: Scalars['String']['output']; }; @@ -1523,7 +1717,7 @@ export type GetProposalByIdQueryVariables = Exact<{ }>; -export type GetProposalByIdQuery = { __typename?: 'Query', proposal?: { __typename?: 'proposal_200_response', id: string, daoId: string, proposerAccountId: string, title: string, description: string, startBlock: number, endBlock: number, endTimestamp: string, timestamp: string, status: string, forVotes: string, againstVotes: string, abstainVotes: string, txHash: string } | null }; +export type GetProposalByIdQuery = { __typename?: 'Query', proposal?: { __typename?: 'proposal_200_response', id: string, daoId: string, proposerAccountId: string, title?: string | null, description: string, startBlock: number, endBlock: number, endTimestamp: string, timestamp: string, status: string, forVotes: string, againstVotes: string, abstainVotes: string, txHash: string } | null }; export type ListProposalsQueryVariables = Exact<{ skip?: InputMaybe; @@ -1536,7 +1730,15 @@ export type ListProposalsQueryVariables = Exact<{ }>; -export type ListProposalsQuery = { __typename?: 'Query', proposals?: { __typename?: 'proposals_200_response', totalCount: number, items: Array<{ __typename?: 'query_proposals_items_items', id: string, daoId: string, proposerAccountId: string, title: string, description: string, startBlock: number, endBlock: number, endTimestamp: string, timestamp: string, status: string, forVotes: string, againstVotes: string, abstainVotes: string, txHash: string } | null> } | null }; +export type ListProposalsQuery = { __typename?: 'Query', proposals?: { __typename?: 'proposals_200_response', totalCount: number, items: Array<{ __typename?: 'query_proposals_items_items', id: string, daoId: string, proposerAccountId: string, title?: string | null, description: string, startBlock: number, endBlock: number, endTimestamp: string, timestamp: string, status: string, forVotes: string, againstVotes: string, abstainVotes: string, txHash: string } | null> } | null }; + +export type GetEventRelevanceThresholdQueryVariables = Exact<{ + relevance: QueryInput_GetEventRelevanceThreshold_Relevance; + type: QueryInput_GetEventRelevanceThreshold_Type; +}>; + + +export type GetEventRelevanceThresholdQuery = { __typename?: 'Query', getEventRelevanceThreshold?: { __typename?: 'getEventRelevanceThreshold_200_response', threshold: string } | null }; export type ListVotesQueryVariables = Exact<{ voterAddressIn?: InputMaybe; @@ -1550,7 +1752,7 @@ export type ListVotesQueryVariables = Exact<{ }>; -export type ListVotesQuery = { __typename?: 'Query', votes?: { __typename?: 'votes_200_response', totalCount: number, items: Array<{ __typename?: 'query_votes_items_items', transactionHash: string, proposalId: string, voterAddress: string, support: number, votingPower: string, timestamp: number, reason?: string | null, proposalTitle: string } | null> } | null }; +export type ListVotesQuery = { __typename?: 'Query', votes?: { __typename?: 'votes_200_response', totalCount: number, items: Array<{ __typename?: 'query_votes_items_items', transactionHash: string, proposalId: string, voterAddress: string, support?: number | null, votingPower: string, timestamp: number, reason?: string | null, proposalTitle?: string | null } | null> } | null }; export type ListHistoricalVotingPowerQueryVariables = Exact<{ limit?: InputMaybe; @@ -1569,5 +1771,6 @@ export const GetDaOsDocument = {"kind":"Document","definitions":[{"kind":"Operat export const ProposalNonVotersDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ProposalNonVoters"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"addresses"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"proposalNonVoters"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}},{"kind":"Argument","name":{"kind":"Name","value":"addresses"},"value":{"kind":"Variable","name":{"kind":"Name","value":"addresses"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"voter"}}]}}]}}]}}]} as unknown as DocumentNode; export const GetProposalByIdDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetProposalById"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"proposal"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"daoId"}},{"kind":"Field","name":{"kind":"Name","value":"proposerAccountId"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"startBlock"}},{"kind":"Field","name":{"kind":"Name","value":"endBlock"}},{"kind":"Field","name":{"kind":"Name","value":"endTimestamp"}},{"kind":"Field","name":{"kind":"Name","value":"timestamp"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"forVotes"}},{"kind":"Field","name":{"kind":"Name","value":"againstVotes"}},{"kind":"Field","name":{"kind":"Name","value":"abstainVotes"}},{"kind":"Field","name":{"kind":"Name","value":"txHash"}}]}}]}}]} as unknown as DocumentNode; export const ListProposalsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ListProposals"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"skip"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"NonNegativeInt"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"limit"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PositiveInt"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"orderDirection"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"queryInput_proposals_orderDirection"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"status"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"fromDate"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"fromEndDate"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"includeOptimisticProposals"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"queryInput_proposals_includeOptimisticProposals"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"proposals"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"skip"},"value":{"kind":"Variable","name":{"kind":"Name","value":"skip"}}},{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"Variable","name":{"kind":"Name","value":"limit"}}},{"kind":"Argument","name":{"kind":"Name","value":"orderDirection"},"value":{"kind":"Variable","name":{"kind":"Name","value":"orderDirection"}}},{"kind":"Argument","name":{"kind":"Name","value":"status"},"value":{"kind":"Variable","name":{"kind":"Name","value":"status"}}},{"kind":"Argument","name":{"kind":"Name","value":"fromDate"},"value":{"kind":"Variable","name":{"kind":"Name","value":"fromDate"}}},{"kind":"Argument","name":{"kind":"Name","value":"fromEndDate"},"value":{"kind":"Variable","name":{"kind":"Name","value":"fromEndDate"}}},{"kind":"Argument","name":{"kind":"Name","value":"includeOptimisticProposals"},"value":{"kind":"Variable","name":{"kind":"Name","value":"includeOptimisticProposals"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"daoId"}},{"kind":"Field","name":{"kind":"Name","value":"proposerAccountId"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"startBlock"}},{"kind":"Field","name":{"kind":"Name","value":"endBlock"}},{"kind":"Field","name":{"kind":"Name","value":"endTimestamp"}},{"kind":"Field","name":{"kind":"Name","value":"timestamp"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"forVotes"}},{"kind":"Field","name":{"kind":"Name","value":"againstVotes"}},{"kind":"Field","name":{"kind":"Name","value":"abstainVotes"}},{"kind":"Field","name":{"kind":"Name","value":"txHash"}}]}},{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}}]}}]} as unknown as DocumentNode; +export const GetEventRelevanceThresholdDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetEventRelevanceThreshold"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"relevance"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"queryInput_getEventRelevanceThreshold_relevance"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"type"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"queryInput_getEventRelevanceThreshold_type"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getEventRelevanceThreshold"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"relevance"},"value":{"kind":"Variable","name":{"kind":"Name","value":"relevance"}}},{"kind":"Argument","name":{"kind":"Name","value":"type"},"value":{"kind":"Variable","name":{"kind":"Name","value":"type"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"threshold"}}]}}]}}]} as unknown as DocumentNode; export const ListVotesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ListVotes"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"voterAddressIn"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"fromDate"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"toDate"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"limit"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"skip"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"NonNegativeInt"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"orderBy"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"queryInput_votes_orderBy"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"orderDirection"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"queryInput_votes_orderDirection"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"support"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"votes"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"voterAddressIn"},"value":{"kind":"Variable","name":{"kind":"Name","value":"voterAddressIn"}}},{"kind":"Argument","name":{"kind":"Name","value":"fromDate"},"value":{"kind":"Variable","name":{"kind":"Name","value":"fromDate"}}},{"kind":"Argument","name":{"kind":"Name","value":"toDate"},"value":{"kind":"Variable","name":{"kind":"Name","value":"toDate"}}},{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"Variable","name":{"kind":"Name","value":"limit"}}},{"kind":"Argument","name":{"kind":"Name","value":"skip"},"value":{"kind":"Variable","name":{"kind":"Name","value":"skip"}}},{"kind":"Argument","name":{"kind":"Name","value":"orderBy"},"value":{"kind":"Variable","name":{"kind":"Name","value":"orderBy"}}},{"kind":"Argument","name":{"kind":"Name","value":"orderDirection"},"value":{"kind":"Variable","name":{"kind":"Name","value":"orderDirection"}}},{"kind":"Argument","name":{"kind":"Name","value":"support"},"value":{"kind":"Variable","name":{"kind":"Name","value":"support"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"transactionHash"}},{"kind":"Field","name":{"kind":"Name","value":"proposalId"}},{"kind":"Field","name":{"kind":"Name","value":"voterAddress"}},{"kind":"Field","name":{"kind":"Name","value":"support"}},{"kind":"Field","name":{"kind":"Name","value":"votingPower"}},{"kind":"Field","name":{"kind":"Name","value":"timestamp"}},{"kind":"Field","name":{"kind":"Name","value":"reason"}},{"kind":"Field","name":{"kind":"Name","value":"proposalTitle"}}]}},{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}}]}}]} as unknown as DocumentNode; export const ListHistoricalVotingPowerDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ListHistoricalVotingPower"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"limit"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PositiveInt"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"skip"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"NonNegativeInt"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"orderBy"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"queryInput_historicalVotingPower_orderBy"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"orderDirection"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"queryInput_historicalVotingPower_orderDirection"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"fromDate"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"address"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"historicalVotingPower"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"Variable","name":{"kind":"Name","value":"limit"}}},{"kind":"Argument","name":{"kind":"Name","value":"skip"},"value":{"kind":"Variable","name":{"kind":"Name","value":"skip"}}},{"kind":"Argument","name":{"kind":"Name","value":"orderBy"},"value":{"kind":"Variable","name":{"kind":"Name","value":"orderBy"}}},{"kind":"Argument","name":{"kind":"Name","value":"orderDirection"},"value":{"kind":"Variable","name":{"kind":"Name","value":"orderDirection"}}},{"kind":"Argument","name":{"kind":"Name","value":"fromDate"},"value":{"kind":"Variable","name":{"kind":"Name","value":"fromDate"}}},{"kind":"Argument","name":{"kind":"Name","value":"address"},"value":{"kind":"Variable","name":{"kind":"Name","value":"address"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"accountId"}},{"kind":"Field","name":{"kind":"Name","value":"timestamp"}},{"kind":"Field","name":{"kind":"Name","value":"votingPower"}},{"kind":"Field","name":{"kind":"Name","value":"delta"}},{"kind":"Field","name":{"kind":"Name","value":"daoId"}},{"kind":"Field","name":{"kind":"Name","value":"transactionHash"}},{"kind":"Field","name":{"kind":"Name","value":"logIndex"}},{"kind":"Field","name":{"kind":"Name","value":"delegation"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"from"}},{"kind":"Field","name":{"kind":"Name","value":"to"}},{"kind":"Field","name":{"kind":"Name","value":"value"}},{"kind":"Field","name":{"kind":"Name","value":"previousDelegate"}}]}},{"kind":"Field","name":{"kind":"Name","value":"transfer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"from"}},{"kind":"Field","name":{"kind":"Name","value":"to"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}}]}}]} as unknown as DocumentNode; \ No newline at end of file From 6521cb3d4214151b2870b053076e779018854f7a Mon Sep 17 00:00:00 2001 From: Leonardo Vieira Date: Wed, 4 Mar 2026 10:33:26 -0300 Subject: [PATCH 20/42] feat: GetEventRelevanceThreshold query --- packages/anticapture-client/queries/threshold.graphql | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 packages/anticapture-client/queries/threshold.graphql diff --git a/packages/anticapture-client/queries/threshold.graphql b/packages/anticapture-client/queries/threshold.graphql new file mode 100644 index 00000000..8ea5facb --- /dev/null +++ b/packages/anticapture-client/queries/threshold.graphql @@ -0,0 +1,5 @@ +query GetEventRelevanceThreshold($relevance: queryInput_getEventRelevanceThreshold_relevance!, $type: queryInput_getEventRelevanceThreshold_type!) { + getEventRelevanceThreshold(relevance: $relevance, type: $type) { + threshold + } +} \ No newline at end of file From c4feda8bfd5275de4bda6a9e112fc421a427582c Mon Sep 17 00:00:00 2001 From: Leonardo Vieira Date: Wed, 4 Mar 2026 10:35:04 -0300 Subject: [PATCH 21/42] add: threshold repo instance on app.ts --- apps/logic-system/src/app.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/logic-system/src/app.ts b/apps/logic-system/src/app.ts index 809a5d1d..89a7cf34 100644 --- a/apps/logic-system/src/app.ts +++ b/apps/logic-system/src/app.ts @@ -5,6 +5,7 @@ import { VoteConfirmationTrigger } from './triggers/vote-confirmation-trigger'; import { VotingReminderTrigger } from './triggers/voting-reminder-trigger'; import { ProposalRepository } from './repositories/proposal.repository'; import { VotingPowerRepository } from './repositories/voting-power.repository'; +import { ThresholdRepository } from './repositories/threshold.repository'; import { VotesRepository } from './repositories/votes.repository'; import { RabbitMQDispatcherService } from './api-clients/rabbitmq-dispatcher.service'; import { AnticaptureClient } from '@notification-system/anticapture-client'; @@ -37,15 +38,17 @@ export class App { const anticaptureClient = new AnticaptureClient(anticaptureHttpClient); const proposalRepository = new ProposalRepository(anticaptureClient); const votingPowerRepository = new VotingPowerRepository(anticaptureClient); + const thresholdRepository = new ThresholdRepository(anticaptureClient); const votesRepository = new VotesRepository(anticaptureClient); - this.initPromise = this.initializeRabbitMQ(rabbitmqUrl, proposalRepository, votingPowerRepository, votesRepository, triggerInterval, initialTimestamp); + this.initPromise = this.initializeRabbitMQ(rabbitmqUrl, proposalRepository, votingPowerRepository, thresholdRepository, votesRepository, triggerInterval, initialTimestamp); } private async initializeRabbitMQ( rabbitmqUrl: string, proposalRepository: ProposalRepository, votingPowerRepository: VotingPowerRepository, + thresholdRepository: ThresholdRepository, votesRepository: VotesRepository, triggerInterval: number, initialTimestamp?: string @@ -66,6 +69,7 @@ export class App { this.votingPowerTrigger = new VotingPowerChangedTrigger( dispatcherService, votingPowerRepository, + thresholdRepository, triggerInterval ); From 4e565ea2dabe3b6c88b8eb17acb5f283c0d1d9dd Mon Sep 17 00:00:00 2001 From: Leonardo Vieira Date: Wed, 4 Mar 2026 10:36:45 -0300 Subject: [PATCH 22/42] feat: threshold repository --- .../src/repositories/threshold.repository.ts | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 apps/logic-system/src/repositories/threshold.repository.ts diff --git a/apps/logic-system/src/repositories/threshold.repository.ts b/apps/logic-system/src/repositories/threshold.repository.ts new file mode 100644 index 00000000..4f3e7787 --- /dev/null +++ b/apps/logic-system/src/repositories/threshold.repository.ts @@ -0,0 +1,46 @@ +import { + AnticaptureClient, + FeedEventType, + FeedRelevance +} from '@notification-system/anticapture-client'; + +interface CacheEntry { + value: string; + fetchedAt: number; +} + +const ONE_DAY_MS = 86_400_000; + +export class ThresholdRepository { + private cache = new Map(); + + constructor( + private readonly anticaptureClient: AnticaptureClient, + private readonly cacheTtlMs: number = ONE_DAY_MS + ) {} + + async getThreshold(daoId: string, type: FeedEventType): Promise { + const cacheKey = `${daoId}:${type}`; + const cached = this.cache.get(cacheKey); + + if (cached && Date.now() - cached.fetchedAt < this.cacheTtlMs) { + return cached.value; + } + + try { + const threshold = await this.anticaptureClient.getEventThreshold(daoId, type, FeedRelevance.High); + + if (threshold !== null) { + this.cache.set(cacheKey, { value: threshold, fetchedAt: Date.now() }); + } + + return threshold; + } catch (error) { + console.warn( + `[ThresholdRepository] Error fetching threshold for ${daoId}/${type}:`, + error instanceof Error ? error.message : error + ); + return null; + } + } +} From 1fd2f75fb9fc6c6835d3737a7c661e8e096f1a13 Mon Sep 17 00:00:00 2001 From: Leonardo Vieira Date: Wed, 4 Mar 2026 10:39:12 -0300 Subject: [PATCH 23/42] fix: typesafety on dispatcher --- .../vote-confirmation-trigger.service.ts | 2 +- .../dist/anticapture-client.js | 11 +------ .../src/anticapture-client.ts | 33 +++++++++++++++++-- 3 files changed, 32 insertions(+), 14 deletions(-) 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 20292262..3188aa25 100644 --- a/apps/dispatcher/src/services/triggers/vote-confirmation-trigger.service.ts +++ b/apps/dispatcher/src/services/triggers/vote-confirmation-trigger.service.ts @@ -166,7 +166,7 @@ export class VoteConfirmationTriggerHandler extends BaseTriggerHandler['items']; type VotingPowerHistoryItems = ProcessedVotingPowerHistory[]; @@ -249,7 +249,7 @@ export class AnticaptureClient { variables, daoId ); - return validated.votes.items.filter((item): item is VoteItem => item !== null); + return validated.votes.items.filter(item => item !== null) as VoteItem[]; } catch (error) { console.warn(`Error fetching votes for DAO ${daoId}:`, error); return []; @@ -329,4 +329,31 @@ export class AnticaptureClient { return allVotes; } + + /** + * Fetches the event relevance threshold for a given DAO, event type, and relevance level. + * Used to filter out low-impact events (e.g., small delegation changes). + * @returns Threshold as a numeric string, or null if unavailable (fail-open) + */ + async getEventThreshold( + daoId: string, + type: FeedEventType, + relevance: FeedRelevance + ): Promise { + try { + const validated = await this.query( + GetEventRelevanceThresholdDocument, + EventThresholdResponseSchema, + { type, relevance }, + daoId + ); + return validated.getEventRelevanceThreshold.threshold; + } catch (error) { + console.warn( + `[AnticaptureClient] Error fetching threshold for ${daoId}/${type}:`, + error instanceof Error ? error.message : error + ); + return null; + } + } } \ No newline at end of file From 9446dd1e2c9396f96570678ae0ce4c0e443f9b7b Mon Sep 17 00:00:00 2001 From: Leonardo Vieira Date: Wed, 4 Mar 2026 10:43:03 -0300 Subject: [PATCH 24/42] refactor: vp trigger to filter by threshold --- .../triggers/voting-power-changed-trigger.ts | 34 +++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/apps/logic-system/src/triggers/voting-power-changed-trigger.ts b/apps/logic-system/src/triggers/voting-power-changed-trigger.ts index 70961b3f..0b047ac3 100644 --- a/apps/logic-system/src/triggers/voting-power-changed-trigger.ts +++ b/apps/logic-system/src/triggers/voting-power-changed-trigger.ts @@ -5,8 +5,9 @@ import { Trigger } from './base-trigger'; import { VotingPowerRepository } from '../repositories/voting-power.repository'; +import { ThresholdRepository } from '../repositories/threshold.repository'; import { DispatcherService, DispatcherMessage } from '../interfaces/dispatcher.interface'; -import { ProcessedVotingPowerHistory } from '@notification-system/anticapture-client'; +import { ProcessedVotingPowerHistory, FeedEventType } from '@notification-system/anticapture-client'; const triggerId = 'voting-power-changed'; @@ -16,6 +17,7 @@ export class VotingPowerChangedTrigger extends Trigger = { triggerId: this.id, - events: data + events: filtered }; await this.dispatcherService.sendMessage(message); + } - // Update the last processed timestamp to the most recent timestamp + 1 second - // Since data comes ordered by timestamp asc, the last item has the latest timestamp - // Adding 1 avoids reprocessing the same event since the API uses >= (gte) for fromDate - this.lastProcessedTimestamp = String(Number(data[data.length - 1].timestamp) + 1); + private async filterByThreshold( + data: ProcessedVotingPowerHistory[] + ): Promise { + const keep = await Promise.all( + data.map(async (event) => { + const type = event.changeType.toUpperCase(); + if (!Object.values(FeedEventType).includes(type as FeedEventType)) return true; + + const threshold = await this.thresholdRepository.getThreshold(event.daoId, type as FeedEventType); + return threshold === null || Math.abs(Number(event.delta)) >= Number(threshold); + }) + ); + + return data.filter((_, i) => keep[i]); } /** From 755e132c0e6198770b1342ea4d322c721d2dd3ee Mon Sep 17 00:00:00 2001 From: Leonardo Vieira Date: Wed, 4 Mar 2026 10:44:50 -0300 Subject: [PATCH 25/42] feat: logic system's tests --- apps/logic-system/tests/mocks.ts | 7 ++ .../tests/threshold-repository.test.ts | 102 ++++++++++++++++++ .../tests/voting-power-trigger.test.ts | 95 +++++++++++++++- 3 files changed, 203 insertions(+), 1 deletion(-) create mode 100644 apps/logic-system/tests/threshold-repository.test.ts diff --git a/apps/logic-system/tests/mocks.ts b/apps/logic-system/tests/mocks.ts index 6a809d36..079796de 100644 --- a/apps/logic-system/tests/mocks.ts +++ b/apps/logic-system/tests/mocks.ts @@ -105,6 +105,13 @@ export const createMockVotingPowerRepository = () => ({ listVotingPowerHistory: jest.fn() }); +/** + * Creates a mocked ThresholdRepository + */ +export const createMockThresholdRepository = () => ({ + getThreshold: jest.fn<() => Promise>() +}); + // Sample voting power data for tests export const mockVotingPowerData = [ createVotingPowerHistory(), diff --git a/apps/logic-system/tests/threshold-repository.test.ts b/apps/logic-system/tests/threshold-repository.test.ts new file mode 100644 index 00000000..8565adb4 --- /dev/null +++ b/apps/logic-system/tests/threshold-repository.test.ts @@ -0,0 +1,102 @@ +import { describe, it, expect, jest, beforeEach } from '@jest/globals'; +import { ThresholdRepository } from '../src/repositories/threshold.repository'; +import { FeedEventType, FeedRelevance } from '@notification-system/anticapture-client'; + +const createMockAnticaptureClient = () => ({ + getEventThreshold: jest.fn<() => Promise>() +}); + +describe('ThresholdRepository', () => { + let repository: ThresholdRepository; + let mockClient: ReturnType; + + beforeEach(() => { + jest.clearAllMocks(); + mockClient = createMockAnticaptureClient(); + repository = new ThresholdRepository(mockClient as any, 300_000); + }); + + describe('getThreshold', () => { + it('should fetch threshold from client on cache miss', async () => { + mockClient.getEventThreshold.mockResolvedValue('40000000000000000000000'); + + const result = await repository.getThreshold('ENS', FeedEventType.Delegation); + + expect(result).toBe('40000000000000000000000'); + expect(mockClient.getEventThreshold).toHaveBeenCalledWith( + 'ENS', FeedEventType.Delegation, FeedRelevance.High + ); + }); + + it('should return cached value on cache hit', async () => { + mockClient.getEventThreshold.mockResolvedValue('40000000000000000000000'); + + await repository.getThreshold('ENS', FeedEventType.Delegation); + const result = await repository.getThreshold('ENS', FeedEventType.Delegation); + + expect(result).toBe('40000000000000000000000'); + expect(mockClient.getEventThreshold).toHaveBeenCalledTimes(1); + }); + + it('should cache separately per daoId and type', async () => { + mockClient.getEventThreshold + .mockResolvedValueOnce('1000') + .mockResolvedValueOnce('2000') + .mockResolvedValueOnce('3000'); + + const r1 = await repository.getThreshold('ENS', FeedEventType.Delegation); + const r2 = await repository.getThreshold('ENS', FeedEventType.Transfer); + const r3 = await repository.getThreshold('UNISWAP', FeedEventType.Delegation); + + expect(r1).toBe('1000'); + expect(r2).toBe('2000'); + expect(r3).toBe('3000'); + expect(mockClient.getEventThreshold).toHaveBeenCalledTimes(3); + }); + + it('should refetch after TTL expires', async () => { + const shortTtlRepo = new ThresholdRepository(mockClient as any, 100); + mockClient.getEventThreshold + .mockResolvedValueOnce('1000') + .mockResolvedValueOnce('2000'); + + const r1 = await shortTtlRepo.getThreshold('ENS', FeedEventType.Delegation); + expect(r1).toBe('1000'); + + await new Promise(resolve => setTimeout(resolve, 150)); + + const r2 = await shortTtlRepo.getThreshold('ENS', FeedEventType.Delegation); + expect(r2).toBe('2000'); + expect(mockClient.getEventThreshold).toHaveBeenCalledTimes(2); + }); + + it('should return null when client returns null (fail-open)', async () => { + mockClient.getEventThreshold.mockResolvedValue(null); + + const result = await repository.getThreshold('ENS', FeedEventType.Delegation); + + expect(result).toBeNull(); + }); + + it('should not cache null responses', async () => { + mockClient.getEventThreshold + .mockResolvedValueOnce(null) + .mockResolvedValueOnce('5000'); + + const r1 = await repository.getThreshold('ENS', FeedEventType.Delegation); + const r2 = await repository.getThreshold('ENS', FeedEventType.Delegation); + + expect(r1).toBeNull(); + expect(r2).toBe('5000'); + expect(mockClient.getEventThreshold).toHaveBeenCalledTimes(2); + }); + + it('should return null when client throws (fail-open)', async () => { + mockClient.getEventThreshold.mockRejectedValue(new Error('Network error')); + + const result = await repository.getThreshold('ENS', FeedEventType.Delegation); + + expect(result).toBeNull(); + }); + }); +}); diff --git a/apps/logic-system/tests/voting-power-trigger.test.ts b/apps/logic-system/tests/voting-power-trigger.test.ts index 13d402b5..1e746d04 100644 --- a/apps/logic-system/tests/voting-power-trigger.test.ts +++ b/apps/logic-system/tests/voting-power-trigger.test.ts @@ -4,20 +4,24 @@ import { describe, it, expect, jest, beforeEach } from '@jest/globals'; import { VotingPowerChangedTrigger } from '../src/triggers/voting-power-changed-trigger'; -import { createMockDispatcherService, createMockVotingPowerRepository, mockVotingPowerData } from './mocks'; +import { createMockDispatcherService, createMockVotingPowerRepository, createMockThresholdRepository, createVotingPowerHistory, mockVotingPowerData } from './mocks'; describe('VotingPowerChangedTrigger', () => { let trigger: VotingPowerChangedTrigger; let mockDispatcherService: ReturnType; let mockVotingPowerRepository: ReturnType; + let mockThresholdRepository: ReturnType; beforeEach(() => { jest.clearAllMocks(); mockDispatcherService = createMockDispatcherService(); mockVotingPowerRepository = createMockVotingPowerRepository(); + mockThresholdRepository = createMockThresholdRepository(); + mockThresholdRepository.getThreshold.mockResolvedValue(null); trigger = new VotingPowerChangedTrigger( mockDispatcherService, mockVotingPowerRepository as any, + mockThresholdRepository as any, 5000 // 5 second interval for testing ); }); @@ -27,6 +31,7 @@ describe('VotingPowerChangedTrigger', () => { const trigger2 = new VotingPowerChangedTrigger( createMockDispatcherService(), createMockVotingPowerRepository() as any, + createMockThresholdRepository() as any, 5000 ); @@ -139,9 +144,97 @@ describe('VotingPowerChangedTrigger', () => { }); it('should handle dispatcher errors gracefully', async () => { + mockThresholdRepository.getThreshold.mockResolvedValue(null); mockDispatcherService.sendMessage.mockRejectedValue(new Error('Dispatcher Error')); await expect(trigger.process(mockVotingPowerData)).rejects.toThrow('Dispatcher Error'); }); }); + + describe('Threshold Filtering', () => { + it('should drop delegation events below threshold', async () => { + mockThresholdRepository.getThreshold.mockResolvedValue('500'); + + const events = [ + createVotingPowerHistory({ delta: '100', changeType: 'delegation', timestamp: '1000' }), + createVotingPowerHistory({ delta: '600', changeType: 'delegation', timestamp: '1001' }), + ]; + + await trigger.process(events); + + expect(mockDispatcherService.sendMessage).toHaveBeenCalledWith({ + triggerId: 'voting-power-changed', + events: [events[1]] + }); + }); + + it('should drop transfer events below threshold', async () => { + mockThresholdRepository.getThreshold.mockResolvedValue('200'); + + const events = [ + createVotingPowerHistory({ + delta: '50', changeType: 'transfer', timestamp: '1000', + delegation: null, + transfer: { from: '0x1', to: '0x2', value: '50' } + }), + createVotingPowerHistory({ + delta: '300', changeType: 'transfer', timestamp: '1001', + delegation: null, + transfer: { from: '0x1', to: '0x2', value: '300' } + }), + ]; + + await trigger.process(events); + + expect(mockDispatcherService.sendMessage).toHaveBeenCalledWith({ + triggerId: 'voting-power-changed', + events: [events[1]] + }); + }); + + it('should use abs(delta) for negative deltas', async () => { + mockThresholdRepository.getThreshold.mockResolvedValue('200'); + + const events = [ + createVotingPowerHistory({ delta: '-300', changeType: 'delegation', timestamp: '1000' }), + createVotingPowerHistory({ delta: '-50', changeType: 'delegation', timestamp: '1001' }), + ]; + + await trigger.process(events); + + expect(mockDispatcherService.sendMessage).toHaveBeenCalledWith({ + triggerId: 'voting-power-changed', + events: [events[0]] + }); + }); + + it('should pass all events through when threshold is null (fail-open)', async () => { + mockThresholdRepository.getThreshold.mockResolvedValue(null); + + const events = [ + createVotingPowerHistory({ delta: '1', changeType: 'delegation', timestamp: '1000' }), + ]; + + await trigger.process(events); + + expect(mockDispatcherService.sendMessage).toHaveBeenCalledWith({ + triggerId: 'voting-power-changed', + events + }); + }); + + it('should always advance timestamp even when all events are filtered', async () => { + mockThresholdRepository.getThreshold.mockResolvedValue('99999999'); + + const events = [ + createVotingPowerHistory({ delta: '1', changeType: 'delegation', timestamp: '5000' }), + createVotingPowerHistory({ delta: '2', changeType: 'delegation', timestamp: '6000' }), + ]; + + await trigger.process(events); + + expect(mockDispatcherService.sendMessage).not.toHaveBeenCalled(); + expect((trigger as any).lastProcessedTimestamp).toBe('6001'); + }); + }); }); \ No newline at end of file From f4813b372f009097aea91be5327b07005ae9acb5 Mon Sep 17 00:00:00 2001 From: Leonardo Vieira Date: Wed, 4 Mar 2026 10:47:10 -0300 Subject: [PATCH 26/42] feat: type exports and tests on the anticapture client --- packages/anticapture-client/src/index.ts | 3 +- packages/anticapture-client/src/schemas.ts | 11 +++++++ .../tests/anticapture-client.test.ts | 29 +++++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/packages/anticapture-client/src/index.ts b/packages/anticapture-client/src/index.ts index ea29719c..f64fd3a1 100644 --- a/packages/anticapture-client/src/index.ts +++ b/packages/anticapture-client/src/index.ts @@ -25,4 +25,5 @@ export { QueryInput_Votes_OrderDirection } from './gql/graphql'; -export type { ProcessedVotingPowerHistory } from './schemas'; \ No newline at end of file +export type { ProcessedVotingPowerHistory } from './schemas'; +export { FeedEventType, FeedRelevance } from './schemas'; \ No newline at end of file diff --git a/packages/anticapture-client/src/schemas.ts b/packages/anticapture-client/src/schemas.ts index 3a09c7f3..17d09488 100644 --- a/packages/anticapture-client/src/schemas.ts +++ b/packages/anticapture-client/src/schemas.ts @@ -1,5 +1,10 @@ import { z } from 'zod'; +export { + QueryInput_GetEventRelevanceThreshold_Type as FeedEventType, + QueryInput_GetEventRelevanceThreshold_Relevance as FeedRelevance, +} from './gql/graphql'; + // Schema with built-in transformation and fallbacks export const SafeDaosResponseSchema = z.object({ daos: z.object({ @@ -121,6 +126,12 @@ export const SafeProposalNonVotersResponseSchema = z.object({ }); +export const EventThresholdResponseSchema = z.object({ + getEventRelevanceThreshold: z.object({ + threshold: z.string() + }) +}); + // Internal types for schema validation type SafeProposalsResponse = z.infer; type SafeHistoricalVotingPowerResponse = z.infer; diff --git a/packages/anticapture-client/tests/anticapture-client.test.ts b/packages/anticapture-client/tests/anticapture-client.test.ts index 66ac671b..fabe44ba 100644 --- a/packages/anticapture-client/tests/anticapture-client.test.ts +++ b/packages/anticapture-client/tests/anticapture-client.test.ts @@ -1,5 +1,6 @@ import { describe, it, expect, jest, beforeEach, afterEach } from '@jest/globals'; import { AnticaptureClient } from '../src/anticapture-client'; +import { FeedEventType, FeedRelevance } from '../src/schemas'; import { createMockClient, createProposalResponse, createVotingPowerResponse } from './test-helpers'; import { TEST_FIXTURES } from './constants'; @@ -149,6 +150,34 @@ describe('AnticaptureClient', () => { }); }); + describe('getEventThreshold', () => { + it('returns threshold string for a valid response', async () => { + mockQuery.mockResolvedValue({ + getEventRelevanceThreshold: { threshold: '40000000000000000000000' } + }); + + const result = await client.getEventThreshold('ENS', FeedEventType.Delegation, FeedRelevance.High); + + expect(result).toBe('40000000000000000000000'); + }); + + it('returns null when query throws', async () => { + mockQuery.mockRejectedValue(new Error('Something went wrong')); + + const result = await client.getEventThreshold('ENS', FeedEventType.Vote, FeedRelevance.High); + + expect(result).toBeNull(); + }); + + it('returns null when response has unexpected shape', async () => { + mockQuery.mockResolvedValue({ unexpected: 'data' }); + + const result = await client.getEventThreshold('ENS', FeedEventType.Transfer, FeedRelevance.High); + + expect(result).toBeNull(); + }); + }); + describe('listVotingPowerHistory', () => { describe('error handling', () => { beforeEach(() => { From 0c37eef2aab6b01960f6de3cd75b594372598866 Mon Sep 17 00:00:00 2001 From: Leonardo Vieira Date: Wed, 4 Mar 2026 17:04:32 -0300 Subject: [PATCH 27/42] refactor: metadata on each trigger --- .../triggers/new-proposal-trigger.service.ts | 6 ++++-- .../triggers/non-voting-handler.service.ts | 12 ++++++------ .../vote-confirmation-trigger.service.ts | 5 ++++- .../triggers/voting-power-trigger.service.ts | 16 ++++++++++------ .../triggers/voting-reminder-trigger.service.ts | 7 +++++-- 5 files changed, 29 insertions(+), 17 deletions(-) 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 93abee73..d6daa3a7 100644 --- a/apps/dispatcher/src/services/triggers/new-proposal-trigger.service.ts +++ b/apps/dispatcher/src/services/triggers/new-proposal-trigger.service.ts @@ -44,7 +44,9 @@ export class NewProposalTriggerHandler extends BaseTriggerHandler { const buttons = buildButtons({ triggerType: 'newProposal', txHash: txHash, - chainId + chainId, + daoId, + proposalId }); await this.sendNotificationsToSubscribers( @@ -52,7 +54,7 @@ export class NewProposalTriggerHandler extends BaseTriggerHandler { notificationMessage, proposalId, daoId, - undefined, + { triggerType: 'newProposal' }, buttons ); } diff --git a/apps/dispatcher/src/services/triggers/non-voting-handler.service.ts b/apps/dispatcher/src/services/triggers/non-voting-handler.service.ts index b0ec5d29..6a0c5e61 100644 --- a/apps/dispatcher/src/services/triggers/non-voting-handler.service.ts +++ b/apps/dispatcher/src/services/triggers/non-voting-handler.service.ts @@ -123,11 +123,6 @@ export class NonVotingHandler extends BaseTriggerHandler { const proposalTitles = FormattingService.formatProposalList(lastProposals); - // Build buttons for non-voting (no tx hash) - const buttons = buildButtons({ - triggerType: 'nonVoting' - }); - await this.batchNotificationService.sendBatchNotifications( nonVoters, daoId, @@ -140,11 +135,16 @@ export class NonVotingHandler extends BaseTriggerHandler ({ + triggerType: 'nonVoting', addresses: { 'nonVoterAddress': address } }), - () => buttons + (address) => buildButtons({ + triggerType: 'nonVoting', + daoId, + address + }) ); } 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 20292262..19e21e0d 100644 --- a/apps/dispatcher/src/services/triggers/vote-confirmation-trigger.service.ts +++ b/apps/dispatcher/src/services/triggers/vote-confirmation-trigger.service.ts @@ -130,7 +130,9 @@ export class VoteConfirmationTriggerHandler extends BaseTriggerHandler `${event.id}-${event.thresholdPercentage}-reminder`, (address) => this.createReminderMessage(event, address), (address) => ({ + triggerType: 'votingReminder', proposalId: event.id, thresholdPercentage: event.thresholdPercentage, timeElapsedPercentage: event.timeElapsedPercentage, From 4fb82a80c21c5247d887ef5fc1bc85ded923423d Mon Sep 17 00:00:00 2001 From: Leonardo Vieira Date: Wed, 4 Mar 2026 17:10:24 -0300 Subject: [PATCH 28/42] feat: utm functions --- packages/messages/src/formatters/utm.ts | 19 +++++++++++++++++++ packages/messages/src/index.ts | 3 ++- 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 packages/messages/src/formatters/utm.ts diff --git a/packages/messages/src/formatters/utm.ts b/packages/messages/src/formatters/utm.ts new file mode 100644 index 00000000..5eb29317 --- /dev/null +++ b/packages/messages/src/formatters/utm.ts @@ -0,0 +1,19 @@ +/** + * UTM tracking parameter utilities + * Appends UTM params to URLs for tracking notification engagement + */ + +export interface UtmParams { + source: string; // "Notification" + medium: string; // Consumer + campaign: string; // Trigger type +} + +/** + * Appends UTM tracking parameters to a URL + * Handles both URLs with and without existing query parameters + */ +export function appendUtmParams(url: string, params: UtmParams): string { + const separator = url.includes('?') ? '&' : '?'; + return `${url}${separator}utm_source=${params.source}&utm_medium=${params.medium}&utm_campaign=${params.campaign}`; +} diff --git a/packages/messages/src/index.ts b/packages/messages/src/index.ts index 7b463702..29bb2e27 100644 --- a/packages/messages/src/index.ts +++ b/packages/messages/src/index.ts @@ -22,4 +22,5 @@ export * from './formatters/placeholders'; export type * from './formatters/placeholders'; export * from './formatters/dao-emoji'; export * from './formatters/explorer.service'; -export * from './formatters/markdown-slack-converter'; \ No newline at end of file +export * from './formatters/markdown-slack-converter'; +export * from './formatters/utm'; \ No newline at end of file From f625e46f1140d09e6e61428df9bb4958440e69dd Mon Sep 17 00:00:00 2001 From: Leonardo Vieira Date: Wed, 4 Mar 2026 18:01:57 -0300 Subject: [PATCH 29/42] feat: utm addition on url --- .../src/services/bot/slack-bot.service.ts | 15 +++- .../src/services/bot/telegram-bot.service.ts | 15 +++- packages/messages/src/triggers/buttons.ts | 76 ++++++++++++++----- 3 files changed, 79 insertions(+), 27 deletions(-) diff --git a/apps/consumers/src/services/bot/slack-bot.service.ts b/apps/consumers/src/services/bot/slack-bot.service.ts index 817c86cf..4e826da6 100644 --- a/apps/consumers/src/services/bot/slack-bot.service.ts +++ b/apps/consumers/src/services/bot/slack-bot.service.ts @@ -8,7 +8,7 @@ import { SlackClientInterface } from '../../interfaces/slack-client.interface'; import { NotificationPayload } from '../../interfaces/notification.interface'; import { BotServiceInterface } from '../../interfaces/bot-service.interface'; -import { slackMessages, convertMarkdownToSlack } from '@notification-system/messages'; +import { slackMessages, convertMarkdownToSlack, appendUtmParams } from '@notification-system/messages'; import { EnsResolverService } from '../ens-resolver.service'; import { SlackDAOService } from '../dao/slack-dao.service'; import { SlackWalletService } from '../wallet/slack-wallet.service'; @@ -212,8 +212,17 @@ export class SlackBotService implements BotServiceInterface { throw new Error('Slack notification requires workspace OAuth token. No bot_token provided in notification payload.'); } + // Append UTM tracking params to button URLs + const triggerType = payload.metadata?.triggerType; + const buttons = payload.metadata?.buttons?.map(btn => ({ + text: btn.text, + url: triggerType + ? appendUtmParams(btn.url, { source: 'notification', medium: 'slack', campaign: triggerType }) + : btn.url + })); + // Build message options with buttons if provided - const messageOptions = payload.metadata?.buttons ? { + const messageOptions = buttons ? { blocks: [ { type: 'section' as const, @@ -221,7 +230,7 @@ export class SlackBotService implements BotServiceInterface { }, { type: 'actions' as const, - elements: payload.metadata.buttons.map(btn => ({ + elements: buttons.map(btn => ({ type: 'button' as const, text: { type: 'plain_text' as const, text: btn.text }, url: btn.url diff --git a/apps/consumers/src/services/bot/telegram-bot.service.ts b/apps/consumers/src/services/bot/telegram-bot.service.ts index f762c79f..97d2e815 100644 --- a/apps/consumers/src/services/bot/telegram-bot.service.ts +++ b/apps/consumers/src/services/bot/telegram-bot.service.ts @@ -5,7 +5,7 @@ */ import { Markup } from 'telegraf'; -import { telegramMessages, uiMessages, ExplorerService } from '@notification-system/messages'; +import { telegramMessages, uiMessages, ExplorerService, appendUtmParams } from '@notification-system/messages'; import { TelegramDAOService } from '../dao/telegram-dao.service'; import { TelegramWalletService } from '../wallet/telegram-wallet.service'; import { EnsResolverService } from '../ens-resolver.service'; @@ -160,10 +160,19 @@ export class TelegramBotService implements BotServiceInterface { } } + // Append UTM tracking params to button URLs + const triggerType = payload.metadata?.triggerType; + const buttons = payload.metadata?.buttons?.map(btn => ({ + text: btn.text, + url: triggerType + ? appendUtmParams(btn.url, { source: 'notification', medium: 'telegram', campaign: triggerType }) + : btn.url + })); + // Build inline keyboard if buttons are provided - const replyMarkup = payload.metadata?.buttons ? { + const replyMarkup = buttons ? { inline_keyboard: [[ - ...payload.metadata.buttons.map(btn => ({ text: btn.text, url: btn.url })) + ...buttons.map(btn => ({ text: btn.text, url: btn.url })) ]] } : undefined; diff --git a/packages/messages/src/triggers/buttons.ts b/packages/messages/src/triggers/buttons.ts index 1a9902b0..32cefbc1 100644 --- a/packages/messages/src/triggers/buttons.ts +++ b/packages/messages/src/triggers/buttons.ts @@ -1,6 +1,6 @@ /** * Button definitions for trigger notifications - * Contains call-to-action buttons for each trigger type + * Contains call-to-action buttons with dynamic URL builders for each trigger type */ import { ExplorerService } from '../formatters/explorer.service'; @@ -10,36 +10,61 @@ export interface Button { url: string; } +const BASE_URL = 'https://anticapture.com'; + +interface CtaButtonConfig { + text: string; + buildUrl: (params: Record) => string; +} + /** - * Call-to-action buttons for each trigger type - * All CTAs link to AntiCapture main page + * CTA button configurations with dynamic URL builders per trigger type + * Falls back to BASE_URL when required params are missing */ -export const callToActionButtons = { +const ctaButtonConfigs: Record = { delegationChange: { - text: "Explore delegates activity", - url: 'https://anticapture.com/' + text: 'Check delegation details', + buildUrl: ({ daoId, address }) => + daoId && address + ? `${BASE_URL}/${daoId}/holders-and-delegates?tab=delegates&drawerAddress=${address}&drawerTab=voteComposition` + : BASE_URL }, newProposal: { - text: 'Review DAO data before voting', - url: 'https://anticapture.com/' + text: 'Check proposal details', + buildUrl: ({ daoId, proposalId }) => + daoId && proposalId + ? `${BASE_URL}/${daoId}/governance/proposal/${proposalId}` + : BASE_URL }, nonVoting: { - text: 'Check delegates and proposals', - url: 'https://anticapture.com/' + text: 'Check previous votes', + buildUrl: ({ daoId, address }) => + daoId && address + ? `${BASE_URL}/${daoId}/holders-and-delegates?tab=delegates&drawerAddress=${address}` + : BASE_URL }, voteConfirmation: { - text: "See delegates activity", - url: 'https://anticapture.com/' + text: 'Check vote details', + buildUrl: ({ daoId, address }) => + daoId && address + ? `${BASE_URL}/${daoId}/holders-and-delegates?tab=delegates&drawerAddress=${address}` + : BASE_URL }, votingPowerChange: { - text: 'Check voting power shifts', - url: 'https://anticapture.com/' + text: 'Check voting power changes', + buildUrl: ({ daoId, address }) => + daoId && address + ? `${BASE_URL}/${daoId}/holders-and-delegates?tab=delegates&drawerAddress=${address}&drawerTab=votingPowerHistory` + : BASE_URL }, votingReminder: { - text: 'Check about the delegates and proposal information', - url: 'https://anticapture.com/' + text: 'Cast your vote', + buildUrl: ({ daoId, proposalId }) => + daoId && proposalId + ? `${BASE_URL}/${daoId}/governance/proposal/${proposalId}` + : BASE_URL } -} as const; +}; /** * Text for blockchain explorer (scan) button @@ -50,22 +75,31 @@ export const scanButtonText = 'View Transaction'; * Parameters for building notification buttons */ export interface BuildButtonsParams { - triggerType: keyof typeof callToActionButtons; + triggerType: keyof typeof ctaButtonConfigs; txHash?: string; chainId?: number; + daoId?: string; + address?: string; + proposalId?: string; } const explorerService = new ExplorerService(); /** * Build buttons for a notification - * Always includes CTA button, optionally includes scan button if transaction info is available + * Always includes CTA button with dynamic URL, optionally includes scan button */ export function buildButtons(params: BuildButtonsParams): Button[] { const buttons: Button[] = []; + const config = ctaButtonConfigs[params.triggerType]; + + const url = config.buildUrl({ + daoId: params.daoId, + address: params.address, + proposalId: params.proposalId + }); - // Always add CTA button - buttons.push(callToActionButtons[params.triggerType]); + buttons.push({ text: config.text, url }); // Add scan button if transaction info is available if (params.txHash && params.chainId) { From 5acca0522b6ea5b43b662c4a649e8eef436de61b Mon Sep 17 00:00:00 2001 From: Leonardo Vieira Date: Wed, 4 Mar 2026 18:06:06 -0300 Subject: [PATCH 30/42] refactor: unit tests --- .../src/services/triggers/non-voting-handler.service.test.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/dispatcher/src/services/triggers/non-voting-handler.service.test.ts b/apps/dispatcher/src/services/triggers/non-voting-handler.service.test.ts index 2e861c10..7eb3a064 100644 --- a/apps/dispatcher/src/services/triggers/non-voting-handler.service.test.ts +++ b/apps/dispatcher/src/services/triggers/non-voting-handler.service.test.ts @@ -204,13 +204,14 @@ describe('NonVotingHandler', () => { message: ExpectedMessages.createNonVotingAlert('ENS'), bot_token: undefined, metadata: { + triggerType: 'nonVoting', addresses: { 'nonVoterAddress': TestAddresses.ADDRESS_LONG }, buttons: [ { - text: 'Check delegates and proposals', - url: 'https://anticapture.com/' + text: 'Check previous votes', + url: `https://anticapture.com/ENS/holders-and-delegates?tab=delegates&drawerAddress=${TestAddresses.ADDRESS_LONG}` } ] } From f702037936c2a6093fd31564cbf7bda6db0b1a31 Mon Sep 17 00:00:00 2001 From: Leonardo Vieira Date: Thu, 5 Mar 2026 16:23:52 -0300 Subject: [PATCH 31/42] refactor: update common UI messages for onboarding flow Update welcome, help, wallet and DAO messages with new copy. Add new button labels (start, wallets, settings, selectAll, unselectAll). Add wallet selectionPrefix, onboardingComplete, and welcomeDao messages. Co-Authored-By: Claude Opus 4.6 --- packages/messages/src/ui/common.ts | 41 ++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/packages/messages/src/ui/common.ts b/packages/messages/src/ui/common.ts index 152079d2..821adee8 100644 --- a/packages/messages/src/ui/common.ts +++ b/packages/messages/src/ui/common.ts @@ -5,21 +5,24 @@ export const uiMessages = { // Welcome and help messages welcome: `🔔 Welcome to the Anticapture notification system! -Spotting the "oh no" before it hits your treasury. +Spotting the "oh no" before it hits your treasury.`, -➡️ To start using the system, you'll need to add the DAOs you want to receive notifications from by clicking on "DAOs". -➡️ After that, click on "Tracked Wallets" and add your wallet address to receive custom notifications.`, + welcomeDao:`➡️ To get started, add the DAOs you want to track. + + You will receive alerts for: +- New Proposals on the DAO +- Proposal results when it finishes +- Vote reminders + +Stay ahead of governance risk. Stay informed.`, help: `What is Anticapture? A governance security research, notification system and dashboard that tracks social dynamics, governance models, and contracts, ensuring security and preventing malicious capture. What is this bot for? -Get notified about risks, changes and proposals that you care about the DAOs you're in. +Get notified about risks, changes and proposals that you care about in the DAOs you follow. -Commands that might be useful -/start -/learn_more -/daos`, +Actions that might be useful`, unknownCommand: '❌ Unknown command. Use /learn_more to see available commands.', @@ -38,15 +41,33 @@ You'll be notified when things get spicy:`, myWallets: '📝 Tracked Wallets', addWallet: '➕ Add wallet', removeWallet: '❌ Remove wallet', - confirmRemoval: '🗑️ Confirm removal' + confirmRemoval: '🗑️ Confirm removal', + start: '🚀 Start', + wallets: '📝 Wallets', + settings: '⚙️ Settings', + selectAll: 'Select all', + unselectAll: 'Unselect all', + settingsComingSoon: '⚙️ Settings coming soon!' }, // Wallet management messages wallet: { - selection: `Here's the wallets you have added to receive custom notifications:`, + selectionPrefix: '👉 Next step: ', + selection: `Add your wallet address + +This allows us to personalize alerts based on your governance activity and delegations. + +You'll receive notifications for: +- Delegation changes that affect your voting power +- Transfers that affect your voting power +- Non-voting alerts +- Vote confirmations + +Stay aware of how changes in governance affect you.`, input: '👉 Please enter your address or ENS name:', processing: '⏱️ Hang tight, we\'re just connecting your data…', success: '✅ All set! Your wallet has been added.', + onboardingComplete: `🎉 You're all set! Stay tuned — we'll notify you as soon as something important happens in your DAOs.`, error: '❌ Invalid wallet address. Please try again.', removeConfirmation: 'Select the wallets you want to remove:', removeSuccess: '✅ Selected wallets have been removed.', From e8c9b13a5bf55f6c51e5293a95b5a1e253433987 Mon Sep 17 00:00:00 2001 From: Leonardo Vieira Date: Thu, 5 Mar 2026 16:24:04 -0300 Subject: [PATCH 32/42] feat: Telegram linear onboarding flow with select/unselect all - /start now shows welcome + DAO prompt with inline button - learn_more shows inline action buttons (start, daos, wallets, settings) - Add select all / unselect all buttons to DAO keyboard - After DAO confirm, trigger wallet flow if fromStart - Send onboarding complete message after wallet added - Refactor DAO keyboard refresh into shared method Co-Authored-By: Claude Opus 4.6 --- .../consumers/src/interfaces/bot.interface.ts | 1 + .../src/services/bot/telegram-bot.service.ts | 98 ++++++++++++++++--- .../src/services/dao/telegram-dao.service.ts | 51 ++++++---- .../wallet/telegram-wallet.service.ts | 17 ++-- 4 files changed, 127 insertions(+), 40 deletions(-) diff --git a/apps/consumers/src/interfaces/bot.interface.ts b/apps/consumers/src/interfaces/bot.interface.ts index 1d154227..23102f03 100644 --- a/apps/consumers/src/interfaces/bot.interface.ts +++ b/apps/consumers/src/interfaces/bot.interface.ts @@ -10,6 +10,7 @@ export interface ContextWithSession extends Context { walletAction?: 'add' | 'remove'; walletsToRemove?: Set; awaitingWalletInput?: boolean; + fromStart?: boolean; }; } diff --git a/apps/consumers/src/services/bot/telegram-bot.service.ts b/apps/consumers/src/services/bot/telegram-bot.service.ts index 97d2e815..969e1fa6 100644 --- a/apps/consumers/src/services/bot/telegram-bot.service.ts +++ b/apps/consumers/src/services/bot/telegram-bot.service.ts @@ -9,7 +9,7 @@ import { telegramMessages, uiMessages, ExplorerService, appendUtmParams } from ' import { TelegramDAOService } from '../dao/telegram-dao.service'; import { TelegramWalletService } from '../wallet/telegram-wallet.service'; import { EnsResolverService } from '../ens-resolver.service'; -import { MatchedContext } from '../../interfaces/bot.interface'; +import { ContextWithSession, MatchedContext } from '../../interfaces/bot.interface'; import { NotificationPayload } from '../../interfaces/notification.interface'; import { TelegramClientInterface } from '../../interfaces/telegram-client.interface'; import { BotServiceInterface } from '../../interfaces/bot-service.interface'; @@ -51,14 +51,11 @@ export class TelegramBotService implements BotServiceInterface { private setupCommands(): void { this.telegramClient.setupHandlers((handlers) => { handlers.command(/^start$/i, async (ctx) => { - await ctx.reply(uiMessages.welcome, this.createPersistentKeyboard()); + await this.replyStartFlow(ctx); }); handlers.command(/^learn_more$/i, async (ctx) => { - await ctx.reply(uiMessages.help, { - parse_mode: 'HTML', - ...this.createPersistentKeyboard() - }); + await this.replyLearnMore(ctx); }); handlers.command(/^daos$/i, async (ctx) => { @@ -78,45 +75,78 @@ export class TelegramBotService implements BotServiceInterface { }); handlers.hears(uiMessages.buttons.learnMore, async (ctx) => { - await ctx.reply(uiMessages.help, { - parse_mode: 'HTML', - ...this.createPersistentKeyboard() - }); + await this.replyLearnMore(ctx); + }); + + handlers.action(/^start$/, async (ctx) => { + await ctx.answerCbQuery(); + if (ctx.session) ctx.session.fromStart = true; + await this.daoService.initialize(ctx); }); handlers.action(/^dao_toggle_(\w+)$/, async (ctx) => { + await ctx.answerCbQuery(); const matchedCtx = ctx as MatchedContext; const daoName = matchedCtx.match[1]; await this.daoService.toggle(ctx, daoName); - await ctx.answerCbQuery(); }); handlers.action(/^dao_confirm$/, async (ctx) => { + await ctx.answerCbQuery(); await this.daoService.confirm(ctx); + await this.triggerWalletFlowIfFromStart(ctx); + }); + + handlers.action(/^dao_select_all$/, async (ctx) => { + await ctx.answerCbQuery(); + await this.daoService.selectAll(ctx); + }); + + handlers.action(/^dao_unselect_all$/, async (ctx) => { await ctx.answerCbQuery(); + await this.daoService.unselectAll(ctx); }); // Wallet action handlers handlers.action(/^wallet_add$/, async (ctx) => { - await this.walletService.addWallet(ctx); await ctx.answerCbQuery(); + await this.walletService.addWallet(ctx); }); handlers.action(/^wallet_remove$/, async (ctx) => { - await this.walletService.removeWallet(ctx); await ctx.answerCbQuery(); + await this.walletService.removeWallet(ctx); }); handlers.action(/^wallet_toggle_(.+)$/, async (ctx) => { + await ctx.answerCbQuery(); const matchedCtx = ctx as MatchedContext; const address = matchedCtx.match[1]; await this.walletService.toggleWalletForRemoval(ctx, address); - await ctx.answerCbQuery(); }); handlers.action(/^wallet_confirm_remove$/, async (ctx) => { + await ctx.answerCbQuery(); await this.walletService.confirmRemoval(ctx); + }); + + handlers.action(/^lm_start$/, async (ctx) => { await ctx.answerCbQuery(); + await this.replyStartFlow(ctx); + }); + + handlers.action(/^lm_daos$/, async (ctx) => { + await ctx.answerCbQuery(); + await this.daoService.initialize(ctx); + }); + + handlers.action(/^lm_wallets$/, async (ctx) => { + await ctx.answerCbQuery(); + await this.walletService.initialize(ctx); + }); + + handlers.action(/^lm_settings$/, async (ctx) => { + await ctx.answerCbQuery(uiMessages.buttons.settingsComingSoon); }); handlers.on('message', async (ctx, next) => { @@ -134,6 +164,46 @@ export class TelegramBotService implements BotServiceInterface { }); } + private async replyStartFlow(ctx: ContextWithSession): Promise { + await ctx.reply(uiMessages.welcome, this.createPersistentKeyboard()); + await ctx.reply(uiMessages.welcomeDao, { + reply_markup: { + inline_keyboard: [ + [{ text: uiMessages.buttons.daos, callback_data: 'start' }] + ] + } + }); + } + + private async replyLearnMore(ctx: ContextWithSession): Promise { + await ctx.reply(uiMessages.help, { + parse_mode: 'HTML', + reply_markup: { + inline_keyboard: [ + [ + { text: uiMessages.buttons.start, callback_data: 'lm_start' }, + { text: uiMessages.buttons.daos, callback_data: 'lm_daos' }, + ], + [ + { text: uiMessages.buttons.wallets, callback_data: 'lm_wallets' }, + { text: uiMessages.buttons.settings, callback_data: 'lm_settings' }, + ] + ] + } + }); + } + + private async triggerWalletFlowIfFromStart(ctx: ContextWithSession): Promise { + if (!ctx.session?.fromStart) return; + const user = ctx.from?.id; + if (user) { + const userWallets = await this.walletService.getUserWalletsWithDisplayNames(user.toString(), 'telegram'); + if (!userWallets || userWallets.length === 0) { + await this.walletService.initialize(ctx, true); + } + } + } + async launch(): Promise { await this.telegramClient.launch(); } diff --git a/apps/consumers/src/services/dao/telegram-dao.service.ts b/apps/consumers/src/services/dao/telegram-dao.service.ts index 20330feb..3f801d4d 100644 --- a/apps/consumers/src/services/dao/telegram-dao.service.ts +++ b/apps/consumers/src/services/dao/telegram-dao.service.ts @@ -89,13 +89,8 @@ export class TelegramDAOService extends BaseDAOService { * Toggle DAO selection when user clicks a button */ async toggle(ctx: ContextWithSession, daoName: string): Promise { - const chatId = ctx.chat?.id; - const messageId = ctx.callbackQuery?.message?.message_id; - if (!chatId || !messageId) return; - this.ensureSession(ctx); - // Toggle selection in session const normalizedDaoName = daoName.toUpperCase(); if (ctx.session.daoSelections.has(normalizedDaoName)) { ctx.session.daoSelections.delete(normalizedDaoName); @@ -103,15 +98,7 @@ export class TelegramDAOService extends BaseDAOService { ctx.session.daoSelections.add(normalizedDaoName); } - try { - // Update inline keyboard to reflect new state - const daos = await this.fetchAvailableDAOs(); - const keyboard = this.buildInlineKeyboard(daos, ctx.session.daoSelections); - await ctx.editMessageReplyMarkup(keyboard); - } catch (error) { - console.error('Error updating keyboard:', error); - await ctx.answerCbQuery(uiMessages.errors.updateFailed); - } + await this.refreshKeyboard(ctx); } /** @@ -143,6 +130,32 @@ export class TelegramDAOService extends BaseDAOService { await ctx.reply(uiMessages.errors.updateSubscriptionsFailed); } } + + async selectAll(ctx: ContextWithSession): Promise { + this.ensureSession(ctx); + const daos = await this.fetchAvailableDAOs(); + daos.forEach(dao => ctx.session.daoSelections.add(dao.id.toUpperCase())); + await this.refreshKeyboard(ctx); + } + + async unselectAll(ctx: ContextWithSession): Promise { + this.ensureSession(ctx); + ctx.session.daoSelections.clear(); + await this.refreshKeyboard(ctx); + } + + /** + * Refresh the inline keyboard to reflect current session selections + */ + private async refreshKeyboard(ctx: ContextWithSession): Promise { + try { + const daos = await this.fetchAvailableDAOs(); + const keyboard = this.buildInlineKeyboard(daos, ctx.session.daoSelections); + await ctx.editMessageReplyMarkup(keyboard); + } catch (error) { + console.error('Error updating keyboard:', error); + } + } /** * Build Telegram inline keyboard for DAO selection @@ -160,7 +173,6 @@ export class TelegramDAOService extends BaseDAOService { }; }); - // Group buttons into rows of 4 const BUTTONS_PER_ROW = 3; const daoButtonRows: any[][] = []; @@ -171,9 +183,12 @@ export class TelegramDAOService extends BaseDAOService { return { inline_keyboard: [ ...daoButtonRows, - // Confirm button row [ - { text: uiMessages.confirmSelection, callback_data: 'dao_confirm' } + { text: uiMessages.buttons.selectAll, callback_data: 'dao_select_all' }, + { text: uiMessages.buttons.unselectAll, callback_data: 'dao_unselect_all' }, + ], + [ + { text: uiMessages.confirmSelection, callback_data: 'dao_confirm' }, ] ] }; @@ -182,7 +197,7 @@ export class TelegramDAOService extends BaseDAOService { /** * Show confirmation message after updating subscriptions */ - private async showConfirmationMessage(ctx: any, selectedDAOs: Set): Promise { + private async showConfirmationMessage(ctx: ContextWithSession, selectedDAOs: Set): Promise { if (selectedDAOs.size > 0) { const daoList = this.formatDAOListWithBullets(selectedDAOs); diff --git a/apps/consumers/src/services/wallet/telegram-wallet.service.ts b/apps/consumers/src/services/wallet/telegram-wallet.service.ts index 45949c77..40cd132d 100644 --- a/apps/consumers/src/services/wallet/telegram-wallet.service.ts +++ b/apps/consumers/src/services/wallet/telegram-wallet.service.ts @@ -33,7 +33,7 @@ export class TelegramWalletService extends BaseWalletService { /** * Display the wallet management interface */ - async initialize(ctx: ContextWithSession): Promise { + async initialize(ctx: ContextWithSession, fromStart: boolean = false): Promise { const userId = ctx.from?.id; if (!userId) return; @@ -43,17 +43,14 @@ export class TelegramWalletService extends BaseWalletService { // Get user's current wallets const wallets = await this.getUserWalletsWithDisplayNames(userId.toString(), 'telegram'); - let message = uiMessages.wallet.selection; + const prefix = fromStart ? uiMessages.wallet.selectionPrefix : ''; + let message = `${prefix}${uiMessages.wallet.selection}`; - if (wallets.length === 0) { - message = uiMessages.wallet.noWallets; - } else { - // Show current wallets with ENS names when available + if (wallets.length > 0) { const walletList = wallets.map((wallet, index) => `${index + 1}. ${wallet.displayName || wallet.address}` ); - - message = `${uiMessages.wallet.selection}\n\n${walletList.join('\n')}`; + message += `\n\n${walletList.join('\n')}`; } const keyboard = { @@ -145,6 +142,10 @@ export class TelegramWalletService extends BaseWalletService { if (result.success) { await ctx.reply(uiMessages.wallet.success); + if (ctx.session.fromStart) { + await ctx.reply(uiMessages.wallet.onboardingComplete); + ctx.session.fromStart = false; + } } else { await ctx.reply(`${uiMessages.status.error} ${result.message}`); } From 272f7ce79f68893ab57abe135216edfecd85bb64 Mon Sep 17 00:00:00 2001 From: Leonardo Vieira Date: Thu, 5 Mar 2026 16:25:10 -0300 Subject: [PATCH 33/42] refactor: update Slack UI messages to match Telegram copy - Update welcome message with notification types and tagline - Update homePage with Anticapture description and /anticapture reference - Update wallet listHeader with governance activity copy - Add wallet selectionPrefix and onboardingComplete messages Co-Authored-By: Claude Opus 4.6 --- packages/messages/src/ui/slack.ts | 32 +++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/messages/src/ui/slack.ts b/packages/messages/src/ui/slack.ts index 897bc705..3f1dda48 100644 --- a/packages/messages/src/ui/slack.ts +++ b/packages/messages/src/ui/slack.ts @@ -20,7 +20,9 @@ export const slackMessages = { // Wallet management messages wallet: { - listHeader: '*Your Wallet Addresses:*', + listHeader: '*Add your wallet address*\n\nThis allows us to personalize alerts based on your governance activity and delegations.', + selectionPrefix: '*Next step:* ', + onboardingComplete: '🎉 You\'re all set! Stay tuned — we\'ll notify you as soon as something important happens in your DAOs.', emptyList: "You can add wallets and receive custom notifications related to them and the DAOs you follow!", instructions: "Use '/anticapture wallet add' or '/anticapture wallet remove' to manage your wallets", buttonAdd: 'Add Wallet', @@ -75,18 +77,12 @@ export const slackMessages = { type: 'section', text: { type: 'mrkdwn', - text: '✨ *[Mission Initiated: Navigating the Governance Space]*\n\n' + - 'Set up your dashboard to stay on course with proposal signals from the DAOs you participate in.\n\n' + - '\n\n' + - '*💎 Mission Features:*\n' + - '• Receive real-time alerts for new proposals\n' + - '• Be reminded when a voting window is open — don\'t miss your chance to engage\n' + - '• Get mission reports with proposal outcomes\n' + - '• Lock in the DAOs you want to monitor directly\n' + - '• Connect your wallet and sync your DAOs of interest\n' + - '• Track if your addresses are actively voting\n\n' + - '\n\n' + - '*Another links that might be useful*' + text: '*What is Anticapture?*\n' + + 'A governance security research, notification system and dashboard that tracks social dynamics, governance models, and contracts, ensuring security and preventing malicious capture.\n\n' + + '*What is this bot for?*\n' + + 'Get notified about risks, changes and proposals that you care about in the DAOs you follow.\n\n' + + 'Use the `/anticapture` command to get started.\n\n' + + '*Links that might be useful*' } }, { @@ -133,9 +129,13 @@ export const slackMessages = { type: 'section', text: { type: 'mrkdwn', - text: '🚨 *Anticapture Notification System*\n\n' + - 'Spot the "oh no" before it reaches your treasury.\n\n' + - '*Manage your notification preferences:*' + text: '🔔 *Welcome to the Anticapture notification system!*\n\n' + + '_Spotting the "oh no" before it hits your treasury._\n\n' + + 'You will receive alerts for:\n' + + '• New Proposals on the DAO\n' + + '• Proposal results when it finishes\n' + + '• Vote reminders\n\n' + + 'Stay ahead of governance risk. Stay informed.' } }, { From f934b1fcffdde109b8f19f59075bba261a54ec46 Mon Sep 17 00:00:00 2001 From: Leonardo Vieira Date: Thu, 5 Mar 2026 16:26:07 -0300 Subject: [PATCH 34/42] feat: Slack linear onboarding flow with select/unselect all - Add fromStart flag to SlackSession for onboarding tracking - welcome_select_daos sets fromStart, dao_confirm triggers wallet prompt - Add select all / unselect all buttons to DAO checkbox list - Add selectAll/unselectAll methods to SlackDAOService - Add showOnboardingWallet prompt to SlackWalletService - Pass fromStart through modal private_metadata for onboarding complete - Send onboarding complete message after wallet added in start flow Co-Authored-By: Claude Opus 4.6 --- .../src/interfaces/slack-context.interface.ts | 1 + .../src/services/bot/slack-bot.service.ts | 18 ++++++ .../src/services/dao/slack-dao.service.ts | 59 ++++++++++++++++++ .../services/wallet/slack-wallet.service.ts | 61 ++++++++++++++++++- .../src/utils/slack-blocks-templates.ts | 6 +- 5 files changed, 141 insertions(+), 4 deletions(-) diff --git a/apps/consumers/src/interfaces/slack-context.interface.ts b/apps/consumers/src/interfaces/slack-context.interface.ts index 921e3e1b..3bd83b17 100644 --- a/apps/consumers/src/interfaces/slack-context.interface.ts +++ b/apps/consumers/src/interfaces/slack-context.interface.ts @@ -56,6 +56,7 @@ export interface SlackSession { type: 'wallet' | 'dao'; action: 'add' | 'remove'; }; + fromStart?: boolean; } /** diff --git a/apps/consumers/src/services/bot/slack-bot.service.ts b/apps/consumers/src/services/bot/slack-bot.service.ts index 4e826da6..088ed791 100644 --- a/apps/consumers/src/services/bot/slack-bot.service.ts +++ b/apps/consumers/src/services/bot/slack-bot.service.ts @@ -48,6 +48,7 @@ export class SlackBotService implements BotServiceInterface { // Welcome message actions handlers.action('welcome_select_daos', async (ctx) => { if (this.daoService) { + ctx.session.fromStart = true; await this.daoService.initialize(ctx); } }); @@ -74,6 +75,11 @@ export class SlackBotService implements BotServiceInterface { handlers.action('dao_confirm_subscribe', async (ctx) => { if (this.daoService) { await this.daoService.confirm(ctx); + + // If from onboarding flow, trigger wallet setup + if (ctx.session.fromStart && this.walletService) { + await this.walletService.showOnboardingWallet(ctx); + } } }); @@ -81,6 +87,18 @@ export class SlackBotService implements BotServiceInterface { await ctx.ack(); }); + handlers.action('dao_select_all', async (ctx) => { + if (this.daoService) { + await this.daoService.selectAll(ctx); + } + }); + + handlers.action('dao_unselect_all', async (ctx) => { + if (this.daoService) { + await this.daoService.unselectAll(ctx); + } + }); + handlers.action('wallet_checkboxes', async (ctx) => { await ctx.ack(); }); diff --git a/apps/consumers/src/services/dao/slack-dao.service.ts b/apps/consumers/src/services/dao/slack-dao.service.ts index e84a7703..6870e712 100644 --- a/apps/consumers/src/services/dao/slack-dao.service.ts +++ b/apps/consumers/src/services/dao/slack-dao.service.ts @@ -118,6 +118,65 @@ export class SlackDAOService extends BaseDAOService { } } + /** + * Select all DAOs - re-render checkboxes with all selected + */ + async selectAll(context: SlackActionContext): Promise { + try { + await context.ack(); + + const daos = await this.fetchAvailableDAOs(); + const allSelected = new Set(daos.map(dao => dao.id.toUpperCase())); + + const blocks = daoSelectionList( + daos, + allSelected, + 'dao_checkboxes', + 'dao_confirm_subscribe', + slackMessages.dao.subscribeInstructions + ); + + if (context.respond) { + await context.respond({ + blocks, + response_type: 'in_channel', + replace_original: true + }); + } + } catch (error) { + console.error('Error selecting all DAOs:', error); + } + } + + /** + * Unselect all DAOs - re-render checkboxes with none selected + */ + async unselectAll(context: SlackActionContext): Promise { + try { + await context.ack(); + + const daos = await this.fetchAvailableDAOs(); + + const blocks = daoSelectionList( + daos, + new Set(), + 'dao_checkboxes', + 'dao_confirm_subscribe', + slackMessages.dao.subscribeInstructions + ); + + if (context.respond) { + await context.respond({ + blocks, + response_type: 'in_channel', + replace_original: true + }); + } + } catch (error) { + console.error('Error unselecting all DAOs:', error); + } + } + /** * Confirm DAO selection changes from checkboxes */ diff --git a/apps/consumers/src/services/wallet/slack-wallet.service.ts b/apps/consumers/src/services/wallet/slack-wallet.service.ts index d9595af8..7325e47b 100644 --- a/apps/consumers/src/services/wallet/slack-wallet.service.ts +++ b/apps/consumers/src/services/wallet/slack-wallet.service.ts @@ -11,7 +11,7 @@ import { EnsResolverService } from '../ens-resolver.service'; import { SlackCommandContext, SlackActionContext, - SlackViewContext + SlackViewContext, } from '../../interfaces/slack-context.interface'; import { walletEmptyState, @@ -29,6 +29,38 @@ export class SlackWalletService extends BaseWalletService { super(subscriptionApi, ensResolver); } + /** + * Show wallet prompt during onboarding flow (after DAO selection) + */ + async showOnboardingWallet(context: SlackActionContext): Promise { + if (context.respond) { + await context.respond({ + replace_original: false, + blocks: [ + { + type: 'section', + text: { + type: 'mrkdwn', + text: slackMessages.wallet.selectionPrefix + slackMessages.wallet.listHeader + } + }, + { + type: 'actions', + elements: [ + { + type: 'button', + text: { type: 'plain_text', text: slackMessages.wallet.buttonAdd, emoji: true }, + style: 'primary', + action_id: 'wallet_add' + } + ] + } + ], + response_type: 'in_channel' + }); + } + } + /** * Display the wallet management interface * Always shows list with add/remove buttons @@ -147,13 +179,17 @@ export class SlackWalletService extends BaseWalletService { throw new Error('No trigger_id available for modal'); } + // Encode channel + fromStart flag in private_metadata + const fromStart = context.session?.fromStart || false; + const metadata = JSON.stringify({ channelId, fromStart }); + // Open modal with wallet input await context.client.views.open({ trigger_id: triggerId, view: { type: 'modal', callback_id: 'wallet_add_modal', - private_metadata: channelId, + private_metadata: metadata, title: { type: 'plain_text', text: 'Add Wallet' @@ -214,7 +250,18 @@ export class SlackWalletService extends BaseWalletService { */ async processWalletSubmission(context: SlackViewContext): Promise { const workspaceId = context.body.team?.id || context.body.user?.team_id; - const channelId = context.view.private_metadata || context.body.user?.id; + + // Parse private_metadata (may be JSON with fromStart flag or plain channelId) + let channelId: string | undefined; + let fromStart = false; + try { + const parsed = JSON.parse(context.view.private_metadata); + channelId = parsed.channelId; + fromStart = parsed.fromStart || false; + } catch { + channelId = context.view.private_metadata || context.body.user?.id; + } + const fullUserId = `${workspaceId}:${channelId}`; try { @@ -258,6 +305,14 @@ export class SlackWalletService extends BaseWalletService { channel: channelId, blocks: successMessage(replacePlaceholders(slackMessages.wallet.addSuccess, { displayName })) }); + + // Send onboarding complete message if from start flow + if (fromStart) { + await context.client.chat.postMessage({ + channel: channelId, + text: slackMessages.wallet.onboardingComplete + }); + } } } catch (error) { console.error('Error processing wallet submission:', error); diff --git a/apps/consumers/src/utils/slack-blocks-templates.ts b/apps/consumers/src/utils/slack-blocks-templates.ts index 9c4802f7..cead8004 100644 --- a/apps/consumers/src/utils/slack-blocks-templates.ts +++ b/apps/consumers/src/utils/slack-blocks-templates.ts @@ -99,7 +99,11 @@ export const checkboxSelectionList = ( ] }, { type: 'divider' }, - actions(button(slackMessages.dao.confirmButton, confirmActionId, { style: confirmButtonStyle })) + actions( + button(slackMessages.dao.confirmButton, confirmActionId, { style: confirmButtonStyle }), + button('Select all', 'dao_select_all'), + button('Unselect all', 'dao_unselect_all') + ) ]; }; From a075cf62e08e061a28dfd96718be57f20293066c Mon Sep 17 00:00:00 2001 From: Leonardo Vieira Date: Thu, 5 Mar 2026 17:07:40 -0300 Subject: [PATCH 35/42] add: onboarding flow to slack --- apps/consumers/src/services/bot/slack-bot.service.ts | 10 +++++++++- apps/consumers/src/services/dao/base-dao.service.ts | 8 ++++++++ .../src/services/wallet/slack-wallet.service.ts | 4 +++- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/apps/consumers/src/services/bot/slack-bot.service.ts b/apps/consumers/src/services/bot/slack-bot.service.ts index 088ed791..2181b438 100644 --- a/apps/consumers/src/services/bot/slack-bot.service.ts +++ b/apps/consumers/src/services/bot/slack-bot.service.ts @@ -48,7 +48,11 @@ export class SlackBotService implements BotServiceInterface { // Welcome message actions handlers.action('welcome_select_daos', async (ctx) => { if (this.daoService) { - ctx.session.fromStart = true; + const channelId = ctx.body.channel?.id; + const workspaceId = ctx.body.team?.id || ctx.body.user?.team_id; + const fullUserId = `${workspaceId}:${channelId}`; + const hasDaos = await this.daoService.hasSubscriptions(fullUserId); + ctx.session.fromStart = !hasDaos; await this.daoService.initialize(ctx); } }); @@ -79,6 +83,7 @@ export class SlackBotService implements BotServiceInterface { // If from onboarding flow, trigger wallet setup if (ctx.session.fromStart && this.walletService) { await this.walletService.showOnboardingWallet(ctx); + ctx.session.fromStart = false; } } }); @@ -112,6 +117,9 @@ export class SlackBotService implements BotServiceInterface { handlers.action('wallet_add', async (ctx) => { if (this.walletService) { + // Set fromStart only when wallet_add comes from onboarding button + const actions = (ctx.body as any).actions; + ctx.session.fromStart = actions?.[0]?.value === 'onboarding'; await this.walletService.startAddWallet(ctx); } }); diff --git a/apps/consumers/src/services/dao/base-dao.service.ts b/apps/consumers/src/services/dao/base-dao.service.ts index 4d7bada9..026bd2cd 100644 --- a/apps/consumers/src/services/dao/base-dao.service.ts +++ b/apps/consumers/src/services/dao/base-dao.service.ts @@ -32,6 +32,14 @@ export abstract class BaseDAOService { return await this.anticaptureClient.getDAOs(); } + /** + * Check if user has any DAO subscriptions + */ + public async hasSubscriptions(userId: string): Promise { + const subs = await this.getUserSubscriptions(userId); + return subs.length > 0; + } + /** * Get user's current DAO subscriptions */ diff --git a/apps/consumers/src/services/wallet/slack-wallet.service.ts b/apps/consumers/src/services/wallet/slack-wallet.service.ts index 7325e47b..19bd7395 100644 --- a/apps/consumers/src/services/wallet/slack-wallet.service.ts +++ b/apps/consumers/src/services/wallet/slack-wallet.service.ts @@ -51,7 +51,8 @@ export class SlackWalletService extends BaseWalletService { type: 'button', text: { type: 'plain_text', text: slackMessages.wallet.buttonAdd, emoji: true }, style: 'primary', - action_id: 'wallet_add' + action_id: 'wallet_add', + value: 'onboarding' } ] } @@ -312,6 +313,7 @@ export class SlackWalletService extends BaseWalletService { channel: channelId, text: slackMessages.wallet.onboardingComplete }); + context.session.fromStart = false; } } } catch (error) { From 9dd9cba5e76524a60ad646ef8db84cf5162ca5a6 Mon Sep 17 00:00:00 2001 From: Leonardo Vieira Date: Thu, 5 Mar 2026 17:14:59 -0300 Subject: [PATCH 36/42] refactor: remove select all buttons from slack --- .../src/services/bot/slack-bot.service.ts | 11 ---- .../src/services/dao/slack-dao.service.ts | 58 ------------------- .../src/utils/slack-blocks-templates.ts | 4 +- 3 files changed, 1 insertion(+), 72 deletions(-) diff --git a/apps/consumers/src/services/bot/slack-bot.service.ts b/apps/consumers/src/services/bot/slack-bot.service.ts index 2181b438..807b993a 100644 --- a/apps/consumers/src/services/bot/slack-bot.service.ts +++ b/apps/consumers/src/services/bot/slack-bot.service.ts @@ -92,17 +92,6 @@ export class SlackBotService implements BotServiceInterface { await ctx.ack(); }); - handlers.action('dao_select_all', async (ctx) => { - if (this.daoService) { - await this.daoService.selectAll(ctx); - } - }); - - handlers.action('dao_unselect_all', async (ctx) => { - if (this.daoService) { - await this.daoService.unselectAll(ctx); - } - }); handlers.action('wallet_checkboxes', async (ctx) => { await ctx.ack(); diff --git a/apps/consumers/src/services/dao/slack-dao.service.ts b/apps/consumers/src/services/dao/slack-dao.service.ts index 6870e712..2b6db396 100644 --- a/apps/consumers/src/services/dao/slack-dao.service.ts +++ b/apps/consumers/src/services/dao/slack-dao.service.ts @@ -118,64 +118,6 @@ export class SlackDAOService extends BaseDAOService { } } - /** - * Select all DAOs - re-render checkboxes with all selected - */ - async selectAll(context: SlackActionContext): Promise { - try { - await context.ack(); - - const daos = await this.fetchAvailableDAOs(); - const allSelected = new Set(daos.map(dao => dao.id.toUpperCase())); - - const blocks = daoSelectionList( - daos, - allSelected, - 'dao_checkboxes', - 'dao_confirm_subscribe', - slackMessages.dao.subscribeInstructions - ); - - if (context.respond) { - await context.respond({ - blocks, - response_type: 'in_channel', - replace_original: true - }); - } - } catch (error) { - console.error('Error selecting all DAOs:', error); - } - } - - /** - * Unselect all DAOs - re-render checkboxes with none selected - */ - async unselectAll(context: SlackActionContext): Promise { - try { - await context.ack(); - - const daos = await this.fetchAvailableDAOs(); - - const blocks = daoSelectionList( - daos, - new Set(), - 'dao_checkboxes', - 'dao_confirm_subscribe', - slackMessages.dao.subscribeInstructions - ); - - if (context.respond) { - await context.respond({ - blocks, - response_type: 'in_channel', - replace_original: true - }); - } - } catch (error) { - console.error('Error unselecting all DAOs:', error); - } - } /** * Confirm DAO selection changes from checkboxes diff --git a/apps/consumers/src/utils/slack-blocks-templates.ts b/apps/consumers/src/utils/slack-blocks-templates.ts index cead8004..0928eb01 100644 --- a/apps/consumers/src/utils/slack-blocks-templates.ts +++ b/apps/consumers/src/utils/slack-blocks-templates.ts @@ -100,9 +100,7 @@ export const checkboxSelectionList = ( }, { type: 'divider' }, actions( - button(slackMessages.dao.confirmButton, confirmActionId, { style: confirmButtonStyle }), - button('Select all', 'dao_select_all'), - button('Unselect all', 'dao_unselect_all') + button(slackMessages.dao.confirmButton, confirmActionId, { style: confirmButtonStyle }) ) ]; }; From 795e71bba4a72748119f7afe93612aa2f80f4bad Mon Sep 17 00:00:00 2001 From: Leonardo Vieira Date: Thu, 5 Mar 2026 17:35:23 -0300 Subject: [PATCH 37/42] refactor: code improviments --- .../src/interfaces/slack-context.interface.ts | 1 + .../src/services/bot/slack-bot.service.ts | 5 ++-- .../src/services/bot/telegram-bot.service.ts | 16 ++++++------- .../src/services/dao/slack-dao.service.ts | 1 - .../services/wallet/slack-wallet.service.ts | 23 ++----------------- .../src/utils/slack-blocks-templates.ts | 9 ++++++++ packages/messages/src/ui/slack.ts | 13 ++++++++++- 7 files changed, 34 insertions(+), 34 deletions(-) diff --git a/apps/consumers/src/interfaces/slack-context.interface.ts b/apps/consumers/src/interfaces/slack-context.interface.ts index 3bd83b17..fc691b44 100644 --- a/apps/consumers/src/interfaces/slack-context.interface.ts +++ b/apps/consumers/src/interfaces/slack-context.interface.ts @@ -33,6 +33,7 @@ export interface SlackBodyWithIds { }; }; } | string; // Can be string for DialogSubmitAction or object for BlockAction + actions?: Array<{ action_id?: string; value?: string; type?: string }>; } /** diff --git a/apps/consumers/src/services/bot/slack-bot.service.ts b/apps/consumers/src/services/bot/slack-bot.service.ts index 807b993a..80aec5f8 100644 --- a/apps/consumers/src/services/bot/slack-bot.service.ts +++ b/apps/consumers/src/services/bot/slack-bot.service.ts @@ -106,9 +106,8 @@ export class SlackBotService implements BotServiceInterface { handlers.action('wallet_add', async (ctx) => { if (this.walletService) { - // Set fromStart only when wallet_add comes from onboarding button - const actions = (ctx.body as any).actions; - ctx.session.fromStart = actions?.[0]?.value === 'onboarding'; + const firstAction = ctx.body.actions?.[0]; + ctx.session.fromStart = firstAction?.value === 'onboarding'; await this.walletService.startAddWallet(ctx); } }); diff --git a/apps/consumers/src/services/bot/telegram-bot.service.ts b/apps/consumers/src/services/bot/telegram-bot.service.ts index 969e1fa6..d699b622 100644 --- a/apps/consumers/src/services/bot/telegram-bot.service.ts +++ b/apps/consumers/src/services/bot/telegram-bot.service.ts @@ -130,22 +130,22 @@ export class TelegramBotService implements BotServiceInterface { await this.walletService.confirmRemoval(ctx); }); - handlers.action(/^lm_start$/, async (ctx) => { + handlers.action(/^learn_more_start$/, async (ctx) => { await ctx.answerCbQuery(); await this.replyStartFlow(ctx); }); - handlers.action(/^lm_daos$/, async (ctx) => { + handlers.action(/^learn_more_daos$/, async (ctx) => { await ctx.answerCbQuery(); await this.daoService.initialize(ctx); }); - handlers.action(/^lm_wallets$/, async (ctx) => { + handlers.action(/^learn_more_wallets$/, async (ctx) => { await ctx.answerCbQuery(); await this.walletService.initialize(ctx); }); - handlers.action(/^lm_settings$/, async (ctx) => { + handlers.action(/^learn_more_settings$/, async (ctx) => { await ctx.answerCbQuery(uiMessages.buttons.settingsComingSoon); }); @@ -181,12 +181,12 @@ export class TelegramBotService implements BotServiceInterface { reply_markup: { inline_keyboard: [ [ - { text: uiMessages.buttons.start, callback_data: 'lm_start' }, - { text: uiMessages.buttons.daos, callback_data: 'lm_daos' }, + { text: uiMessages.buttons.start, callback_data: 'learn_more_start' }, + { text: uiMessages.buttons.daos, callback_data: 'learn_more_daos' }, ], [ - { text: uiMessages.buttons.wallets, callback_data: 'lm_wallets' }, - { text: uiMessages.buttons.settings, callback_data: 'lm_settings' }, + { text: uiMessages.buttons.wallets, callback_data: 'learn_more_wallets' }, + { text: uiMessages.buttons.settings, callback_data: 'learn_more_settings' }, ] ] } diff --git a/apps/consumers/src/services/dao/slack-dao.service.ts b/apps/consumers/src/services/dao/slack-dao.service.ts index 2b6db396..e84a7703 100644 --- a/apps/consumers/src/services/dao/slack-dao.service.ts +++ b/apps/consumers/src/services/dao/slack-dao.service.ts @@ -118,7 +118,6 @@ export class SlackDAOService extends BaseDAOService { } } - /** * Confirm DAO selection changes from checkboxes */ diff --git a/apps/consumers/src/services/wallet/slack-wallet.service.ts b/apps/consumers/src/services/wallet/slack-wallet.service.ts index 19bd7395..6054dc11 100644 --- a/apps/consumers/src/services/wallet/slack-wallet.service.ts +++ b/apps/consumers/src/services/wallet/slack-wallet.service.ts @@ -15,6 +15,7 @@ import { } from '../../interfaces/slack-context.interface'; import { walletEmptyState, + walletOnboardingPromptBlocks, successMessage, walletSelectionList } from '../../utils/slack-blocks-templates'; @@ -36,27 +37,7 @@ export class SlackWalletService extends BaseWalletService { if (context.respond) { await context.respond({ replace_original: false, - blocks: [ - { - type: 'section', - text: { - type: 'mrkdwn', - text: slackMessages.wallet.selectionPrefix + slackMessages.wallet.listHeader - } - }, - { - type: 'actions', - elements: [ - { - type: 'button', - text: { type: 'plain_text', text: slackMessages.wallet.buttonAdd, emoji: true }, - style: 'primary', - action_id: 'wallet_add', - value: 'onboarding' - } - ] - } - ], + blocks: walletOnboardingPromptBlocks(), response_type: 'in_channel' }); } diff --git a/apps/consumers/src/utils/slack-blocks-templates.ts b/apps/consumers/src/utils/slack-blocks-templates.ts index 0928eb01..1b95c9c1 100644 --- a/apps/consumers/src/utils/slack-blocks-templates.ts +++ b/apps/consumers/src/utils/slack-blocks-templates.ts @@ -164,6 +164,15 @@ export const walletSelectionList = ( ); }; +/** + * Onboarding wallet prompt (after DAO selection): "Next step" message + Add wallet button. + * Shared so showOnboardingWallet and list logic use the same block structure. + */ +export const walletOnboardingPromptBlocks = (): KnownBlock[] => [ + section(slackMessages.wallet.selectionPrefix + slackMessages.wallet.listHeader), + actions(button(slackMessages.wallet.buttonAdd, 'wallet_add', { style: 'primary', value: 'onboarding' })) +]; + /** * Wallet empty state */ diff --git a/packages/messages/src/ui/slack.ts b/packages/messages/src/ui/slack.ts index 3f1dda48..1ec732f6 100644 --- a/packages/messages/src/ui/slack.ts +++ b/packages/messages/src/ui/slack.ts @@ -20,7 +20,18 @@ export const slackMessages = { // Wallet management messages wallet: { - listHeader: '*Add your wallet address*\n\nThis allows us to personalize alerts based on your governance activity and delegations.', + /** Same content as Telegram wallet onboarding (common.ts wallet.selection) for consistency */ + listHeader: `*Add your wallet address* + +This allows us to personalize alerts based on your governance activity and delegations. + +You'll receive notifications for: +• Delegation changes that affect your voting power +• Transfers that affect your voting power +• Non-voting alerts +• Vote confirmations + +Stay aware of how changes in governance affect you.`, selectionPrefix: '*Next step:* ', onboardingComplete: '🎉 You\'re all set! Stay tuned — we\'ll notify you as soon as something important happens in your DAOs.', emptyList: "You can add wallets and receive custom notifications related to them and the DAOs you follow!", From 2b295302c52bf839bcb582ea78e2141f7fb8e8a5 Mon Sep 17 00:00:00 2001 From: Leonardo Vieira Date: Fri, 6 Mar 2026 14:50:53 -0300 Subject: [PATCH 38/42] feat: proposal link to be added on the button --- ...-offchain-proposal-trigger.service.test.ts | 23 ++++++++++--------- .../new-offchain-proposal-trigger.service.ts | 3 ++- packages/anticapture-client/dist/gql/gql.d.ts | 4 ++-- packages/anticapture-client/dist/gql/gql.js | 2 +- .../anticapture-client/dist/gql/graphql.d.ts | 1 + .../anticapture-client/dist/gql/graphql.js | 2 +- packages/anticapture-client/dist/schemas.d.ts | 12 ++++++++++ packages/anticapture-client/dist/schemas.js | 1 + .../queries/offchain-proposals.graphql | 1 + packages/anticapture-client/src/gql/gql.ts | 6 ++--- .../anticapture-client/src/gql/graphql.ts | 4 ++-- packages/anticapture-client/src/schemas.ts | 1 + packages/messages/src/triggers/buttons.ts | 9 +++++++- 13 files changed, 47 insertions(+), 22 deletions(-) diff --git a/apps/dispatcher/src/services/triggers/new-offchain-proposal-trigger.service.test.ts b/apps/dispatcher/src/services/triggers/new-offchain-proposal-trigger.service.test.ts index 5a31193e..96e7428f 100644 --- a/apps/dispatcher/src/services/triggers/new-offchain-proposal-trigger.service.test.ts +++ b/apps/dispatcher/src/services/triggers/new-offchain-proposal-trigger.service.test.ts @@ -72,7 +72,7 @@ describe('NewOffchainProposalTriggerHandler', () => { triggerId: 'new-offchain-proposal', events: [{ daoId: 'test-dao', id: 'snap-1', title: 'Grant Program', - created: 1700000000, discussion: '', state: 'active', + created: 1700000000, discussion: '', link: 'https://snapshot.org/#/test-dao/proposal/snap-1', state: 'active', }], }; @@ -89,7 +89,7 @@ describe('NewOffchainProposalTriggerHandler', () => { triggerId: 'new-offchain-proposal', events: [{ daoId: 'test-dao', id: 'snap-1', title: '', - created: 1700000000, discussion: '', state: 'active', + created: 1700000000, discussion: '', link: 'https://snapshot.org/#/test-dao/proposal/snap-1', state: 'active', }], }; @@ -105,7 +105,7 @@ describe('NewOffchainProposalTriggerHandler', () => { triggerId: 'new-offchain-proposal', events: [{ daoId: 'test-dao', id: 'snap-123', title: 'Test', - created: 1700000000, discussion: '', state: 'active', + created: 1700000000, discussion: '', link: 'https://snapshot.org/#/test-dao/proposal/snap-123', state: 'active', }], }; @@ -114,14 +114,14 @@ describe('NewOffchainProposalTriggerHandler', () => { expect(subscriptionClient.sentNotifications[0].event_id).toBe('offchain-snap-123'); }); - it('should always include CTA button "Review DAO data before voting"', async () => { + it('should always include CTA button "Cast your vote"', async () => { subscriptionClient.subscribers.set('test-dao', [testUser]); const message: DispatcherMessage = { triggerId: 'new-offchain-proposal', events: [{ daoId: 'test-dao', id: 'snap-1', title: 'Test', - created: 1700000000, discussion: '', state: 'active', + created: 1700000000, discussion: '', link: 'https://snapshot.org/#/test-dao/proposal/snap-1', state: 'active', }], }; @@ -129,7 +129,8 @@ describe('NewOffchainProposalTriggerHandler', () => { const buttons = notificationClient.sentPayloads[0].metadata?.buttons; expect(buttons).toBeDefined(); - expect(buttons[0].text).toBe('Review DAO data before voting'); + expect(buttons[0].text).toBe('Cast your vote'); + expect(buttons[0].url).toBe('https://snapshot.org/#/test-dao/proposal/snap-1'); }); it('should include "View Discussion" button when discussion URL is provided', async () => { @@ -139,7 +140,7 @@ describe('NewOffchainProposalTriggerHandler', () => { triggerId: 'new-offchain-proposal', events: [{ daoId: 'test-dao', id: 'snap-1', title: 'Test', - created: 1700000000, discussion: 'https://forum.example.com/123', state: 'active', + created: 1700000000, discussion: 'https://forum.example.com/123', link: 'https://snapshot.org/#/test-dao/proposal/snap-1', state: 'active', }], }; @@ -158,7 +159,7 @@ describe('NewOffchainProposalTriggerHandler', () => { triggerId: 'new-offchain-proposal', events: [{ daoId: 'test-dao', id: 'snap-1', title: 'Test', - created: 1700000000, discussion: '', state: 'active', + created: 1700000000, discussion: '', link: 'https://snapshot.org/#/test-dao/proposal/snap-1', state: 'active', }], }; @@ -176,8 +177,8 @@ describe('NewOffchainProposalTriggerHandler', () => { const message: DispatcherMessage = { triggerId: 'new-offchain-proposal', events: [ - { daoId: 'dao-a', id: 'snap-1', title: 'Proposal A', created: 1700000000, discussion: '', state: 'active' }, - { daoId: 'dao-b', id: 'snap-2', title: 'Proposal B', created: 1700000100, discussion: '', state: 'active' }, + { daoId: 'dao-a', id: 'snap-1', title: 'Proposal A', created: 1700000000, discussion: '', link: 'https://snapshot.org/#/dao-a/proposal/snap-1', state: 'active' }, + { daoId: 'dao-b', id: 'snap-2', title: 'Proposal B', created: 1700000100, discussion: '', link: 'https://snapshot.org/#/dao-b/proposal/snap-2', state: 'active' }, ], }; @@ -207,7 +208,7 @@ describe('NewOffchainProposalTriggerHandler', () => { triggerId: 'new-offchain-proposal', events: [{ daoId: 'test-dao', id: 'snap-1', title: 'Test', - created: 1700000000, discussion: '', state: 'active', + created: 1700000000, discussion: '', link: 'https://snapshot.org/#/test-dao/proposal/snap-1', state: 'active', }], }; diff --git a/apps/dispatcher/src/services/triggers/new-offchain-proposal-trigger.service.ts b/apps/dispatcher/src/services/triggers/new-offchain-proposal-trigger.service.ts index 693cef95..7eaa2a2e 100644 --- a/apps/dispatcher/src/services/triggers/new-offchain-proposal-trigger.service.ts +++ b/apps/dispatcher/src/services/triggers/new-offchain-proposal-trigger.service.ts @@ -22,7 +22,7 @@ export class NewOffchainProposalTriggerHandler extends BaseTriggerHandler { */ async handleMessage(message: DispatcherMessage): Promise { for (const proposal of message.events) { - const { daoId, id: proposalId, title, created, discussion } = proposal; + const { daoId, id: proposalId, title, created, discussion, link } = proposal; const eventId = `offchain-${proposalId}`; const proposalTimestamp = String(created); @@ -35,6 +35,7 @@ export class NewOffchainProposalTriggerHandler extends BaseTriggerHandler { // Build buttons — include discussion link if available, no txHash for offchain const buttons = buildButtons({ triggerType: 'newOffchainProposal', + proposalUrl: link || undefined, discussionUrl: discussion || undefined, }); diff --git a/packages/anticapture-client/dist/gql/gql.d.ts b/packages/anticapture-client/dist/gql/gql.d.ts index 8df8eec4..bd814514 100644 --- a/packages/anticapture-client/dist/gql/gql.d.ts +++ b/packages/anticapture-client/dist/gql/gql.d.ts @@ -13,7 +13,7 @@ import type { TypedDocumentNode as DocumentNode } from '@graphql-typed-document- */ type Documents = { "query GetDAOs {\n daos {\n items {\n id\n votingDelay\n chainId\n }\n }\n}": typeof types.GetDaOsDocument; - "query ListOffchainProposals($skip: NonNegativeInt, $limit: PositiveInt, $orderDirection: queryInput_offchainProposals_orderDirection, $status: JSON, $fromDate: Float) {\n offchainProposals(\n skip: $skip\n limit: $limit\n orderDirection: $orderDirection\n status: $status\n fromDate: $fromDate\n ) {\n items {\n id\n title\n discussion\n state\n created\n }\n totalCount\n }\n}": typeof types.ListOffchainProposalsDocument; + "query ListOffchainProposals($skip: NonNegativeInt, $limit: PositiveInt, $orderDirection: queryInput_offchainProposals_orderDirection, $status: JSON, $fromDate: Float) {\n offchainProposals(\n skip: $skip\n limit: $limit\n orderDirection: $orderDirection\n status: $status\n fromDate: $fromDate\n ) {\n items {\n id\n title\n discussion\n link\n state\n created\n }\n totalCount\n }\n}": typeof types.ListOffchainProposalsDocument; "query ProposalNonVoters($id: String!, $addresses: JSON) {\n proposalNonVoters(id: $id, addresses: $addresses) {\n items {\n voter\n }\n }\n}": typeof types.ProposalNonVotersDocument; "query GetProposalById($id: String!) {\n proposal(id: $id) {\n id\n daoId\n proposerAccountId\n title\n description\n startBlock\n endBlock\n endTimestamp\n timestamp\n status\n forVotes\n againstVotes\n abstainVotes\n txHash\n }\n}\n\nquery ListProposals($skip: NonNegativeInt, $limit: PositiveInt, $orderDirection: queryInput_proposals_orderDirection, $status: JSON, $fromDate: Float, $fromEndDate: Float, $includeOptimisticProposals: queryInput_proposals_includeOptimisticProposals) {\n proposals(\n skip: $skip\n limit: $limit\n orderDirection: $orderDirection\n status: $status\n fromDate: $fromDate\n fromEndDate: $fromEndDate\n includeOptimisticProposals: $includeOptimisticProposals\n ) {\n items {\n id\n daoId\n proposerAccountId\n title\n description\n startBlock\n endBlock\n endTimestamp\n timestamp\n status\n forVotes\n againstVotes\n abstainVotes\n txHash\n }\n totalCount\n }\n}": typeof types.GetProposalByIdDocument; "query ListVotes($voterAddressIn: JSON, $fromDate: Float, $toDate: Float, $limit: Float, $skip: NonNegativeInt, $orderBy: queryInput_votes_orderBy, $orderDirection: queryInput_votes_orderDirection, $support: Float) {\n votes(\n voterAddressIn: $voterAddressIn\n fromDate: $fromDate\n toDate: $toDate\n limit: $limit\n skip: $skip\n orderBy: $orderBy\n orderDirection: $orderDirection\n support: $support\n ) {\n items {\n transactionHash\n proposalId\n voterAddress\n support\n votingPower\n timestamp\n reason\n proposalTitle\n }\n totalCount\n }\n}": typeof types.ListVotesDocument; @@ -40,7 +40,7 @@ export declare function graphql(source: "query GetDAOs {\n daos {\n items {\ /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export declare function graphql(source: "query ListOffchainProposals($skip: NonNegativeInt, $limit: PositiveInt, $orderDirection: queryInput_offchainProposals_orderDirection, $status: JSON, $fromDate: Float) {\n offchainProposals(\n skip: $skip\n limit: $limit\n orderDirection: $orderDirection\n status: $status\n fromDate: $fromDate\n ) {\n items {\n id\n title\n discussion\n state\n created\n }\n totalCount\n }\n}"): (typeof documents)["query ListOffchainProposals($skip: NonNegativeInt, $limit: PositiveInt, $orderDirection: queryInput_offchainProposals_orderDirection, $status: JSON, $fromDate: Float) {\n offchainProposals(\n skip: $skip\n limit: $limit\n orderDirection: $orderDirection\n status: $status\n fromDate: $fromDate\n ) {\n items {\n id\n title\n discussion\n state\n created\n }\n totalCount\n }\n}"]; +export declare function graphql(source: "query ListOffchainProposals($skip: NonNegativeInt, $limit: PositiveInt, $orderDirection: queryInput_offchainProposals_orderDirection, $status: JSON, $fromDate: Float) {\n offchainProposals(\n skip: $skip\n limit: $limit\n orderDirection: $orderDirection\n status: $status\n fromDate: $fromDate\n ) {\n items {\n id\n title\n discussion\n link\n state\n created\n }\n totalCount\n }\n}"): (typeof documents)["query ListOffchainProposals($skip: NonNegativeInt, $limit: PositiveInt, $orderDirection: queryInput_offchainProposals_orderDirection, $status: JSON, $fromDate: Float) {\n offchainProposals(\n skip: $skip\n limit: $limit\n orderDirection: $orderDirection\n status: $status\n fromDate: $fromDate\n ) {\n items {\n id\n title\n discussion\n link\n state\n created\n }\n totalCount\n }\n}"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/packages/anticapture-client/dist/gql/gql.js b/packages/anticapture-client/dist/gql/gql.js index 3cc6078a..59e9b9f7 100644 --- a/packages/anticapture-client/dist/gql/gql.js +++ b/packages/anticapture-client/dist/gql/gql.js @@ -38,7 +38,7 @@ exports.graphql = graphql; const types = __importStar(require("./graphql")); const documents = { "query GetDAOs {\n daos {\n items {\n id\n votingDelay\n chainId\n }\n }\n}": types.GetDaOsDocument, - "query ListOffchainProposals($skip: NonNegativeInt, $limit: PositiveInt, $orderDirection: queryInput_offchainProposals_orderDirection, $status: JSON, $fromDate: Float) {\n offchainProposals(\n skip: $skip\n limit: $limit\n orderDirection: $orderDirection\n status: $status\n fromDate: $fromDate\n ) {\n items {\n id\n title\n discussion\n state\n created\n }\n totalCount\n }\n}": types.ListOffchainProposalsDocument, + "query ListOffchainProposals($skip: NonNegativeInt, $limit: PositiveInt, $orderDirection: queryInput_offchainProposals_orderDirection, $status: JSON, $fromDate: Float) {\n offchainProposals(\n skip: $skip\n limit: $limit\n orderDirection: $orderDirection\n status: $status\n fromDate: $fromDate\n ) {\n items {\n id\n title\n discussion\n link\n state\n created\n }\n totalCount\n }\n}": types.ListOffchainProposalsDocument, "query ProposalNonVoters($id: String!, $addresses: JSON) {\n proposalNonVoters(id: $id, addresses: $addresses) {\n items {\n voter\n }\n }\n}": types.ProposalNonVotersDocument, "query GetProposalById($id: String!) {\n proposal(id: $id) {\n id\n daoId\n proposerAccountId\n title\n description\n startBlock\n endBlock\n endTimestamp\n timestamp\n status\n forVotes\n againstVotes\n abstainVotes\n txHash\n }\n}\n\nquery ListProposals($skip: NonNegativeInt, $limit: PositiveInt, $orderDirection: queryInput_proposals_orderDirection, $status: JSON, $fromDate: Float, $fromEndDate: Float, $includeOptimisticProposals: queryInput_proposals_includeOptimisticProposals) {\n proposals(\n skip: $skip\n limit: $limit\n orderDirection: $orderDirection\n status: $status\n fromDate: $fromDate\n fromEndDate: $fromEndDate\n includeOptimisticProposals: $includeOptimisticProposals\n ) {\n items {\n id\n daoId\n proposerAccountId\n title\n description\n startBlock\n endBlock\n endTimestamp\n timestamp\n status\n forVotes\n againstVotes\n abstainVotes\n txHash\n }\n totalCount\n }\n}": types.GetProposalByIdDocument, "query ListVotes($voterAddressIn: JSON, $fromDate: Float, $toDate: Float, $limit: Float, $skip: NonNegativeInt, $orderBy: queryInput_votes_orderBy, $orderDirection: queryInput_votes_orderDirection, $support: Float) {\n votes(\n voterAddressIn: $voterAddressIn\n fromDate: $fromDate\n toDate: $toDate\n limit: $limit\n skip: $skip\n orderBy: $orderBy\n orderDirection: $orderDirection\n support: $support\n ) {\n items {\n transactionHash\n proposalId\n voterAddress\n support\n votingPower\n timestamp\n reason\n proposalTitle\n }\n totalCount\n }\n}": types.ListVotesDocument, diff --git a/packages/anticapture-client/dist/gql/graphql.d.ts b/packages/anticapture-client/dist/gql/graphql.d.ts index f32a3d12..12c94066 100644 --- a/packages/anticapture-client/dist/gql/graphql.d.ts +++ b/packages/anticapture-client/dist/gql/graphql.d.ts @@ -1682,6 +1682,7 @@ export type ListOffchainProposalsQuery = { id: string; title: string; discussion: string; + link: string; state: string; created: number; } | null>; diff --git a/packages/anticapture-client/dist/gql/graphql.js b/packages/anticapture-client/dist/gql/graphql.js index 20d2c665..f670e10e 100644 --- a/packages/anticapture-client/dist/gql/graphql.js +++ b/packages/anticapture-client/dist/gql/graphql.js @@ -407,7 +407,7 @@ var Timestamp_Const; Timestamp_Const["Timestamp"] = "timestamp"; })(Timestamp_Const || (exports.Timestamp_Const = Timestamp_Const = {})); exports.GetDaOsDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "GetDAOs" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "daos" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "items" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "votingDelay" } }, { "kind": "Field", "name": { "kind": "Name", "value": "chainId" } }] } }] } }] } }] }; -exports.ListOffchainProposalsDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "ListOffchainProposals" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "skip" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "NonNegativeInt" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "limit" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "PositiveInt" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "orderDirection" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "queryInput_offchainProposals_orderDirection" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "status" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "JSON" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "fromDate" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Float" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "offchainProposals" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "skip" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "skip" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "limit" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "limit" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "orderDirection" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "orderDirection" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "status" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "status" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "fromDate" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "fromDate" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "items" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "title" } }, { "kind": "Field", "name": { "kind": "Name", "value": "discussion" } }, { "kind": "Field", "name": { "kind": "Name", "value": "state" } }, { "kind": "Field", "name": { "kind": "Name", "value": "created" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "totalCount" } }] } }] } }] }; +exports.ListOffchainProposalsDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "ListOffchainProposals" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "skip" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "NonNegativeInt" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "limit" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "PositiveInt" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "orderDirection" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "queryInput_offchainProposals_orderDirection" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "status" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "JSON" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "fromDate" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Float" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "offchainProposals" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "skip" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "skip" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "limit" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "limit" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "orderDirection" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "orderDirection" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "status" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "status" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "fromDate" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "fromDate" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "items" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "title" } }, { "kind": "Field", "name": { "kind": "Name", "value": "discussion" } }, { "kind": "Field", "name": { "kind": "Name", "value": "link" } }, { "kind": "Field", "name": { "kind": "Name", "value": "state" } }, { "kind": "Field", "name": { "kind": "Name", "value": "created" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "totalCount" } }] } }] } }] }; exports.ProposalNonVotersDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "ProposalNonVoters" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "id" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "String" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "addresses" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "JSON" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "proposalNonVoters" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "id" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "id" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "addresses" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "addresses" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "items" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "voter" } }] } }] } }] } }] }; exports.GetProposalByIdDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "GetProposalById" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "id" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "String" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "proposal" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "id" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "id" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "daoId" } }, { "kind": "Field", "name": { "kind": "Name", "value": "proposerAccountId" } }, { "kind": "Field", "name": { "kind": "Name", "value": "title" } }, { "kind": "Field", "name": { "kind": "Name", "value": "description" } }, { "kind": "Field", "name": { "kind": "Name", "value": "startBlock" } }, { "kind": "Field", "name": { "kind": "Name", "value": "endBlock" } }, { "kind": "Field", "name": { "kind": "Name", "value": "endTimestamp" } }, { "kind": "Field", "name": { "kind": "Name", "value": "timestamp" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }, { "kind": "Field", "name": { "kind": "Name", "value": "forVotes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "againstVotes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "abstainVotes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "txHash" } }] } }] } }] }; exports.ListProposalsDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "ListProposals" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "skip" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "NonNegativeInt" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "limit" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "PositiveInt" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "orderDirection" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "queryInput_proposals_orderDirection" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "status" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "JSON" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "fromDate" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Float" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "fromEndDate" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Float" } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "includeOptimisticProposals" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "queryInput_proposals_includeOptimisticProposals" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "proposals" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "skip" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "skip" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "limit" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "limit" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "orderDirection" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "orderDirection" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "status" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "status" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "fromDate" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "fromDate" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "fromEndDate" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "fromEndDate" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "includeOptimisticProposals" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "includeOptimisticProposals" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "items" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "daoId" } }, { "kind": "Field", "name": { "kind": "Name", "value": "proposerAccountId" } }, { "kind": "Field", "name": { "kind": "Name", "value": "title" } }, { "kind": "Field", "name": { "kind": "Name", "value": "description" } }, { "kind": "Field", "name": { "kind": "Name", "value": "startBlock" } }, { "kind": "Field", "name": { "kind": "Name", "value": "endBlock" } }, { "kind": "Field", "name": { "kind": "Name", "value": "endTimestamp" } }, { "kind": "Field", "name": { "kind": "Name", "value": "timestamp" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }, { "kind": "Field", "name": { "kind": "Name", "value": "forVotes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "againstVotes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "abstainVotes" } }, { "kind": "Field", "name": { "kind": "Name", "value": "txHash" } }] } }, { "kind": "Field", "name": { "kind": "Name", "value": "totalCount" } }] } }] } }] }; diff --git a/packages/anticapture-client/dist/schemas.d.ts b/packages/anticapture-client/dist/schemas.d.ts index 542e6374..ecca3558 100644 --- a/packages/anticapture-client/dist/schemas.d.ts +++ b/packages/anticapture-client/dist/schemas.d.ts @@ -563,15 +563,18 @@ export declare const OffchainProposalItemSchema: z.ZodObject<{ id: z.ZodString; title: z.ZodString; discussion: z.ZodString; + link: z.ZodString; state: z.ZodString; created: z.ZodNumber; }, "strip", z.ZodTypeAny, { + link: string; created: number; id: string; title: string; discussion: string; state: string; }, { + link: string; created: number; id: string; title: string; @@ -585,15 +588,18 @@ export declare const SafeOffchainProposalsResponseSchema: z.ZodEffects, { offchainProposals: { items: { + link: string; created: number; id: string; title: string; @@ -656,6 +667,7 @@ export declare const SafeOffchainProposalsResponseSchema: z.ZodEffects; -export type ListOffchainProposalsQuery = { __typename?: 'Query', offchainProposals?: { __typename?: 'offchainProposals_200_response', totalCount: number, items: Array<{ __typename?: 'query_offchainProposals_items_items', id: string, title: string, discussion: string, state: string, created: number } | null> } | null }; +export type ListOffchainProposalsQuery = { __typename?: 'Query', offchainProposals?: { __typename?: 'offchainProposals_200_response', totalCount: number, items: Array<{ __typename?: 'query_offchainProposals_items_items', id: string, title: string, discussion: string, link: string, state: string, created: number } | null> } | null }; export type ProposalNonVotersQueryVariables = Exact<{ id: Scalars['String']['input']; @@ -1962,7 +1962,7 @@ export type ListHistoricalVotingPowerQuery = { __typename?: 'Query', historicalV export const GetDaOsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetDAOs"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"daos"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"votingDelay"}},{"kind":"Field","name":{"kind":"Name","value":"chainId"}}]}}]}}]}}]} as unknown as DocumentNode; -export const ListOffchainProposalsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ListOffchainProposals"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"skip"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"NonNegativeInt"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"limit"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PositiveInt"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"orderDirection"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"queryInput_offchainProposals_orderDirection"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"status"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"fromDate"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"offchainProposals"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"skip"},"value":{"kind":"Variable","name":{"kind":"Name","value":"skip"}}},{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"Variable","name":{"kind":"Name","value":"limit"}}},{"kind":"Argument","name":{"kind":"Name","value":"orderDirection"},"value":{"kind":"Variable","name":{"kind":"Name","value":"orderDirection"}}},{"kind":"Argument","name":{"kind":"Name","value":"status"},"value":{"kind":"Variable","name":{"kind":"Name","value":"status"}}},{"kind":"Argument","name":{"kind":"Name","value":"fromDate"},"value":{"kind":"Variable","name":{"kind":"Name","value":"fromDate"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"discussion"}},{"kind":"Field","name":{"kind":"Name","value":"state"}},{"kind":"Field","name":{"kind":"Name","value":"created"}}]}},{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}}]}}]} as unknown as DocumentNode; +export const ListOffchainProposalsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ListOffchainProposals"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"skip"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"NonNegativeInt"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"limit"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PositiveInt"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"orderDirection"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"queryInput_offchainProposals_orderDirection"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"status"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"fromDate"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"offchainProposals"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"skip"},"value":{"kind":"Variable","name":{"kind":"Name","value":"skip"}}},{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"Variable","name":{"kind":"Name","value":"limit"}}},{"kind":"Argument","name":{"kind":"Name","value":"orderDirection"},"value":{"kind":"Variable","name":{"kind":"Name","value":"orderDirection"}}},{"kind":"Argument","name":{"kind":"Name","value":"status"},"value":{"kind":"Variable","name":{"kind":"Name","value":"status"}}},{"kind":"Argument","name":{"kind":"Name","value":"fromDate"},"value":{"kind":"Variable","name":{"kind":"Name","value":"fromDate"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"discussion"}},{"kind":"Field","name":{"kind":"Name","value":"link"}},{"kind":"Field","name":{"kind":"Name","value":"state"}},{"kind":"Field","name":{"kind":"Name","value":"created"}}]}},{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}}]}}]} as unknown as DocumentNode; export const ProposalNonVotersDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ProposalNonVoters"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"addresses"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"proposalNonVoters"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}},{"kind":"Argument","name":{"kind":"Name","value":"addresses"},"value":{"kind":"Variable","name":{"kind":"Name","value":"addresses"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"voter"}}]}}]}}]}}]} as unknown as DocumentNode; export const GetProposalByIdDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetProposalById"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"proposal"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"daoId"}},{"kind":"Field","name":{"kind":"Name","value":"proposerAccountId"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"startBlock"}},{"kind":"Field","name":{"kind":"Name","value":"endBlock"}},{"kind":"Field","name":{"kind":"Name","value":"endTimestamp"}},{"kind":"Field","name":{"kind":"Name","value":"timestamp"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"forVotes"}},{"kind":"Field","name":{"kind":"Name","value":"againstVotes"}},{"kind":"Field","name":{"kind":"Name","value":"abstainVotes"}},{"kind":"Field","name":{"kind":"Name","value":"txHash"}}]}}]}}]} as unknown as DocumentNode; export const ListProposalsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ListProposals"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"skip"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"NonNegativeInt"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"limit"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"PositiveInt"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"orderDirection"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"queryInput_proposals_orderDirection"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"status"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"fromDate"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"fromEndDate"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Float"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"includeOptimisticProposals"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"queryInput_proposals_includeOptimisticProposals"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"proposals"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"skip"},"value":{"kind":"Variable","name":{"kind":"Name","value":"skip"}}},{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"Variable","name":{"kind":"Name","value":"limit"}}},{"kind":"Argument","name":{"kind":"Name","value":"orderDirection"},"value":{"kind":"Variable","name":{"kind":"Name","value":"orderDirection"}}},{"kind":"Argument","name":{"kind":"Name","value":"status"},"value":{"kind":"Variable","name":{"kind":"Name","value":"status"}}},{"kind":"Argument","name":{"kind":"Name","value":"fromDate"},"value":{"kind":"Variable","name":{"kind":"Name","value":"fromDate"}}},{"kind":"Argument","name":{"kind":"Name","value":"fromEndDate"},"value":{"kind":"Variable","name":{"kind":"Name","value":"fromEndDate"}}},{"kind":"Argument","name":{"kind":"Name","value":"includeOptimisticProposals"},"value":{"kind":"Variable","name":{"kind":"Name","value":"includeOptimisticProposals"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"daoId"}},{"kind":"Field","name":{"kind":"Name","value":"proposerAccountId"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"startBlock"}},{"kind":"Field","name":{"kind":"Name","value":"endBlock"}},{"kind":"Field","name":{"kind":"Name","value":"endTimestamp"}},{"kind":"Field","name":{"kind":"Name","value":"timestamp"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"forVotes"}},{"kind":"Field","name":{"kind":"Name","value":"againstVotes"}},{"kind":"Field","name":{"kind":"Name","value":"abstainVotes"}},{"kind":"Field","name":{"kind":"Name","value":"txHash"}}]}},{"kind":"Field","name":{"kind":"Name","value":"totalCount"}}]}}]}}]} as unknown as DocumentNode; diff --git a/packages/anticapture-client/src/schemas.ts b/packages/anticapture-client/src/schemas.ts index b28e8835..4fd23d6f 100644 --- a/packages/anticapture-client/src/schemas.ts +++ b/packages/anticapture-client/src/schemas.ts @@ -125,6 +125,7 @@ export const OffchainProposalItemSchema = z.object({ id: z.string(), title: z.string(), discussion: z.string(), + link: z.string(), state: z.string(), created: z.number(), }); diff --git a/packages/messages/src/triggers/buttons.ts b/packages/messages/src/triggers/buttons.ts index c63cc9ab..7d7c8cd4 100644 --- a/packages/messages/src/triggers/buttons.ts +++ b/packages/messages/src/triggers/buttons.ts @@ -63,6 +63,11 @@ const ctaButtonConfigs: Record = { daoId && proposalId ? `${BASE_URL}/${daoId}/governance/proposal/${proposalId}` : BASE_URL + }, + newOffchainProposal: { + text: 'Cast your vote', + buildUrl: ({ proposalUrl }) => + proposalUrl || BASE_URL } }; @@ -87,6 +92,7 @@ export interface BuildButtonsParams { daoId?: string; address?: string; proposalId?: string; + proposalUrl?: string; } const explorerService = new ExplorerService(); @@ -102,7 +108,8 @@ export function buildButtons(params: BuildButtonsParams): Button[] { const url = config.buildUrl({ daoId: params.daoId, address: params.address, - proposalId: params.proposalId + proposalId: params.proposalId, + proposalUrl: params.proposalUrl }); buttons.push({ text: config.text, url }); From d993cf142dc2281883710c307a22cd3679112211 Mon Sep 17 00:00:00 2001 From: Leonardo Vieira Date: Fri, 6 Mar 2026 15:15:10 -0300 Subject: [PATCH 39/42] add: generated files --- .../anticapture-client/dist/gql/graphql.d.ts | 68 +++++++++++++++++-- .../anticapture-client/dist/gql/graphql.js | 10 +-- packages/anticapture-client/dist/schemas.d.ts | 20 +++--- 3 files changed, 78 insertions(+), 20 deletions(-) diff --git a/packages/anticapture-client/dist/gql/graphql.d.ts b/packages/anticapture-client/dist/gql/graphql.d.ts index 78a63ea6..5283b599 100644 --- a/packages/anticapture-client/dist/gql/graphql.d.ts +++ b/packages/anticapture-client/dist/gql/graphql.d.ts @@ -155,6 +155,10 @@ export type Query = { delegators?: Maybe; /** Get feed events */ feedEvents?: Maybe; + /** Returns label information from Arkham, ENS data, and whether the address is an EOA or contract. Arkham data is stored permanently. ENS data is cached with a configurable TTL. */ + getAddress?: Maybe; + /** Returns label information from Arkham, ENS data, and address type for multiple addresses. Maximum 100 addresses per request. Arkham data is stored permanently. ENS data is cached with a configurable TTL. */ + getAddresses?: Maybe; /** Get historical DAO Token Treasury value (governance token quantity × token price) */ getDaoTokenTreasury?: Maybe; /** Get event relevance threshold */ @@ -323,6 +327,12 @@ export type QueryFeedEventsArgs = { toDate?: InputMaybe; type?: InputMaybe; }; +export type QueryGetAddressArgs = { + address: Scalars['String']['input']; +}; +export type QueryGetAddressesArgs = { + addresses: Scalars['JSON']['input']; +}; export type QueryGetDaoTokenTreasuryArgs = { days?: InputMaybe; order?: InputMaybe; @@ -655,6 +665,17 @@ export type FeedEvents_200_Response = { items: Array>; totalCount: Scalars['Float']['output']; }; +export type GetAddress_200_Response = { + __typename?: 'getAddress_200_response'; + address: Scalars['String']['output']; + arkham?: Maybe; + ens?: Maybe; + isContract: Scalars['Boolean']['output']; +}; +export type GetAddresses_200_Response = { + __typename?: 'getAddresses_200_response'; + results: Array>; +}; export type GetDaoTokenTreasury_200_Response = { __typename?: 'getDaoTokenTreasury_200_response'; items: Array>; @@ -773,6 +794,7 @@ export declare enum QueryInput_AccountBalanceVariations_OrderDirection { } export declare enum QueryInput_AccountBalances_OrderBy { Balance = "balance", + SignedVariation = "signedVariation", Variation = "variation" } export declare enum QueryInput_AccountBalances_OrderDirection { @@ -1044,16 +1066,16 @@ export declare enum QueryInput_VotesByProposalId_OrderDirection { Desc = "desc" } export declare enum QueryInput_VotesOffchainByProposalId_OrderBy { - Created = "created", - Vp = "vp" + Timestamp = "timestamp", + VotingPower = "votingPower" } export declare enum QueryInput_VotesOffchainByProposalId_OrderDirection { Asc = "asc", Desc = "desc" } export declare enum QueryInput_VotesOffchain_OrderBy { - Created = "created", - Vp = "vp" + Timestamp = "timestamp", + VotingPower = "votingPower" } export declare enum QueryInput_VotesOffchain_OrderDirection { Asc = "asc", @@ -1073,6 +1095,7 @@ export declare enum QueryInput_VotingPowerVariations_OrderDirection { } export declare enum QueryInput_VotingPowers_OrderBy { DelegationsCount = "delegationsCount", + SignedVariation = "signedVariation", Variation = "variation", VotingPower = "votingPower" } @@ -1203,6 +1226,39 @@ export declare enum Query_FeedEvents_Items_Items_Type { Transfer = "TRANSFER", Vote = "VOTE" } +export type Query_GetAddress_Arkham = { + __typename?: 'query_getAddress_arkham'; + entity?: Maybe; + entityType?: Maybe; + label?: Maybe; + twitter?: Maybe; +}; +export type Query_GetAddress_Ens = { + __typename?: 'query_getAddress_ens'; + avatar?: Maybe; + banner?: Maybe; + name?: Maybe; +}; +export type Query_GetAddresses_Results_Items = { + __typename?: 'query_getAddresses_results_items'; + address: Scalars['String']['output']; + arkham?: Maybe; + ens?: Maybe; + isContract: Scalars['Boolean']['output']; +}; +export type Query_GetAddresses_Results_Items_Arkham = { + __typename?: 'query_getAddresses_results_items_arkham'; + entity?: Maybe; + entityType?: Maybe; + label?: Maybe; + twitter?: Maybe; +}; +export type Query_GetAddresses_Results_Items_Ens = { + __typename?: 'query_getAddresses_results_items_ens'; + avatar?: Maybe; + banner?: Maybe; + name?: Maybe; +}; export type Query_GetDaoTokenTreasury_Items_Items = { __typename?: 'query_getDaoTokenTreasury_items_items'; /** Unix timestamp in milliseconds */ @@ -1469,7 +1525,7 @@ export type Query_VotesOffchainByProposalId_Items_Items = { proposalTitle: Scalars['String']['output']; reason: Scalars['String']['output']; voter: Scalars['String']['output']; - vp: Scalars['Float']['output']; + vp?: Maybe; }; export type Query_VotesOffchain_Items_Items = { __typename?: 'query_votesOffchain_items_items'; @@ -1479,7 +1535,7 @@ export type Query_VotesOffchain_Items_Items = { proposalTitle: Scalars['String']['output']; reason: Scalars['String']['output']; voter: Scalars['String']['output']; - vp: Scalars['Float']['output']; + vp?: Maybe; }; export type Query_Votes_Items_Items = { __typename?: 'query_votes_items_items'; diff --git a/packages/anticapture-client/dist/gql/graphql.js b/packages/anticapture-client/dist/gql/graphql.js index 0040cc86..2dcff416 100644 --- a/packages/anticapture-client/dist/gql/graphql.js +++ b/packages/anticapture-client/dist/gql/graphql.js @@ -22,6 +22,7 @@ var QueryInput_AccountBalanceVariations_OrderDirection; var QueryInput_AccountBalances_OrderBy; (function (QueryInput_AccountBalances_OrderBy) { QueryInput_AccountBalances_OrderBy["Balance"] = "balance"; + QueryInput_AccountBalances_OrderBy["SignedVariation"] = "signedVariation"; QueryInput_AccountBalances_OrderBy["Variation"] = "variation"; })(QueryInput_AccountBalances_OrderBy || (exports.QueryInput_AccountBalances_OrderBy = QueryInput_AccountBalances_OrderBy = {})); var QueryInput_AccountBalances_OrderDirection; @@ -346,8 +347,8 @@ var QueryInput_VotesByProposalId_OrderDirection; })(QueryInput_VotesByProposalId_OrderDirection || (exports.QueryInput_VotesByProposalId_OrderDirection = QueryInput_VotesByProposalId_OrderDirection = {})); var QueryInput_VotesOffchainByProposalId_OrderBy; (function (QueryInput_VotesOffchainByProposalId_OrderBy) { - QueryInput_VotesOffchainByProposalId_OrderBy["Created"] = "created"; - QueryInput_VotesOffchainByProposalId_OrderBy["Vp"] = "vp"; + QueryInput_VotesOffchainByProposalId_OrderBy["Timestamp"] = "timestamp"; + QueryInput_VotesOffchainByProposalId_OrderBy["VotingPower"] = "votingPower"; })(QueryInput_VotesOffchainByProposalId_OrderBy || (exports.QueryInput_VotesOffchainByProposalId_OrderBy = QueryInput_VotesOffchainByProposalId_OrderBy = {})); var QueryInput_VotesOffchainByProposalId_OrderDirection; (function (QueryInput_VotesOffchainByProposalId_OrderDirection) { @@ -356,8 +357,8 @@ var QueryInput_VotesOffchainByProposalId_OrderDirection; })(QueryInput_VotesOffchainByProposalId_OrderDirection || (exports.QueryInput_VotesOffchainByProposalId_OrderDirection = QueryInput_VotesOffchainByProposalId_OrderDirection = {})); var QueryInput_VotesOffchain_OrderBy; (function (QueryInput_VotesOffchain_OrderBy) { - QueryInput_VotesOffchain_OrderBy["Created"] = "created"; - QueryInput_VotesOffchain_OrderBy["Vp"] = "vp"; + QueryInput_VotesOffchain_OrderBy["Timestamp"] = "timestamp"; + QueryInput_VotesOffchain_OrderBy["VotingPower"] = "votingPower"; })(QueryInput_VotesOffchain_OrderBy || (exports.QueryInput_VotesOffchain_OrderBy = QueryInput_VotesOffchain_OrderBy = {})); var QueryInput_VotesOffchain_OrderDirection; (function (QueryInput_VotesOffchain_OrderDirection) { @@ -382,6 +383,7 @@ var QueryInput_VotingPowerVariations_OrderDirection; var QueryInput_VotingPowers_OrderBy; (function (QueryInput_VotingPowers_OrderBy) { QueryInput_VotingPowers_OrderBy["DelegationsCount"] = "delegationsCount"; + QueryInput_VotingPowers_OrderBy["SignedVariation"] = "signedVariation"; QueryInput_VotingPowers_OrderBy["Variation"] = "variation"; QueryInput_VotingPowers_OrderBy["VotingPower"] = "votingPower"; })(QueryInput_VotingPowers_OrderBy || (exports.QueryInput_VotingPowers_OrderBy = QueryInput_VotingPowers_OrderBy = {})); diff --git a/packages/anticapture-client/dist/schemas.d.ts b/packages/anticapture-client/dist/schemas.d.ts index 63f6eccf..e553a4bf 100644 --- a/packages/anticapture-client/dist/schemas.d.ts +++ b/packages/anticapture-client/dist/schemas.d.ts @@ -586,18 +586,18 @@ export declare const OffchainProposalItemSchema: z.ZodObject<{ created: z.ZodNumber; }, "strip", z.ZodTypeAny, { link: string; - created: number; id: string; title: string; discussion: string; state: string; + created: number; }, { link: string; - created: number; id: string; title: string; discussion: string; state: string; + created: number; }>; export type OffchainProposalItem = z.infer; export declare const SafeOffchainProposalsResponseSchema: z.ZodEffects>, "many">; totalCount: z.ZodNumber; }, "strip", z.ZodTypeAny, { items: ({ link: string; - created: number; id: string; title: string; discussion: string; state: string; + created: number; } | null)[]; totalCount: number; }, { items: ({ link: string; - created: number; id: string; title: string; discussion: string; state: string; + created: number; } | null)[]; totalCount: number; }>>; @@ -650,11 +650,11 @@ export declare const SafeOffchainProposalsResponseSchema: z.ZodEffects Date: Fri, 6 Mar 2026 15:22:32 -0300 Subject: [PATCH 40/42] add: link to the offchain tests --- .../anticapture-client/tests/offchain-proposal.test.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/anticapture-client/tests/offchain-proposal.test.ts b/packages/anticapture-client/tests/offchain-proposal.test.ts index b4be4489..ad012b81 100644 --- a/packages/anticapture-client/tests/offchain-proposal.test.ts +++ b/packages/anticapture-client/tests/offchain-proposal.test.ts @@ -10,6 +10,7 @@ interface OffchainProposalStub { id: string; title: string; discussion: string; + link: string; state: string; created: number; } @@ -81,7 +82,7 @@ describe('listOffchainProposals', () => { server.use(handleGraphQL({ daos: [{ id: 'ENS' }], proposals: { - ENS: [{ id: 'snap-1', title: 'Test Proposal', discussion: 'https://forum.example.com', state: 'active', created: 1700000000 }], + ENS: [{ id: 'snap-1', title: 'Test Proposal', discussion: 'https://forum.example.com', link: 'https://snapshot.org/snap-1', state: 'active', created: 1700000000 }], }, })); @@ -96,8 +97,8 @@ describe('listOffchainProposals', () => { server.use(handleGraphQL({ daos: [{ id: 'DAO_A' }, { id: 'DAO_B' }], proposals: { - DAO_A: [{ id: 'snap-a', title: 'From A', discussion: '', state: 'active', created: 1700000100 }], - DAO_B: [{ id: 'snap-b', title: 'From B', discussion: '', state: 'pending', created: 1700000200 }], + DAO_A: [{ id: 'snap-a', title: 'From A', discussion: '', link: '', state: 'active', created: 1700000100 }], + DAO_B: [{ id: 'snap-b', title: 'From B', discussion: '', link: '', state: 'pending', created: 1700000200 }], }, })); @@ -112,7 +113,7 @@ describe('listOffchainProposals', () => { server.use(handleGraphQL({ daos: [{ id: 'OK_DAO' }, { id: 'BAD_DAO' }], proposals: { - OK_DAO: [{ id: 'snap-ok', title: 'OK', discussion: '', state: 'active', created: 1700000000 }], + OK_DAO: [{ id: 'snap-ok', title: 'OK', discussion: '', link: '', state: 'active', created: 1700000000 }], }, errors: { BAD_DAO: 'API exploded', From 4b163a1e1aa7e4c46e59c64adf8e17713111aba8 Mon Sep 17 00:00:00 2001 From: Leonardo Vieira Date: Fri, 6 Mar 2026 16:20:50 -0300 Subject: [PATCH 41/42] add: link on mock --- .../src/fixtures/factories/offchain-proposal-factory.ts | 2 ++ apps/integrated-tests/src/mocks/graphql-mock-setup.ts | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/integrated-tests/src/fixtures/factories/offchain-proposal-factory.ts b/apps/integrated-tests/src/fixtures/factories/offchain-proposal-factory.ts index 566fc370..a8a15b87 100644 --- a/apps/integrated-tests/src/fixtures/factories/offchain-proposal-factory.ts +++ b/apps/integrated-tests/src/fixtures/factories/offchain-proposal-factory.ts @@ -7,6 +7,7 @@ export interface OffchainProposalData { daoId: string; title: string; discussion: string; + link: string; state: string; created: number; } @@ -35,6 +36,7 @@ export class OffchainProposalFactory { daoId, title: `Test Snapshot Proposal ${proposalId}`, discussion: '', + link: '', state: 'active', created: futureTimestamp, ...overrides, diff --git a/apps/integrated-tests/src/mocks/graphql-mock-setup.ts b/apps/integrated-tests/src/mocks/graphql-mock-setup.ts index 3dac31fd..df44085a 100644 --- a/apps/integrated-tests/src/mocks/graphql-mock-setup.ts +++ b/apps/integrated-tests/src/mocks/graphql-mock-setup.ts @@ -79,7 +79,7 @@ export class GraphQLMockSetup { filtered = filtered.filter(p => p.daoId === config.headers['anticapture-dao-id']); } return Promise.resolve({ - data: { data: { offchainProposals: { items: filtered.map(p => ({ id: p.id, title: p.title, discussion: p.discussion, state: p.state, created: p.created })), totalCount: filtered.length } } } + data: { data: { offchainProposals: { items: filtered.map(p => ({ id: p.id, title: p.title, discussion: p.discussion, link: p.link, state: p.state, created: p.created })), totalCount: filtered.length } } } }); } From cc5a1d25ccdc17cef65ff71c5b80b42967c7be50 Mon Sep 17 00:00:00 2001 From: Leonardo Vieira Date: Mon, 9 Mar 2026 13:58:59 -0300 Subject: [PATCH 42/42] add: RPC_URL as an optional value for consumer --- AGENTS.md | 55 +++++++++++++++---- apps/consumers/src/config/env.ts | 2 + apps/consumers/src/index.ts | 2 +- .../src/services/ens-resolver.service.ts | 6 +- 4 files changed, 49 insertions(+), 16 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index ebccde2e..592c2e5e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -181,39 +181,68 @@ ALTER TABLE votes_onchain ENABLE TRIGGER ALL; ``` ### Voting Power Change Insert (Delegation Received) + +**Important:** The underlying tables are in a UUID schema (e.g. `ecbe454c-b8fe-4659-8864-4cc68148cfde`), not in `anticapture` (which has views). Find the correct schema via: `SELECT pg_get_viewdef('anticapture.voting_power_history', true);` + +**Critical:** Use a **fixed transaction hash** (not `extract(epoch from now())`) so both tables share the exact same value. The API joins `voting_power_history` with `delegations` on `transaction_hash`, and requires `delegation.log_index < voting_power_history.log_index`. If the join fails, `changeType` becomes `'other'`, which bypasses threshold filtering entirely. + ```sql -SET search_path TO ""; +SET search_path TO ""; ALTER TABLE voting_power_history DISABLE TRIGGER ALL; ALTER TABLE delegations DISABLE TRIGGER ALL; -INSERT INTO voting_power_history (transaction_hash, dao_id, account_id, voting_power, delta, delta_mod, timestamp, log_index) +-- Insert delegations FIRST with log_index = 0 +INSERT INTO delegations (transaction_hash, dao_id, delegate_account_id, delegator_account_id, delegated_value, previous_delegate, timestamp, log_index) VALUES ( - '0xmock_vp_' || extract(epoch from now())::bigint, + '0xmock_vp_test', 'ENS', '', - 5000000000000000000, - 1000000000000000000, + '0x1111111111111111111111111111111111111111', 1000000000000000000, + '0x0000000000000000000000000000000000000000', extract(epoch from now())::bigint, - 1 + 0 -- must be < voting_power_history.log_index ); -INSERT INTO delegations (transaction_hash, dao_id, delegate_account_id, delegator_account_id, delegated_value, previous_delegate, timestamp, log_index) +-- Then insert voting_power_history with log_index = 1 +INSERT INTO voting_power_history (transaction_hash, dao_id, account_id, voting_power, delta, delta_mod, timestamp, log_index) VALUES ( - '0xmock_vp_' || extract(epoch from now())::bigint, + '0xmock_vp_test', 'ENS', '', - '0x1111111111111111111111111111111111111111', + 5000000000000000000, + 1000000000000000000, 1000000000000000000, - '0x0000000000000000000000000000000000000000', extract(epoch from now())::bigint, - 1 + 1 -- must be > delegation.log_index ); ALTER TABLE voting_power_history ENABLE TRIGGER ALL; ALTER TABLE delegations ENABLE TRIGGER ALL; ``` +### New Offchain Proposal Insert (Snapshot) +```sql +-- No triggers on snapshot.proposals, safe to insert directly +INSERT INTO snapshot.proposals (id, space_id, author, title, body, discussion, type, start, "end", state, created, updated, link, flagged) +VALUES ( + '0xmock_offchain_' || extract(epoch from now())::bigint, + 'ens.eth', + '0x1111111111111111111111111111111111111111', + '[MOCK] Test Offchain Proposal for Notification System', + 'This is a mock offchain proposal inserted for testing the notification pipeline.', + '', -- e.g. https://discuss.ens.domains/t/... + 'single-choice', + extract(epoch from now())::integer, + (extract(epoch from now()) + 604800)::integer, -- ends in 7 days + 'active', + extract(epoch from now())::integer, + extract(epoch from now())::integer, + '', -- copy from: SELECT link FROM snapshot.proposals ORDER BY created DESC LIMIT 5 + false +); +``` + ### Cleanup Mock Data ```sql SET search_path TO ""; @@ -224,6 +253,7 @@ ALTER TABLE delegations DISABLE TRIGGER ALL; DELETE FROM votes_onchain WHERE tx_hash LIKE '0xmock%'; DELETE FROM voting_power_history WHERE transaction_hash LIKE '0xmock%'; DELETE FROM delegations WHERE transaction_hash LIKE '0xmock%'; +DELETE FROM snapshot.proposals WHERE id LIKE '0xmock%'; ALTER TABLE votes_onchain ENABLE TRIGGER ALL; ALTER TABLE voting_power_history ENABLE TRIGGER ALL; @@ -241,5 +271,6 @@ SELECT v.* FROM votes_onchain v LEFT JOIN proposals_onchain p ON v.proposal_id = -- List mock records SELECT 'VOTE' as type, tx_hash, timestamp FROM votes_onchain WHERE tx_hash LIKE '0xmock%' UNION ALL SELECT 'VP', transaction_hash, timestamp FROM voting_power_history WHERE transaction_hash LIKE '0xmock%' -UNION ALL SELECT 'DELEG', transaction_hash, timestamp FROM delegations WHERE transaction_hash LIKE '0xmock%'; +UNION ALL SELECT 'DELEG', transaction_hash, timestamp FROM delegations WHERE transaction_hash LIKE '0xmock%' +UNION ALL SELECT 'OFFCHAIN', id, created FROM snapshot.proposals WHERE id LIKE '0xmock%'; ``` diff --git a/apps/consumers/src/config/env.ts b/apps/consumers/src/config/env.ts index 361d9f30..4369b93e 100644 --- a/apps/consumers/src/config/env.ts +++ b/apps/consumers/src/config/env.ts @@ -14,6 +14,7 @@ const envSchema = z.object({ SUBSCRIPTION_SERVER_URL: z.string(), RABBITMQ_URL: z.string().url(), PORT: z.coerce.number().positive().optional().default(3002), + RPC_URL: z.string().optional(), }); export function loadConfig() { @@ -29,5 +30,6 @@ export function loadConfig() { subscriptionServerUrl: env.SUBSCRIPTION_SERVER_URL, rabbitmqUrl: env.RABBITMQ_URL, port: env.PORT, + rpcUrl: env.RPC_URL } as const; } \ No newline at end of file diff --git a/apps/consumers/src/index.ts b/apps/consumers/src/index.ts index 296a5920..24331e46 100644 --- a/apps/consumers/src/index.ts +++ b/apps/consumers/src/index.ts @@ -19,7 +19,7 @@ import { SlackClient } from './clients/slack.client'; const config = loadConfig(); // Create ENS resolver -const ensResolver = new EnsResolverService(); +const ensResolver = new EnsResolverService(config.rpcUrl); // Create Telegram client for production const telegramClient = new TelegramClient(config.telegramBotToken); diff --git a/apps/consumers/src/services/ens-resolver.service.ts b/apps/consumers/src/services/ens-resolver.service.ts index a40fe7af..02055b7b 100644 --- a/apps/consumers/src/services/ens-resolver.service.ts +++ b/apps/consumers/src/services/ens-resolver.service.ts @@ -10,12 +10,12 @@ import { normalize } from 'viem/ens'; export class EnsResolverService { private client; - constructor() { + constructor(rpcUrl?: string) { this.client = createPublicClient({ chain: mainnet, - transport: http(undefined, { + transport: http(rpcUrl, { timeout: 5_000, // 5 seconds timeout - retryCount: 10, // Try 10 times + retryCount: 3, // Try 3 times retryDelay: 500 // Wait 500ms between retries }) });